Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Aug 2015 12:04:00 +0000 (UTC)
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r286577 - in head/sys: net netinet netinet6
Message-ID:  <201508101204.t7AC40vB011879@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: melifaro
Date: Mon Aug 10 12:03:59 2015
New Revision: 286577
URL: https://svnweb.freebsd.org/changeset/base/286577

Log:
  Partially merge r274887,r275334,r275577,r275578,r275586 to minimize
  differences between projects/routing and HEAD.
  
  This commit tries to keep code logic the same while changing underlying
  code to use unified callbacks.
  
  * Add llt_foreach_entry method to traverse all entries in given llt
  * Add llt_dump_entry method to export particular lle entry in sysctl/rtsock
    format (code is not indented properly to minimize diff). Will be fixed
    in the next commits.
  * Add llt_link_entry/llt_unlink_entry methods to link/unlink particular lle.
  * Add llt_fill_sa_entry method to export address in the lle to sockaddr
    format.
  * Add llt_hash method to use in generic hash table support code.
  * Add llt_free_entry method which is used in llt_prefix_free code.
  
  * Prepare for fine-grained locking by separating lle unlink and deletion in
    lltable_free() and lltable_prefix_free().
  
  * Provide lltable_get<ifp|af>() functions to reduce direct 'struct lltable'
   access by external callers.
  
  * Remove @llt agrument from lle_free() lle callback since it was unused.
  * Temporarily add L3_CADDR() macro for 'const' sockaddr typecasting.
  * Switch to per-af hashing code.
  * Rename LLE_FREE_LOCKED() callback from in[6]_lltable_free() to
    in_[6]lltable_destroy() to avoid clashing with llt_free_entry() method.
    Update description from these functions.
  * Use unified lltable_free_entry() function instead of per-af one.
  
  Reviewed by:	ae

Modified:
  head/sys/net/if_llatbl.c
  head/sys/net/if_llatbl.h
  head/sys/netinet/in.c
  head/sys/netinet6/in6.c

Modified: head/sys/net/if_llatbl.c
==============================================================================
--- head/sys/net/if_llatbl.c	Mon Aug 10 11:52:54 2015	(r286576)
+++ head/sys/net/if_llatbl.c	Mon Aug 10 12:03:59 2015	(r286577)
@@ -70,6 +70,35 @@ static void vnet_lltable_init(void);
 struct rwlock lltable_rwlock;
 RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock");
 
+static void llentries_unlink(struct lltable *llt, struct llentries *head);
+
+static void htable_unlink_entry(struct llentry *lle);
+static void htable_link_entry(struct lltable *llt, struct llentry *lle);
+static int htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f,
+    void *farg);
+
+/*
+ * Dump lle state for a specific address family.
+ */
+static int
+lltable_dump_af(struct lltable *llt, struct sysctl_req *wr)
+{
+	int error;
+
+	LLTABLE_LOCK_ASSERT();
+
+	if (llt->llt_ifp->if_flags & IFF_LOOPBACK)
+		return (0);
+	error = 0;
+
+	IF_AFDATA_RLOCK(llt->llt_ifp);
+	error = lltable_foreach_lle(llt,
+	    (llt_foreach_cb_t *)llt->llt_dump_entry, wr);
+	IF_AFDATA_RUNLOCK(llt->llt_ifp);
+
+	return (error);
+}
+
 /*
  * Dump arp state for a specific address family.
  */
