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 ***
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to