Module Name:    src
Committed By:   yamaguchi
Date:           Thu Mar 31 02:04:50 UTC 2022

Modified Files:
        src/sys/net/lagg: if_lagg_lacp.c if_lagg_lacp.h

Log Message:
handle LACPDU and MarkerDU in thread context

Those handler move from softint to thread context to
improve throughput in high load, because they hold LACP_LOCK.

pointed out by k-goda@IIJ


To generate a diff of this commit:
cvs rdiff -u -r1.17 -r1.18 src/sys/net/lagg/if_lagg_lacp.c
cvs rdiff -u -r1.3 -r1.4 src/sys/net/lagg/if_lagg_lacp.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/lagg/if_lagg_lacp.c
diff -u src/sys/net/lagg/if_lagg_lacp.c:1.17 src/sys/net/lagg/if_lagg_lacp.c:1.18
--- src/sys/net/lagg/if_lagg_lacp.c:1.17	Thu Mar 31 02:00:27 2022
+++ src/sys/net/lagg/if_lagg_lacp.c	Thu Mar 31 02:04:50 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_lagg_lacp.c,v 1.17 2022/03/31 02:00:27 yamaguchi Exp $	*/
+/*	$NetBSD: if_lagg_lacp.c,v 1.18 2022/03/31 02:04:50 yamaguchi Exp $	*/
 
 /*-
  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_lagg_lacp.c,v 1.17 2022/03/31 02:00:27 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_lagg_lacp.c,v 1.18 2022/03/31 02:04:50 yamaguchi Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_lagg.h"
@@ -42,6 +42,7 @@ __KERNEL_RCSID(0, "$NetBSD: if_lagg_lacp
 
 #include <sys/evcnt.h>
 #include <sys/kmem.h>
+#include <sys/pcq.h>
 #include <sys/pslist.h>
 #include <sys/sysctl.h>
 #include <sys/syslog.h>
@@ -163,13 +164,18 @@ struct lacp_softc {
 				 lsc_aggregators;
 	struct workqueue	*lsc_workq;
 	struct lagg_work	 lsc_work_tick;
+	struct lagg_work	 lsc_work_rcvdu;
 	callout_t		 lsc_tick;
+	pcq_t			*lsc_du_q;
 
 	char			 lsc_evgroup[32];
 	struct evcnt		 lsc_mgethdr_failed;
 	struct evcnt		 lsc_mpullup_failed;
 	struct evcnt		 lsc_badlacpdu;
 	struct evcnt		 lsc_badmarkerdu;
+	struct evcnt		 lsc_norcvif;
+	struct evcnt		 lsc_nolaggport;
+	struct evcnt		 lsc_duq_nospc;
 
 	bool			 lsc_optimistic;
 	bool			 lsc_stop_lacpdu;
@@ -277,6 +283,7 @@ static void	lacp_sm_ptx_timer(struct lac
 static void	lacp_sm_ptx_schedule(struct lacp_port *);
 static void	lacp_sm_ptx_update_timeout(struct lacp_port *, uint8_t);
 
+static void	lacp_rcvdu_work(struct lagg_work *, void *);
 static void	lacp_marker_work(struct lagg_work *, void *);
 static void	lacp_dump_lacpdutlv(const struct lacpdu_peerinfo *,
 		    const struct lacpdu_peerinfo *,
@@ -463,6 +470,12 @@ lacp_attach(struct lagg_softc *sc, struc
 	if (lsc == NULL)
 		return ENOMEM;
 
+	lsc->lsc_du_q = pcq_create(LACP_RCVDU_LIMIT, KM_NOSLEEP);
+	if (lsc->lsc_du_q == NULL) {
+		error = ENOMEM;
+		goto free_lsc;
+	}
+
 	mutex_init(&lsc->lsc_lock, MUTEX_DEFAULT, IPL_SOFTNET);
 	lsc->lsc_softc = sc;
 	lsc->lsc_key = htons(if_get_index(&sc->sc_if));
@@ -473,6 +486,8 @@ lacp_attach(struct lagg_softc *sc, struc
 	TAILQ_INIT(&lsc->lsc_aggregators);
 
 	lagg_work_set(&lsc->lsc_work_tick, lacp_tick_work, lsc);
+	lagg_work_set(&lsc->lsc_work_rcvdu, lacp_rcvdu_work, lsc);
+
 	snprintf(xnamebuf, sizeof(xnamebuf), "%s.lacp",
 	    sc->sc_if.if_xname);
 	lsc->lsc_workq = lagg_workq_create(xnamebuf,
@@ -494,14 +509,18 @@ lacp_attach(struct lagg_softc *sc, struc
 	lacp_evcnt_attach(lsc, &lsc->lsc_mpullup_failed, "m_pullup failed");
 	lacp_evcnt_attach(lsc, &lsc->lsc_badlacpdu, "Bad LACPDU recieved");
 	lacp_evcnt_attach(lsc, &lsc->lsc_badmarkerdu, "Bad MarkerDU recieved");
+	lacp_evcnt_attach(lsc, &lsc->lsc_norcvif, "No received interface");
+	lacp_evcnt_attach(lsc, &lsc->lsc_nolaggport, "No lagg context");
+	lacp_evcnt_attach(lsc, &lsc->lsc_duq_nospc, "No space left on queues");
 
 	if_link_state_change(&sc->sc_if, LINK_STATE_DOWN);
 
 	*lscp = (struct lagg_proto_softc *)lsc;
 	return 0;
-
 destroy_lock:
 	mutex_destroy(&lsc->lsc_lock);
+	pcq_destroy(lsc->lsc_du_q);
+free_lsc:
 	kmem_free(lsc, sizeof(*lsc));
 
 	return error;
@@ -519,13 +538,18 @@ lacp_detach(struct lagg_proto_softc *xls
 
 	lacp_down(xlsc);
 
+	lagg_workq_wait(lsc->lsc_workq, &lsc->lsc_work_rcvdu);
 	evcnt_detach(&lsc->lsc_mgethdr_failed);
 	evcnt_detach(&lsc->lsc_mpullup_failed);
 	evcnt_detach(&lsc->lsc_badlacpdu);
 	evcnt_detach(&lsc->lsc_badmarkerdu);
+	evcnt_detach(&lsc->lsc_norcvif);
+	evcnt_detach(&lsc->lsc_nolaggport);
+	evcnt_detach(&lsc->lsc_duq_nospc);
 	lagg_workq_destroy(lsc->lsc_workq);
 	pserialize_destroy(lsc->lsc_psz);
 	mutex_destroy(&lsc->lsc_lock);
+	pcq_destroy(lsc->lsc_du_q);
 	kmem_free(lsc, sizeof(*lsc));
 }
 
@@ -1223,12 +1247,17 @@ lacp_input(struct lagg_proto_softc *xlsc
 
 		m_copydata(m, sizeof(struct ether_header),
 		    sizeof(subtype), &subtype);
+
 		switch (subtype) {
 		case SLOWPROTOCOLS_SUBTYPE_LACP:
-			(void)lacp_pdu_input(lsc, lacpp, m);
-			return NULL;
 		case SLOWPROTOCOLS_SUBTYPE_MARKER:
-			(void)lacp_marker_input(lsc, lacpp, m);
+			if (pcq_put(lsc->lsc_du_q, (void *)m)) {
+				lagg_workq_add(lsc->lsc_workq,
+				    &lsc->lsc_work_rcvdu);
+			} else {
+				m_freem(m);
+				lsc->lsc_duq_nospc.ev_count++;
+			}
 			return NULL;
 		}
 	}
@@ -1242,6 +1271,62 @@ lacp_input(struct lagg_proto_softc *xlsc
 	return m;
 }
 
+static void
+lacp_rcvdu_work(struct lagg_work *lw __unused, void *xlsc)
+{
+	struct lacp_softc *lsc = (struct lacp_softc *)xlsc;
+	struct ifnet *ifp;
+	struct psref psref_lp;
+	struct lagg_port *lp;
+	struct mbuf *m;
+	uint8_t subtype;
+	int bound, s;
+
+	bound = curlwp_bind();
+
+	for (;;) {
+		m = pcq_get(lsc->lsc_du_q);
+		if (m == NULL)
+			break;
+
+		ifp = m_get_rcvif(m, &s);
+		if (ifp == NULL) {
+			m_freem(m);
+			lsc->lsc_norcvif.ev_count++;
+			continue;
+		}
+
+		lp = atomic_load_consume(&ifp->if_lagg);
+		if (lp == NULL) {
+			m_put_rcvif(ifp, &s);
+			m_freem(m);
+			lsc->lsc_norcvif.ev_count++;
+			continue;
+		}
+
+		lagg_port_getref(lp, &psref_lp);
+		m_put_rcvif(ifp, &s);
+
+		m_copydata(m, sizeof(struct ether_header),
+		    sizeof(subtype), &subtype);
+
+		switch (subtype) {
+		case SLOWPROTOCOLS_SUBTYPE_LACP:
+			(void)lacp_pdu_input(lsc,
+			    lp->lp_proto_ctx, m);
+			break;
+		case SLOWPROTOCOLS_SUBTYPE_MARKER:
+			(void)lacp_marker_input(lsc,
+			    lp->lp_proto_ctx, m);
+			break;
+		}
+
+		lagg_port_putref(lp, &psref_lp);
+	}
+
+	curlwp_bindx(bound);
+}
+
 static bool
 lacp_port_need_to_tell(struct lacp_port *lacpp)
 {
@@ -1262,7 +1347,7 @@ lacp_port_need_to_tell(struct lacp_port 
 		return false;
 
 	if (ppsratecheck(&lacpp->lp_last_lacpdu, &lacpp->lp_lacpdu_sent,
-	    (3 / LACP_FAST_PERIODIC_TIME)) == 0)
+	    (LACP_SENDDU_PPS / LACP_FAST_PERIODIC_TIME)) == 0)
 		return false;
 
 	return true;

Index: src/sys/net/lagg/if_lagg_lacp.h
diff -u src/sys/net/lagg/if_lagg_lacp.h:1.3 src/sys/net/lagg/if_lagg_lacp.h:1.4
--- src/sys/net/lagg/if_lagg_lacp.h:1.3	Tue Nov 30 01:17:02 2021
+++ src/sys/net/lagg/if_lagg_lacp.h	Thu Mar 31 02:04:50 2022
@@ -1,4 +1,4 @@
-/*	$NetBSD: if_lagg_lacp.h,v 1.3 2021/11/30 01:17:02 yamaguchi Exp $	*/
+/*	$NetBSD: if_lagg_lacp.h,v 1.4 2022/03/31 02:04:50 yamaguchi Exp $	*/
 
 /*
  * Copyright (c) 2021 Internet Initiative Japan Inc.
@@ -41,6 +41,8 @@
 #define LACP_MAX_PORTS		16
 #define LACP_SYSTEM_PRIO	0x8000U
 #define LACP_PORT_PRIO		LAGG_PORT_PRIO
+#define LACP_SENDDU_PPS		3
+#define LACP_RCVDU_LIMIT	(LACP_SENDDU_PPS * LACP_MAX_PORTS)
 
 #define LACP_PARTNER_ADMIN_OPTIMISTIC	(LACP_STATE_SYNC | \
 					LACP_STATE_AGGREGATION | \

Reply via email to