@@ -82,7 +111,7 @@ lltable_sysctl_dumparp(int af, struct sy
 	LLTABLE_RLOCK();
 	SLIST_FOREACH(llt, &V_lltables, llt_link) {
 		if (llt->llt_af == af) {
-			error = llt->llt_dump(llt, wr);
+			error = lltable_dump_af(llt, wr);
 			if (error != 0)
 				goto done;
 		}
@@ -93,25 +122,136 @@ done:
 }
 
 /*
- * 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.
+ * Common function helpers for chained hash table.
+ */
+
+/*
+ * Runs specified callback for each entry in @llt.
+ * Caller does the locking.
+ *
+ */
+static int
+htable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
+{
+	struct llentry *lle, *next;
+	int i, error;
+
+	error = 0;
+
+	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
+		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
+			error = f(llt, lle, farg);
+			if (error != 0)
+				break;
+		}
+	}
+
+	return (error);
+}
+
+static void
+htable_link_entry(struct lltable *llt, struct llentry *lle)
+{
+	struct llentries *lleh;
+	uint32_t hashidx;
+
+	if ((lle->la_flags & LLE_LINKED) != 0)
+		return;
+
+	IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
+
+	hashidx = llt->llt_hash(lle, LLTBL_HASHTBL_SIZE);
+	lleh = &llt->lle_head[hashidx];
+
+	lle->lle_tbl  = llt;
+	lle->lle_head = lleh;
+	lle->la_flags |= LLE_LINKED;
+	LIST_INSERT_HEAD(lleh, lle, lle_next);
+}
+
+static void
+htable_unlink_entry(struct llentry *lle)
+{
+
+	if ((lle->la_flags & LLE_LINKED) != 0) {
+		IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
+		LIST_REMOVE(lle, lle_next);
+		lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
+#if 0
+		lle->lle_tbl = NULL;
+		lle->lle_head = NULL;
+#endif
+	}
+}
+
+struct prefix_match_data {
+	const struct sockaddr *prefix;
+	const struct sockaddr *mask;
+	struct llentries dchain;
+	u_int flags;
+};
+
+static int
+htable_prefix_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
+{
+	struct prefix_match_data *pmd;
+
+	pmd = (struct prefix_match_data *)farg;
+
+	if (llt->llt_match_prefix(pmd->prefix, pmd->mask, pmd->flags, lle)) {
+		LLE_WLOCK(lle);
+		LIST_INSERT_HEAD(&pmd->dchain, lle, lle_chain);
+	}
+
+	return (0);
+}
+
+static void
+htable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
+    const struct sockaddr *mask, u_int flags)
+{
+	struct llentry *lle, *next;
+	struct prefix_match_data pmd;
+
+	bzero(&pmd, sizeof(pmd));
+	pmd.prefix = prefix;
+	pmd.mask = mask;
+	pmd.flags = flags;
+	LIST_INIT(&pmd.dchain);
+
+	IF_AFDATA_WLOCK(llt->llt_ifp);
+	/* Push matching lles to chain */
+	lltable_foreach_lle(llt, htable_prefix_free_cb, &pmd);
+
+	llentries_unlink(llt, &pmd.dchain);
+	IF_AFDATA_WUNLOCK(llt->llt_ifp);
+
+	LIST_FOREACH_SAFE(lle, &pmd.dchain, lle_chain, next)
+		llt->llt_free_entry(llt, lle);
+}
+
+static void
+llentries_unlink(struct lltable *llt, struct llentries *head)
+{
+	struct llentry *lle, *next;
+
+	LIST_FOREACH_SAFE(lle, head, lle_chain, next)
+		llt->llt_unlink_entry(lle);
+}
+
+/*
+ * Helper function used to drop all mbufs in hold queue.
  *
  * Returns the number of held packets, if any, that were dropped.
  */
 size_t
-llentry_free(struct llentry *lle)
+lltable_drop_entry_queue(struct llentry *lle)
 {
 	size_t pkts_dropped;
 	struct mbuf *next;
 
-	IF_AFDATA_WLOCK_ASSERT(lle->lle_tbl->llt_ifp);
 	LLE_WLOCK_ASSERT(lle);
 
-	LIST_REMOVE(lle, lle_next);
-	lle->la_flags &= ~(LLE_VALID | LLE_LINKED);
-
 	pkts_dropped = 0;
 	while ((lle->la_numheld > 0) && (lle->la_hold != NULL)) {
 		next = lle->la_hold->m_nextpkt;
@@ -125,6 +265,34 @@ llentry_free(struct llentry *lle)
 		("%s: la_numheld %d > 0, pkts_droped %zd", __func__,
 		 lle->la_numheld, pkts_dropped));
 
+	return (pkts_dropped);
+}
+
+/*
+ * 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.
+ *
+ * Returns the number of held packets, if any, that were dropped.
+ */
+size_t
+llentry_free(struct llentry *lle)
+{
+	struct lltable *llt;
+	size_t pkts_dropped;
+
+	LLE_WLOCK_ASSERT(lle);
+
+	if ((lle->la_flags & LLE_LINKED) != 0) {
+		llt = lle->lle_tbl;
+
+		IF_AFDATA_WLOCK_ASSERT(llt->llt_ifp);
+		llt->llt_unlink_entry(lle);
+	}
+
+	pkts_dropped = lltable_drop_entry_queue(lle);
+
 	LLE_FREE_LOCKED(lle);
 
 	return (pkts_dropped);
@@ -162,11 +330,28 @@ llentry_alloc(struct ifnet *ifp, struct 
 /*
  * Free all entries from given table and free itself.
  */
+
+static int
+lltable_free_cb(struct lltable *llt, struct llentry *lle, void *farg)
+{
+	struct llentries *dchain;
+
+	dchain = (struct llentries *)farg;
+
+	LLE_WLOCK(lle);
+	LIST_INSERT_HEAD(dchain, lle, lle_chain);
+
+	return (0);
+}
+
+/*
+ * Free all entries from given table and free itself.
+ */
 void
 lltable_free(struct lltable *llt)
 {
 	struct llentry *lle, *next;
-	int i;
+	struct llentries dchain;
 
 	KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
 
@@ -174,17 +359,19 @@ lltable_free(struct lltable *llt)
 	SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
 	LLTABLE_WUNLOCK();
 
+	LIST_INIT(&dchain);
 	IF_AFDATA_WLOCK(llt->llt_ifp);
-	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
-		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
-			LLE_WLOCK(lle);
-			if (callout_stop(&lle->la_timer))
-				LLE_REMREF(lle);
-			llentry_free(lle);
-		}
-	}
+	/* Push all lles to @dchain */
+	lltable_foreach_lle(llt, lltable_free_cb, &dchain);
+	llentries_unlink(llt, &dchain);
 	IF_AFDATA_WUNLOCK(llt->llt_ifp);
 
+	LIST_FOREACH_SAFE(lle, &dchain, lle_chain, next) {
+		if (callout_stop(&lle->la_timer))
+			LLE_REMREF(lle);
+		llentry_free(lle);
+	}
+
 	free(llt, M_LLTABLE);
 }
 
