Changeset View
Standalone View
sys/net/route.c
Show First 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | |||||
SYSCTL_PROC(_net, OID_AUTO, my_fibnum, CTLTYPE_INT|CTLFLAG_RD, | SYSCTL_PROC(_net, OID_AUTO, my_fibnum, CTLTYPE_INT|CTLFLAG_RD, | ||||
NULL, 0, &sysctl_my_fibnum, "I", "default FIB of caller"); | NULL, 0, &sysctl_my_fibnum, "I", "default FIB of caller"); | ||||
static __inline struct rib_head ** | static __inline struct rib_head ** | ||||
rt_tables_get_rnh_ptr(int table, int fam) | rt_tables_get_rnh_ptr(int table, int fam) | ||||
{ | { | ||||
struct rib_head **rnh; | struct rib_head **rnh; | ||||
KASSERT(table >= 0 && table < rt_numfibs, ("%s: table out of bounds.", | KASSERT(table >= 0 && table < rt_numfibs, | ||||
__func__)); | ("%s: table out of bounds (0 <= %d < %d)", __func__, table, | ||||
bz: If you don't break up the first line, the KASSERT will still fit on two lines. | |||||
Done Inline ActionsShouldn't it be 0 <= %d < %d? bz: Shouldn't it be 0 <= %d < %d? | |||||
KASSERT(fam >= 0 && fam < (AF_MAX+1), ("%s: fam out of bounds.", | rt_numfibs)); | ||||
__func__)); | KASSERT(fam >= 0 && fam < (AF_MAX + 1), | ||||
("%s: fam out of bounds (0 <= %d < %d)", __func__, fam, AF_MAX+1)); | |||||
Done Inline ActionsAnd here as well: 0 <= .. bz: And here as well: 0 <= .. | |||||
/* rnh is [fib=0][af=0]. */ | /* rnh is [fib=0][af=0]. */ | ||||
rnh = (struct rib_head **)V_rt_tables; | rnh = (struct rib_head **)V_rt_tables; | ||||
/* Get the offset to the requested table and fam. */ | /* Get the offset to the requested table and fam. */ | ||||
rnh += table * (AF_MAX+1) + fam; | rnh += table * (AF_MAX+1) + fam; | ||||
return (rnh); | return (rnh); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | rt_table_init(int offset, int family, u_int fibnum) | ||||
/* Save metadata associated with this routing table. */ | /* Save metadata associated with this routing table. */ | ||||
rh->rib_family = family; | rh->rib_family = family; | ||||
rh->rib_fibnum = fibnum; | rh->rib_fibnum = fibnum; | ||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
rh->rib_vnet = curvnet; | rh->rib_vnet = curvnet; | ||||
#endif | #endif | ||||
tmproutes_init(rh); | |||||
/* Init locks */ | /* Init locks */ | ||||
RIB_LOCK_INIT(rh); | RIB_LOCK_INIT(rh); | ||||
/* Finally, set base callbacks */ | /* Finally, set base callbacks */ | ||||
rh->rnh_addaddr = rn_addroute; | rh->rnh_addaddr = rn_addroute; | ||||
rh->rnh_deladdr = rn_delete; | rh->rnh_deladdr = rn_delete; | ||||
rh->rnh_matchaddr = rn_match; | rh->rnh_matchaddr = rn_match; | ||||
rh->rnh_lookup = rn_lookup; | rh->rnh_lookup = rn_lookup; | ||||
Show All 14 Lines | if (x != NULL) | ||||
R_Free(x); | R_Free(x); | ||||
return (0); | return (0); | ||||
} | } | ||||
void | void | ||||
rt_table_destroy(struct rib_head *rh) | rt_table_destroy(struct rib_head *rh) | ||||
{ | { | ||||
tmproutes_destroy(rh); | |||||
rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head); | rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head); | ||||
/* Assume table is already empty */ | /* Assume table is already empty */ | ||||
RIB_LOCK_DESTROY(rh); | RIB_LOCK_DESTROY(rh); | ||||
free(rh, M_RTABLE); | free(rh, M_RTABLE); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 174 Lines • ▼ Show 20 Lines | #endif | ||||
*/ | */ | ||||
uma_zfree(V_rtzone, rt); | uma_zfree(V_rtzone, rt); | ||||
return; | return; | ||||
} | } | ||||
done: | done: | ||||
RT_UNLOCK(rt); | RT_UNLOCK(rt); | ||||
} | } | ||||
/* | /* | ||||
* Force a routing table entry to the specified | * Adds a temporal redirect entry to the routing table. | ||||
* destination to go through the given gateway. | * @fibnum: fib number | ||||
* Normally called as a result of a routing redirect | * @dst: destination to install redirect to | ||||
* message from the network layer. | * @gateway: gateway to go via | ||||
* @author: sockaddr of originating router, can be NULL | |||||
* @ifp: interface to use for the redirected route | |||||
* @flags: set of flags to add. Allowed: RTF_GATEWAY | |||||
* @lifetime_sec: time in seconds to expire this redirect. | |||||
* | |||||
* Retuns 0 on success, errno otherwise. | |||||
*/ | */ | ||||
void | int | ||||
rtredirect_fib(struct sockaddr *dst, | rib_add_redirect(u_int fibnum, struct sockaddr *dst, struct sockaddr *gateway, | ||||
struct sockaddr *gateway, | struct sockaddr *author, struct ifnet *ifp, int flags, int lifetime_sec) | ||||
struct sockaddr *netmask, | |||||
int flags, | |||||
struct sockaddr *src, | |||||
u_int fibnum) | |||||
{ | { | ||||
struct rtentry *rt; | struct rtentry *rt; | ||||
int error = 0; | int error; | ||||
struct rt_addrinfo info; | struct rt_addrinfo info; | ||||
struct rt_metrics rti_rmx; | |||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
struct rib_head *rnh; | |||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
ifa = NULL; | if (rt_tables_get_rnh(fibnum, dst->sa_family) == NULL) | ||||
rnh = rt_tables_get_rnh(fibnum, dst->sa_family); | return (EAFNOSUPPORT); | ||||
if (rnh == NULL) { | |||||
error = EAFNOSUPPORT; | |||||
goto out; | |||||
} | |||||
/* verify the gateway is directly reachable */ | |||||
if ((ifa = ifa_ifwithnet(gateway, 0, fibnum)) == NULL) { | |||||
error = ENETUNREACH; | |||||
goto out; | |||||
} | |||||
rt = rtalloc1_fib(dst, 0, 0UL, fibnum); /* NB: rt is locked */ | |||||
/* | |||||
* If the redirect isn't from our current router for this dst, | |||||
* it's either old or wrong. If it redirects us to ourselves, | |||||
* we have a routing loop, perhaps as a result of an interface | |||||
* going down recently. | |||||
*/ | |||||
if (!(flags & RTF_DONE) && rt) { | |||||
if (!sa_equal(src, rt->rt_gateway)) { | |||||
error = EINVAL; | |||||
goto done; | |||||
} | |||||
if (rt->rt_ifa != ifa && ifa->ifa_addr->sa_family != AF_LINK) { | |||||
error = EINVAL; | |||||
goto done; | |||||
} | |||||
} | |||||
if ((flags & RTF_GATEWAY) && ifa_ifwithaddr_check(gateway)) { | |||||
error = EHOSTUNREACH; | |||||
goto done; | |||||
} | |||||
/* | |||||
* Create a new entry if we just got back a wildcard entry | |||||
* or the lookup failed. This is necessary for hosts | |||||
* which use routing redirects generated by smart gateways | |||||
* to dynamically build the routing tables. | |||||
*/ | |||||
if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) | |||||
goto create; | |||||
/* | |||||
* Don't listen to the redirect if it's | |||||
* for a route to an interface. | |||||
*/ | |||||
if (rt->rt_flags & RTF_GATEWAY) { | |||||
if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) { | |||||
/* | |||||
* Changing from route to net => route to host. | |||||
* Create new route, rather than smashing route to net. | |||||
*/ | |||||
create: | |||||
if (rt != NULL) | |||||
RTFREE_LOCKED(rt); | |||||
flags |= RTF_DYNAMIC; | /* Verify the allowed flag mask. */ | ||||
bzero((caddr_t)&info, sizeof(info)); | KASSERT(((flags & ~(RTF_GATEWAY)) == 0), | ||||
("invalid redirect flags: %x", flags)); | |||||
/* Get the best ifa for the given interface and gateway. */ | |||||
if ((ifa = ifaof_ifpforaddr(gateway, ifp)) == NULL) | |||||
return (ENETUNREACH); | |||||
ifa_ref(ifa); | |||||
bzero(&info, sizeof(info)); | |||||
info.rti_info[RTAX_DST] = dst; | info.rti_info[RTAX_DST] = dst; | ||||
info.rti_info[RTAX_GATEWAY] = gateway; | info.rti_info[RTAX_GATEWAY] = gateway; | ||||
info.rti_info[RTAX_NETMASK] = netmask; | |||||
ifa_ref(ifa); | |||||
info.rti_ifa = ifa; | info.rti_ifa = ifa; | ||||
info.rti_flags = flags; | info.rti_ifp = ifp; | ||||
info.rti_flags = flags | RTF_DYNAMIC; | |||||
/* Setup route metrics to define expire time. */ | |||||
bzero(&rti_rmx, sizeof(rti_rmx)); | |||||
/* Set expire time as absolute. */ | |||||
rti_rmx.rmx_expire = lifetime_sec + time_second; | |||||
info.rti_mflags |= RTV_EXPIRE; | |||||
info.rti_rmx = &rti_rmx; | |||||
error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); | error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum); | ||||
if (rt != NULL) { | ifa_free(ifa); | ||||
RT_LOCK(rt); | |||||
flags = rt->rt_flags; | if (error != 0) { | ||||
/* TODO: add per-fib redirect stats. */ | |||||
return (error); | |||||
} | } | ||||
if (error == 0) | |||||
RTSTAT_INC(rts_dynamic); | |||||
} else { | |||||
Not Done Inline ActionsWhile changing the code, can we start the comment upper case and end in a '.' as well? One the other hand, these checks violate RFC 4861 I think? (Haven't checked if there is a specified behaviour for IPv4) A host MUST NOT consider a redirect invalid just because the Target Address of the redirect is not covered under one of the link's prefixes. Part of the semantics of the Redirect message is that the Target Address is on-link. Given we are currently not prepared to add an interface route to my understanding, /* XXX-BZ RFC 4861 8.1 does not mandate this check. */ and fix it later (unless you do want to fix it as well, but I fear that will require more code changes which are better done in a follow-up? bz: While changing the code, can we start the comment upper case and end in a '.' as well?
One… | |||||
Done Inline Actions
IMHO It does not strictly violate RFC 4861. 8.1 indeed requires calling the message "valid redirect", while 8.3 suggest that A host receiving a valid redirect SHOULD update its Destination Cache accordingly so that subsequent traffic goes to the specified target. and not honouring SHOULD is not exactly a violation. I'd certainly prefer the scope of this review to be limited to bringing back generic functionality, relying on existing verifications and fixing the message processing parts as a separate changes. I'll add the comment on the RFC compliance' However, looking further for the way suggested by the RFC: if we have global unicast IP as destination (IP1) and GU ip as a target (IP2),
Do we want to? melifaro: > One the other hand, these checks violate RFC 4861 I think?
IMHO It does not strictly violate… | |||||
Done Inline ActionsWas looking into the code once again - we have most of the checks in the icmp6_redirect_input() and they are different (in the details) between IPv4 and IPv6. Maybe it would be better to move the most existing verification to IPv4 code, like "icmp_redirect_input()" and making ipv6 codepath not making some of the checks twice. melifaro: Was looking into the code once again - we have most of the checks in the `icmp6_redirect_input… | |||||
Not Done Inline ActionsSounds good to me as well. bz: Sounds good to me as well. | |||||
/* | |||||
* Smash the current notion of the gateway to | |||||
* this destination. Should check about netmask!!! | |||||
*/ | |||||
if ((flags & RTF_GATEWAY) == 0) | |||||
rt->rt_flags &= ~RTF_GATEWAY; | |||||
rt->rt_flags |= RTF_MODIFIED; | |||||
flags |= RTF_MODIFIED; | |||||
RTSTAT_INC(rts_newgateway); | |||||
/* | |||||
* add the key and gateway (in one malloc'd chunk). | |||||
*/ | |||||
RT_UNLOCK(rt); | |||||
RIB_WLOCK(rnh); | |||||
RT_LOCK(rt); | RT_LOCK(rt); | ||||
Done Inline Actions'.' at the end of comment. bz: '.' at the end of comment. | |||||
Not Done Inline ActionsHmm... I wonder if that should be done for other errors as well? bz: Hmm... I wonder if that should be done for other errors as well? | |||||
Done Inline ActionsI guess more granular statistics is needed. I'd prefer to deal with it as a separate change. melifaro: I guess more granular statistics is needed. I'd prefer to deal with it as a separate change. | |||||
rt_setgate(rt, rt_key(rt), gateway); | flags = rt->rt_flags; | ||||
Done Inline ActionsI keep wondering if I'd swap the two last checks with the first (currently) if (rt != NULL) block and do the flags checks before comparing addresses? bz: I keep wondering if I'd swap the two last checks with the first (currently) if (rt != NULL)… | |||||
RIB_WUNLOCK(rnh); | |||||
} | |||||
} else | |||||
error = EHOSTUNREACH; | |||||
done: | |||||
if (rt) | |||||
RTFREE_LOCKED(rt); | RTFREE_LOCKED(rt); | ||||
out: | |||||
if (error) | RTSTAT_INC(rts_dynamic); | ||||
RTSTAT_INC(rts_badredirect); | |||||
bzero((caddr_t)&info, sizeof(info)); | /* Send notification of a route addition to userland. */ | ||||
Done Inline ActionsIf rt is NULL we don't do anything up to the end and there we (a) call RTFREE_LOCKED() and will have a NULL pointer deref and then (b) return (0); bz: If rt is NULL we don't do anything up to the end and there we (a) call RTFREE_LOCKED() and will… | |||||
bzero(&info, sizeof(info)); | |||||
info.rti_info[RTAX_DST] = dst; | info.rti_info[RTAX_DST] = dst; | ||||
info.rti_info[RTAX_GATEWAY] = gateway; | info.rti_info[RTAX_GATEWAY] = gateway; | ||||
info.rti_info[RTAX_NETMASK] = netmask; | info.rti_info[RTAX_AUTHOR] = author; | ||||
info.rti_info[RTAX_AUTHOR] = src; | |||||
rt_missmsg_fib(RTM_REDIRECT, &info, flags, error, fibnum); | rt_missmsg_fib(RTM_REDIRECT, &info, flags, error, fibnum); | ||||
Done Inline ActionsThe comment could be re-wrapped to three lines. bz: The comment could be re-wrapped to three lines. | |||||
return (0); | |||||
} | } | ||||
Done Inline ActionsIndentation looks too much here. And as mentioned for the declaration I think the argument order should change? bz: Indentation looks too much here.
And as mentioned for the declaration I think the argument… | |||||
/* | /* | ||||
* Routing table ioctl interface. | * Routing table ioctl interface. | ||||
*/ | */ | ||||
Done Inline ActionsPlease don't assign values in variable declaration. Set it after NET_EPOCH_ASSERT() maybe. bz: Please don't assign values in variable declaration. Set it after NET_EPOCH_ASSERT() maybe. | |||||
int | int | ||||
rtioctl_fib(u_long req, caddr_t data, u_int fibnum) | rtioctl_fib(u_long req, caddr_t data, u_int fibnum) | ||||
{ | { | ||||
/* | /* | ||||
* If more ioctl commands are added here, make sure the proper | * If more ioctl commands are added here, make sure the proper | ||||
* super-user checks are being performed because it is possible for | * super-user checks are being performed because it is possible for | ||||
* prison-root to make it this far if raw sockets have been enabled | * prison-root to make it this far if raw sockets have been enabled | ||||
Done Inline Actionserror is 0 here? bz: error is 0 here? | |||||
* in jails. | * in jails. | ||||
*/ | */ | ||||
#ifdef INET | #ifdef INET | ||||
/* Multicast goop, grrr... */ | /* Multicast goop, grrr... */ | ||||
return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP; | return mrt_ioctl ? mrt_ioctl(req, data, fibnum) : EOPNOTSUPP; | ||||
#else /* INET */ | #else /* INET */ | ||||
Done Inline ActionsComments start with upper case and end in punctuation. bz: Comments start with upper case and end in punctuation. | |||||
return ENXIO; | return ENXIO; | ||||
#endif /* INET */ | #endif /* INET */ | ||||
Not Done Inline ActionsThis is the same "on-link" vs. prefix issue as in the previous function, right? We should add another comment here? bz: This is the same "on-link" vs. prefix issue as in the previous function, right? We should add… | |||||
} | } | ||||
struct ifaddr * | struct ifaddr * | ||||
ifa_ifwithroute(int flags, const struct sockaddr *dst, struct sockaddr *gateway, | ifa_ifwithroute(int flags, const struct sockaddr *dst, struct sockaddr *gateway, | ||||
u_int fibnum) | u_int fibnum) | ||||
{ | { | ||||
struct ifaddr *ifa; | struct ifaddr *ifa; | ||||
int not_found = 0; | int not_found = 0; | ||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
if ((flags & RTF_GATEWAY) == 0) { | if ((flags & RTF_GATEWAY) == 0) { | ||||
Done Inline Actions'.' at the end. bz: '.' at the end. | |||||
/* | /* | ||||
* If we are adding a route to an interface, | * If we are adding a route to an interface, | ||||
Done Inline Actions'.' at the end. bz: '.' at the end. | |||||
* and the interface is a pt to pt link | * and the interface is a pt to pt link | ||||
Not Done Inline ActionsI think time_second + "expire_sec"; would read better. I am still confused if this is "expire_sec" or actually "lifetime" as it seems to be the lifetime of the redirect whereas rmx_expire then indeed is the "second in which to expire this entry". bz: I think time_second + "expire_sec"; would read better. I am still confused if this is… | |||||
Done Inline Actions
Certainly!
Would like to indicate the unit as well, are you okay with lifetime_sec? melifaro: > I think time_second + "expire_sec"; would read better.
Certainly!
> I am still confused if… | |||||
Done Inline Actionslifetime_sec is great! bz: lifetime_sec is great! | |||||
* we should search for the destination | * we should search for the destination | ||||
* as our clue to the interface. Otherwise | * as our clue to the interface. Otherwise | ||||
* we can use the local address. | * we can use the local address. | ||||
*/ | */ | ||||
ifa = NULL; | ifa = NULL; | ||||
if (flags & RTF_HOST) | if (flags & RTF_HOST) | ||||
ifa = ifa_ifwithdstaddr(dst, fibnum); | ifa = ifa_ifwithdstaddr(dst, fibnum); | ||||
if (ifa == NULL) | if (ifa == NULL) | ||||
▲ Show 20 Lines • Show All 297 Lines • ▼ Show 20 Lines | rt_checkdelroute(struct radix_node *rn, void *arg) | ||||
/* Entry was unlinked. Add to the list and return */ | /* Entry was unlinked. Add to the list and return */ | ||||
rt->rt_chain = di->head; | rt->rt_chain = di->head; | ||||
di->head = rt; | di->head = rt; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Iterates over all existing fibs in system. | * Iterates over a routing table specified by @fibnum and @family and | ||||
Done Inline ActionsIterates over a routing table specified by @fibnum and @family and deletes elements marked by @filter_f. (replacing rtable, fixinf af argument name, removing white space on 2nd line). bz: Iterates over a routing table specified by @fibnum and @family and
deletes elements… | |||||
Done Inline Actions, "it " iterates .. in "the " particular .. bz: , "it " iterates .. in "the " particular .. | |||||
Done Inline ActionsCould be one sentence with an 'and'. also "returns a" not "returned" maybe? bz: Could be one sentence with an 'and'. also "returns a" not "returned" maybe? | |||||
* Deletes each element for which @filter_f function returned | * deletes elements marked by @filter_f. | ||||
* non-zero value. | * @fibnum: rtable id | ||||
* If @af is not AF_UNSPEC, iterates over fibs in particular | * @family: AF_ address family | ||||
* address family. | * @filter_f: function returning non-zero value for items to delete | ||||
* @arg: data to pass to the @filter_f function | |||||
Done Inline Actionsremove "the" or add "function" at the end. bz: remove "the" or add "function" at the end. | |||||
* @report: true if rtsock notification is needed. | |||||
Done Inline ActionsThen it could almost be a bool instead of int? bz: Then it could almost be a bool instead of int? | |||||
*/ | */ | ||||
void | void | ||||
rt_foreach_fib_walk_del(int af, rt_filter_f_t *filter_f, void *arg) | rib_walk_del(u_int fibnum, int family, rt_filter_f_t *filter_f, void *arg, bool report) | ||||
{ | { | ||||
struct rib_head *rnh; | struct rib_head *rnh; | ||||
struct rt_delinfo di; | struct rt_delinfo di; | ||||
struct rtentry *rt; | struct rtentry *rt; | ||||
uint32_t fibnum; | |||||
int i, start, end; | |||||
Done Inline Actionsu_int fibnum? bz: u_int fibnum? | |||||
rnh = rt_tables_get_rnh(fibnum, family); | |||||
if (rnh == NULL) | |||||
return; | |||||
bzero(&di, sizeof(di)); | bzero(&di, sizeof(di)); | ||||
di.info.rti_filter = filter_f; | di.info.rti_filter = filter_f; | ||||
di.info.rti_filterdata = arg; | di.info.rti_filterdata = arg; | ||||
for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { | |||||
/* Do we want some specific family? */ | |||||
if (af != AF_UNSPEC) { | |||||
start = af; | |||||
end = af; | |||||
} else { | |||||
start = 1; | |||||
end = AF_MAX; | |||||
} | |||||
for (i = start; i <= end; i++) { | |||||
rnh = rt_tables_get_rnh(fibnum, i); | |||||
if (rnh == NULL) | |||||
continue; | |||||
di.rnh = rnh; | di.rnh = rnh; | ||||
RIB_WLOCK(rnh); | RIB_WLOCK(rnh); | ||||
rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di); | rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di); | ||||
RIB_WUNLOCK(rnh); | RIB_WUNLOCK(rnh); | ||||
if (di.head == NULL) | if (di.head == NULL) | ||||
continue; | return; | ||||
/* We might have something to reclaim */ | /* We might have something to reclaim. */ | ||||
Done Inline Actions'.' at the end. bz: '.' at the end. | |||||
while (di.head != NULL) { | while (di.head != NULL) { | ||||
rt = di.head; | rt = di.head; | ||||
di.head = rt->rt_chain; | di.head = rt->rt_chain; | ||||
rt->rt_chain = NULL; | rt->rt_chain = NULL; | ||||
/* TODO std rt -> rt_addrinfo export */ | /* TODO std rt -> rt_addrinfo export */ | ||||
di.info.rti_info[RTAX_DST] = rt_key(rt); | di.info.rti_info[RTAX_DST] = rt_key(rt); | ||||
di.info.rti_info[RTAX_NETMASK] = rt_mask(rt); | di.info.rti_info[RTAX_NETMASK] = rt_mask(rt); | ||||
rt_notifydelete(rt, &di.info); | rt_notifydelete(rt, &di.info); | ||||
if (report) | |||||
rt_routemsg(RTM_DELETE, rt, rt->rt_ifp, 0, fibnum); | |||||
RTFREE_LOCKED(rt); | RTFREE_LOCKED(rt); | ||||
} | } | ||||
} | |||||
/* | |||||
* Iterates over all existing fibs in system and deletes each element | |||||
* for which @filter_f function returns non-zero value. | |||||
* If @family is not AF_UNSPEC, iterates over fibs in particular | |||||
* address family. | |||||
*/ | |||||
void | |||||
rt_foreach_fib_walk_del(int family, rt_filter_f_t *filter_f, void *arg) | |||||
{ | |||||
u_int fibnum; | |||||
int i, start, end; | |||||
for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { | |||||
/* Do we want some specific family? */ | |||||
if (family != AF_UNSPEC) { | |||||
start = family; | |||||
end = family; | |||||
} else { | |||||
start = 1; | |||||
end = AF_MAX; | |||||
} | } | ||||
for (i = start; i <= end; i++) { | |||||
if (rt_tables_get_rnh(fibnum, i) == NULL) | |||||
continue; | |||||
rib_walk_del(fibnum, i, filter_f, arg, 0); | |||||
} | } | ||||
} | } | ||||
} | |||||
/* | /* | ||||
* Delete Routes for a Network Interface | * Delete Routes for a Network Interface | ||||
* | * | ||||
* Called for each routing entry via the rnh->rnh_walktree() call above | * Called for each routing entry via the rnh->rnh_walktree() call above | ||||
* to delete all route entries referencing a detaching network interface. | * to delete all route entries referencing a detaching network interface. | ||||
* | * | ||||
* Arguments: | * Arguments: | ||||
▲ Show 20 Lines • Show All 565 Lines • ▼ Show 20 Lines | if (rt_mpath_capable(rnh) && | ||||
R_Free(rt_key(rt)); | R_Free(rt_key(rt)); | ||||
uma_zfree(V_rtzone, rt); | uma_zfree(V_rtzone, rt); | ||||
return (EEXIST); | return (EEXIST); | ||||
} | } | ||||
#endif | #endif | ||||
/* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ | /* XXX mtu manipulation will be done in rnh_addaddr -- itojun */ | ||||
rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes); | rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes); | ||||
if (rn != NULL && rt->rt_expire > 0) | |||||
tmproutes_update(rnh, rt); | |||||
rt_old = NULL; | rt_old = NULL; | ||||
if (rn == NULL && (info->rti_flags & RTF_PINNED) != 0) { | if (rn == NULL && (info->rti_flags & RTF_PINNED) != 0) { | ||||
/* | /* | ||||
* Force removal and re-try addition | * Force removal and re-try addition | ||||
* TODO: better multipath&pinned support | * TODO: better multipath&pinned support | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 605 Lines • Show Last 20 Lines |
If you don't break up the first line, the KASSERT will still fit on two lines.