svn commit: r280787 - head/sys/netinet

Gleb Smirnoff glebius at FreeBSD.org
Sat Mar 28 16:06:48 UTC 2015


Author: glebius
Date: Sat Mar 28 16:06:46 2015
New Revision: 280787
URL: https://svnweb.freebsd.org/changeset/base/280787

Log:
  Initialize random IP ID engine via SYSINIT() instead of doing that on
  first packet.  This allow to use M_WAITOK and cut down some error handling.
  
  Sponsored by:	Nginx, Inc.

Modified:
  head/sys/netinet/ip_id.c

Modified: head/sys/netinet/ip_id.c
==============================================================================
--- head/sys/netinet/ip_id.c	Sat Mar 28 15:07:19 2015	(r280786)
+++ head/sys/netinet/ip_id.c	Sat Mar 28 16:06:46 2015	(r280787)
@@ -91,18 +91,17 @@ __FBSDID("$FreeBSD$");
 
 static MALLOC_DEFINE(M_IPID, "ipid", "randomized ip id state");
 
-static u_int16_t 	*id_array = NULL;
-static bitstr_t		*id_bits = NULL;
-static int		 array_ptr = 0;
-static int		 array_size = 8192;
-static int		 random_id_collisions = 0;
-static int		 random_id_total = 0;
+static uint16_t 	*id_array;
+static bitstr_t		*id_bits;
+static int		 array_ptr;
+static int		 array_size;
+static int		 random_id_collisions;
+static int		 random_id_total;
 static struct mtx	 ip_id_mtx;
 
-static void	ip_initid(void);
+static void	ip_initid(int);
 static int	sysctl_ip_id_change(SYSCTL_HANDLER_ARGS);
-
-MTX_SYSINIT(ip_id_mtx, &ip_id_mtx, "ip_id_mtx", MTX_DEF);
+static void	ip_sysinitid(void);
 
 SYSCTL_DECL(_net_inet_ip);
 SYSCTL_PROC(_net_inet_ip, OID_AUTO, random_id_period, CTLTYPE_INT|CTLFLAG_RW,
@@ -120,73 +119,44 @@ sysctl_ip_id_change(SYSCTL_HANDLER_ARGS)
 	new = array_size;
 	error = sysctl_handle_int(oidp, &new, 0, req);
 	if (error == 0 && req->newptr) {
-		if (new >= 512 && new <= 32768) {
-			mtx_lock(&ip_id_mtx);
-			array_size = new;
-			ip_initid();
-			mtx_unlock(&ip_id_mtx);
-		} else
+		if (new >= 512 && new <= 32768)
+			ip_initid(new);
+		else
 			error = EINVAL;
 	}
 	return (error);
 }
 
-/*
- * ip_initid() runs with a mutex held and may execute in a network context.
- * As a result, it uses M_NOWAIT.  Ideally, we would always do this
- * allocation from the sysctl contact and have it be an invariant that if
- * this random ID allocation mode is selected, the buffers are present.  This
- * would also avoid potential network context failures of IP ID generation.
- */
 static void
-ip_initid(void)
+ip_initid(int new_size)
 {
+	uint16_t *new_array;
+	bitstr_t *new_bits;
 
-	mtx_assert(&ip_id_mtx, MA_OWNED);
+	new_array = malloc(new_size * sizeof(uint16_t), M_IPID,
+	    M_WAITOK | M_ZERO);
+	new_bits = malloc(bitstr_size(65536), M_IPID, M_WAITOK | M_ZERO);
 
+	mtx_lock(&ip_id_mtx);
 	if (id_array != NULL) {
 		free(id_array, M_IPID);
 		free(id_bits, M_IPID);
 	}
+	id_array = new_array;
+	id_bits = new_bits;
+	array_size = new_size;
+	array_ptr = 0;
 	random_id_collisions = 0;
 	random_id_total = 0;
-	array_ptr = 0;
-	id_array = (u_int16_t *) malloc(array_size * sizeof(u_int16_t),
-	    M_IPID, M_NOWAIT | M_ZERO);
-	id_bits = (bitstr_t *) malloc(bitstr_size(65536), M_IPID,
-	    M_NOWAIT | M_ZERO);
-	if (id_array == NULL || id_bits == NULL) {
-		/* Neither or both. */
-		if (id_array != NULL) {
-			free(id_array, M_IPID);
-			id_array = NULL;
-		}
-		if (id_bits != NULL) {
-			free(id_bits, M_IPID);
-			id_bits = NULL;
-		}
-	}
+	mtx_unlock(&ip_id_mtx);
 }
 
-u_int16_t
+uint16_t
 ip_randomid(void)
 {
-	u_int16_t new_id;
+	uint16_t new_id;
 
 	mtx_lock(&ip_id_mtx);
-	if (id_array == NULL)
-		ip_initid();
-
-	/*
-	 * Fail gracefully; return a fixed id if memory allocation failed;
-	 * ideally we wouldn't do allocation in this context in order to
-	 * avoid the possibility of this failure mode.
-	 */
-	if (id_array == NULL) {
-		mtx_unlock(&ip_id_mtx);
-		return (1);
-	}
-
 	/*
 	 * To avoid a conflict with the zeros that the array is initially
 	 * filled with, we never hand out an id of zero.
@@ -207,3 +177,12 @@ ip_randomid(void)
 	mtx_unlock(&ip_id_mtx);
 	return (new_id);
 }
+
+static void
+ip_sysinitid(void)
+{
+
+	mtx_init(&ip_id_mtx, "ip_id_mtx", NULL, MTX_DEF);
+	ip_initid(8192);
+}
+SYSINIT(ip_id, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, ip_sysinitid, NULL);


More information about the svn-src-all mailing list