Page MenuHomeFreeBSD

D24035.diff
No OneTemporary

D24035.diff

Index: sys/netinet6/in6.c
===================================================================
--- sys/netinet6/in6.c
+++ sys/netinet6/in6.c
@@ -104,6 +104,7 @@
#include <netinet/ip_carp.h>
#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
#include <netinet6/mld6_var.h>
@@ -125,6 +126,14 @@
VNET_DECLARE(int, icmp6_nodeinfo_oldmcprefix);
#define V_icmp6_nodeinfo_oldmcprefix VNET(icmp6_nodeinfo_oldmcprefix)
+SYSCTL_DECL(_net_inet6_icmp6);
+
+static int in6_llt_max_entries;
+SYSCTL_INT(_net_inet6_icmp6, OID_AUTO, in6_llt_max_entries,
+ CTLFLAG_RW, &in6_llt_max_entries, 0,
+ "Maximum number of IPv6 neighbour entries per interface. "
+ "0 accept unlimited.");
+
/*
* Definitions of some costant IP6 addresses.
*/
@@ -164,7 +173,22 @@
#define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa))
#define ia62ifa(ia6) (&((ia6)->ia_ifa))
+void
+in6_init(void)
+{
+ /*
+ * physmem is the number of physical memory in pages. This means that
+ * up to 16GB we are scaling the number of table entries according to
+ * memory (1 table entry for each MB of physical memory). That way a
+ * small devices might not be overloaded as quickly in case of a flood
+ * as would big servers be. We ensure that there is a minimum of 128
+ * entries in all cases per-interface and cap the default value at
+ * 16k neighbour entries to avoid the DoS problem.
+ */
+ in6_llt_max_entries = max(128, min(physmem / 256, 16384));
+}
+
void
in6_newaddrmsg(struct in6_ifaddr *ia, int cmd)
{
@@ -2420,6 +2444,8 @@
llt = lltable_allocate_htbl(IN6_LLTBL_DEFAULT_HSIZE);
llt->llt_af = AF_INET6;
llt->llt_ifp = ifp;
+ /* XXX-BZ re-think SYSCTL_PROC to update? Make it more integrated? */
+ llt->llt_maxentries = in6_llt_max_entries;
llt->llt_lookup = in6_lltable_lookup;
llt->llt_alloc_entry = in6_lltable_alloc;
Index: sys/netinet6/nd6.h
===================================================================
--- sys/netinet6/nd6.h
+++ sys/netinet6/nd6.h
@@ -352,6 +352,9 @@
#define nd_opts_last nd_opt_each.last
#define nd_opts_done nd_opt_each.done
+/* in6.c */
+void in6_init(void);
+
/* XXX: need nd6_var.h?? */
/* nd6.c */
void nd6_init(void);
Index: sys/netinet6/nd6.c
===================================================================
--- sys/netinet6/nd6.c
+++ sys/netinet6/nd6.c
@@ -231,6 +231,8 @@
nd6_dad_init();
if (IS_DEFAULT_VNET(curvnet)) {
+ in6_init();
+
lle_event_eh = EVENTHANDLER_REGISTER(lle_event, nd6_lle_event,
NULL, EVENTHANDLER_PRI_ANY);
iflladdr_event_eh = EVENTHANDLER_REGISTER(iflladdr_event,
@@ -1929,7 +1931,7 @@
struct mbuf *chain = NULL;
u_char linkhdr[LLE_MAX_LINKHDR];
size_t linkhdrsize;
- int lladdr_off;
+ int linked, lladdr_off;
NET_EPOCH_ASSERT();
IF_AFDATA_UNLOCK_ASSERT(ifp);
@@ -1976,8 +1978,14 @@
LLE_WLOCK(ln);
/* Prefer any existing lle over newly-created one */
ln_tmp = nd6_lookup(from, LLE_EXCLUSIVE, ifp);
- if (ln_tmp == NULL)
- lltable_link_entry(LLTABLE6(ifp), ln);
+ if (ln_tmp == NULL) {
+ linked = lltable_link_entry(LLTABLE6(ifp), ln);
+ if (linked < 0) {
+ IF_AFDATA_WUNLOCK(ifp);
+ lltable_free_entry(LLTABLE6(ifp), ln);
+ return;
+ }
+ }
IF_AFDATA_WUNLOCK(ifp);
if (ln_tmp == NULL) {
/* No existing lle, mark as new entry (6,7) */
@@ -2285,7 +2293,7 @@
{
struct llentry *lle = NULL, *lle_tmp;
struct in6_addr *psrc, src;
- int send_ns, ll_len;
+ int linked, send_ns, ll_len;
char *lladdr;
NET_EPOCH_ASSERT();
@@ -2320,8 +2328,12 @@
/* Prefer any existing entry over newly-created one */
lle_tmp = nd6_lookup(&dst->sin6_addr, LLE_EXCLUSIVE, ifp);
if (lle_tmp == NULL)
- lltable_link_entry(LLTABLE6(ifp), lle);
+ linked = lltable_link_entry(LLTABLE6(ifp), lle);
IF_AFDATA_WUNLOCK(ifp);
+ if (lle_tmp == NULL && linked < 0) {
+ lltable_free_entry(LLTABLE6(ifp), lle);
+ lle = NULL;
+ }
if (lle_tmp != NULL) {
lltable_free_entry(LLTABLE6(ifp), lle);
lle = lle_tmp;
@@ -2506,6 +2518,7 @@
struct ifnet *ifp;
struct llentry *ln, *ln_tmp;
struct sockaddr *dst;
+ int error, linked;
ifp = ia->ia_ifa.ifa_ifp;
if (nd6_need_cache(ifp) == 0)
@@ -2517,24 +2530,44 @@
if (ln == NULL)
return (ENOBUFS);
+ error = 0;
IF_AFDATA_WLOCK(ifp);
LLE_WLOCK(ln);
- /* Unlink any entry if exists */
+ /*
+ * Historically we would unlink any entry if it existed and then link
+ * the new one. Given we could still fail linking after unlink (e.g.,
+ * if the table limits were lowered) we are going through some extra
+ * complications here so that we do not change the status-quo in case
+ * we cannot link the new entry.
+ * It may seem that we could link before lookup but that could change
+ * out later lookup result. This is why the order is: lookup, link,
+ * unlink, announce (in the non-error case).
+ */
ln_tmp = lla_lookup(LLTABLE6(ifp), LLE_EXCLUSIVE, dst);
- if (ln_tmp != NULL)
- lltable_unlink_entry(LLTABLE6(ifp), ln_tmp);
- lltable_link_entry(LLTABLE6(ifp), ln);
+ linked = lltable_link_entry(LLTABLE6(ifp), ln);
+ if (linked < 0) {
+ lltable_free_entry(LLTABLE6(ifp), ln);
+ error = ENOBUFS;
+ }
+ if (ln_tmp != NULL) {
+ if (error == 0)
+ lltable_unlink_entry(LLTABLE6(ifp), ln_tmp);
+ else
+ LLE_WUNLOCK(ln_tmp);
+ }
IF_AFDATA_WUNLOCK(ifp);
- if (ln_tmp != NULL)
- EVENTHANDLER_INVOKE(lle_event, ln_tmp, LLENTRY_EXPIRED);
- EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_RESOLVED);
+ if (error == 0) {
+ if (ln_tmp != NULL)
+ EVENTHANDLER_INVOKE(lle_event, ln_tmp, LLENTRY_EXPIRED);
+ EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_RESOLVED);
- LLE_WUNLOCK(ln);
- if (ln_tmp != NULL)
- llentry_free(ln_tmp);
+ LLE_WUNLOCK(ln);
+ if (ln_tmp != NULL)
+ llentry_free(ln_tmp);
+ }
- return (0);
+ return (error);
}
/*

File Metadata

Mime Type
text/plain
Expires
Wed, Nov 20, 9:40 AM (20 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14735175
Default Alt Text
D24035.diff (5 KB)

Event Timeline