diff options
Diffstat (limited to 'sys/net/route.c')
-rw-r--r-- | sys/net/route.c | 109 |
1 files changed, 104 insertions, 5 deletions
diff --git a/sys/net/route.c b/sys/net/route.c index 992cf8e..1517dca 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -139,6 +139,7 @@ static VNET_DEFINE(uma_zone_t, rtzone); /* Routing table UMA zone. */ static int rtrequest1_fib_change(struct radix_node_head *, struct rt_addrinfo *, struct rtentry **, u_int); static void rt_setmetrics(const struct rt_addrinfo *, struct rtentry *); +static int rt_ifdelroute(struct rtentry *rt, void *arg); struct if_mtuinfo { @@ -519,7 +520,7 @@ rtfree(struct rtentry *rt) * This also frees the gateway, as they are always malloc'd * together. */ - Free(rt_key(rt)); + R_Free(rt_key(rt)); /* * and the rtentry itself of course @@ -703,7 +704,7 @@ rtioctl_fib(u_long req, caddr_t data, u_int fibnum) } struct ifaddr * -ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway, +ifa_ifwithroute(int flags, const struct sockaddr *dst, struct sockaddr *gateway, u_int fibnum) { struct ifaddr *ifa; @@ -811,6 +812,104 @@ rtrequest_fib(int req, return rtrequest1_fib(req, &info, ret_nrt, fibnum); } + +/* + * Iterates over all existing fibs in system calling + * @setwa_f function prior to traversing each fib. + * Calls @wa_f function for each element in current fib. + * If af is not AF_UNSPEC, iterates over fibs in particular + * address family. + */ +void +rt_foreach_fib_walk(int af, rt_setwarg_t *setwa_f, rt_walktree_f_t *wa_f, + void *arg) +{ + struct radix_node_head *rnh; + uint32_t fibnum; + int i; + + for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { + /* Do we want some specific family? */ + if (af != AF_UNSPEC) { + rnh = rt_tables_get_rnh(fibnum, af); + if (rnh == NULL) + continue; + if (setwa_f != NULL) + setwa_f(rnh, fibnum, i, arg); + + RADIX_NODE_HEAD_LOCK(rnh); + rnh->rnh_walktree(rnh, (walktree_f_t *)wa_f, arg); + RADIX_NODE_HEAD_UNLOCK(rnh); + continue; + } + + for (i = 1; i <= AF_MAX; i++) { + rnh = rt_tables_get_rnh(fibnum, i); + if (rnh == NULL) + continue; + if (setwa_f != NULL) + setwa_f(rnh, fibnum, i, arg); + + RADIX_NODE_HEAD_LOCK(rnh); + rnh->rnh_walktree(rnh, (walktree_f_t *)wa_f, arg); + RADIX_NODE_HEAD_UNLOCK(rnh); + } + } +} + +/* + * Delete Routes for a Network Interface + * + * Called for each routing entry via the rnh->rnh_walktree() call above + * to delete all route entries referencing a detaching network interface. + * + * Arguments: + * rt pointer to rtentry + * arg argument passed to rnh->rnh_walktree() - detaching interface + * + * Returns: + * 0 successful + * errno failed - reason indicated + */ +static int +rt_ifdelroute(struct rtentry *rt, void *arg) +{ + struct ifnet *ifp = arg; + int err; + + if (rt->rt_ifp != ifp) + return (0); + + /* + * Protect (sorta) against walktree recursion problems + * with cloned routes + */ + if ((rt->rt_flags & RTF_UP) == 0) + return (0); + + err = rtrequest_fib(RTM_DELETE, rt_key(rt), rt->rt_gateway, + rt_mask(rt), + rt->rt_flags | RTF_RNH_LOCKED | RTF_PINNED, + (struct rtentry **) NULL, rt->rt_fibnum); + if (err != 0) + log(LOG_WARNING, "rt_ifdelroute: error %d\n", err); + + return (0); +} + +/* + * Delete all remaining routes using this interface + * Unfortuneatly the only way to do this is to slog through + * the entire routing table looking for routes which point + * to this interface...oh well... + */ +void +rt_flushifroutes(struct ifnet *ifp) +{ + + rt_foreach_fib_walk(AF_UNSPEC, NULL, rt_ifdelroute, ifp); +} + /* * These (questionable) definitions of apparent local variables apply * to the next two functions. XXXXXX!!! @@ -1352,7 +1451,7 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, if (rn_mpath_capable(rnh) && rt_mpath_conflict(rnh, rt, netmask)) { ifa_free(rt->rt_ifa); - Free(rt_key(rt)); + R_Free(rt_key(rt)); uma_zfree(V_rtzone, rt); senderr(EEXIST); } @@ -1419,7 +1518,7 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt, */ if (rn == NULL) { ifa_free(rt->rt_ifa); - Free(rt_key(rt)); + R_Free(rt_key(rt)); uma_zfree(V_rtzone, rt); #ifdef FLOWTABLE if (rt0 != NULL) @@ -1641,7 +1740,7 @@ rt_setgate(struct rtentry *rt, struct sockaddr *dst, struct sockaddr *gate) * Free()/free() handle a NULL argument just fine. */ bcopy(dst, new, dlen); - Free(rt_key(rt)); /* free old block, if any */ + R_Free(rt_key(rt)); /* free old block, if any */ rt_key(rt) = (struct sockaddr *)new; rt->rt_gateway = (struct sockaddr *)(new + dlen); } |