diff options
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if.c | 65 | ||||
-rw-r--r-- | sys/net/if_llatbl.c | 125 | ||||
-rw-r--r-- | sys/net/if_llatbl.h | 47 | ||||
-rw-r--r-- | sys/net/route.c | 91 | ||||
-rw-r--r-- | sys/net/route.h | 5 |
5 files changed, 188 insertions, 145 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index 6ebfdbf..9997692 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -166,7 +166,6 @@ static int if_setflag(struct ifnet *, int, int, int *, int); static int if_transmit(struct ifnet *ifp, struct mbuf *m); static void if_unroute(struct ifnet *, int flag, int fam); static void link_rtrequest(int, struct rtentry *, struct rt_addrinfo *); -static int if_rtdel(struct radix_node *, void *); static int ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *); static int if_delmulti_locked(struct ifnet *, struct ifmultiaddr *, int); static void do_link_state_change(void *, int); @@ -885,8 +884,7 @@ static void if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp) { struct ifaddr *ifa; - struct radix_node_head *rnh; - int i, j; + int i; struct domain *dp; struct ifnet *iter; int found = 0; @@ -974,23 +972,7 @@ if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp) } } - /* - * 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... - */ - for (i = 1; i <= AF_MAX; i++) { - for (j = 0; j < rt_numfibs; j++) { - rnh = rt_tables_get_rnh(j, i); - if (rnh == NULL) - continue; - RADIX_NODE_HEAD_LOCK(rnh); - (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); - RADIX_NODE_HEAD_UNLOCK(rnh); - } - } - + rt_flushifroutes(ifp); if_delgroups(ifp); /* @@ -1411,49 +1393,6 @@ if_getgroupmembers(struct ifgroupreq *data) } /* - * 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: - * rn pointer to node in the routing table - * arg argument passed to rnh->rnh_walktree() - detaching interface - * - * Returns: - * 0 successful - * errno failed - reason indicated - * - */ -static int -if_rtdel(struct radix_node *rn, void *arg) -{ - struct rtentry *rt = (struct rtentry *)rn; - struct ifnet *ifp = arg; - int err; - - if (rt->rt_ifp == ifp) { - - /* - * 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) { - log(LOG_WARNING, "if_rtdel: error %d\n", err); - } - } - - return (0); -} - -/* * Return counter values from counter(9)s stored in ifnet. */ uint64_t diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c index 84ea6c6..3f4e737 100644 --- a/sys/net/if_llatbl.c +++ b/sys/net/if_llatbl.c @@ -147,8 +147,7 @@ llentry_alloc(struct ifnet *ifp, struct lltable *lt, if ((la == NULL) && (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) { IF_AFDATA_WLOCK(ifp); - la = lla_lookup(lt, (LLE_CREATE | LLE_EXCLUSIVE), - (struct sockaddr *)dst); + la = lla_create(lt, 0, (struct sockaddr *)dst); IF_AFDATA_WUNLOCK(ifp); } @@ -259,7 +258,7 @@ lltable_init(struct ifnet *ifp, int af) } /* - * Called in route_output when adding/deleting a route to an interface. + * Called in route_output when rtm_flags contains RTF_LLDATA. */ int lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) @@ -270,8 +269,8 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) struct ifnet *ifp; struct lltable *llt; struct llentry *lle; - u_int laflags = 0, flags = 0; - int error = 0; + u_int laflags = 0; + int error; KASSERT(dl != NULL && dl->sdl_family == AF_LINK, ("%s: invalid dl\n", __func__)); @@ -283,24 +282,6 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) return EINVAL; } - switch (rtm->rtm_type) { - case RTM_ADD: - if (rtm->rtm_flags & RTF_ANNOUNCE) - flags |= LLE_PUB; - flags |= LLE_CREATE; - break; - - case RTM_DELETE: - flags |= LLE_DELETE; - break; - - case RTM_CHANGE: - break; - - default: - return EINVAL; /* XXX not implemented yet */ - } - /* XXX linked list may be too expensive */ LLTABLE_RLOCK(); SLIST_FOREACH(llt, &V_lltables, llt_link) { @@ -311,58 +292,62 @@ lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info) LLTABLE_RUNLOCK(); KASSERT(llt != NULL, ("Yep, ugly hacks are bad\n")); - if (flags & LLE_CREATE) - flags |= LLE_EXCLUSIVE; - - IF_AFDATA_LOCK(ifp); - lle = lla_lookup(llt, flags, dst); - IF_AFDATA_UNLOCK(ifp); - if (LLE_IS_VALID(lle)) { - if (flags & LLE_CREATE) { - /* - * If we delay the delete, then a subsequent - * "arp add" should look up this entry, reset the - * LLE_DELETED flag, and reset the expiration timer - */ - bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen); - lle->la_flags |= (flags & LLE_PUB); - lle->la_flags |= LLE_VALID; - lle->la_flags &= ~LLE_DELETED; + error = 0; + + switch (rtm->rtm_type) { + case RTM_ADD: + /* Add static LLE */ + IF_AFDATA_WLOCK(ifp); + lle = lla_create(llt, 0, dst); + if (lle == NULL) { + IF_AFDATA_WUNLOCK(ifp); + return (ENOMEM); + } + + + bcopy(LLADDR(dl), &lle->ll_addr, ifp->if_addrlen); + if ((rtm->rtm_flags & RTF_ANNOUNCE)) + lle->la_flags |= LLE_PUB; + lle->la_flags |= LLE_VALID; #ifdef INET6 - /* - * ND6 - */ - if (dst->sa_family == AF_INET6) - lle->ln_state = ND6_LLINFO_REACHABLE; + /* + * ND6 + */ + if (dst->sa_family == AF_INET6) + lle->ln_state = ND6_LLINFO_REACHABLE; #endif - /* - * NB: arp and ndp always set (RTF_STATIC | RTF_HOST) - */ - - if (rtm->rtm_rmx.rmx_expire == 0) { - lle->la_flags |= LLE_STATIC; - lle->la_expire = 0; - } else - lle->la_expire = rtm->rtm_rmx.rmx_expire; - laflags = lle->la_flags; - LLE_WUNLOCK(lle); + /* + * NB: arp and ndp always set (RTF_STATIC | RTF_HOST) + */ + + if (rtm->rtm_rmx.rmx_expire == 0) { + lle->la_flags |= LLE_STATIC; + lle->la_expire = 0; + } else + lle->la_expire = rtm->rtm_rmx.rmx_expire; + laflags = lle->la_flags; + LLE_WUNLOCK(lle); + IF_AFDATA_WUNLOCK(ifp); #ifdef INET - /* gratuitous ARP */ - if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) - arprequest(ifp, - &((struct sockaddr_in *)dst)->sin_addr, - &((struct sockaddr_in *)dst)->sin_addr, - (u_char *)LLADDR(dl)); + /* gratuitous ARP */ + if ((laflags & LLE_PUB) && dst->sa_family == AF_INET) + arprequest(ifp, + &((struct sockaddr_in *)dst)->sin_addr, + &((struct sockaddr_in *)dst)->sin_addr, + (u_char *)LLADDR(dl)); #endif - } else { - if (flags & LLE_EXCLUSIVE) - LLE_WUNLOCK(lle); - else - LLE_RUNLOCK(lle); - } - } else if ((lle == NULL) && (flags & LLE_DELETE)) - error = EINVAL; + break; + + case RTM_DELETE: + IF_AFDATA_WLOCK(ifp); + error = lla_delete(llt, 0, dst); + IF_AFDATA_WUNLOCK(ifp); + return (error == 0 ? 0 : ENOENT); + + default: + error = EINVAL; + } return (error); } diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h index 4f21fde..69c340c 100644 --- a/sys/net/if_llatbl.h +++ b/sys/net/if_llatbl.h @@ -144,25 +144,33 @@ struct llentry { #define LLTBL_HASHMASK (LLTBL_HASHTBL_SIZE - 1) #endif +typedef struct llentry *(llt_lookup_t)(struct lltable *, u_int flags, + const struct sockaddr *l3addr); +typedef struct llentry *(llt_create_t)(struct lltable *, u_int flags, + const struct sockaddr *l3addr); +typedef int (llt_delete_t)(struct lltable *, u_int flags, + const struct sockaddr *l3addr); +typedef void (llt_prefix_free_t)(struct lltable *, + const struct sockaddr *prefix, const struct sockaddr *mask, u_int flags); +typedef int (llt_dump_t)(struct lltable *, struct sysctl_req *); + struct lltable { SLIST_ENTRY(lltable) llt_link; struct llentries lle_head[LLTBL_HASHTBL_SIZE]; int llt_af; struct ifnet *llt_ifp; - void (*llt_prefix_free)(struct lltable *, - const struct sockaddr *prefix, - const struct sockaddr *mask, - u_int flags); - struct llentry * (*llt_lookup)(struct lltable *, u_int flags, - const struct sockaddr *l3addr); - int (*llt_dump)(struct lltable *, - struct sysctl_req *); + llt_lookup_t *llt_lookup; + llt_create_t *llt_create; + llt_delete_t *llt_delete; + llt_prefix_free_t *llt_prefix_free; + llt_dump_t *llt_dump; }; + MALLOC_DECLARE(M_LLTABLE); /* - * flags to be passed to arplookup. + * LLentry flags */ #define LLE_DELETED 0x0001 /* entry must be deleted */ #define LLE_STATIC 0x0002 /* entry is static */ @@ -170,9 +178,8 @@ MALLOC_DECLARE(M_LLTABLE); #define LLE_VALID 0x0008 /* ll_addr is valid */ #define LLE_PUB 0x0020 /* publish entry ??? */ #define LLE_LINKED 0x0040 /* linked to lookup structure */ +/* LLE request flags */ #define LLE_EXCLUSIVE 0x2000 /* return lle xlocked */ -#define LLE_DELETE 0x4000 /* delete on a lookup - match LLE_IFADDR */ -#define LLE_CREATE 0x8000 /* create on a lookup miss */ #define LLATBL_HASH(key, mask) \ (((((((key >> 8) ^ key) >> 8) ^ key) >> 8) ^ key) & mask) @@ -196,9 +203,25 @@ struct llentry *llentry_alloc(struct ifnet *, struct lltable *, static __inline struct llentry * lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) { - return llt->llt_lookup(llt, flags, l3addr); + + return (llt->llt_lookup(llt, flags, l3addr)); } +static __inline struct llentry * +lla_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +{ + + return (llt->llt_create(llt, flags, l3addr)); +} + +static __inline int +lla_delete(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) +{ + + return (llt->llt_delete(llt, flags, l3addr)); +} + + int lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *); #include <sys/eventhandler.h> diff --git a/sys/net/route.c b/sys/net/route.c index a887422..90dd843 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 { @@ -811,6 +812,96 @@ rtrequest_fib(int req, return rtrequest1_fib(req, &info, ret_nrt, fibnum); } + +void +rt_foreach_fib(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(AF_UNSPEC, NULL, rt_ifdelroute, ifp); +} + /* * These (questionable) definitions of apparent local variables apply * to the next two functions. XXXXXX!!! diff --git a/sys/net/route.h b/sys/net/route.h index ef00877..dc72d05 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -380,6 +380,11 @@ void rtfree(struct rtentry *); int rt_check(struct rtentry **, struct rtentry **, struct sockaddr *); void rt_updatemtu(struct ifnet *); +typedef int rt_walktree_f_t(struct rtentry *, void *); +typedef void rt_setwarg_t(struct radix_node_head *, uint32_t, int, void *); +void rt_foreach_fib(int af, rt_setwarg_t *, rt_walktree_f_t *, void *); +void rt_flushifroutes(struct ifnet *ifp); + /* XXX MRT COMPAT VERSIONS THAT SET UNIVERSE to 0 */ /* Thes are used by old code not yet converted to use multiple FIBS */ int rt_getifa(struct rt_addrinfo *); |