summaryrefslogtreecommitdiffstats
path: root/sys/netinet/in_rmx.c
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2003-10-04 03:44:50 +0000
committersam <sam@FreeBSD.org>2003-10-04 03:44:50 +0000
commit9d93fce265aeeeb266999d5092d6d4224cc16829 (patch)
tree7bd40aa381e3ec3f09e84ae6cc70b74bf5683aa2 /sys/netinet/in_rmx.c
parent420e26096448ac273dab52190262aa9d55cb6c91 (diff)
downloadFreeBSD-src-9d93fce265aeeeb266999d5092d6d4224cc16829.zip
FreeBSD-src-9d93fce265aeeeb266999d5092d6d4224cc16829.tar.gz
Locking for updates to routing table entries. Each rtentry gets a mutex
that covers updates to the contents. Note this is separate from holding a reference and/or locking the routing table itself. Other/related changes: o rtredirect loses the final parameter by which an rtentry reference may be returned; this was never used and added unwarranted complexity for locking. o minor style cleanups to routing code (e.g. ansi-fy function decls) o remove the logic to bump the refcnt on the parent of cloned routes, we assume the parent will remain as long as the clone; doing this avoids a circularity in locking during delete o convert some timeouts to MPSAFE callouts Notes: 1. rt_mtx in struct rtentry is guarded by #ifdef _KERNEL as user-level applications cannot/do-no know about mutex's. Doing this requires that the mutex be the last element in the structure. A better solution is to introduce an externalized version of struct rtentry but this is a major task because of the intertwining of rtentry and other data structures that are visible to user applications. 2. There are known LOR's that are expected to go away with forthcoming work to eliminate many held references. If not these will be resolved prior to release. 3. ATM changes are untested. Sponsored by: FreeBSD Foundation Obtained from: BSD/OS (partly)
Diffstat (limited to 'sys/netinet/in_rmx.c')
-rw-r--r--sys/netinet/in_rmx.c29
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;
}
OpenPOWER on IntegriCloud