@@ -232,8 +419,6 @@ lltable_prefix_free(int af, struct socka
 	LLTABLE_RUNLOCK();
 }
 
-
-
 /*
  * Create a new lltable.
  */
@@ -250,6 +435,12 @@ lltable_init(struct ifnet *ifp, int af)
 	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++)
 		LIST_INIT(&llt->lle_head[i]);
 
+	/* Set some default callbacks */
+	llt->llt_link_entry = htable_link_entry;
+	llt->llt_unlink_entry = htable_unlink_entry;
+	llt->llt_prefix_free = htable_prefix_free;
+	llt->llt_foreach_entry = htable_foreach_lle;
+
 	LLTABLE_WLOCK();
 	SLIST_INSERT_HEAD(&V_lltables, llt, llt_link);
 	LLTABLE_WUNLOCK();
@@ -258,6 +449,54 @@ lltable_init(struct ifnet *ifp, int af)
 }
 
 /*
+ * External methods used by lltable consumers
+ */
+
+int
+lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f, void *farg)
+{
+
+	return (llt->llt_foreach_entry(llt, f, farg));
+}
+
+void
+lltable_link_entry(struct lltable *llt, struct llentry *lle)
+{
+
+	llt->llt_link_entry(llt, lle);
+}
+
+void
+lltable_unlink_entry(struct lltable *llt, struct llentry *lle)
+{
+
+	llt->llt_unlink_entry(lle);
+}
+
+void
+lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
+{
+	struct lltable *llt;
+
+	llt = lle->lle_tbl;
+	llt->llt_fill_sa_entry(lle, sa);
+}
+
+struct ifnet *
+lltable_get_ifp(const struct lltable *llt)
+{
+
+	return (llt->llt_ifp);
+}
+
+int
+lltable_get_af(const struct lltable *llt)
+{
+
+	return (llt->llt_af);
+}
+
+/*
  * Called in route_output when rtm_flags contains RTF_LLDATA.
  */
 int

