void rtalloc_mpath_fib(struct route *ro, uint32_t hash, u_int fibnum) { struct radix_node *rn0, *rn; u_int32_t n; struct rtentry *rt; int64_t weight; /* * XXX we don't attempt to lookup cached route again; what should * be done for sendto(3) case? */ if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP) && RT_LINK_IS_UP(ro->ro_rt->rt_ifp)) return; ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, 0, fibnum); /* if the route does not exist or it is not multipath, don't care */ if (ro->ro_rt == NULL) return; if (rn_mpath_next((struct radix_node *)ro->ro_rt) == NULL) { RT_UNLOCK(ro->ro_rt); return; } /* beyond here, we use rn as the master copy */ rn0 = rn = (struct radix_node *)ro->ro_rt; n = rn_mpath_count(rn0); /* gw selection by Modulo-N Hash (RFC2991) XXX need improvement? */ hash += hashjitter; hash %= n; for (weight = abs((int32_t)hash), rt = ro->ro_rt; weight >= rt->rt_weight && rn; weight -= rt->rt_weight) { /* stay within the multipath routes */ if (rn->rn_dupedkey && rn->rn_mask != rn->rn_dupedkey->rn_mask) break; rn = rn->rn_dupedkey; rt = (struct rtentry *)rn; } /* XXX try filling rt_gwroute and avoid unreachable gw */ /* gw selection has failed - there must be only zero weight routes */ if (!rn) { RT_UNLOCK(ro->ro_rt); ro->ro_rt = NULL; return; } if (ro->ro_rt != rt) { RTFREE_LOCKED(ro->ro_rt); ro->ro_rt = (struct rtentry *)rn; RT_LOCK(ro->ro_rt); RT_ADDREF(ro->ro_rt); } RT_UNLOCK(ro->ro_rt); }
void rtalloc_mpath_fib(struct route *ro, uint32_t hash, u_int fibnum) { struct rtentry *rt; /* * XXX we don't attempt to lookup cached route again; what should * be done for sendto(3) case? */ if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP) && RT_LINK_IS_UP(ro->ro_rt->rt_ifp)) return; ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, 0, fibnum); /* if the route does not exist or it is not multipath, don't care */ if (ro->ro_rt == NULL) return; if (rn_mpath_next((struct radix_node *)ro->ro_rt) == NULL) { RT_UNLOCK(ro->ro_rt); return; } rt = rt_mpath_selectrte(ro->ro_rt, hash); /* XXX try filling rt_gwroute and avoid unreachable gw */ /* gw selection has failed - there must be only zero weight routes */ if (!rt) { RT_UNLOCK(ro->ro_rt); ro->ro_rt = NULL; return; } if (ro->ro_rt != rt) { RTFREE_LOCKED(ro->ro_rt); ro->ro_rt = rt; RT_LOCK(ro->ro_rt); RT_ADDREF(ro->ro_rt); } RT_UNLOCK(ro->ro_rt); }
struct rtentry * in6_rtalloc1(struct sockaddr *dst, int report, u_long ignflags, u_int fibnum) { return (rtalloc1_fib(dst, report, ignflags, fibnum)); }
/* * Accept by socket(4) in AF_ROUTE received service requests. * * o RTAX_DST holds key x for fec = < x, nh > where nh -> ifp * * o RTAX_GATEWAY holds by sockaddr_ftn{} for MPLS label * binding necessary * * < seg_i , seg_j > * * tuple where seg_i denotes key for by nhlfe generated ilm, * Furthermore, seg_j denotes typically upstream label for * transmission downstream by interface ifp in link-layer. * * o In rt_addrinfo{} Service Primitive (spi) contained flags * encodes with MPLS label binding linked operation. * * RTF_{POP|PUSH|SWAP} - self expanatory. * * RTF_MPE, denotes initial label of Label Switch Path. * * RTF_STK, denotes label stacking, but not yet fully * implemented. */ int mpls_rt_output_fib(struct rt_msghdr *rtm, struct rt_addrinfo *rti, struct rtentry **rt, u_int fibnum) { struct rtentry *fec = NULL; struct ifnet *ifp = NULL; struct mpls_aliasreq ifra; int error = 0, cmd = 0; #ifdef MPLS_DEBUG (void)printf("%s\n", __func__); #endif /* MPLS_DEBUG */ if (rti_dst(rti)->sa_len > sizeof(ifra.ifra_x)) { log(LOG_INFO, "%s: destination x in fec invalid\n", __func__); error = EMSGSIZE; goto out; } if (rti_gateway(rti)->sa_family != AF_MPLS) { log(LOG_INFO, "%s: segment invalid\n", __func__); error = EINVAL; goto out; } if (rti_gateway(rti)->sa_len > sizeof(ifra.ifra_seg)) { log(LOG_INFO, "%s: segment invalid\n", __func__); error = EMSGSIZE; goto out; } /* * Fetch interface by Forward Equivalence Class (fec). */ fec = rtalloc1_fib(rti_dst(rti), 0, 0UL, fibnum); if ((fec == NULL) || (fec->rt_gateway == NULL) || ((ifp = fec->rt_ifp) == NULL) || (fec->rt_ifa == NULL) || ((fec->rt_flags & RTF_UP) == 0)) { error = ESRCH; goto out; } bzero(&ifra, sizeof(ifra)); bcopy(rti_dst(rti), &ifra.ifra_x, rti_dst(rti)->sa_len); switch ((int)rtm->rtm_type) { case RTM_ADD: /* * Apply MPLS label binding on Forward Equivalence Class (fec). */ cmd = SIOCAIFADDR; /* FALLTHROUGH */ case RTM_DELETE: /* * Delete MPLS label binding on fec. */ cmd = (cmd == 0) ? SIOCDIFADDR : cmd; /* * Perform MPLS control operations on interface-layer. */ bcopy(rti_gateway(rti), &ifra.ifra_seg, rti_gateway(rti)->sa_len); ifra.ifra_flags = rti_flags(rti); RT_UNLOCK(fec); error = mpls_control(NULL, cmd, (caddr_t)&ifra, ifp, NULL); RT_LOCK(fec); break; case RTM_GET: /* * XXX: looks ugly... I'll delegate this operation * XXX: back to rt_output, but I'm not yet sure, if * XXX: I'll should do that... */ ifra.ifra_seg.sftn_len = SMPLS_LEN; ifra.ifra_seg.sftn_family = AF_MPLS; ((struct sockaddr_mpls *)&ifra.ifra_seg)->smpls_label = satosmpls_label(rti_gateway(rti)); /* * Fetch Incoming Label Map (ilm) by MPLS label binding on fec. */ *rt = ((ifra.ifra_flags & RTF_MPE) == 0) ? rtalloc1_fib((struct sockaddr *)&ifra.ifra_seg, 0, 0UL, ifp->if_fib) : NULL; if (*rt != NULL) { /* * Update by socket(2) on route(4) used Service Data Unit (sdu). */ bcopy(rt_key(*rt), rti_dst(rti), rt_key(*rt)->sa_len); bcopy((*rt)->rt_gateway, rti_gateway(rti), (*rt)->rt_gateway->sa_len); } else error = EADDRNOTAVAIL; break; default: log(LOG_INFO, "%s: command invalid\n", __func__); error = EOPNOTSUPP; break; } out: if (fec != NULL) RTFREE_LOCKED(fec); return (error); }