Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 20 Oct 2013 20:10:01 GMT
From:      Eitan Adler <lists@eitanadler.com>
To:        freebsd-net@FreeBSD.org
Subject:   Re: kern/157410: [ip6] IPv6 Router Advertisements Cause Excessive CPU Use
Message-ID:  <201310202010.r9KKA1Xa097982@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR kern/157410; it has been noted by GNATS.

From: Eitan Adler <lists@eitanadler.com>
To: bug-followup <bug-followup@freebsd.org>
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 <logan@elandsys.com>
 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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201310202010.r9KKA1Xa097982>