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