Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Use lltable/llentry for NDP
details: https://anonhg.NetBSD.org/src/rev/e7b2064b20ee
branches: trunk
changeset: 341834:e7b2064b20ee
user: ozaki-r <ozaki-r%NetBSD.org@localhost>
date: Wed Nov 25 06:21:26 2015 +0000
description:
Use lltable/llentry for NDP
lltable and llentry were introduced to replace ARP cache data structure
for further restructuring of the routing table: L2 nexthop cache
separation. This change replaces the NDP cache data structure
(llinfo_nd6) with them as well as ARP.
One noticeable change is for neighbor cache GC mechanism that was
introduced to prevent IPv6 DoS attacks. net.inet6.ip6.neighborgcthresh
was the max number of caches that we store in the system. After
introducing lltable/llentry, the value is changed to be per-interface
basis because lltable/llentry stores neighbor caches in each interface
separately. And the change brings one degradation; the old GC mechanism
dropped exceeded packets based on LRU while the new implementation drops
packets in order from the beginning of lltable (a hash table + linked
lists). It would be improved in the future.
Added functions in in6.c come from FreeBSD (as of r286629) and are
tweaked for NetBSD.
Proposed on tech-kern and tech-net.
diffstat:
sys/net/if_llatbl.c | 25 ++-
sys/net/if_llatbl.h | 15 +-
sys/netinet6/in6.c | 324 ++++++++++++++++++++++++++++++++++++++++-
sys/netinet6/in6_var.h | 8 +-
sys/netinet6/nd6.c | 383 +++++++++++++++++++++++++++++-------------------
sys/netinet6/nd6.h | 25 +--
sys/netinet6/nd6_nbr.c | 10 +-
sys/netinet6/nd6_rtr.c | 8 +-
8 files changed, 607 insertions(+), 191 deletions(-)
diffs (truncated from 1457 to 300 lines):
diff -r 0dc5dc5f0aab -r e7b2064b20ee sys/net/if_llatbl.c
--- a/sys/net/if_llatbl.c Wed Nov 25 04:04:13 2015 +0000
+++ b/sys/net/if_llatbl.c Wed Nov 25 06:21:26 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_llatbl.c,v 1.7 2015/10/20 07:35:15 ozaki-r Exp $ */
+/* $NetBSD: if_llatbl.c,v 1.8 2015/11/25 06:21:26 ozaki-r Exp $ */
/*
* Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
* Copyright (c) 2004-2008 Qing Li. All rights reserved.
@@ -162,6 +162,8 @@
lle->lle_head = lleh;
lle->la_flags |= LLE_LINKED;
LIST_INSERT_HEAD(lleh, lle, lle_next);
+
+ llt->llt_lle_count++;
}
static void
@@ -176,6 +178,8 @@
lle->lle_tbl = NULL;
lle->lle_head = NULL;
#endif
+ KASSERT(lle->lle_tbl->llt_lle_count != 0);
+ lle->lle_tbl->llt_lle_count--;
}
}
@@ -352,18 +356,16 @@
}
/*
- * Free all entries from given table and free itself.
+ * Free all entries from given table.
*/
void
-lltable_free(struct lltable *llt)
+lltable_purge_entries(struct lltable *llt)
{
struct llentry *lle, *next;
struct llentries dchain;
KASSERTMSG(llt != NULL, "llt is NULL");
- lltable_unlink(llt);
-
LIST_INIT(&dchain);
IF_AFDATA_WLOCK(llt->llt_ifp);
/* Push all lles to @dchain */
@@ -394,6 +396,19 @@
llentry_free(lle);
}
+}
+
+/*
+ * Free all entries from given table and free itself.
+ */
+void
+lltable_free(struct lltable *llt)
+{
+
+ KASSERTMSG(llt != NULL, "llt is NULL");
+
+ lltable_unlink(llt);
+ lltable_purge_entries(llt);
llt->llt_free_tbl(llt);
}
diff -r 0dc5dc5f0aab -r e7b2064b20ee sys/net/if_llatbl.h
--- a/sys/net/if_llatbl.h Wed Nov 25 04:04:13 2015 +0000
+++ b/sys/net/if_llatbl.h Wed Nov 25 06:21:26 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: if_llatbl.h,v 1.5 2015/11/05 06:50:51 ozaki-r Exp $ */
+/* $NetBSD: if_llatbl.h,v 1.6 2015/11/25 06:21:26 ozaki-r Exp $ */
/*
* Copyright (c) 2004 Luigi Rizzo, Alessandro Cerri. All rights reserved.
* Copyright (c) 2004-2008 Qing Li. All rights reserved.
@@ -101,7 +101,12 @@
#ifdef __NetBSD__
#define la_timer lle_timer
+#define ln_timer_ch lle_timer
+#define ln_expire la_expire
+#define ln_asked la_asked
+#define ln_hold la_hold
struct rtentry *la_rt;
+#define ln_rt la_rt
void *la_opaque; /* For tokenring */
#endif
};
@@ -240,6 +245,7 @@
int llt_af;
int llt_hsize;
struct llentries *lle_head;
+ unsigned int llt_lle_count;
struct ifnet *llt_ifp;
llt_lookup_t *llt_lookup;
@@ -282,6 +288,7 @@
void lltable_prefix_free(int, struct sockaddr *,
struct sockaddr *, u_int);
void lltable_drain(int);
+void lltable_purge_entries(struct lltable *);
int lltable_sysctl_dumparp(int, struct sysctl_req *);
size_t llentry_free(struct llentry *);
@@ -299,6 +306,12 @@
struct ifnet *lltable_get_ifp(const struct lltable *llt);
int lltable_get_af(const struct lltable *llt);
+static inline unsigned int
+lltable_get_entry_count(struct lltable *llt)
+{
+ return llt->llt_lle_count;
+}
+
int lltable_foreach_lle(struct lltable *llt, llt_foreach_cb_t *f,
void *farg);
/*
diff -r 0dc5dc5f0aab -r e7b2064b20ee sys/netinet6/in6.c
--- a/sys/netinet6/in6.c Wed Nov 25 04:04:13 2015 +0000
+++ b/sys/netinet6/in6.c Wed Nov 25 06:21:26 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: in6.c,v 1.190 2015/08/24 22:21:27 pooka Exp $ */
+/* $NetBSD: in6.c,v 1.191 2015/11/25 06:21:26 ozaki-r Exp $ */
/* $KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $ */
/*
@@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.190 2015/08/24 22:21:27 pooka Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.191 2015/11/25 06:21:26 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -83,16 +83,18 @@
#include <sys/syslog.h>
#include <sys/kauth.h>
#include <sys/cprng.h>
+#include <sys/kmem.h>
#include <net/if.h>
#include <net/if_types.h>
-#include <net/route.h>
+#include <net/if_llatbl.h>
+#include <net/if_ether.h>
#include <net/if_dl.h>
#include <net/pfil.h>
+#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
-#include <net/if_ether.h>
#include <netinet/ip6.h>
#include <netinet6/ip6_var.h>
@@ -1761,6 +1763,34 @@
return (struct in6_ifaddr *)best_ifa;
}
+/*
+ * find the internet address corresponding to a given address.
+ * ifaddr is returned referenced.
+ */
+struct in6_ifaddr *
+in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid)
+{
+ struct in6_ifaddr *ia;
+
+#ifdef __FreeBSD__
+ IN6_IFADDR_RLOCK();
+ LIST_FOREACH(ia, IN6ADDR_HASH(addr), ia6_hash) {
+#else
+ for (ia = in6_ifaddr; ia; ia = ia->ia_next) {
+#endif
+ if (IN6_ARE_ADDR_EQUAL(IA6_IN6(ia), addr)) {
+ if (zoneid != 0 &&
+ zoneid != ia->ia_addr.sin6_scope_id)
+ continue;
+ ifaref(&ia->ia_ifa);
+ break;
+ }
+ }
+#ifdef __FreeBSD__
+ IN6_IFADDR_RUNLOCK();
+#endif
+ return ia;
+}
/*
* find the internet address corresponding to a given interface and address.
@@ -2196,6 +2226,287 @@
}
}
+struct in6_llentry {
+ struct llentry base;
+};
+
+#define IN6_LLTBL_DEFAULT_HSIZE 32
+#define IN6_LLTBL_HASH(k, h) \
+ (((((((k >> 8) ^ k) >> 8) ^ k) >> 8) ^ k) & ((h) - 1))
+
+/*
+ * Do actual deallocation of @lle.
+ * Called by LLE_FREE_LOCKED when number of references
+ * drops to zero.
+ */
+static void
+in6_lltable_destroy_lle(struct llentry *lle)
+{
+
+ LLE_WUNLOCK(lle);
+ LLE_LOCK_DESTROY(lle);
+ kmem_intr_free(lle, sizeof(struct in6_llentry));
+}
+
+static struct llentry *
+in6_lltable_new(const struct in6_addr *addr6, u_int flags)
+{
+ struct in6_llentry *lle;
+
+ lle = kmem_intr_zalloc(sizeof(struct in6_llentry), KM_NOSLEEP);
+ if (lle == NULL) /* NB: caller generates msg */
+ return NULL;
+
+ lle->base.r_l3addr.addr6 = *addr6;
+ lle->base.lle_refcnt = 1;
+ lle->base.lle_free = in6_lltable_destroy_lle;
+ LLE_LOCK_INIT(&lle->base);
+ callout_init(&lle->base.lle_timer, CALLOUT_MPSAFE);
+
+ return &lle->base;
+}
+
+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;
+
+ if (IN6_ARE_MASKED_ADDR_EQUAL(&lle->r_l3addr.addr6,
+ &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);
+
+ /* 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);
+ }
+
+ KASSERT(mutex_owned(softnet_lock));
+ callout_halt(&lle->lle_timer, softnet_lock);
+ LLE_REMREF(lle);
+
+ llentry_free(lle);
+}
+
+static int
+in6_lltable_rtcheck(struct ifnet *ifp,
+ u_int flags,
+ const struct sockaddr *l3addr)
+{
+ struct rtentry *rt;
+
+ KASSERTMSG(l3addr->sa_family == AF_INET6,
+ "sin_family %d", l3addr->sa_family);
+
+ rt = rtalloc1(l3addr, 0);
+ if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
+ struct ifaddr *ifa;
+ /*
+ * Create an ND6 cache for an IPv6 neighbor
+ * that is not covered by our own prefix.
+ */
+ /* XXX ifaof_ifpforaddr should take a const param */
+ ifa = ifaof_ifpforaddr(l3addr, ifp);
+ if (ifa != NULL) {
+ ifafree(ifa);
+ if (rt != NULL)
+ rtfree(rt);
+ return 0;
+ }
Home |
Main Index |
Thread Index |
Old Index