summaryrefslogtreecommitdiffstats
path: root/sys/netinet/in.c
diff options
context:
space:
mode:
authormelifaro <melifaro@FreeBSD.org>2015-08-10 12:03:59 +0000
committermelifaro <melifaro@FreeBSD.org>2015-08-10 12:03:59 +0000
commit4f240a9c31022feb60343e2e1108338b44edb083 (patch)
tree112dd76676cd486bd689769878bb091803964520 /sys/netinet/in.c
parentfa26a290636c09c75688724a15b3624e6c44c8e4 (diff)
downloadFreeBSD-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/in.c')
-rw-r--r--sys/netinet/in.c176
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;
OpenPOWER on IntegriCloud