summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if.c65
-rw-r--r--sys/net/if_llatbl.c125
-rw-r--r--sys/net/if_llatbl.h47
-rw-r--r--sys/net/route.c91
-rw-r--r--sys/net/route.h5
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 *);
OpenPOWER on IntegriCloud