summaryrefslogtreecommitdiffstats
path: root/sys/net/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/route.c')
-rw-r--r--sys/net/route.c109
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);
}
OpenPOWER on IntegriCloud