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/2d17bea313dc
branches:  trunk
changeset: 811976:2d17bea313dc
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 360cf59b9c54 -r 2d17bea313dc 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 360cf59b9c54 -r 2d17bea313dc 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 360cf59b9c54 -r 2d17bea313dc 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