summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Thomas McBride <mcbride@cvs.openbsd.org>2008-06-11 06:30:37 +0000
committerRyan Thomas McBride <mcbride@cvs.openbsd.org>2008-06-11 06:30:37 +0000
commit6e2057037e5c43bc7b88c33b2fabad186bec204d (patch)
treef7fc445c32ef0a25287f75d454a176c2120691c1
parente066d625d113d9f5ae8a7ec7deb270370b8cdadf (diff)
From KAME, allow adjustable limits on NDP entries and discovered routes.
ok mpf naddy
-rw-r--r--sys/netinet6/icmp6.c7
-rw-r--r--sys/netinet6/in6.c4
-rw-r--r--sys/netinet6/in6.h17
-rw-r--r--sys/netinet6/in6_proto.c6
-rw-r--r--sys/netinet6/in6_var.h4
-rw-r--r--sys/netinet6/ip6_var.h6
-rw-r--r--sys/netinet6/nd6.c52
-rw-r--r--sys/netinet6/nd6.h3
-rw-r--r--sys/netinet6/nd6_rtr.c75
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);
@@ -1157,6 +1168,35 @@ nd6_rtrequest(req, rt, info)
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);