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 | \