From owner-freebsd-net@FreeBSD.ORG Sun Oct 20 20:10:01 2013 Return-Path: Delivered-To: freebsd-net@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTP id CCD29C9E for ; Sun, 20 Oct 2013 20:10:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id AA5D22CC0 for ; Sun, 20 Oct 2013 20:10:01 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.7/8.14.7) with ESMTP id r9KKA1Bc097983 for ; Sun, 20 Oct 2013 20:10:01 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.7/8.14.7/Submit) id r9KKA1Xa097982; Sun, 20 Oct 2013 20:10:01 GMT (envelope-from gnats) Date: Sun, 20 Oct 2013 20:10:01 GMT Message-Id: <201310202010.r9KKA1Xa097982@freefall.freebsd.org> To: freebsd-net@FreeBSD.org Cc: From: Eitan Adler Subject: Re: kern/157410: [ip6] IPv6 Router Advertisements Cause Excessive CPU Use X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: Eitan Adler List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 20 Oct 2013 20:10:01 -0000 The following reply was made to PR kern/157410; it has been noted by GNATS. From: Eitan Adler To: bug-followup Cc: Subject: Re: kern/157410: [ip6] IPv6 Router Advertisements Cause Excessive CPU Use Date: Sun, 20 Oct 2013 16:04:34 -0400 ---------- Forwarded message ---------- From: Loganaden Velvindron Date: Mon, Jul 1, 2013 at 4:30 PM Subject: Re: kern/157410: [ip6] IPv6 Router Advertisements Cause Excessive CPU Use To: freebsd-net@freebsd.org Cc: bz@freebsd.org On Mon, Jul 01, 2013 at 12:58:23PM -0700, Loganaden Velvindron wrote: > Hi I came across this old PR. It appears that it's not fixed in -current. > > I attempted to port the diff to our FreeBSD 9.1 release machines which > have IPv6 connectivity and are affected by RA flooding. > > I can report that it mitigates RA_flooding. > > Feedback welcomed. I'd be happy to polish it so that it can > make it to 9.2 and 10.0 :-) > > I broke down the diffs into separate ones. > > The last diff (nd6_rtr.diff) was garbled and another diff was missing. I'm resending the whole patchset. --- in6.c.orig 2013-06-30 23:07:46.000000000 +0400 +++ in6.c 2013-07-01 19:20:15.000000000 +0400 @@ -2694,6 +2694,8 @@ in6_domifattach(struct ifnet *ifp) ext->nd_ifinfo = nd6_ifattach(ifp); ext->scope6_id = scope6_ifattach(ifp); ext->lltable = lltable_init(ifp, AF_INET6); + ext->nprefixes = 0; + ext->ndefrouters = 0; if (ext->lltable != NULL) { ext->lltable->llt_free = in6_lltable_free; ext->lltable->llt_prefix_free = in6_lltable_prefix_free; --- in6_proto.c.orig 2013-06-30 23:07:58.000000000 +0400 +++ in6_proto.c 2013-07-01 21:05:08.000000000 +0400 @@ -413,7 +413,8 @@ VNET_DEFINE(int, ip6_rr_prune) = 5; /* r * walk list every 5 sec. */ VNET_DEFINE(int, ip6_mcast_pmtu) = 0; /* enable pMTU discovery for multicast? */ VNET_DEFINE(int, ip6_v6only) = 1; - +VNET_DEFINE(int, ip6_maxifprefixes) = 16; +VNET_DEFINE(int, ip6_maxifdefrouters) = 16; VNET_DEFINE(int, ip6_keepfaith) = 0; VNET_DEFINE(time_t, ip6_log_time) = (time_t)0L; #ifdef IPSTEALTH @@ -524,6 +525,10 @@ SYSCTL_VNET_STRUCT(_net_inet6_ip6, IPV6C &VNET_NAME(ip6stat), ip6stat, ""); SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_MAXFRAGPACKETS, maxfragpackets, CTLFLAG_RW, &VNET_NAME(ip6_maxfragpackets), 0, ""); +SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_MAXIFPREFIXES, maxifprefixes, + CTLFLAG_RW, &VNET_NAME(ip6_maxifprefixes), 0, ""); +SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_MAXIFDEFROUTERS, maxifdefrouters, + CTLFLAG_RW, &VNET_NAME(ip6_maxifdefrouters), 0, ""); SYSCTL_VNET_INT(_net_inet6_ip6, IPV6CTL_ACCEPT_RTADV, accept_rtadv, CTLFLAG_RW, &VNET_NAME(ip6_accept_rtadv), 0, "Default value of per-interface flag for accepting ICMPv6 Router" --- in6_var.h.orig 2013-06-30 23:08:28.000000000 +0400 +++ in6_var.h 2013-07-01 22:38:03.000000000 +0400 @@ -104,6 +104,8 @@ struct in6_ifextra { struct scope6_id *scope6_id; struct lltable *lltable; struct mld_ifinfo *mld_ifinfo; + int nprefixes; + int ndefrouters; }; #define LLTABLE6(ifp) (((struct in6_ifextra *)(ifp)->if_afdata[AF_INET6])->lltable) --- ip6_var.h.orig 2013-06-30 23:09:22.000000000 +0400 +++ ip6_var.h 2013-07-01 20:28:30.000000000 +0400 @@ -315,6 +315,8 @@ VNET_DECLARE(int, ip6_maxfragpackets); / * queue */ VNET_DECLARE(int, ip6_maxfrags); /* Maximum fragments in reassembly * queue */ +VNET_DECLARE(int, ip6_maxifprefixes); +VNET_DECLARE(int, ip6_maxifdefrouters); VNET_DECLARE(int, ip6_accept_rtadv); /* Acts as a host not a router */ VNET_DECLARE(int, ip6_no_radr); /* No defroute from RA */ VNET_DECLARE(int, ip6_norbit_raif); /* Disable R-bit in NA on RA --- nd6.h.orig 2013-06-30 23:09:42.000000000 +0400 +++ nd6.h 2013-07-01 22:16:09.000000000 +0400 @@ -277,6 +277,7 @@ struct nd_prefix { u_char ndpr_plen; int ndpr_refcnt; /* reference couter from addresses */ }; +#define ndpr_next ndpr_entry.le_next #define ndpr_raf ndpr_flags #define ndpr_raf_onlink ndpr_flags.onlink --- in6.h.orig 2013-07-02 00:24:36.000000000 +0400 +++ in6.h 2013-07-01 21:58:04.000000000 +0400 @@ -607,7 +607,6 @@ struct ip6_mtuinfo { #define IPV6CTL_ISATAPRTR 43 /* isatap router */ #endif #define IPV6CTL_MCAST_PMTU 44 /* enable pMTU discovery for multicast? */ - /* New entries should be added here from current IPV6CTL_MAXID value. */ /* to define items, should talk with KAME guys first, for *BSD compatibility */ #define IPV6CTL_STEALTH 45 @@ -619,6 +618,9 @@ struct ip6_mtuinfo { #define IPV6CTL_RFC6204W3 50 /* Accept defroute even when forwarding enabled */ #define IPV6CTL_MAXID 51 +#define IPV6CTL_MAXIFPREFIXES 52 +#define IPV6CTL_MAXIFDEFROUTERS 53 + #endif /* __BSD_VISIBLE */ /* --- nd6_rtr.c.orig 2013-06-30 23:10:24.000000000 +0400 +++ nd6_rtr.c 2013-07-01 22:40:29.000000000 +0400 @@ -83,6 +83,7 @@ static void nd6_rtmsg(int, struct rtentr static int in6_init_prefix_ltimes(struct nd_prefix *); static void in6_init_address_ltimes __P((struct nd_prefix *, struct in6_addrlifetime *)); +static void purge_detached(struct ifnet *); static int nd6_prefix_onlink(struct nd_prefix *); static int nd6_prefix_offlink(struct nd_prefix *); @@ -565,6 +566,7 @@ defrtrlist_del(struct nd_defrouter *dr) { struct nd_defrouter *deldr = NULL; struct nd_prefix *pr; + struct in6_ifextra *ext = dr->ifp->if_afdata[AF_INET6]; /* * Flush all the routing table entries that use the router @@ -597,6 +599,12 @@ defrtrlist_del(struct nd_defrouter *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); } @@ -734,6 +742,7 @@ static struct nd_defrouter * defrtrlist_update(struct nd_defrouter *new) { struct nd_defrouter *dr, *n; + struct in6_ifextra *ext = new->ifp->if_afdata[AF_INET6]; int s = splnet(); if ((dr = defrouter_lookup(&new->rtaddr, new->ifp)) != NULL) { @@ -775,6 +784,12 @@ defrtrlist_update(struct nd_defrouter *n splx(s); return (dr); } + /*struct in6_ifextra *ext = new->ifp->if_afdata[AF_INET6];*/ + if (ip6_maxifdefrouters >= 0 && + ext->ndefrouters >= ip6_maxifdefrouters) { + splx(s); + return (NULL); + } /* entry does not exist */ if (new->rtlifetime == 0) { @@ -810,6 +825,8 @@ insert: defrouter_select(); + ext->ndefrouters++; + splx(s); return (n); @@ -868,6 +885,44 @@ nd6_prefix_lookup(struct nd_prefixctl *k return (search); } +static void +purge_detached(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(struct nd_prefixctl *pr, struct nd_defrouter *dr, struct nd_prefix **newp) @@ -876,6 +931,14 @@ nd6_prelist_add(struct nd_prefixctl *pr, int error = 0; int i, s; char ip6buf[INET6_ADDRSTRLEN]; + 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 = (struct nd_prefix *)malloc(sizeof(*new), M_IP6NDP, M_NOWAIT); if (new == NULL) @@ -923,7 +986,7 @@ nd6_prelist_add(struct nd_prefixctl *pr, if (dr) pfxrtr_add(new, dr); - + ext->nprefixes++; return 0; } @@ -933,6 +996,7 @@ prelist_remove(struct nd_prefix *pr) struct nd_pfxrouter *pfr, *next; int e, s; char ip6buf[INET6_ADDRSTRLEN]; + 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; @@ -965,6 +1029,12 @@ prelist_remove(struct nd_prefix *pr) LIST_FOREACH_SAFE(pfr, &pr->ndpr_advrtrs, pfr_entry, next) { 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); _______________________________________________ freebsd-net@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-net To unsubscribe, send any mail to "freebsd-net-unsubscribe@freebsd.org" -- Eitan Adler