diff options
author | melifaro <melifaro@FreeBSD.org> | 2015-08-10 12:03:59 +0000 |
---|---|---|
committer | melifaro <melifaro@FreeBSD.org> | 2015-08-10 12:03:59 +0000 |
commit | 4f240a9c31022feb60343e2e1108338b44edb083 (patch) | |
tree | 112dd76676cd486bd689769878bb091803964520 /sys/netinet | |
parent | fa26a290636c09c75688724a15b3624e6c44c8e4 (diff) | |
download | FreeBSD-src-4f240a9c31022feb60343e2e1108338b44edb083.zip FreeBSD-src-4f240a9c31022feb60343e2e1108338b44edb083.tar.gz |
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
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/in.c | 176 |
1 files changed, 96 insertions, 80 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 9d3642e..5f3620a 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -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 *l3addr, u_int flags) 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 *l3addr, u_int flags) #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; + + /* + * (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; - 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); - } - } + 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); } - IF_AFDATA_WUNLOCK(llt->llt_ifp); -} + /* 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_int flags, const struct sockaddr *l3addr 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_int flags, const struct sockaddr *l3add 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_int flags, const struct sockaddr *l3add 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_int flags, const struct sockaddr *l3add { 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_int flags, const struct sockaddr *l3add } 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, struct sysctl_req *wr) 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; |