diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-11-29 16:02:19 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2015-11-29 16:02:19 +0000 |
commit | 15000000648aa5768f9d9dc744cf3b1348d4c348 (patch) | |
tree | 18fa2f16b84298356cacddd6390c84317c28e680 /sys/net | |
parent | 20523e10e8e7bff326904510eab3c76ee9157ef4 (diff) |
Convert the simple list of multipath route entries used by ART kernels
to a SRP list.
This turns the rtable_* layer mpsafe. We now only need to protect the
ART implementation itself.
Note that route(8) regress tests will now fail due to a supplementary
reference taken by the SRPL_INIT(9) API.
ok dlg@
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/art.h | 4 | ||||
-rw-r--r-- | sys/net/route.h | 4 | ||||
-rw-r--r-- | sys/net/rtable.c | 97 |
3 files changed, 73 insertions, 32 deletions
diff --git a/sys/net/art.h b/sys/net/art.h index fe2e71d49ab..20a0d40595b 100644 --- a/sys/net/art.h +++ b/sys/net/art.h @@ -1,4 +1,4 @@ -/* $OpenBSD: art.h,v 1.6 2015/11/24 12:06:30 mpi Exp $ */ +/* $OpenBSD: art.h,v 1.7 2015/11/29 16:02:18 mpi Exp $ */ /* * Copyright (c) 2015 Martin Pieuchot @@ -46,7 +46,7 @@ struct art_node { struct sockaddr *an_dst; /* Destination address (key) */ int an_plen; /* Prefix length */ - SLIST_HEAD(, rtentry) an_rtlist; /* Route related to this node */ + struct srpl an_rtlist; /* Route related to this node */ }; void art_init(void); diff --git a/sys/net/route.h b/sys/net/route.h index 0d79922dd97..1c51a4ac9f2 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -1,4 +1,4 @@ -/* $OpenBSD: route.h,v 1.121 2015/11/09 10:26:26 mpi Exp $ */ +/* $OpenBSD: route.h,v 1.122 2015/11/29 16:02:18 mpi Exp $ */ /* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */ /* @@ -99,7 +99,7 @@ struct rtentry { struct art_node *rt_node; /* ART entry */ struct sockaddr *rt_dest; /* destination */ struct sockaddr *rt_mask; /* mask (radix tree compat) */ - SLIST_ENTRY(rtentry) rt_next; /* Next multipath entry to our dst. */ + struct srpl_entry rt_next; /* Next multipath entry to our dst. */ #endif struct sockaddr *rt_gateway; /* value */ struct ifnet *rt_ifp; /* the answer: interface to use */ diff --git a/sys/net/rtable.c b/sys/net/rtable.c index 1209f6a1bf5..9bff8ffaca0 100644 --- a/sys/net/rtable.c +++ b/sys/net/rtable.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtable.c,v 1.27 2015/11/27 12:13:22 mpi Exp $ */ +/* $OpenBSD: rtable.c,v 1.28 2015/11/29 16:02:18 mpi Exp $ */ /* * Copyright (c) 2014-2015 Martin Pieuchot @@ -497,11 +497,16 @@ rtable_mpath_next(struct rtentry *rt) #else /* ART */ -struct pool an_pool; /* pool for ART node structures */ +struct pool an_pool; /* pool for ART node structures */ static inline int satoplen(struct art_root *, struct sockaddr *); static inline uint8_t *satoaddr(struct art_root *, struct sockaddr *); +void rtentry_ref(void *, void *); +void rtentry_unref(void *, void *); + +struct srpl_rc rt_rc = SRPL_RC_INITIALIZER(rtentry_ref, rtentry_unref, NULL); + void rtable_init_backend(unsigned int keylen) { @@ -522,6 +527,7 @@ rtable_lookup(unsigned int rtableid, struct sockaddr *dst, struct art_root *ar; struct art_node *an; struct rtentry *rt; + struct srpl_iter i; uint8_t *addr; int plen; @@ -549,9 +555,9 @@ rtable_lookup(unsigned int rtableid, struct sockaddr *dst, } #ifdef SMALL_KERNEL - rt = SLIST_FIRST(&an->an_rtlist); + rt = SRPL_ENTER(&an->an_rtlist, &i); #else - SLIST_FOREACH(rt, &an->an_rtlist, rt_next) { + SRPL_FOREACH(rt, &an->an_rtlist, &i, rt_next) { if (prio != RTP_ANY && (rt->rt_priority & RTP_MASK) != (prio & RTP_MASK)) continue; @@ -563,11 +569,14 @@ rtable_lookup(unsigned int rtableid, struct sockaddr *dst, memcmp(rt->rt_gateway, gateway, gateway->sa_len) == 0) break; } - if (rt == NULL) + if (rt == NULL) { + SRPL_LEAVE(&i, rt); return (NULL); + } #endif /* SMALL_KERNEL */ rtref(rt); + SRPL_LEAVE(&i, rt); return (rt); } @@ -578,6 +587,7 @@ rtable_match(unsigned int rtableid, struct sockaddr *dst) struct art_root *ar; struct art_node *an; struct rtentry *rt; + struct srpl_iter i; uint8_t *addr; ar = rtable_get(rtableid, dst->sa_family); @@ -589,8 +599,9 @@ rtable_match(unsigned int rtableid, struct sockaddr *dst) if (an == NULL) return (NULL); - rt = SLIST_FIRST(&an->an_rtlist); + rt = SRPL_ENTER(&an->an_rtlist, &i); rtref(rt); + SRPL_LEAVE(&i, rt); return (rt); } @@ -608,6 +619,8 @@ rtable_insert(unsigned int rtableid, struct sockaddr *dst, uint8_t *addr; int plen; + KERNEL_ASSERT_LOCKED(); + ar = rtable_get(rtableid, dst->sa_family); if (ar == NULL) return (EAFNOSUPPORT); @@ -625,7 +638,7 @@ rtable_insert(unsigned int rtableid, struct sockaddr *dst, struct rtentry *mrt; int mpathok = ISSET(rt->rt_flags, RTF_MPATH); - SLIST_FOREACH(mrt, &an->an_rtlist, rt_next) { + SRPL_FOREACH_LOCKED(mrt, &an->an_rtlist, rt_next) { if (prio != RTP_ANY && (mrt->rt_priority & RTP_MASK) != (prio & RTP_MASK)) continue; @@ -660,6 +673,7 @@ rtable_insert(unsigned int rtableid, struct sockaddr *dst, an->an_dst = dst; an->an_plen = plen; + SRPL_INIT(&an->an_rtlist); prev = art_insert(ar, an, addr, plen); if (prev == NULL) { @@ -676,7 +690,7 @@ rtable_insert(unsigned int rtableid, struct sockaddr *dst, #ifndef SMALL_KERNEL an = prev; - mrt = SLIST_FIRST(&an->an_rtlist); + mrt = SRPL_FIRST_LOCKED(&an->an_rtlist); KASSERT(mrt != NULL); KASSERT((rt->rt_flags & RTF_MPATH) || mrt->rt_priority != prio); @@ -690,7 +704,7 @@ rtable_insert(unsigned int rtableid, struct sockaddr *dst, * the same gateway. */ rt->rt_flags &= ~RTF_MPATH; - SLIST_FOREACH(mrt, &an->an_rtlist, rt_next) { + SRPL_FOREACH_LOCKED(mrt, &an->an_rtlist, rt_next) { if (mrt->rt_priority == prio) { mrt->rt_flags |= RTF_MPATH; rt->rt_flags |= RTF_MPATH; @@ -705,7 +719,7 @@ rtable_insert(unsigned int rtableid, struct sockaddr *dst, rt->rt_node = an; rt->rt_dest = dst; rtref(rt); - SLIST_INSERT_HEAD(&an->an_rtlist, rt, rt_next); + SRPL_INSERT_HEAD_LOCKED(&rt_rc, &an->an_rtlist, rt, rt_next); #ifndef SMALL_KERNEL /* Put newly inserted entry at the right place. */ @@ -727,22 +741,25 @@ rtable_delete(unsigned int rtableid, struct sockaddr *dst, struct rtentry *mrt; int npaths = 0; + KERNEL_ASSERT_LOCKED(); + /* * If other multipath route entries are still attached to * this ART node we only have to unlink it. */ - SLIST_FOREACH(mrt, &an->an_rtlist, rt_next) + SRPL_FOREACH_LOCKED(mrt, &an->an_rtlist, rt_next) npaths++; if (npaths > 1) { free(rt->rt_mask, M_RTABLE, 0); rt->rt_mask = NULL; rt->rt_node = NULL; - SLIST_REMOVE(&an->an_rtlist, rt, rtentry, rt_next); - KASSERT(rt->rt_refcnt >= 1); + KASSERT(rt->rt_refcnt >= 2); + SRPL_REMOVE_LOCKED(&rt_rc, &an->an_rtlist, rt, rtentry, + rt_next); rtfree(rt); - mrt = SLIST_FIRST(&an->an_rtlist); + mrt = SRPL_FIRST_LOCKED(&an->an_rtlist); an->an_dst = mrt->rt_dest; if (npaths == 2) mrt->rt_flags &= ~RTF_MPATH; @@ -774,8 +791,8 @@ rtable_delete(unsigned int rtableid, struct sockaddr *dst, free(rt->rt_mask, M_RTABLE, 0); rt->rt_node = NULL; rt->rt_mask = NULL; - SLIST_REMOVE(&an->an_rtlist, rt, rtentry, rt_next); - KASSERT(rt->rt_refcnt >= 1); + KASSERT(rt->rt_refcnt >= 2); + SRPL_REMOVE_LOCKED(&rt_rc, &an->an_rtlist, rt, rtentry, rt_next); rtfree(rt); pool_put(&an_pool, an); @@ -798,7 +815,9 @@ rtable_walk_helper(struct art_node *an, void *xrwc) struct rtentry *rt, *nrt; int error = 0; - SLIST_FOREACH_SAFE(rt, &an->an_rtlist, rt_next, nrt) { + KERNEL_ASSERT_LOCKED(); + + SRPL_FOREACH_SAFE_LOCKED(rt, &an->an_rtlist, rt_next, nrt) { if ((error = (*rwc->rwc_func)(rt, rwc->rwc_arg, rwc->rwc_rid))) break; } @@ -837,22 +856,24 @@ rtable_mpath_select(struct rtentry *rt, uint32_t hash) { struct art_node *an = rt->rt_node; struct rtentry *mrt; + struct srpl_iter i; int npaths, threshold; npaths = 0; - SLIST_FOREACH(mrt, &an->an_rtlist, rt_next) { + SRPL_FOREACH(mrt, &an->an_rtlist, &i, rt_next) { /* Only count nexthops with the same priority. */ if (mrt->rt_priority == rt->rt_priority) npaths++; } + SRPL_LEAVE(&i, mrt); threshold = (0xffff / npaths) + 1; - mrt = SLIST_FIRST(&an->an_rtlist); + mrt = SRPL_ENTER(&an->an_rtlist, &i); while (hash > threshold && mrt != NULL) { if (mrt->rt_priority == rt->rt_priority) hash -= threshold; - mrt = SLIST_NEXT(mrt, rt_next); + mrt = SRPL_NEXT(&i, mrt, rt_next); } if (mrt != NULL) { @@ -860,6 +881,7 @@ rtable_mpath_select(struct rtentry *rt, uint32_t hash) rtfree(rt); rt = mrt; } + SRPL_LEAVE(&i, mrt); return (rt); } @@ -870,39 +892,58 @@ rtable_mpath_reprio(struct rtentry *rt, uint8_t prio) struct art_node *an = rt->rt_node; struct rtentry *mrt, *prt; - SLIST_REMOVE(&an->an_rtlist, rt, rtentry, rt_next); + KERNEL_ASSERT_LOCKED(); + + SRPL_REMOVE_LOCKED(&rt_rc, &an->an_rtlist, rt, rtentry, rt_next); rt->rt_priority = prio; - if ((mrt = SLIST_FIRST(&an->an_rtlist)) != NULL) { + if ((mrt = SRPL_FIRST_LOCKED(&an->an_rtlist)) != NULL) { /* * Select the order of the MPATH routes. */ - while (SLIST_NEXT(mrt, rt_next) != NULL) { + while (SRPL_NEXT_LOCKED(mrt, rt_next) != NULL) { if (mrt->rt_priority > prio) break; prt = mrt; - mrt = SLIST_NEXT(mrt, rt_next); + mrt = SRPL_NEXT_LOCKED(mrt, rt_next); } if (mrt->rt_priority > prio) { /* prt -> rt -> mrt */ - SLIST_INSERT_AFTER(prt, rt, rt_next); + SRPL_INSERT_AFTER_LOCKED(&rt_rc, prt, rt, rt_next); } else { /* prt -> mrt -> rt */ - SLIST_INSERT_AFTER(mrt, rt, rt_next); + SRPL_INSERT_AFTER_LOCKED(&rt_rc, mrt, rt, rt_next); } } else { - SLIST_INSERT_HEAD(&an->an_rtlist, rt, rt_next); + SRPL_INSERT_HEAD_LOCKED(&rt_rc, &an->an_rtlist, rt, rt_next); } } struct rtentry * rtable_mpath_next(struct rtentry *rt) { - return (SLIST_NEXT(rt, rt_next)); + KERNEL_ASSERT_LOCKED(); + return (SRPL_NEXT_LOCKED(rt, rt_next)); } #endif /* SMALL_KERNEL */ +void +rtentry_ref(void *null, void *xrt) +{ + struct rtentry *rt = xrt; + + rtref(rt); +} + +void +rtentry_unref(void *null, void *xrt) +{ + struct rtentry *rt = xrt; + + rtfree(rt); +} + /* * Return a pointer to the address (key). This is an heritage from the * BSD radix tree needed to skip the non-address fields from the flavor |