Modified: head/sys/net/if_llatbl.h
==============================================================================
--- head/sys/net/if_llatbl.h	Mon Aug 10 11:52:54 2015	(r286576)
+++ head/sys/net/if_llatbl.h	Mon Aug 10 12:03:59 2015	(r286577)
@@ -57,7 +57,7 @@ struct llentry {
 	struct rwlock		 lle_lock;
 	struct lltable		 *lle_tbl;
 	struct llentries	 *lle_head;
-	void			(*lle_free)(struct lltable *, struct llentry *);
+	void			(*lle_free)(struct llentry *);
 	struct mbuf		 *la_hold;
 	int			 la_numheld;  /* # of packets currently held */
 	time_t			 la_expire;
@@ -76,6 +76,7 @@ struct llentry {
 		uint8_t		mac8[20];	/* IB needs 20 bytes. */
 	} ll_addr;
 
+	LIST_ENTRY(llentry)	lle_chain;	/* chain of deleted items */
 	/* XXX af-private? */
 	union {
 		struct callout	ln_timer_ch;
@@ -114,7 +115,7 @@ struct llentry {
 
 #define	LLE_FREE_LOCKED(lle) do {				\
 	if ((lle)->lle_refcnt == 1)				\
-		(lle)->lle_free((lle)->lle_tbl, (lle));		\
+		(lle)->lle_free(lle);				\
 	else {							\
 		LLE_REMREF(lle);				\
 		LLE_WUNLOCK(lle);				\
@@ -133,6 +134,7 @@ struct llentry {
 #define	la_timer	lle_timer.la_timer
 
 /* XXX bad name */
+#define	L3_CADDR(lle)	((const struct sockaddr *)(&lle[1]))
 #define	L3_ADDR(lle)	((struct sockaddr *)(&lle[1]))
 #define	L3_ADDR_LEN(lle)	(((struct sockaddr *)(&lle[1]))->sa_len)
 
@@ -152,7 +154,18 @@ typedef	int (llt_delete_t)(struct lltabl
     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 *);
+typedef int (llt_dump_entry_t)(struct lltable *, struct llentry *,
+    struct sysctl_req *);
+typedef uint32_t (llt_hash_t)(const struct llentry *, uint32_t);
+typedef int (llt_match_prefix_t)(const struct sockaddr *,
+    const struct sockaddr *, u_int, struct llentry *);
+typedef void (llt_free_entry_t)(struct lltable *, struct llentry *);
+typedef void (llt_fill_sa_entry_t)(const struct llentry *, struct sockaddr *);
+typedef void (llt_link_entry_t)(struct lltable *, struct llentry *);
+typedef void (llt_unlink_entry_t)(struct llentry *);
+
+typedef int (llt_foreach_cb_t)(struct lltable *, struct llentry *, void *);
+typedef int (llt_foreach_entry_t)(struct lltable *, llt_foreach_cb_t *, void *);
 
 struct lltable {
 	SLIST_ENTRY(lltable)	llt_link;
@@ -164,7 +177,14 @@ struct lltable {
 	llt_create_t		*llt_create;
 	llt_delete_t		*llt_delete;
 	llt_prefix_free_t	*llt_prefix_free;
-	llt_dump_t		*llt_dump;
+	llt_dump_entry_t	*llt_dump_entry;
+	llt_hash_t		*llt_hash;
+	llt_match_prefix_t	*llt_match_prefix;
+	llt_free_entry_t	*llt_free_entry;
+	llt_foreach_entry_t	*llt_foreach_entry;
+	llt_link_entry_t	*llt_link_entry;
+	llt_unlink_entry_t	*llt_unlink_entry;
+	llt_fill_sa_entry_t	*llt_fill_sa_entry;
 };
 
 MALLOC_DECLARE(M_LLTABLE);
@@ -197,6 +217,19 @@ size_t		llentry_free(struct llentry *);
 struct llentry  *llentry_alloc(struct ifnet *, struct lltable *,
 		    struct sockaddr_storage *);
 
+/* helper functions */
+size_t lltable_drop_entry_queue(struct llentry *);
+
+struct llentry *lltable_create_lle(struct lltable *llt, u_int flags,
+    const void *paddr);
+void lltable_link_entry(struct lltable *llt, struct llentry *lle);
+void lltable_unlink_entry(struct lltable *llt, struct llentry *lle);
+void lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa);
+struct ifnet *lltable_get_ifp(const struct lltable *llt);
+int lltable_get_af(const struct lltable *llt);
+
+int lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f,
+    void *farg);
 /*
  * Generic link layer address lookup function.
  */

Modified: head/sys/netinet/in.c
==============================================================================
--- head/sys/netinet/in.c	Mon Aug 10 11:52:54 2015	(r286576)
+++ head/sys/netinet/in.c	Mon Aug 10 12:03:59 2015	(r286577)
@@ -961,15 +961,19 @@ struct in_llentry {
 	struct sockaddr_in	l3_addr4;
 };
 
+#define	IN_LLTBL_DEFAULT_HSIZE	32
+#define	IN_LLTBL_HASH(k, h) \
+	(((((((k >> 8) ^ k) >> 8) ^ k) >> 8) ^ k) & ((h) - 1))
+
 /*
- * 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.
+ * Do actual deallocation of @lle.
+ * Called by LLE_FREE_LOCKED when number of references
+ * drops to zero.
  */
 static void
-in_lltable_free(struct lltable *llt, struct llentry *lle)
+in_lltable_destroy_lle(struct llentry *lle)
 {
+
 	LLE_WUNLOCK(lle);
 	LLE_LOCK_DESTROY(lle);
 	free(lle, M_LLTABLE);
@@ -991,7 +995,7 @@ in_lltable_new(const struct sockaddr *l3
 	lle->base.la_expire = time_uptime; /* mark expired */
 	lle->l3_addr4 = *(const struct sockaddr_in *)l3addr;
 	lle->base.lle_refcnt = 1;
-	lle->base.lle_free = in_lltable_free;
+	lle->base.lle_free = in_lltable_destroy_lle;
 	LLE_LOCK_INIT(&lle->base);
 	callout_init(&lle->base.la_timer, 1);
 
@@ -1001,37 +1005,48 @@ in_lltable_new(const struct sockaddr *l3
 #define IN_ARE_MASKED_ADDR_EQUAL(d, a, m)	(			\
 	    (((ntohl((d)->sin_addr.s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 )
 
-static void
-in_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
-    const struct sockaddr *mask, u_int flags)
+static int
+in_lltable_match_prefix(const struct sockaddr *prefix,
+    const struct sockaddr *mask, u_int flags, struct llentry *lle)
 {
 	const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix;
 	const struct sockaddr_in *msk = (const struct sockaddr_in *)mask;
-	struct llentry *lle, *next;
-	int i;
-	size_t pkts_dropped;
 
-	IF_AFDATA_WLOCK(llt->llt_ifp);
-	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
-		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
-			/*
-			 * (flags & LLE_STATIC) means deleting all entries
-			 * including static ARP entries.
-			 */
-			if (IN_ARE_MASKED_ADDR_EQUAL(satosin(L3_ADDR(lle)),
-			    pfx, msk) && ((flags & LLE_STATIC) ||
-			    !(lle->la_flags & LLE_STATIC))) {
-				LLE_WLOCK(lle);
-				if (callout_stop(&lle->la_timer))
-					LLE_REMREF(lle);
-				pkts_dropped = llentry_free(lle);
-				ARPSTAT_ADD(dropped, pkts_dropped);
-			}
-		}
-	}
-	IF_AFDATA_WUNLOCK(llt->llt_ifp);
+	/*
+	 * (flags & LLE_STATIC) means deleting all entries
+	 * including static ARP entries.
+	 */
+	if (IN_ARE_MASKED_ADDR_EQUAL(satosin(L3_ADDR(lle)), pfx, msk) &&
+	    ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)))
+		return (1);
+
+	return (0);
 }
 
+static void
+in_lltable_free_entry(struct lltable *llt, struct llentry *lle)
+{
+	struct ifnet *ifp;
+	size_t pkts_dropped;
+
+	LLE_WLOCK_ASSERT(lle);
+	KASSERT(llt != NULL, ("lltable is NULL"));
+
+	/* Unlink entry from table if not already */
+	if ((lle->la_flags & LLE_LINKED) != 0) {
+		ifp = llt->llt_ifp;
+		IF_AFDATA_WLOCK_ASSERT(ifp);
+		lltable_unlink_entry(llt, lle);
+	}
+
+	/* cancel timer */
+	if (callout_stop(&lle->la_timer))
+		LLE_REMREF(lle);
+
+	/* Drop hold queue */
+	pkts_dropped = llentry_free(lle);
+	ARPSTAT_ADD(dropped, pkts_dropped);
+}
 
 static int
 in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr)
@@ -1107,16 +1122,45 @@ in_lltable_rtcheck(struct ifnet *ifp, u_
 	return (0);
 }
 
+static inline uint32_t
+in_lltable_hash_dst(const struct in_addr dst, uint32_t hsize)
+{
+
+	return (IN_LLTBL_HASH(dst.s_addr, hsize));
+}
+
+static uint32_t
+in_lltable_hash(const struct llentry *lle, uint32_t hsize)
+{
+	const struct sockaddr_in *sin;
+
+	sin = (const struct sockaddr_in *)(L3_CADDR(lle));
+
+	return (in_lltable_hash_dst(sin->sin_addr, hsize));
+}
+
+static void
+in_lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
+{
+	struct sockaddr_in *sin;
+
+	sin = (struct sockaddr_in *)sa;
+	bzero(sin, sizeof(*sin));
+	sin->sin_family = AF_INET;
+	sin->sin_len = sizeof(*sin);
+	sin->sin_addr = ((const struct sockaddr_in *)(L3_CADDR(lle)))->sin_addr;
+}
+
 static inline struct llentry *
 in_lltable_find_dst(struct lltable *llt, struct in_addr dst)
 {
 	struct llentry *lle;
 	struct llentries *lleh;
 	struct sockaddr_in *sin;
-	u_int hashkey;
+	u_int hashidx;
 
-	hashkey = dst.s_addr;
-	lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
+	hashidx = in_lltable_hash_dst(dst, LLTBL_HASHTBL_SIZE);
+	lleh = &llt->lle_head[hashidx];
 	LIST_FOREACH(lle, lleh, lle_next) {
 		sin = satosin(L3_ADDR(lle));
 		if (lle->la_flags & LLE_DELETED)
@@ -1169,8 +1213,6 @@ in_lltable_create(struct lltable *llt, u
 	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;
 
 	IF_AFDATA_WLOCK_ASSERT(ifp);
 	KASSERT(l3addr->sa_family == AF_INET,
@@ -1205,13 +1247,7 @@ in_lltable_create(struct lltable *llt, u
 		lle->la_flags |= (LLE_VALID | LLE_STATIC);
 	}
 
-	hashkey = sin->sin_addr.s_addr;
-	lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
-
-	lle->lle_tbl  = llt;
-	lle->lle_head = lleh;
-	lle->la_flags |= LLE_LINKED;
-	LIST_INSERT_HEAD(lleh, lle, lle_next);
+	lltable_link_entry(llt, lle);
 	LLE_WLOCK(lle);
 
 	return (lle);
@@ -1226,22 +1262,11 @@ in_lltable_lookup(struct lltable *llt, u
 {
 	const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr;
 	struct llentry *lle;
-	struct llentries *lleh;
-	u_int hashkey;
 
 	IF_AFDATA_LOCK_ASSERT(llt->llt_ifp);
 	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) {
-		struct sockaddr_in *sa2 = satosin(L3_ADDR(lle));
-		if (lle->la_flags & LLE_DELETED)
-			continue;
-		if (sa2->sin_addr.s_addr == sin->sin_addr.s_addr)
-			break;
-	}
+	lle = in_lltable_find_dst(llt, sin->sin_addr);
 
 	if (lle == NULL)
 		return (NULL);
@@ -1255,47 +1280,39 @@ in_lltable_lookup(struct lltable *llt, u
 }
 
 static int
-in_lltable_dump(struct lltable *llt, struct sysctl_req *wr)
+in_lltable_dump_entry(struct lltable *llt, struct llentry *lle,
+    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_in	sin;
 		struct sockaddr_dl	sdl;
 	} arpc;
-	int error, i;
-
-	LLTABLE_LOCK_ASSERT();
-
-	error = 0;
-	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
-		LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
-			struct sockaddr_dl *sdl;
+	struct sockaddr_dl *sdl;
+	int error;
 
+	bzero(&arpc, sizeof(arpc));
 			/* skip deleted entries */
 			if ((lle->la_flags & LLE_DELETED) == LLE_DELETED)
-				continue;
+				return (0);
 			/* Skip if jailed and not a valid IP of the prison. */
-			if (prison_if(wr->td->td_ucred, L3_ADDR(lle)) != 0)
-				continue;
+			lltable_fill_sa_entry(lle,(struct sockaddr *)&arpc.sin);
+			if (prison_if(wr->td->td_ucred,
+			    (struct sockaddr *)&arpc.sin) != 0)
+				return (0);
 			/*
 			 * produce a msg made of:
 			 *  struct rt_msghdr;
 			 *  struct sockaddr_in; (IPv4)
 			 *  struct sockaddr_dl;
 			 */
-			bzero(&arpc, sizeof(arpc));
 			arpc.rtm.rtm_msglen = sizeof(arpc);
 			arpc.rtm.rtm_version = RTM_VERSION;
 			arpc.rtm.rtm_type = RTM_GET;
 			arpc.rtm.rtm_flags = RTF_UP;
 			arpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
-			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)
@@ -1321,12 +1338,8 @@ in_lltable_dump(struct lltable *llt, str
 				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
+
+	return (error);
 }
 
 void *
@@ -1339,11 +1352,14 @@ in_domifattach(struct ifnet *ifp)
 
 	llt = lltable_init(ifp, AF_INET);
 	if (llt != NULL) {
-		llt->llt_prefix_free = in_lltable_prefix_free;
 		llt->llt_lookup = in_lltable_lookup;
 		llt->llt_create = in_lltable_create;
 		llt->llt_delete = in_lltable_delete;
-		llt->llt_dump = in_lltable_dump;
+		llt->llt_dump_entry = in_lltable_dump_entry;
+		llt->llt_hash = in_lltable_hash;
+		llt->llt_fill_sa_entry = in_lltable_fill_sa_entry;
+		llt->llt_free_entry = in_lltable_free_entry;
+		llt->llt_match_prefix = in_lltable_match_prefix;
 	}
 	ii->ii_llt = llt;
 

Modified: head/sys/netinet6/in6.c
==============================================================================
--- head/sys/netinet6/in6.c	Mon Aug 10 11:52:54 2015	(r286576)
+++ head/sys/netinet6/in6.c	Mon Aug 10 12:03:59 2015	(r286577)
@@ -2050,15 +2050,19 @@ struct in6_llentry {
 	struct sockaddr_in6	l3_addr6;
 };
 
+#define	IN6_LLTBL_DEFAULT_HSIZE	32
+#define	IN6_LLTBL_HASH(k, h) \
+	(((((((k >> 8) ^ k) >> 8) ^ k) >> 8) ^ k) & ((h) - 1))
+
 /*
- * 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.
+ * Do actual deallocation of @lle.
+ * Called by LLE_FREE_LOCKED when number of references
+ * drops to zero.
  */
 static void
-in6_lltable_free(struct lltable *llt, struct llentry *lle)
+in6_lltable_destroy_lle(struct llentry *lle)
 {
+
 	LLE_WUNLOCK(lle);
 	LLE_LOCK_DESTROY(lle);
 	free(lle, M_LLTABLE);
@@ -2075,42 +2079,48 @@ in6_lltable_new(const struct sockaddr *l
 
 	lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr;
 	lle->base.lle_refcnt = 1;
-	lle->base.lle_free = in6_lltable_free;
+	lle->base.lle_free = in6_lltable_destroy_lle;
 	LLE_LOCK_INIT(&lle->base);
 	callout_init(&lle->base.ln_timer_ch, 1);
 
 	return (&lle->base);
 }
 
-static void
-in6_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix,
-    const struct sockaddr *mask, u_int flags)
+static int
+in6_lltable_match_prefix(const struct sockaddr *prefix,
+    const struct sockaddr *mask, u_int flags, struct llentry *lle)
 {
 	const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix;
 	const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask;
-	struct llentry *lle, *next;
-	int i;
 
-	/*
-	 * (flags & LLE_STATIC) means deleting all entries
-	 * including static ND6 entries.
-	 */
-	IF_AFDATA_WLOCK(llt->llt_ifp);
-	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
-		LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) {
-			if (IN6_ARE_MASKED_ADDR_EQUAL(
-			    &satosin6(L3_ADDR(lle))->sin6_addr,
-			    &pfx->sin6_addr, &msk->sin6_addr) &&
-			    ((flags & LLE_STATIC) ||
-			    !(lle->la_flags & LLE_STATIC))) {
-				LLE_WLOCK(lle);
-				if (callout_stop(&lle->la_timer))
-					LLE_REMREF(lle);
-				llentry_free(lle);
-			}
-		}
+	if (IN6_ARE_MASKED_ADDR_EQUAL(&satosin6(L3_ADDR(lle))->sin6_addr,
+	    &pfx->sin6_addr, &msk->sin6_addr) &&
+	    ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC)))
+		return (1);
+
+	return (0);
+}
+
+static void
+in6_lltable_free_entry(struct lltable *llt, struct llentry *lle)
+{
+	struct ifnet *ifp;
+
+	LLE_WLOCK_ASSERT(lle);
+	KASSERT(llt != NULL, ("lltable is NULL"));
+
+	/* Unlink entry from table */
+	if ((lle->la_flags & LLE_LINKED) != 0) {
+
+		ifp = llt->llt_ifp;
+		IF_AFDATA_WLOCK_ASSERT(ifp);
+		lltable_unlink_entry(llt, lle);
 	}
-	IF_AFDATA_WUNLOCK(llt->llt_ifp);
+
+	if (callout_stop(&lle->la_timer))
+		LLE_REMREF(lle);
+
+	llentry_free(lle);
 }
 
 static int
@@ -2152,18 +2162,47 @@ in6_lltable_rtcheck(struct ifnet *ifp,
 	return 0;
 }
 
+static inline uint32_t
+in6_lltable_hash_dst(const struct in6_addr *dst, uint32_t hsize)
+{
+
+	return (IN6_LLTBL_HASH(dst->s6_addr32[3], hsize));
+}
+
+static uint32_t
+in6_lltable_hash(const struct llentry *lle, uint32_t hsize)
+{
+	const struct sockaddr_in6 *sin6;
+
+	sin6 = (const struct sockaddr_in6 *)L3_CADDR(lle);
+
+	return (in6_lltable_hash_dst(&sin6->sin6_addr, hsize));
+}
+
+static void
+in6_lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa)
+{
+	struct sockaddr_in6 *sin6;
+
+	sin6 = (struct sockaddr_in6 *)sa;
+	bzero(sin6, sizeof(*sin6));
+	sin6->sin6_family = AF_INET6;
+	sin6->sin6_len = sizeof(*sin6);
+	sin6->sin6_addr =((const struct sockaddr_in6*)L3_CADDR(lle))->sin6_addr;
+}
+
 static inline struct llentry *
 in6_lltable_find_dst(struct lltable *llt, const struct in6_addr *dst)
 {
 	struct llentry *lle;
 	struct llentries *lleh;
 	const struct sockaddr_in6 *sin6;
-	u_int hashkey;
+	u_int hashidx;
 
-	hashkey = dst->s6_addr32[3];
-	lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
+	hashidx = in6_lltable_hash_dst(dst, LLTBL_HASHTBL_SIZE);
+	lleh = &llt->lle_head[hashidx];
 	LIST_FOREACH(lle, lleh, lle_next) {
-		sin6 = (const struct sockaddr_in6 *)L3_ADDR(lle);
+		sin6 = (const struct sockaddr_in6 *)L3_CADDR(lle);
 		if (lle->la_flags & LLE_DELETED)
 			continue;
 		if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, dst))
@@ -2212,8 +2251,6 @@ in6_lltable_create(struct lltable *llt, 
 	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;
 
 	IF_AFDATA_WLOCK_ASSERT(ifp);
 	KASSERT(l3addr->sa_family == AF_INET6,
@@ -2246,13 +2283,7 @@ in6_lltable_create(struct lltable *llt, 
 		lle->la_flags |= (LLE_VALID | LLE_STATIC);
 	}
 
-	hashkey = sin6->sin6_addr.s6_addr32[3];
-	lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)];
-
-	lle->lle_tbl  = llt;
-	lle->lle_head = lleh;
-	lle->la_flags |= LLE_LINKED;
-	LIST_INSERT_HEAD(lleh, lle, lle_next);
+	lltable_link_entry(llt, lle);
 	LLE_WLOCK(lle);
 
 	return (lle);
@@ -2282,10 +2313,10 @@ in6_lltable_lookup(struct lltable *llt, 
 }
 
 static int
-in6_lltable_dump(struct lltable *llt, struct sysctl_req *wr)
+in6_lltable_dump_entry(struct lltable *llt, struct llentry *lle,
+    struct sysctl_req *wr)
 {
 	struct ifnet *ifp = llt->llt_ifp;
-	struct llentry *lle;
 	/* XXX stack use */
 	struct {
 		struct rt_msghdr	rtm;
@@ -2298,39 +2329,30 @@ in6_lltable_dump(struct lltable *llt, st
 #endif
 		struct sockaddr_dl	sdl;
 	} ndpc;
-	int i, error;
-
-	if (ifp->if_flags & IFF_LOOPBACK)
-		return 0;
+	struct sockaddr_dl *sdl;
+	int error;
 
-	LLTABLE_LOCK_ASSERT();
-
-	error = 0;
-	for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) {
-		LIST_FOREACH(lle, &llt->lle_head[i], lle_next) {
-			struct sockaddr_dl *sdl;
-
-			/* skip deleted or invalid entries */
+	bzero(&ndpc, sizeof(ndpc));
+			/* skip invalid entries */
 			if ((lle->la_flags & (LLE_DELETED|LLE_VALID)) != LLE_VALID)
-				continue;
+				return (0);
 			/* Skip if jailed and not a valid IP of the prison. */
-			if (prison_if(wr->td->td_ucred, L3_ADDR(lle)) != 0)
-				continue;
+			lltable_fill_sa_entry(lle,
+			    (struct sockaddr *)&ndpc.sin6);
+			if (prison_if(wr->td->td_ucred,
+			    (struct sockaddr *)&ndpc.sin6) != 0)
+				return (0);
 			/*
 			 * 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.rtm.rtm_version = RTM_VERSION;
 			ndpc.rtm.rtm_type = RTM_GET;
 			ndpc.rtm.rtm_flags = RTF_UP;
 			ndpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
-			ndpc.sin6.sin6_family = AF_INET6;
-			ndpc.sin6.sin6_len = sizeof(ndpc.sin6);
-			bcopy(L3_ADDR(lle), &ndpc.sin6, L3_ADDR_LEN(lle));
 			if (V_deembed_scopeid)
 				sa6_recoverscope(&ndpc.sin6);
 
@@ -2352,11 +2374,8 @@ in6_lltable_dump(struct lltable *llt, st
 				ndpc.rtm.rtm_flags |= RTF_STATIC;
 			ndpc.rtm.rtm_index = ifp->if_index;
 			error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc));
-			if (error)
-				break;
-		}
-	}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201508101204.t7AC40vB011879>