From owner-svn-src-head@freebsd.org Mon Aug 10 12:04:01 2015 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 3875199E8B6; Mon, 10 Aug 2015 12:04:01 +0000 (UTC) (envelope-from melifaro@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 27C91646; Mon, 10 Aug 2015 12:04:01 +0000 (UTC) (envelope-from melifaro@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.70]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id t7AC41LA011883; Mon, 10 Aug 2015 12:04:01 GMT (envelope-from melifaro@FreeBSD.org) Received: (from melifaro@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id t7AC40vB011879; Mon, 10 Aug 2015 12:04:00 GMT (envelope-from melifaro@FreeBSD.org) Message-Id: <201508101204.t7AC40vB011879@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: melifaro set sender to melifaro@FreeBSD.org using -f From: "Alexander V. Chernikov" Date: Mon, 10 Aug 2015 12:04:00 +0000 (UTC) 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 X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 10 Aug 2015 12:04:01 -0000 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() 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 ***