Module Name:    src
Committed By:   rmind
Date:           Mon Jun  9 12:57:05 UTC 2014

Modified Files:
        src/sys/net: if.c pktqueue.c pktqueue.h

Log Message:
Implement pktq_set_maxlen() and let sysctl net.inet.{ip,ip6}.ifq.maxlen be
changed on the fly again.


To generate a diff of this commit:
cvs rdiff -u -r1.278 -r1.279 src/sys/net/if.c
cvs rdiff -u -r1.1 -r1.2 src/sys/net/pktqueue.c src/sys/net/pktqueue.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/if.c
diff -u src/sys/net/if.c:1.278 src/sys/net/if.c:1.279
--- src/sys/net/if.c:1.278	Sat Jun  7 13:25:33 2014
+++ src/sys/net/if.c	Mon Jun  9 12:57:04 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.c,v 1.278 2014/06/07 13:25:33 he Exp $	*/
+/*	$NetBSD: if.c,v 1.279 2014/06/09 12:57:04 rmind Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.278 2014/06/07 13:25:33 he Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.279 2014/06/09 12:57:04 rmind Exp $");
 
 #include "opt_inet.h"
 
@@ -2341,6 +2341,20 @@ bad:
 #if defined(INET) || defined(INET6)
 
 static int
+sysctl_pktq_maxlen(SYSCTLFN_ARGS, pktqueue_t *pq)
+{
+	u_int nmaxlen = pktq_get_count(pq, PKTQ_MAXLEN);
+	struct sysctlnode node = *rnode;
+	int error;
+
+	node.sysctl_data = &nmaxlen;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+	return pktq_set_maxlen(pq, nmaxlen);
+}
+
+static int
 sysctl_pktq_count(SYSCTLFN_ARGS, pktqueue_t *pq, u_int count_id)
 {
 	int count = pktq_get_count(pq, count_id);
@@ -2357,12 +2371,21 @@ sysctl_pktq_count(SYSCTLFN_ARGS, pktqueu
 	}
 
 #if defined(INET)
-SYSCTL_NET_PKTQ(ip_pktq, maxlen, PKTQ_MAXLEN)
+static int
+sysctl_net_ip_pktq_maxlen(SYSCTLFN_ARGS)
+{
+	return sysctl_pktq_maxlen(SYSCTLFN_CALL(rnode), ip_pktq);
+}
 SYSCTL_NET_PKTQ(ip_pktq, items, PKTQ_NITEMS)
 SYSCTL_NET_PKTQ(ip_pktq, drops, PKTQ_DROPS)
 #endif
+
 #if defined(INET6)
-SYSCTL_NET_PKTQ(ip6_pktq, maxlen, PKTQ_MAXLEN)
+static int
+sysctl_net_ip6_pktq_maxlen(SYSCTLFN_ARGS)
+{
+	return sysctl_pktq_maxlen(SYSCTLFN_CALL(rnode), ip6_pktq);
+}
 SYSCTL_NET_PKTQ(ip6_pktq, items, PKTQ_NITEMS)
 SYSCTL_NET_PKTQ(ip6_pktq, drops, PKTQ_DROPS)
 #endif

Index: src/sys/net/pktqueue.c
diff -u src/sys/net/pktqueue.c:1.1 src/sys/net/pktqueue.c:1.2
--- src/sys/net/pktqueue.c:1.1	Thu Jun  5 23:48:16 2014
+++ src/sys/net/pktqueue.c	Mon Jun  9 12:57:04 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: pktqueue.c,v 1.1 2014/06/05 23:48:16 rmind Exp $	*/
+/*	$NetBSD: pktqueue.c,v 1.2 2014/06/09 12:57:04 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pktqueue.c,v 1.1 2014/06/05 23:48:16 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pktqueue.c,v 1.2 2014/06/09 12:57:04 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -299,3 +299,63 @@ pktq_flush(pktqueue_t *pq)
 		}
 	}
 }
+
+/*
+ * pktq_set_maxlen: create per-CPU queues using a new size and replace
+ * the existing queues without losing any packets.
+ */
+int
+pktq_set_maxlen(pktqueue_t *pq, size_t maxlen)
+{
+	const u_int slotbytes = ncpu * sizeof(pcq_t *);
+	pcq_t **qs;
+
+	if (!maxlen || maxlen > PCQ_MAXLEN)
+		return EINVAL;
+	if (pq->pq_maxlen == maxlen)
+		return 0;
+
+	/* First, allocate the new queues and replace them. */
+	qs = kmem_zalloc(slotbytes, KM_SLEEP);
+	for (u_int i = 0; i < ncpu; i++) {
+		qs[i] = pcq_create(maxlen, KM_SLEEP);
+	}
+	mutex_enter(&pq->pq_lock);
+	for (u_int i = 0; i < ncpu; i++) {
+		/* Swap: store of a word is atomic. */
+		pcq_t *q = pq->pq_queue[i];
+		pq->pq_queue[i] = qs[i];
+		qs[i] = q;
+	}
+	pq->pq_maxlen = maxlen;
+	mutex_exit(&pq->pq_lock);
+
+	/*
+	 * At this point, the new packets are flowing into the new
+	 * queues.  However, the old queues may have same packets
+	 * present which are no longer being present.  We are going
+	 * to re-enqueue them.  This may change the order of packet
+	 * arrival, but it is not considered an issue.
+	 *
+	 * There may also in-flight interrupts calling pktq_dequeue()
+	 * which reference the old queues.  Issue a barrier to ensure
+	 * that we are going to be the only pcq_get() callers on the
+	 * old queues.
+	 */
+	pktq_barrier(pq);
+
+	for (u_int i = 0; i < ncpu; i++) {
+		struct mbuf *m;
+
+		while ((m = pcq_get(qs[i])) != NULL) {
+			while (!pcq_put(pq->pq_queue[i], m)) {
+				kpause("pktqrenq", false, 1, NULL);
+			}
+		}
+		pcq_destroy(qs[i]);
+	}
+
+	/* Well, that was fun. */
+	kmem_free(qs, slotbytes);
+	return 0;
+}
Index: src/sys/net/pktqueue.h
diff -u src/sys/net/pktqueue.h:1.1 src/sys/net/pktqueue.h:1.2
--- src/sys/net/pktqueue.h:1.1	Thu Jun  5 23:48:16 2014
+++ src/sys/net/pktqueue.h	Mon Jun  9 12:57:04 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: pktqueue.h,v 1.1 2014/06/05 23:48:16 rmind Exp $	*/
+/*	$NetBSD: pktqueue.h,v 1.2 2014/06/09 12:57:04 rmind Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -49,6 +49,7 @@ bool		pktq_enqueue(pktqueue_t *, struct 
 struct mbuf *	pktq_dequeue(pktqueue_t *);
 void		pktq_barrier(pktqueue_t *);
 void		pktq_flush(pktqueue_t *);
+int		pktq_set_maxlen(pktqueue_t *, size_t);
 
 uint32_t	pktq_rps_hash(const struct mbuf *);
 uint64_t	pktq_get_count(pktqueue_t *, pktq_count_t);

Reply via email to