From 6e2057037e5c43bc7b88c33b2fabad186bec204d Mon Sep 17 00:00:00 2001 From: Ryan Thomas McBride Date: Wed, 11 Jun 2008 06:30:37 +0000 Subject: From KAME, allow adjustable limits on NDP entries and discovered routes. ok mpf naddy --- sys/netinet6/icmp6.c | 7 ++--- sys/netinet6/in6.c | 4 ++- sys/netinet6/in6.h | 17 +++++++++-- sys/netinet6/in6_proto.c | 6 +++- sys/netinet6/in6_var.h | 4 ++- sys/netinet6/ip6_var.h | 6 +++- sys/netinet6/nd6.c | 52 +++++++++++++++++++++++++++++++-- sys/netinet6/nd6.h | 3 +- sys/netinet6/nd6_rtr.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++- 9 files changed, 160 insertions(+), 14 deletions(-) diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c index 2083fb4c9a0..b3158b756aa 100644 --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: icmp6.c,v 1.97 2008/05/11 08:13:02 claudio Exp $ */ +/* $OpenBSD: icmp6.c,v 1.98 2008/06/11 06:30:36 mcbride Exp $ */ /* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */ /* @@ -161,7 +161,6 @@ static int icmp6_mtudisc_lowat = 256; static struct rttimer_queue *icmp6_redirect_timeout_q = NULL; /* XXX experimental, turned off */ -static int icmp6_redirect_hiwat = -1; static int icmp6_redirect_lowat = -1; static void icmp6_errcount(struct icmp6errstat *, int, int); @@ -2335,8 +2334,8 @@ icmp6_redirect_input(m, off) * (there will be additional hops, though). */ rtcount = rt_timer_count(icmp6_redirect_timeout_q); - if (0 <= icmp6_redirect_hiwat && rtcount > icmp6_redirect_hiwat) - return; + if (0 <= ip6_maxdynroutes && rtcount >= ip6_maxdynroutes) + goto freeit; else if (0 <= icmp6_redirect_lowat && rtcount > icmp6_redirect_lowat) { /* diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c index e15fd857c37..fc24a021ec4 100644 --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6.c,v 1.75 2008/05/11 08:13:02 claudio Exp $ */ +/* $OpenBSD: in6.c,v 1.76 2008/06/11 06:30:36 mcbride Exp $ */ /* $KAME: in6.c,v 1.372 2004/06/14 08:14:21 itojun Exp $ */ /* @@ -2634,6 +2634,8 @@ in6_domifattach(ifp) M_WAITOK | M_ZERO); ext->nd_ifinfo = nd6_ifattach(ifp); + ext->nprefixes = 0; + ext->ndefrouters = 0; return ext; } diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index d85127b4945..33b0a2ee1a1 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in6.h,v 1.45 2008/03/09 12:03:03 sobrado Exp $ */ +/* $OpenBSD: in6.h,v 1.46 2008/06/11 06:30:36 mcbride Exp $ */ /* $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $ */ /* @@ -614,7 +614,12 @@ struct ip6_mtuinfo { #define IPV6CTL_MFORWARDING 42 #define IPV6CTL_MULTIPATH 43 #define IPV6CTL_MCAST_PMTU 44 /* path MTU discovery for multicast */ -#define IPV6CTL_MAXID 45 +#define IPV6CTL_NEIGHBORGCTHRESH 45 +#define IPV6CTL_MAXIFPREFIXES 46 +#define IPV6CTL_MAXIFDEFROUTERS 47 +#define IPV6CTL_MAXDYNROUTES 48 +#define IPV6CTL_MAXID 49 + /* New entries should be added here from current IPV6CTL_MAXID value. */ /* to define items, should talk with KAME guys first, for *BSD compatibility */ @@ -664,6 +669,10 @@ struct ip6_mtuinfo { { "mforwarding", CTLTYPE_INT }, \ { "multipath", CTLTYPE_INT }, \ { "multicast_mtudisc", CTLTYPE_INT }, \ + { "neighborgcthresh", CTLTYPE_INT }, \ + { "maxifprefixes", CTLTYPE_INT }, \ + { "maxifdefrouters", CTLTYPE_INT }, \ + { "maxdynroutes", CTLTYPE_INT }, \ } #define IPV6CTL_VARS { \ @@ -712,6 +721,10 @@ struct ip6_mtuinfo { &ip6_mforwarding, \ &ip6_multipath, \ &ip6_mcast_pmtu, \ + &ip6_neighborgcthresh, \ + &ip6_maxifprefixes, \ + &ip6_maxifdefrouters, \ + &ip6_maxdynroutes, \ } #endif /* __BSD_VISIBLE */ diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 8c2f41fab16..79d5b2f6fa9 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_proto.c,v 1.55 2008/05/24 19:48:32 thib Exp $ */ +/* $OpenBSD: in6_proto.c,v 1.56 2008/06/11 06:30:36 mcbride Exp $ */ /* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */ /* @@ -271,6 +271,10 @@ int ip6_rr_prune = 5; /* router renumbering prefix * walk list every 5 sec. */ int ip6_mcast_pmtu = 0; /* enable pMTU discovery for multicast? */ const int ip6_v6only = 1; +int ip6_neighborgcthresh = 2048; /* Threshold # of NDP entries for GC */ +int ip6_maxifprefixes = 16; /* Max acceptable prefixes via RA per IF */ +int ip6_maxifdefrouters = 16; /* Max acceptable def routers via RA */ +int ip6_maxdynroutes = 4096; /* Max # of routes created via redirect */ u_int32_t ip6_id = 0UL; int ip6_keepfaith = 0; time_t ip6_log_time = (time_t)0L; diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h index 5333088559d..58bc6da3f28 100644 --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_var.h,v 1.28 2006/07/06 02:56:58 brad Exp $ */ +/* $OpenBSD: in6_var.h,v 1.29 2008/06/11 06:30:36 mcbride Exp $ */ /* $KAME: in6_var.h,v 1.55 2001/02/16 12:49:45 itojun Exp $ */ /* @@ -91,6 +91,8 @@ struct in6_ifextra { struct in6_ifstat *in6_ifstat; struct icmp6_ifstat *icmp6_ifstat; struct nd_ifinfo *nd_ifinfo; + int nprefixes; + int ndefrouters; }; struct in6_ifaddr { diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 33f35df951d..cbce4a70060 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_var.h,v 1.33 2008/06/09 22:47:42 djm Exp $ */ +/* $OpenBSD: ip6_var.h,v 1.34 2008/06/11 06:30:36 mcbride Exp $ */ /* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */ /* @@ -247,6 +247,10 @@ extern int ip6_rr_prune; /* router renumbering prefix * walk list every 5 sec. */ extern int ip6_mcast_pmtu; /* path MTU discovery for multicast */ extern const int ip6_v6only; +extern int ip6_neighborgcthresh; /* Threshold # of NDP entries for GC */ +extern int ip6_maxifprefixes; /* Max acceptable prefixes via RA per IF */ +extern int ip6_maxifdefrouters; /* Max acceptable def routers via RA */ +extern int ip6_maxdynroutes; /* Max # of routes created via redirect */ extern struct socket *ip6_mrouter; /* multicast routing daemon */ extern int ip6_sendredirects; /* send IP redirects when forwarding? */ diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c index 35906a9e1f1..018e26fb8da 100644 --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6.c,v 1.77 2008/05/11 08:13:02 claudio Exp $ */ +/* $OpenBSD: nd6.c,v 1.78 2008/06/11 06:30:36 mcbride Exp $ */ /* $KAME: nd6.c,v 1.280 2002/06/08 19:52:07 itojun Exp $ */ /* @@ -87,7 +87,6 @@ int nd6_debug = 1; int nd6_debug = 0; #endif -/* for debugging? */ static int nd6_inuse, nd6_allocated; struct llinfo_nd6 llinfo_nd6 = {&llinfo_nd6, &llinfo_nd6}; @@ -109,6 +108,17 @@ extern struct timeout in6_tmpaddrtimer_ch; static int fill_drlist(void *, size_t *, size_t); static int fill_prlist(void *, size_t *, size_t); +#define LN_DEQUEUE(ln) do { \ + (ln)->ln_next->ln_prev = (ln)->ln_prev; \ + (ln)->ln_prev->ln_next = (ln)->ln_next; \ + } while (0) +#define LN_INSERTHEAD(ln) do { \ + (ln)->ln_next = llinfo_nd6.ln_next; \ + llinfo_nd6.ln_next = (ln); \ + (ln)->ln_prev = &llinfo_nd6; \ + (ln)->ln_next->ln_prev = (ln); \ + } while (0) + void nd6_init() { @@ -464,6 +474,7 @@ nd6_llinfo_timer(void *arg) break; case ND6_LLINFO_STALE: + case ND6_LLINFO_PURGE: /* Garbage Collection(RFC 2461 5.3) */ if (!ND6_LLINFO_PERMANENT(ln)) { (void)nd6_free(rt, 1); @@ -1156,6 +1167,35 @@ nd6_rtrequest(req, rt, info) ln->ln_prev = &llinfo_nd6; ln->ln_next->ln_prev = ln; + /* + * If we have too many cache entries, initiate immediate + * purging for some "less recently used" entries. Note that + * we cannot directly call nd6_free() here because it would + * cause re-entering rtable related routines triggering an LOR + * problem for FreeBSD. + */ + if (ip6_neighborgcthresh >= 0 && + nd6_inuse >= ip6_neighborgcthresh) { + int i; + + for (i = 0; i < 10 && llinfo_nd6.ln_prev != ln; i++) { + struct llinfo_nd6 *ln_end = llinfo_nd6.ln_prev; + + /* Move this entry to the head */ + LN_DEQUEUE(ln_end); + LN_INSERTHEAD(ln_end); + + if (ND6_LLINFO_PERMANENT(ln_end)) + continue; + + if (ln_end->ln_state > ND6_LLINFO_INCOMPLETE) + ln_end->ln_state = ND6_LLINFO_STALE; + else + ln_end->ln_state = ND6_LLINFO_PURGE; + nd6_llinfo_settimer(ln_end, 0); + } + } + /* * check if rt_key(rt) is one of my address assigned * to the interface. @@ -1835,6 +1875,14 @@ nd6_output(ifp, origifp, m0, dst, rt0) goto sendpkt; /* send anyway */ } + /* + * Move this entry to the head of the queue so that it is less likely + * for this entry to be a target of forced garbage collection (see + * nd6_rtrequest()). + */ + LN_DEQUEUE(ln); + LN_INSERTHEAD(ln); + /* We don't have to do link-layer address resolution on a p2p link. */ if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && ln->ln_state < ND6_LLINFO_REACHABLE) { diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h index 38640429b3f..45d45054784 100644 --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6.h,v 1.25 2003/07/08 21:43:18 itojun Exp $ */ +/* $OpenBSD: nd6.h,v 1.26 2008/06/11 06:30:36 mcbride Exp $ */ /* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */ /* @@ -56,6 +56,7 @@ struct llinfo_nd6 { struct timeout ln_timer_ch; }; +#define ND6_LLINFO_PURGE -3 #define ND6_LLINFO_NOSTATE -2 /* * We don't need the WAITDELETE state any more, but we keep the definition diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c index 97a04993151..cb41a3f7778 100644 --- a/sys/netinet6/nd6_rtr.c +++ b/sys/netinet6/nd6_rtr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nd6_rtr.c,v 1.45 2008/05/11 08:13:02 claudio Exp $ */ +/* $OpenBSD: nd6_rtr.c,v 1.46 2008/06/11 06:30:36 mcbride Exp $ */ /* $KAME: nd6_rtr.c,v 1.97 2001/02/07 11:09:13 itojun Exp $ */ /* @@ -69,6 +69,7 @@ static void pfxrtr_del(struct nd_pfxrouter *); static struct nd_pfxrouter *find_pfxlist_reachable_router(struct nd_prefix *); static void defrouter_delreq(struct nd_defrouter *); static void nd6_rtmsg(int, struct rtentry *); +static void purge_detached(struct ifnet *); static void in6_init_address_ltimes(struct nd_prefix *, struct in6_addrlifetime *); @@ -495,6 +496,7 @@ defrtrlist_del(dr) struct nd_defrouter *dr; { struct nd_defrouter *deldr = NULL; + struct in6_ifextra *ext = dr->ifp->if_afdata[AF_INET6]; struct nd_prefix *pr; /* @@ -528,6 +530,12 @@ defrtrlist_del(dr) if (deldr) defrouter_select(); + ext->ndefrouters--; + if (ext->ndefrouters < 0) { + log(LOG_WARNING, "defrtrlist_del: negative count on %s\n", + dr->ifp->if_xname); + } + free(dr, M_IP6NDP); } @@ -745,6 +753,7 @@ defrtrlist_update(new) struct nd_defrouter *new; { struct nd_defrouter *dr, *n; + struct in6_ifextra *ext = new->ifp->if_afdata[AF_INET6]; int s = splsoftnet(); if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { @@ -792,6 +801,12 @@ defrtrlist_update(new) return (NULL); } + if (ip6_maxifdefrouters >= 0 && + ext->ndefrouters >= ip6_maxifdefrouters) { + splx(s); + return (NULL); + } + n = malloc(sizeof(*n), M_IP6NDP, M_NOWAIT | M_ZERO); if (n == NULL) { splx(s); @@ -820,6 +835,8 @@ insert: defrouter_select(); + ext->ndefrouters++; + splx(s); return (n); @@ -883,6 +900,45 @@ nd6_prefix_lookup(pr) return (search); } +static void +purge_detached(ifp) + struct ifnet *ifp; +{ + struct nd_prefix *pr, *pr_next; + struct in6_ifaddr *ia; + struct ifaddr *ifa, *ifa_next; + + for (pr = nd_prefix.lh_first; pr; pr = pr_next) { + pr_next = pr->ndpr_next; + + /* + * This function is called when we need to make more room for + * new prefixes rather than keeping old, possibly stale ones. + * Detached prefixes would be a good candidate; if all routers + * that advertised the prefix expired, the prefix is also + * probably stale. + */ + if (pr->ndpr_ifp != ifp || + IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr) || + ((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 && + !LIST_EMPTY(&pr->ndpr_advrtrs))) + continue; + + for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa_next) { + ifa_next = ifa->ifa_list.tqe_next; + if (ifa->ifa_addr->sa_family != AF_INET6) + continue; + ia = (struct in6_ifaddr *)ifa; + if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == + IN6_IFF_AUTOCONF && ia->ia6_ndpr == pr) { + in6_purgeaddr(ifa); + } + } + if (pr->ndpr_refcnt == 0) + prelist_remove(pr); + } +} + int nd6_prelist_add(pr, dr, newp) struct nd_prefix *pr, **newp; @@ -890,6 +946,14 @@ nd6_prelist_add(pr, dr, newp) { struct nd_prefix *new = NULL; int i, s; + struct in6_ifextra *ext = pr->ndpr_ifp->if_afdata[AF_INET6]; + + if (ip6_maxifprefixes >= 0) { + if (ext->nprefixes >= ip6_maxifprefixes / 2) + purge_detached(pr->ndpr_ifp); + if (ext->nprefixes >= ip6_maxifprefixes) + return(ENOMEM); + } new = malloc(sizeof(*new), M_IP6NDP, M_NOWAIT | M_ZERO); if (new == NULL) @@ -927,6 +991,8 @@ nd6_prelist_add(pr, dr, newp) if (dr) pfxrtr_add(new, dr); + ext->nprefixes++; + return 0; } @@ -936,6 +1002,7 @@ prelist_remove(pr) { struct nd_pfxrouter *pfr, *next; int e, s; + struct in6_ifextra *ext = pr->ndpr_ifp->if_afdata[AF_INET6]; /* make sure to invalidate the prefix until it is really freed. */ pr->ndpr_vltime = 0; @@ -971,6 +1038,12 @@ prelist_remove(pr) free(pfr, M_IP6NDP); } + + ext->nprefixes--; + if (ext->nprefixes < 0) { + log(LOG_WARNING, "prelist_remove: negative count on %s\n", + pr->ndpr_ifp->if_xname); + } splx(s); free(pr, M_IP6NDP); -- cgit v1.2.3