PERFORCE change 153536 for review
Sam Leffler
sam at FreeBSD.org
Tue Nov 25 09:18:01 PST 2008
http://perforce.freebsd.org/chv.cgi?CH=153536
Change 153536 by sam at sam_ebb on 2008/11/25 17:17:41
Refactor code along adress family-boundaries:
o move af-specific code into the protocol area and add methods
to the llatbl
o rewrite the public api's to use per-af methods instead of handling
in common code w/ switch statements, etc.
o restructure llatbl entries so af-specific state is managed in private
code; this allows us, for example, to not take a hit for ipv6
addresses in the ipv4 data structures
o expose the l3 address in table entries with macros for those cases
where public access is required (should still be limited to within
af code)
o rename sysctl_dumparp to lltable_sysctl_dumparp
o remove private zone for lltable entries; just use malloc for now
Tested with ipv4. Compiles+boots w/ ipv6 but haven't tested operation.
Needs more work: e.g. the lookup method added last and may make the
rtcheck and new methods unneeded.
Per-af code should probably move to new files in netinet and netinet6;
it's in in.c and in6.c for the moment.
L3_ADDR* macros probably need to be renamed to something less common.
Reviewed by: qingli
Affected files ...
.. //depot/projects/arp-v2/src/sys/net/if_llatbl.c#9 edit
.. //depot/projects/arp-v2/src/sys/net/if_llatbl.h#6 edit
.. //depot/projects/arp-v2/src/sys/net/rtsock.c#8 edit
.. //depot/projects/arp-v2/src/sys/netinet/if_ether.c#19 edit
.. //depot/projects/arp-v2/src/sys/netinet/in.c#7 edit
.. //depot/projects/arp-v2/src/sys/netinet6/in6.c#9 edit
.. //depot/projects/arp-v2/src/sys/netinet6/nd6.c#9 edit
.. //depot/projects/arp-v2/src/sys/netinet6/nd6_nbr.c#8 edit
Differences ...
==== //depot/projects/arp-v2/src/sys/net/if_llatbl.c#9 (text+ko) ====
@@ -53,145 +53,16 @@
MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables");
-static uma_zone_t llezone;
static SLIST_HEAD(, lltable) lltables = SLIST_HEAD_INITIALIZER(lltables);
-int sysctl_dumparp(int af, struct sysctl_req *wr);
extern void arprequest(struct ifnet *, struct in_addr *, struct in_addr *,
u_char *);
-/* ARGSUSED*/
-static void
-lla_init(void *dummy __unused)
-{
- /*
- * create uma zone for L2/L3 cache
- */
- llezone = uma_zcreate("llentry", sizeof(struct llentry), NULL, NULL,
- NULL, NULL, UMA_ALIGN_PTR, 0);
-}
-SYSINIT(lla, SI_SUB_INIT_IF, SI_ORDER_FIRST, lla_init, NULL);
-
-static int
-dump_llcache(struct lltable *llt, int af, struct sysctl_req *wr)
-{
- struct ifnet *ifp = llt->llt_ifp;
- struct llentry *lle;
- struct rt_msghdr *rtm = NULL;
- struct sockaddr_dl *sdl = NULL;
- uint8_t *msg = NULL;
- int msgsize = 0;
- int error = 0;
- int i;
-#ifdef INET
- struct {
- struct rt_msghdr rtm;
- struct sockaddr_inarp sin;
- struct sockaddr_dl sdl;
- } arpc;
-#endif
-#ifdef INET6
- struct {
- struct rt_msghdr rtm;
- struct sockaddr_in6 sin6;
- struct sockaddr_dl sdl;
- } ndpc;
-#endif
-
- switch (af) {
-#ifdef INET
- case AF_INET:
- rtm = &arpc.rtm;
- sdl = &arpc.sdl;
- msgsize = sizeof(arpc);
- msg = (uint8_t *)&arpc;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- rtm = &ndpc.rtm;
- sdl = &ndpc.sdl;
- msgsize = sizeof(ndpc);
- msg = (uint8_t *)&ndpc;
- break;
-#endif
- default:
- printf("%s: unknown address family", __func__);
- return EINVAL;
- }
-
- /* XXXXX
- * current IFNET_RLOCK() is mapped to IFNET_WLOCK()
- * so it is okay to use this ASSERT, change it when
- * IFNET lock is finalized
- */
- IFNET_WLOCK_ASSERT();
-
- for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
- LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
- if (lle->la_flags & LLE_DELETED) /* skip deleted entries */
- continue;
- /*
- * produce a msg made of:
- * struct rt_msghdr;
- * struct sockaddr_inarp; (IPv4) struct sockaddr_in6 (IPv6)
- * struct sockaddr_dl;
- */
- bzero(msg, msgsize);
- rtm->rtm_msglen = msgsize;
-
- switch (af) {
-#ifdef INET
- case AF_INET:
- arpc.sin.sin_family = AF_INET;
- arpc.sin.sin_len = sizeof(arpc.sin);
- arpc.sin.sin_addr.s_addr = lle->l3_addr4.sin_addr.s_addr;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- ndpc.sin6.sin6_family = AF_INET6;
- ndpc.sin6.sin6_len = sizeof(ndpc.sin6);
- bcopy(&lle->l3_addr6, &ndpc.sin6, lle->l3_addr6.sin6_len);
- break;
-#endif
- }
- /* publish */
- if (lle->la_flags & LLE_PUB) {
- rtm->rtm_flags |= RTF_ANNOUNCE;
- /* proxy only */
- if ((af == AF_INET) && (lle->la_flags & LLE_PROXY))
- arpc.sin.sin_other = SIN_PROXY;
- }
-
- if (lle->la_flags & LLE_VALID) { /* valid MAC */
- sdl->sdl_family = AF_LINK;
- sdl->sdl_len = sizeof(*sdl);
- sdl->sdl_alen = ifp->if_addrlen;
- sdl->sdl_index = ifp->if_index;
- sdl->sdl_type = ifp->if_type;
- bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
- }
- rtm->rtm_rmx.rmx_expire =
- lle->la_flags & LLE_STATIC ? 0 : lle->la_expire;
- rtm->rtm_flags |= (RTF_LLINFO | RTF_HOST);
- if (lle->la_flags & LLE_STATIC)
- rtm->rtm_flags |= RTF_STATIC;
- rtm->rtm_index = ifp->if_index;
- error = SYSCTL_OUT(wr, msg, msgsize);
- if (error)
- break;
- }
- }
-
- return (error);
-}
-
/*
- * glue to dump arp tables
+ * Dump arp state for a specific address family.
*/
int
-sysctl_dumparp(int af, struct sysctl_req *wr)
+lltable_sysctl_dumparp(int af, struct sysctl_req *wr)
{
struct lltable *llt;
int error = 0;
@@ -199,7 +70,7 @@
IFNET_RLOCK();
SLIST_FOREACH(llt, &lltables, llt_link) {
if (llt->llt_af == af) {
- error = dump_llcache(llt, af, wr);
+ error = llt->llt_dump(llt, wr);
if (error != 0)
goto done;
}
@@ -215,17 +86,16 @@
* such as arptimer() and nd6_llinfo_timer(), and
* the caller does the locking.
*/
-int
+void
llentry_free(struct llentry *lle)
{
- KASSERT(lle != NULL, ("%s: lle is NULL", __func__));
+ struct lltable *llt = lle->lle_tbl;
LIST_REMOVE(lle, lle_next);
if (lle->la_hold != NULL)
m_freem(lle->la_hold);
- uma_zfree(llezone, lle);
- return 0;
+ llt->llt_free(llt, lle);
}
/*
@@ -233,9 +103,10 @@
* Since lltables collects from all of the intefaces,
* the caller of this function must acquire IFNET_WLOCK().
*/
-void lltable_free(struct lltable *llt)
+void
+lltable_free(struct lltable *llt)
{
- struct llentry *lle;
+ struct llentry *lle, *next;
int i;
KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
@@ -245,7 +116,7 @@
IFNET_WUNLOCK();
for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
- LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
+ LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
callout_drain(&lle->la_timer);
llentry_free(lle);
}
@@ -278,7 +149,6 @@
IFNET_RUNLOCK();
}
-
/*
* Create a new lltable.
*/
@@ -304,141 +174,14 @@
return (llt);
}
-
-/*
- * Generic link layer address lookup function, replacement
- * of the old "arplookup"
- */
-struct llentry *
-lla_lookup(struct lltable *llt, u_int flags, struct sockaddr *l3addr)
-{
- struct ifnet *ifp;
- struct llentry *lle;
- struct llentries *lleh;
- struct rtentry *rt;
- u_int hashkey;
-#ifdef INET6
- char ip6buf[INET6_ADDRSTRLEN];
-#endif
-
- KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
- KASSERT(l3addr != NULL, ("%s: L3 address is NULL", __func__));
-
- ifp = llt->llt_ifp;
- switch (l3addr->sa_family) {
-#ifdef INET
- case AF_INET:
- hashkey = ((struct sockaddr_in *)l3addr)->sin_addr.s_addr;
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- hashkey = ((struct sockaddr_in6 *)l3addr)->sin6_addr.s6_addr32[3];
- break;
-#endif
- default:
- return NULL;
- }
-
- lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
- LIST_FOREACH(lle, lleh, lle_next) {
- if (lle->la_flags & LLE_DELETED)
- continue;
- if (bcmp((void *)&lle->l3_addr, l3addr, l3addr->sa_len) == 0)
- break;
- }
-
- if (lle == NULL) {
- if (!(flags & LLE_CREATE))
- return (NULL);
-
- /*
- * a route that covers the given address must have been
- * installed 1st because we are doing a resolution
- */
- if (!(flags & LLE_IFADDR)) {
- rt = rtalloc1(l3addr, 0, 0);
- if ((rt == NULL) || (rt->rt_flags & RTF_GATEWAY) || (rt->rt_ifp != ifp)) {
-#ifdef INET6
- if (l3addr->sa_family == AF_INET6) {
- /*
- * Creating a ND6 cache for an IPv6 neighbor
- * that is not covered by our own prefix.
- */
- struct ifaddr *ifa =
- ifaof_ifpforaddr((struct sockaddr *)l3addr, ifp);
- if (ifa != NULL) {
- if (rt)
- rtfree(rt);
- goto lla_lookup_1;
- }
- }
-#endif
- switch (l3addr->sa_family) {
-#ifdef INET
- case AF_INET:
- log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n", \
- inet_ntoa(((struct sockaddr_in *)l3addr)->sin_addr));
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", \
- ip6_sprintf(ip6buf, &((struct sockaddr_in6 *)l3addr)->sin6_addr));
- break;
-#endif
-
- }
- if (rt)
- rtfree(rt);
- return (NULL);
- }
- rtfree(rt);
- }
-#ifdef INET6
-lla_lookup_1:
-#endif
- lle = uma_zalloc(llezone, M_DONTWAIT | M_ZERO);
- if (lle == NULL) {
- log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
- return (NULL);
- }
-
- callout_init(&lle->la_timer, CALLOUT_MPSAFE);
-
- /* qing
- * For IPv4 this will trigger "arpresolve" to generate
- * an ARP request
- */
- lle->la_expire = time_second; /* mark expired */
- lle->la_flags = flags & ~LLE_CREATE;
-
- bcopy(l3addr, &lle->l3_addr, l3addr->sa_len);
-
- if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) {
- bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
- lle->la_flags |= (LLE_VALID | LLE_STATIC);
- }
-
- lle->lle_tbl = llt;
- lle->lle_head = lleh;
- LIST_INSERT_HEAD(lleh, lle, lle_next);
- } else {
- if (flags & LLE_DELETE)
- lle->la_flags = LLE_DELETED;
- }
-
- return (lle);
-}
-
-
/*
* Called in route_output when adding/deleting a route to an interface.
*/
int
lla_rt_output(struct rt_msghdr *rtm, struct rt_addrinfo *info)
{
- struct sockaddr_dl *dl = (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY];
+ struct sockaddr_dl *dl =
+ (struct sockaddr_dl *)info->rti_info[RTAX_GATEWAY];
struct sockaddr *dst = (struct sockaddr *)info->rti_info[RTAX_DST];
struct ifnet *ifp;
struct lltable *llt;
==== //depot/projects/arp-v2/src/sys/net/if_llatbl.h#6 (text+ko) ====
@@ -31,6 +31,7 @@
#include <netinet/in.h>
struct ifnet;
+struct sysctl_req;
struct rt_msghdr;
struct rt_addrinfo;
@@ -51,24 +52,24 @@
uint16_t ln_router;
time_t ln_ntick;
union {
- struct sockaddr_in addr4;
- struct sockaddr_in6 addr6;
- } l3_addr;
- union {
uint64_t mac_aligned;
uint16_t mac16[3];
} ll_addr;
+
+ /* XXX af-private? */
union {
struct callout ln_timer_ch;
struct callout la_timer;
} lle_timer;
+ /* NB: struct sockaddr must immediately follow */
};
#define ln_timer_ch lle_timer.ln_timer_ch
#define la_timer lle_timer.la_timer
-#define l3_addr4 l3_addr.addr4
-#define l3_addr6 l3_addr.addr6
+/* XXX bad name */
+#define L3_ADDR(lle) ((struct sockaddr *)(&lle[1]))
+#define L3_ADDR_LEN(lle) (((struct sockaddr *)(&lle[1]))->sa_len)
#ifndef LLTBL_HASHTBL_SIZE
#define LLTBL_HASHTBL_SIZE 32 /* default 32 ? */
@@ -79,11 +80,21 @@
#endif
struct lltable {
- SLIST_ENTRY(lltable) llt_link;
- struct llentries lle_head[LLTBL_HASHTBL_SIZE];
- int llt_af;
- struct ifnet *llt_ifp;
+ SLIST_ENTRY(lltable) llt_link;
+ struct llentries lle_head[LLTBL_HASHTBL_SIZE];
+ int llt_af;
+ struct ifnet *llt_ifp;
+
+ struct llentry * (*llt_new)(const struct sockaddr *, u_int);
+ void (*llt_free)(struct lltable *, struct llentry *);
+ struct llentry * (*llt_lookup)(struct lltable *, u_int flags,
+ const struct sockaddr *l3addr);
+ int (*llt_rtcheck)(struct ifnet *,
+ const struct sockaddr *);
+ int (*llt_dump)(struct lltable *,
+ struct sysctl_req *);
};
+MALLOC_DECLARE(M_LLTABLE);
/*
* flags to be passed to arplookup.
@@ -100,11 +111,21 @@
#define LLATBL_HASH(key, mask) \
(((((((key >> 8) ^ key) >> 8) ^ key) >> 8) ^ key) & mask)
-struct llentry *lla_lookup(struct lltable *, u_int, struct sockaddr *);
-int lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *);
-int llentry_free(struct llentry *);
-
struct lltable *lltable_init(struct ifnet *, int);
void lltable_free(struct lltable *);
void lltable_drain(int);
+int lltable_sysctl_dumparp(int, struct sysctl_req *);
+
+void llentry_free(struct llentry *);
+
+/*
+ * Generic link layer address lookup function.
+ */
+static __inline struct llentry *
+lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
+{
+ return llt->llt_lookup(llt, flags, l3addr);
+}
+
+int lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *);
#endif /* _NET_IF_LLATBL_H_ */
==== //depot/projects/arp-v2/src/sys/net/rtsock.c#8 (text+ko) ====
@@ -109,8 +109,6 @@
struct rt_metrics *out);
static void rt_dispatch(struct mbuf *, const struct sockaddr *);
-extern int sysctl_dumparp(int af, struct sysctl_req *wr);
-
static void
rts_init(void)
{
@@ -1311,7 +1309,7 @@
* take care of llinfo entries
*/
if (w.w_op == NET_RT_FLAGS && (RTF_LLINFO & w.w_arg))
- error = sysctl_dumparp(af, w.w_req);
+ error = lltable_sysctl_dumparp(af, w.w_req);
break;
case NET_RT_IFLIST:
==== //depot/projects/arp-v2/src/sys/netinet/if_ether.c#19 (text+ko) ====
@@ -614,8 +614,7 @@
la->la_asked = 0;
la->la_preempt = V_arp_maxtries;
if (la->la_hold) {
- (*ifp->if_output)(ifp, la->la_hold,
- (struct sockaddr *)&la->l3_addr4, NULL);
+ (*ifp->if_output)(ifp, la->la_hold, L3_ADDR(la), NULL);
la->la_hold = 0;
}
}
==== //depot/projects/arp-v2/src/sys/netinet/in.c#7 (text+ko) ====
@@ -1019,11 +1019,207 @@
in_purgemaddrs(ifp);
}
+#include <sys/syslog.h>
+#include <net/if_dl.h>
+#include <netinet/if_ether.h>
+
+struct in_llentry {
+ struct llentry base;
+ struct sockaddr_in l3_addr4;
+};
+
+static struct llentry *
+in_lltable_new(const struct sockaddr *l3addr, u_int flags)
+{
+ struct in_llentry *lle;
+
+ lle = malloc(sizeof(struct in_llentry), M_LLTABLE, M_DONTWAIT | M_ZERO);
+ if (lle == NULL) /* NB: caller generates msg */
+ return NULL;
+
+ callout_init(&lle->base.la_timer, CALLOUT_MPSAFE);
+ /* qing
+ * For IPv4 this will trigger "arpresolve" to generate
+ * an ARP request
+ */
+ lle->base.la_expire = time_second; /* mark expired */
+ lle->l3_addr4 = *(const struct sockaddr_in *)l3addr;
+
+ return &lle->base;
+}
+
+/*
+ * Deletes an address from the address table.
+ * This function is called by the timer functions
+ * such as arptimer() and nd6_llinfo_timer(), and
+ * the caller does the locking.
+ */
+static void
+in_lltable_free(struct lltable *llt, struct llentry *lle)
+{
+ free(lle, M_LLTABLE);
+}
+
+static int
+in_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr)
+{
+ struct rtentry *rt;
+
+ KASSERT(l3addr->sa_family == AF_INET,
+ ("sin_family %d", l3addr->sa_family));
+
+ /* XXX rtalloc1 should take a const param */
+ rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0);
+ if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
+ log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n",
+ inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr));
+ if (rt != NULL)
+ rtfree(rt);
+ return EINVAL;
+ }
+ rtfree(rt);
+ return 0;
+}
+
+static struct llentry *
+in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
+{
+ const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
+ struct ifnet *ifp = llt->llt_ifp;
+ struct llentry *lle;
+ struct llentries *lleh;
+ u_int hashkey;
+
+ KASSERT(l3addr->sa_family == AF_INET,
+ ("sin_family %d", l3addr->sa_family));
+
+ hashkey = sin->sin_addr.s_addr;
+ lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
+ LIST_FOREACH(lle, lleh, lle_next) {
+ if (lle->la_flags & LLE_DELETED)
+ continue;
+ if (bcmp(L3_ADDR(lle), l3addr, sizeof(struct sockaddr_in)) == 0)
+ break;
+ }
+
+ if (lle == NULL) {
+ if (!(flags & LLE_CREATE))
+ return (NULL);
+ /*
+ * A route that covers the given address must have
+ * been installed 1st because we are doing a resolution,
+ * verify this.
+ */
+ if (!(flags & LLE_IFADDR) &&
+ in_lltable_rtcheck(ifp, l3addr) != 0)
+ return NULL;
+
+ lle = in_lltable_new(l3addr, flags);
+ if (lle == NULL) {
+ log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
+ return NULL;
+ }
+ lle->la_flags = flags & ~LLE_CREATE;
+ if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) {
+ bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
+ lle->la_flags |= (LLE_VALID | LLE_STATIC);
+ }
+
+ lle->lle_tbl = llt;
+ lle->lle_head = lleh;
+ LIST_INSERT_HEAD(lleh, lle, lle_next);
+ } else {
+ if (flags & LLE_DELETE)
+ lle->la_flags = LLE_DELETED;
+ }
+ return lle;
+}
+
+static int
+in_lltable_dump(struct lltable *llt, struct sysctl_req *wr)
+{
+#define SIN(lle) ((struct sockaddr_in *) L3_ADDR(lle))
+ struct ifnet *ifp = llt->llt_ifp;
+ struct llentry *lle;
+ /* XXX stack use */
+ struct {
+ struct rt_msghdr rtm;
+ struct sockaddr_inarp sin;
+ struct sockaddr_dl sdl;
+ } arpc;
+ int error, i;
+
+ /* XXXXX
+ * current IFNET_RLOCK() is mapped to IFNET_WLOCK()
+ * so it is okay to use this ASSERT, change it when
+ * IFNET lock is finalized
+ */
+ IFNET_WLOCK_ASSERT();
+
+ error = 0;
+ for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
+ LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
+ /* skip deleted entries */
+ if (lle->la_flags & LLE_DELETED)
+ continue;
+ /*
+ * produce a msg made of:
+ * struct rt_msghdr;
+ * struct sockaddr_inarp; (IPv4)
+ * struct sockaddr_dl;
+ */
+ bzero(&arpc, sizeof(arpc));
+ arpc.rtm.rtm_msglen = sizeof(arpc);
+
+ arpc.sin.sin_family = AF_INET;
+ arpc.sin.sin_len = sizeof(arpc.sin);
+ arpc.sin.sin_addr.s_addr = SIN(lle)->sin_addr.s_addr;
+
+ /* publish */
+ if (lle->la_flags & LLE_PUB) {
+ arpc.rtm.rtm_flags |= RTF_ANNOUNCE;
+ /* proxy only */
+ if (lle->la_flags & LLE_PROXY)
+ arpc.sin.sin_other = SIN_PROXY;
+ }
+
+ if (lle->la_flags & LLE_VALID) { /* valid MAC */
+ struct sockaddr_dl *sdl = &arpc.sdl;
+
+ sdl->sdl_family = AF_LINK;
+ sdl->sdl_len = sizeof(*sdl);
+ sdl->sdl_alen = ifp->if_addrlen;
+ sdl->sdl_index = ifp->if_index;
+ sdl->sdl_type = ifp->if_type;
+ bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
+ }
+ arpc.rtm.rtm_rmx.rmx_expire =
+ lle->la_flags & LLE_STATIC ? 0 : lle->la_expire;
+ arpc.rtm.rtm_flags |= RTF_LLINFO | RTF_HOST;
+ if (lle->la_flags & LLE_STATIC)
+ arpc.rtm.rtm_flags |= RTF_STATIC;
+ arpc.rtm.rtm_index = ifp->if_index;
+ error = SYSCTL_OUT(wr, &arpc, sizeof(arpc));
+ if (error)
+ break;
+ }
+ }
+ return error;
+#undef SIN
+}
+
void *
in_domifattach(struct ifnet *ifp)
{
struct lltable *llt = lltable_init(ifp, AF_INET);
+ if (llt != NULL) {
+ llt->llt_new = in_lltable_new;
+ llt->llt_free = in_lltable_free;
+ llt->llt_rtcheck = in_lltable_rtcheck;
+ llt->llt_lookup = in_lltable_lookup;
+ llt->llt_dump = in_lltable_dump;
+ }
return (llt);
}
==== //depot/projects/arp-v2/src/sys/netinet6/in6.c#9 (text+ko) ====
@@ -2098,6 +2098,197 @@
}
}
+#include <sys/sysctl.h>
+
+struct in6_llentry {
+ struct llentry base;
+ struct sockaddr_in6 l3_addr6;
+};
+
+static struct llentry *
+in6_lltable_new(const struct sockaddr *l3addr, u_int flags)
+{
+ struct in6_llentry *lle;
+
+ lle = malloc(sizeof(struct in6_llentry), M_LLTABLE,
+ M_DONTWAIT | M_ZERO);
+ if (lle == NULL) /* NB: caller generates msg */
+ return NULL;
+
+ callout_init(&lle->base.ln_timer_ch, CALLOUT_MPSAFE);
+ lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr;
+
+ return &lle->base;
+}
+
+/*
+ * Deletes an address from the address table.
+ * This function is called by the timer functions
+ * such as arptimer() and nd6_llinfo_timer(), and
+ * the caller does the locking.
+ */
+static void
+in6_lltable_free(struct lltable *llt, struct llentry *lle)
+{
+ free(lle, M_LLTABLE);
+}
+
+static int
+in6_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr)
+{
+ struct rtentry *rt;
+ char ip6buf[INET6_ADDRSTRLEN];
+
+ KASSERT(l3addr->sa_family == AF_INET6,
+ ("sin_family %d", l3addr->sa_family));
+
+ /* XXX rtalloc1 should take a const param */
+ rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0);
+ if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
+ struct ifaddr *ifa;
+ /*
+ * Create an ND6 cache for an IPv6 neighbor
+ * that is not covered by our own prefix.
+ */
+ /* XXX ifaof_ifpforaddr should take a const param */
+ ifa = ifaof_ifpforaddr(__DECONST(struct sockaddr *, l3addr), ifp);
+ if (ifa != NULL) {
+ if (rt != NULL)
+ rtfree(rt);
+ return 0;
+ }
+ log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n",
+ ip6_sprintf(ip6buf, &((const struct sockaddr_in6 *)l3addr)->sin6_addr));
+ if (rt != NULL)
+ rtfree(rt);
+ return EINVAL;
+ }
+ rtfree(rt);
+ return 0;
+}
+
+static struct llentry *
+in6_lltable_lookup(struct lltable *llt, u_int flags,
+ const struct sockaddr *l3addr)
+{
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr;
+ struct ifnet *ifp = llt->llt_ifp;
+ struct llentry *lle;
+ struct llentries *lleh;
+ u_int hashkey;
+
+ KASSERT(l3addr->sa_family == AF_INET6,
+ ("sin_family %d", l3addr->sa_family));
+
+ hashkey = sin6->sin6_addr.s6_addr32[3];
+ lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
+ LIST_FOREACH(lle, lleh, lle_next) {
+ if (lle->la_flags & LLE_DELETED)
+ continue;
+ if (bcmp(L3_ADDR(lle), l3addr, l3addr->sa_len) == 0)
+ break;
+ }
+
+ if (lle == NULL) {
+ if (!(flags & LLE_CREATE))
+ return (NULL);
+ /*
+ * A route that covers the given address must have
+ * been installed 1st because we are doing a resolution,
+ * verify this.
+ */
+ if (!(flags & LLE_IFADDR) &&
+ in6_lltable_rtcheck(ifp, l3addr) != 0)
+ return NULL;
+
+ lle = in6_lltable_new(l3addr, flags);
+ if (lle == NULL) {
+ log(LOG_INFO, "lla_lookup: new lle malloc failed\n");
+ return NULL;
+ }
+ lle->la_flags = flags & ~LLE_CREATE;
+ if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) {
+ bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen);
+ lle->la_flags |= (LLE_VALID | LLE_STATIC);
+ }
+
+ lle->lle_tbl = llt;
+ lle->lle_head = lleh;
+ LIST_INSERT_HEAD(lleh, lle, lle_next);
+ } else {
+ if (flags & LLE_DELETE)
+ lle->la_flags = LLE_DELETED;
+ }
+ return lle;
+}
+
+static int
+in6_lltable_dump(struct lltable *llt, struct sysctl_req *wr)
+{
+ struct ifnet *ifp = llt->llt_ifp;
+ struct llentry *lle;
+ /* XXX stack use */
+ struct {
+ struct rt_msghdr rtm;
+ struct sockaddr_in6 sin6;
+ struct sockaddr_dl sdl;
+ } ndpc;
+ int i, error;
+
+ /* XXXXX
+ * current IFNET_RLOCK() is mapped to IFNET_WLOCK()
+ * so it is okay to use this ASSERT, change it when
+ * IFNET lock is finalized
+ */
+ IFNET_WLOCK_ASSERT();
+
+ error = 0;
+ for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
+ LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
+ /* skip deleted entries */
+ if (lle->la_flags & LLE_DELETED)
+ continue;
+ /*
+ * produce a msg made of:
+ * struct rt_msghdr;
+ * struct sockaddr_in6 (IPv6)
+ * struct sockaddr_dl;
+ */
+ bzero(&ndpc, sizeof(ndpc));
+ ndpc.rtm.rtm_msglen = sizeof(ndpc);
+
+ ndpc.sin6.sin6_family = AF_INET6;
+ ndpc.sin6.sin6_len = sizeof(ndpc.sin6);
+ bcopy(L3_ADDR(lle), &ndpc.sin6, L3_ADDR_LEN(lle));
+
+ /* publish */
+ if (lle->la_flags & LLE_PUB)
+ ndpc.rtm.rtm_flags |= RTF_ANNOUNCE;
+
+ if (lle->la_flags & LLE_VALID) { /* valid MAC */
+ struct sockaddr_dl *sdl = &ndpc.sdl;
+
+ sdl->sdl_family = AF_LINK;
+ sdl->sdl_len = sizeof(*sdl);
+ sdl->sdl_alen = ifp->if_addrlen;
+ sdl->sdl_index = ifp->if_index;
+ sdl->sdl_type = ifp->if_type;
+ bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen);
+ }
+ ndpc.rtm.rtm_rmx.rmx_expire =
+ lle->la_flags & LLE_STATIC ? 0 : lle->la_expire;
+ ndpc.rtm.rtm_flags |= RTF_LLINFO | RTF_HOST;
+ if (lle->la_flags & LLE_STATIC)
+ ndpc.rtm.rtm_flags |= RTF_STATIC;
+ ndpc.rtm.rtm_index = ifp->if_index;
+ error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc));
+ if (error)
+ break;
+ }
+ }
+ return error;
+}
+
void *
in6_domifattach(struct ifnet *ifp)
{
@@ -2118,6 +2309,13 @@
ext->nd_ifinfo = nd6_ifattach(ifp);
ext->scope6_id = scope6_ifattach(ifp);
ext->lltable = lltable_init(ifp, AF_INET6);
+ if (ext->lltable != NULL) {
+ ext->lltable->llt_new = in6_lltable_new;
+ ext->lltable->llt_free = in6_lltable_free;
+ ext->lltable->llt_rtcheck = in6_lltable_rtcheck;
+ ext->lltable->llt_lookup = in6_lltable_lookup;
+ ext->lltable->llt_dump = in6_lltable_dump;
+ }
return ext;
}
==== //depot/projects/arp-v2/src/sys/netinet6/nd6.c#9 (text+ko) ====
@@ -61,6 +61,7 @@
#include <netinet/in.h>
#include <net/if_llatbl.h>
+#define L3_ADDR_SIN6(le) ((struct sockaddr_in6 *) L3_ADDR(le))
#include <netinet/if_ether.h>
#include <netinet6/in6_var.h>
#include <netinet/ip6.h>
@@ -444,7 +445,7 @@
}
ndi = ND_IFINFO(ifp);
- dst = &ln->l3_addr6.sin6_addr;
+ dst = &L3_ADDR_SIN6(ln)->sin6_addr;
if ((ln->la_flags & LLE_STATIC) || (ln->la_expire > time_second)) {
IF_AFDATA_UNLOCK(ifp);
@@ -963,7 +964,7 @@
if (!V_ip6_forwarding) {
int s;
s = splnet();
- dr = defrouter_lookup(&ln->l3_addr6.sin6_addr, ln->lle_tbl->llt_ifp);
+ dr = defrouter_lookup(&L3_ADDR_SIN6(ln)->sin6_addr, ln->lle_tbl->llt_ifp);
if (dr != NULL && dr->expire &&
ln->ln_state == ND6_LLINFO_STALE && gc) {
@@ -994,7 +995,7 @@
* is in the Default Router List.
* See a corresponding comment in nd6_na_input().
*/
- rt6_flush( &ln->l3_addr6.sin6_addr, ln->lle_tbl->llt_ifp);
+ rt6_flush(&L3_ADDR_SIN6(ln)->sin6_addr, ln->lle_tbl->llt_ifp);
}
if (dr) {
@@ -1454,7 +1455,7 @@
* just set the 2nd argument as the
* 1st one.
*/
- nd6_output(ifp, ifp, m_hold, &ln->l3_addr6, NULL);
+ nd6_output(ifp, ifp, m_hold, L3_ADDR_SIN6(ln), NULL);
}
}
} else if (ln->ln_state == ND6_LLINFO_INCOMPLETE) {
==== //depot/projects/arp-v2/src/sys/netinet6/nd6_nbr.c#8 (text+ko) ====
@@ -64,6 +64,7 @@
#include <netinet/in.h>
#include <netinet/in_var.h>
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list