git: a622030b4bae - main - lagg: Make the none protocol a first-class citizen
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 06 Feb 2026 03:38:51 UTC
The branch main has been updated by zlei:
URL: https://cgit.FreeBSD.org/src/commit/?id=a622030b4baec2136984cea7bd25c2985a2ae9b3
commit a622030b4baec2136984cea7bd25c2985a2ae9b3
Author: Zhenlei Huang <zlei@FreeBSD.org>
AuthorDate: 2026-02-06 03:37:43 +0000
Commit: Zhenlei Huang <zlei@FreeBSD.org>
CommitDate: 2026-02-06 03:37:43 +0000
lagg: Make the none protocol a first-class citizen
All the other protocols have corresponding start and input routines,
which are used in the fast path. Currently the none protocol is
treated specially. In the fast path it is checked to indicate whether
a working protocol is configured. There are two issues raised by this
design:
1. In production, other protocols are commonly used, but not the
none protocol. It smells like an overkill to always check it in the
fast path. It is unfair to other commonly used protocols.
2. PR 289017 reveals that there's a small window between checking the
protocol and calling lagg_proto_start(). lagg_proto_start() is possible
to see the none protocol and do NULL deferencing.
Fix them by making the none protocol a first-class citizen so that it
has start and input routines just the same as other protocols. Then we
can stop checking it in the fast path, since lagg_proto_start() and
lagg_proto_input() will never fail to work.
The error ENETDOWN is chosen for the start routine. Obviously no active
ports are available, and the packets will go nowhere. It is also a
better error than ENXIO, since indeed the interface is configured and
has a TX algorithm (the none protocol).
PR: 289017
Diagnosed by: Qiu-ji Chen <chenqiuji666@gmail.com>
Tested by: Gui-Dong Han <hanguidong02@gmail.com>
Reviewed by: glebius
MFC after: 5 days
Differential Revision: https://reviews.freebsd.org/D55123
---
sys/net/if_lagg.c | 42 +++++++++++++++++++++++++++++++++---------
1 file changed, 33 insertions(+), 9 deletions(-)
diff --git a/sys/net/if_lagg.c b/sys/net/if_lagg.c
index 5b52bfa80e3b..21ea2b30459b 100644
--- a/sys/net/if_lagg.c
+++ b/sys/net/if_lagg.c
@@ -169,6 +169,11 @@ static void lagg_media_status(struct ifnet *, struct ifmediareq *);
static struct lagg_port *lagg_link_active(struct lagg_softc *,
struct lagg_port *);
+/* No proto */
+static int lagg_none_start(struct lagg_softc *, struct mbuf *);
+static struct mbuf *lagg_none_input(struct lagg_softc *, struct lagg_port *,
+ struct mbuf *);
+
/* Simple round robin */
static void lagg_rr_attach(struct lagg_softc *);
static int lagg_rr_start(struct lagg_softc *, struct mbuf *);
@@ -219,7 +224,9 @@ static const struct lagg_proto {
void (*pr_portreq)(struct lagg_port *, void *);
} lagg_protos[] = {
{
- .pr_num = LAGG_PROTO_NONE
+ .pr_num = LAGG_PROTO_NONE,
+ .pr_start = lagg_none_start,
+ .pr_input = lagg_none_input,
},
{
.pr_num = LAGG_PROTO_ROUNDROBIN,
@@ -2129,8 +2136,8 @@ lagg_transmit_ethernet(struct ifnet *ifp, struct mbuf *m)
if (m->m_pkthdr.csum_flags & CSUM_SND_TAG)
MPASS(m->m_pkthdr.snd_tag->ifp == ifp);
#endif
- /* We need a Tx algorithm and at least one port */
- if (sc->sc_proto == LAGG_PROTO_NONE || sc->sc_count == 0) {
+ /* We need at least one port */
+ if (sc->sc_count == 0) {
m_freem(m);
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
return (ENXIO);
@@ -2151,8 +2158,8 @@ lagg_transmit_infiniband(struct ifnet *ifp, struct mbuf *m)
if (m->m_pkthdr.csum_flags & CSUM_SND_TAG)
MPASS(m->m_pkthdr.snd_tag->ifp == ifp);
#endif
- /* We need a Tx algorithm and at least one port */
- if (sc->sc_proto == LAGG_PROTO_NONE || sc->sc_count == 0) {
+ /* We need at least one port */
+ if (sc->sc_count == 0) {
m_freem(m);
if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
return (ENXIO);
@@ -2180,8 +2187,7 @@ lagg_input_ethernet(struct ifnet *ifp, struct mbuf *m)
NET_EPOCH_ASSERT();
if ((scifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
- lp->lp_detaching != 0 ||
- sc->sc_proto == LAGG_PROTO_NONE) {
+ lp->lp_detaching != 0) {
m_freem(m);
return (NULL);
}
@@ -2215,8 +2221,7 @@ lagg_input_infiniband(struct ifnet *ifp, struct mbuf *m)
NET_EPOCH_ASSERT();
if ((scifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
- lp->lp_detaching != 0 ||
- sc->sc_proto == LAGG_PROTO_NONE) {
+ lp->lp_detaching != 0) {
m_freem(m);
return (NULL);
}
@@ -2390,6 +2395,25 @@ lagg_enqueue(struct ifnet *ifp, struct mbuf *m)
return (ifp->if_transmit)(ifp, m);
}
+/*
+ * No proto
+ */
+static int
+lagg_none_start(struct lagg_softc *sc, struct mbuf *m)
+{
+ m_freem(m);
+ if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1);
+ /* No active ports available */
+ return (ENETDOWN);
+}
+
+static struct mbuf *
+lagg_none_input(struct lagg_softc *sc, struct lagg_port *lp, struct mbuf *m)
+{
+ m_freem(m);
+ return (NULL);
+}
+
/*
* Simple round robin aggregation
*/