diff options
Diffstat (limited to 'sys/netinet/in_rmx.c')
-rw-r--r-- | sys/netinet/in_rmx.c | 29 |
1 files changed, 18 insertions, 11 deletions
diff --git a/sys/netinet/in_rmx.c b/sys/netinet/in_rmx.c index 0c743b5..5092bb9 100644 --- a/sys/netinet/in_rmx.c +++ b/sys/netinet/in_rmx.c @@ -49,6 +49,7 @@ #include <sys/socket.h> #include <sys/mbuf.h> #include <sys/syslog.h> +#include <sys/callout.h> #include <net/if.h> #include <net/route.h> @@ -124,14 +125,17 @@ in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head, rt2->rt_flags & RTF_HOST && rt2->rt_gateway && rt2->rt_gateway->sa_family == AF_LINK) { + /* NB: must unlock to avoid recursion */ + RT_UNLOCK(rt2); rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt2), rt2->rt_gateway, rt_mask(rt2), rt2->rt_flags, 0); ret = rn_addroute(v_arg, n_arg, head, treenodes); + RT_LOCK(rt2); } - RTFREE(rt2); + RTFREE_LOCKED(rt2); } } @@ -159,6 +163,7 @@ in_matroute(void *v_arg, struct radix_node_head *head) struct radix_node *rn = rn_match(v_arg, head); struct rtentry *rt = (struct rtentry *)rn; + /*XXX locking? */ if (rt && rt->rt_refcnt == 0) { /* this is first reference */ if (rt->rt_flags & RTPRF_OURS) { rt->rt_flags &= ~RTPRF_OURS; @@ -190,6 +195,8 @@ in_clsroute(struct radix_node *rn, struct radix_node_head *head) { struct rtentry *rt = (struct rtentry *)rn; + RT_LOCK_ASSERT(rt); + if (!(rt->rt_flags & RTF_UP)) return; /* prophylactic measures */ @@ -207,10 +214,13 @@ in_clsroute(struct radix_node *rn, struct radix_node_head *head) rt->rt_flags |= RTPRF_OURS; rt->rt_rmx.rmx_expire = time_second + rtq_reallyold; } else { + /* NB: must unlock to avoid recursion */ + RT_UNLOCK(rt); rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); + RT_LOCK(rt); } } @@ -268,6 +278,7 @@ in_rtqkill(struct radix_node *rn, void *rock) #define RTQ_TIMEOUT 60*10 /* run no less than once every ten minutes */ static int rtq_timeout = RTQ_TIMEOUT; +static struct callout rtq_timer; static void in_rtqtimo(void *rock) @@ -276,17 +287,14 @@ in_rtqtimo(void *rock) struct rtqk_arg arg; struct timeval atv; static time_t last_adjusted_timeout = 0; - int s; arg.found = arg.killed = 0; arg.rnh = rnh; arg.nextstop = time_second + rtq_timeout; arg.draining = arg.updating = 0; - s = splnet(); RADIX_NODE_HEAD_LOCK(rnh); rnh->rnh_walktree(rnh, in_rtqkill, &arg); RADIX_NODE_HEAD_UNLOCK(rnh); - splx(s); /* * Attempt to be somewhat dynamic about this: @@ -311,16 +319,14 @@ in_rtqtimo(void *rock) #endif arg.found = arg.killed = 0; arg.updating = 1; - s = splnet(); RADIX_NODE_HEAD_LOCK(rnh); rnh->rnh_walktree(rnh, in_rtqkill, &arg); RADIX_NODE_HEAD_UNLOCK(rnh); - splx(s); } atv.tv_usec = 0; atv.tv_sec = arg.nextstop - time_second; - timeout(in_rtqtimo, rock, tvtohz(&atv)); + callout_reset(&rtq_timer, tvtohz(&atv), in_rtqtimo, rock); } void @@ -328,17 +334,15 @@ in_rtqdrain(void) { struct radix_node_head *rnh = rt_tables[AF_INET]; struct rtqk_arg arg; - int s; + arg.found = arg.killed = 0; arg.rnh = rnh; arg.nextstop = 0; arg.draining = 1; arg.updating = 0; - s = splnet(); RADIX_NODE_HEAD_LOCK(rnh); rnh->rnh_walktree(rnh, in_rtqkill, &arg); RADIX_NODE_HEAD_UNLOCK(rnh); - splx(s); } /* @@ -359,6 +363,7 @@ in_inithead(void **head, int off) rnh->rnh_addaddr = in_addroute; rnh->rnh_matchaddr = in_matroute; rnh->rnh_close = in_clsroute; + callout_init(&rtq_timer, CALLOUT_MPSAFE); in_rtqtimo(rnh); /* kick off timeout first time */ return 1; } @@ -395,7 +400,9 @@ in_ifadownkill(struct radix_node *rn, void *xap) * the routes that rtrequest() would have in any case, * so that behavior is not needed there. */ + RT_LOCK(rt); rt->rt_flags &= ~(RTF_CLONING | RTF_PRCLONING); + RT_UNLOCK(rt); err = rtrequest(RTM_DELETE, (struct sockaddr *)rt_key(rt), rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0); if (err) { @@ -420,6 +427,6 @@ in_ifadown(struct ifaddr *ifa, int delete) RADIX_NODE_HEAD_LOCK(rnh); rnh->rnh_walktree(rnh, in_ifadownkill, &arg); RADIX_NODE_HEAD_UNLOCK(rnh); - ifa->ifa_flags &= ~IFA_ROUTE; + ifa->ifa_flags &= ~IFA_ROUTE; /* XXXlocking? */ return 0; } |