Module Name: src
Committed By: yamaguchi
Date: Wed Nov 22 03:49:13 UTC 2023
Modified Files:
src/sys/net/lagg: if_lagg.c if_lagg_lacp.c if_lagg_lacp.h
if_laggproto.c if_laggproto.h
Log Message:
Set the fastest linkspeed in each physical interface to lagg(4)
To generate a diff of this commit:
cvs rdiff -u -r1.53 -r1.54 src/sys/net/lagg/if_lagg.c
cvs rdiff -u -r1.27 -r1.28 src/sys/net/lagg/if_lagg_lacp.c
cvs rdiff -u -r1.4 -r1.5 src/sys/net/lagg/if_lagg_lacp.h
cvs rdiff -u -r1.6 -r1.7 src/sys/net/lagg/if_laggproto.c
cvs rdiff -u -r1.18 -r1.19 src/sys/net/lagg/if_laggproto.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.c
diff -u src/sys/net/lagg/if_lagg.c:1.53 src/sys/net/lagg/if_lagg.c:1.54
--- src/sys/net/lagg/if_lagg.c:1.53 Wed Nov 22 03:30:57 2023
+++ src/sys/net/lagg/if_lagg.c Wed Nov 22 03:49:13 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: if_lagg.c,v 1.53 2023/11/22 03:30:57 yamaguchi Exp $ */
+/* $NetBSD: if_lagg.c,v 1.54 2023/11/22 03:49:13 yamaguchi Exp $ */
/*
* Copyright (c) 2005, 2006 Reyk Floeter <[email protected]>
@@ -20,7 +20,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_lagg.c,v 1.53 2023/11/22 03:30:57 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_lagg.c,v 1.54 2023/11/22 03:49:13 yamaguchi Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@@ -1217,6 +1217,9 @@ lagg_media_status(struct ifnet *ifp, str
imr->ifm_active = IFM_ETHER | IFM_AUTO;
LAGG_LOCK(sc);
+
+ imr->ifm_active |= sc->sc_media_active;
+
LAGG_PORTS_FOREACH(sc, lp) {
if (lagg_portactive(lp))
imr->ifm_status |= IFM_ACTIVE;
@@ -1224,6 +1227,52 @@ lagg_media_status(struct ifnet *ifp, str
LAGG_UNLOCK(sc);
}
+static uint64_t
+lagg_search_media_type(uint64_t linkspeed)
+{
+
+ if (linkspeed == IF_Gbps(40))
+ return IFM_40G_T | IFM_FDX;
+
+ if (linkspeed == IF_Gbps(25))
+ return IFM_25G_T | IFM_FDX;
+
+ if (linkspeed == IF_Gbps(10))
+ return IFM_10G_T | IFM_FDX;
+
+ if (linkspeed == IF_Gbps(5))
+ return IFM_5000_T | IFM_FDX;
+
+ if (linkspeed == IF_Mbps(2500))
+ return IFM_2500_T | IFM_FDX;
+
+ if (linkspeed == IF_Gbps(1))
+ return IFM_1000_T | IFM_FDX;
+
+ if (linkspeed == IF_Mbps(100))
+ return IFM_100_TX | IFM_FDX;
+
+ if (linkspeed == IF_Mbps(10))
+ return IFM_10_T | IFM_FDX;
+
+ return 0;
+}
+
+void
+lagg_set_linkspeed(struct lagg_softc *sc, uint64_t linkspeed)
+{
+ struct ifnet *ifp;
+
+ ifp = &sc->sc_if;
+
+ KASSERT(LAGG_LOCKED(sc));
+
+ ifp->if_baudrate = linkspeed;
+
+ sc->sc_media_active =
+ lagg_search_media_type(linkspeed);
+}
+
static int
lagg_port_vlan_cb(struct lagg_port *lp,
struct lagg_vlantag *lvt, bool set)
@@ -1630,6 +1679,8 @@ lagg_pr_attach(struct lagg_softc *sc, la
lagg_proto_detach(oldvar);
cleanup_oldvar = true;
}
+
+ lagg_set_linkspeed(sc, 0);
done:
LAGG_UNLOCK(sc);
Index: src/sys/net/lagg/if_lagg_lacp.c
diff -u src/sys/net/lagg/if_lagg_lacp.c:1.27 src/sys/net/lagg/if_lagg_lacp.c:1.28
--- src/sys/net/lagg/if_lagg_lacp.c:1.27 Wed Nov 22 03:27:00 2023
+++ src/sys/net/lagg/if_lagg_lacp.c Wed Nov 22 03:49:13 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: if_lagg_lacp.c,v 1.27 2023/11/22 03:27:00 yamaguchi Exp $ */
+/* $NetBSD: if_lagg_lacp.c,v 1.28 2023/11/22 03:49:13 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.27 2023/11/22 03:27:00 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_lagg_lacp.c,v 1.28 2023/11/22 03:49:13 yamaguchi Exp $");
#ifdef _KERNEL_OPT
#include "opt_lagg.h"
@@ -126,7 +126,7 @@ struct lacp_port {
struct lacp_aggregator *lp_aggregator;
struct lacp_aggregator_systemid
lp_aggregator_sidbuf;
- uint32_t lp_media;
+ uint64_t lp_linkspeed;
int lp_pending;
LIST_ENTRY(lacp_port) lp_entry_la;
struct timeval lp_last_lacpdu;
@@ -165,6 +165,7 @@ struct lacp_softc {
struct workqueue *lsc_workq;
struct lagg_work lsc_work_tick;
struct lagg_work lsc_work_rcvdu;
+ struct lagg_work lsc_work_linkspeed;
callout_t lsc_tick;
pcq_t *lsc_du_q;
@@ -247,7 +248,6 @@ static void lacp_dprintf(const struct la
static void lacp_tick(void *);
static void lacp_tick_work(struct lagg_work *, void *);
static void lacp_linkstate(struct lagg_proto_softc *, struct lagg_port *);
-static uint32_t lacp_ifmedia2lacpmedia(u_int);
static void lacp_port_disable(struct lacp_softc *, struct lacp_port *);
static void lacp_port_enable(struct lacp_softc *, struct lacp_port *);
static void lacp_peerinfo_actor(struct lacp_softc *, struct lacp_port *,
@@ -285,6 +285,7 @@ static void lacp_sm_ptx_update_timeout(s
static void lacp_rcvdu_work(struct lagg_work *, void *);
static void lacp_marker_work(struct lagg_work *, void *);
+static void lacp_linkspeed_work(struct lagg_work *, void *);
static void lacp_dump_lacpdutlv(const struct lacpdu_peerinfo *,
const struct lacpdu_peerinfo *,
const struct lacpdu_collectorinfo *);
@@ -413,9 +414,9 @@ lacp_port_priority_max(struct lacp_port
if (pri_b < pri_a)
return b;
- if (a->lp_media > b->lp_media)
+ if (a->lp_linkspeed > b->lp_linkspeed)
return a;
- if (b->lp_media > a->lp_media)
+ if (b->lp_linkspeed > a->lp_linkspeed)
return b;
return a;
@@ -487,6 +488,8 @@ lacp_attach(struct lagg_softc *sc, struc
lagg_work_set(&lsc->lsc_work_tick, lacp_tick_work, lsc);
lagg_work_set(&lsc->lsc_work_rcvdu, lacp_rcvdu_work, lsc);
+ lagg_work_set(&lsc->lsc_work_linkspeed,
+ lacp_linkspeed_work, lsc);
snprintf(xnamebuf, sizeof(xnamebuf), "%s.lacp",
sc->sc_if.if_xname);
@@ -852,7 +855,7 @@ lacp_linkstate_ifnet_locked(struct lagg_
struct ifmediareq ifmr;
struct ifnet *ifp_port;
uint8_t old_state;
- uint32_t media, old_media;
+ uint64_t old_linkspeed, new_linkspeed;
int error;
KASSERT(IFNET_LOCKED(lp->lp_ifp));
@@ -861,14 +864,24 @@ lacp_linkstate_ifnet_locked(struct lagg_
ifp_port = lp->lp_ifp;
lacpp = lp->lp_proto_ctx;
- media = LACP_MEDIA_DEFAULT;
memset(&ifmr, 0, sizeof(ifmr));
ifmr.ifm_count = 0;
error = if_ioctl(ifp_port, SIOCGIFMEDIA, (void *)&ifmr);
if (error == 0) {
- media = lacp_ifmedia2lacpmedia(ifmr.ifm_active);
- } else if (error != ENOTTY){
+ new_linkspeed = ifmedia_baudrate(ifmr.ifm_active);
+#ifdef LACP_NOFDX
+ /*
+ * some driver that has no media, e.g. vioif(4),
+ * returns (IFM_ETHER | IFM_AUTO)
+ */
+ if ((ifmr.ifm_active & ~(IFM_ETHER | IFM_AUTO)) == 0)
+ ifmr.ifm_active |= IFM_FDX;
+#endif
+ } else if (error == ENOTTY) {
+ ifmr.ifm_active = IFM_FDX | IF_Gbps(0);
+ new_linkspeed = 0;
+ } else {
LACP_DPRINTF((lsc, lacpp,
"SIOCGIFMEDIA failed (%d)\n", error));
return;
@@ -876,34 +889,31 @@ lacp_linkstate_ifnet_locked(struct lagg_
LACP_LOCK(lsc);
if (lsc->lsc_running) {
- old_media = lacpp->lp_media;
+ old_linkspeed = lacpp->lp_linkspeed;
old_state = lacpp->lp_actor.lpi_state;
- if (lacpp->lp_media != media) {
+ if (new_linkspeed != old_linkspeed) {
LACP_DPRINTF((lsc, lacpp,
- "media changed 0x%"PRIx32"->0x%"PRIx32", "
- "ether = %d, fdx = %d, link = %d, running = %d\n",
- lacpp->lp_media, media,
- ISSET(media, LACP_MEDIA_ETHER) != 0,
- ISSET(media, LACP_MEDIA_FDX) != 0,
- ifp_port->if_link_state != LINK_STATE_DOWN,
- ISSET(ifp_port->if_flags, IFF_RUNNING) != 0));
- lacpp->lp_media = media;
+ "linkspeed changed %"PRIu64" -> %"PRIu64"\n",
+ old_linkspeed, new_linkspeed));
+ lacpp->lp_linkspeed = new_linkspeed;
}
- if (ISSET(media, LACP_MEDIA_ETHER) &&
-#ifndef LACP_NOFDX
- ISSET(media, LACP_MEDIA_FDX) &&
-#endif
- ifp_port->if_link_state != LINK_STATE_DOWN &&
- ISSET(ifp_port->if_flags, IFF_RUNNING)) {
+ if (ISSET(ifmr.ifm_active, IFM_FDX) &&
+ ISSET(ifp_port->if_flags, IFF_RUNNING) &&
+ ifp_port->if_link_state != LINK_STATE_DOWN) {
lacp_port_enable(lsc, lacpp);
} else {
+ LACP_DPRINTF((lsc, lacpp,
+ "FDX=%d, RUNNING=%d, link=%d\n",
+ ISSET(ifmr.ifm_active, IFM_FDX) != 0,
+ ISSET(ifp_port->if_flags, IFF_RUNNING) != 0,
+ ifp_port->if_link_state != LINK_STATE_DOWN));
lacp_port_disable(lsc, lacpp);
}
if (old_state != lacpp->lp_actor.lpi_state ||
- old_media != media) {
+ old_linkspeed != new_linkspeed) {
LACP_DPRINTF((lsc, lacpp,
"state changed to UNSELECTED\n"));
lacpp->lp_selected = LACP_UNSELECTED;
@@ -912,7 +922,6 @@ lacp_linkstate_ifnet_locked(struct lagg_
LACP_DPRINTF((lsc, lacpp,
"LACP is inactive, skip linkstate\n"));
}
-
LACP_UNLOCK(lsc);
}
@@ -2051,6 +2060,8 @@ lacp_update_portmap(struct lacp_softc *l
if_link_state_change(&sc->sc_if, link);
}
+ lagg_workq_add(lsc->lsc_workq, &lsc->lsc_work_linkspeed);
+
/* cleanup */
pm_act->pm_count = 0;
memset(pm_act->pm_ports, 0, sizeof(pm_act->pm_ports));
@@ -2355,7 +2366,7 @@ lacp_selected_update(struct lacp_softc *
{
struct lacp_port *lacpp;
size_t nselected;
- uint32_t media;
+ uint64_t linkspeed;
KASSERT(LACP_LOCKED(lsc));
@@ -2363,14 +2374,13 @@ lacp_selected_update(struct lacp_softc *
if (lacpp == NULL)
return;
- media = lacpp->lp_media;
+ linkspeed = lacpp->lp_linkspeed;
nselected = 0;
LIST_FOREACH(lacpp, &la->la_ports, lp_entry_la) {
if (nselected >= lsc->lsc_max_ports ||
- (!lsc->lsc_multi_linkspeed && media != lacpp->lp_media)) {
+ (!lsc->lsc_multi_linkspeed && linkspeed != lacpp->lp_linkspeed)) {
if (lacpp->lp_selected == LACP_SELECTED)
lacpp->lp_selected = LACP_STANDBY;
- continue;
}
switch (lacpp->lp_selected) {
@@ -2677,62 +2687,6 @@ lacp_dump_markertlv(const struct markerd
}
}
-static uint32_t
-lacp_ifmedia2lacpmedia(u_int ifmedia)
-{
- uint32_t rv;
-
- switch (IFM_SUBTYPE(ifmedia)) {
- case IFM_10_T:
- case IFM_10_2:
- case IFM_10_5:
- case IFM_10_STP:
- case IFM_10_FL:
- rv = LACP_LINKSPEED_10;
- break;
- case IFM_100_TX:
- case IFM_100_FX:
- case IFM_100_T4:
- case IFM_100_VG:
- case IFM_100_T2:
- rv = LACP_LINKSPEED_100;
- break;
- case IFM_1000_SX:
- case IFM_1000_LX:
- case IFM_1000_CX:
- case IFM_1000_T:
- case IFM_1000_BX10:
- case IFM_1000_KX:
- rv = LACP_LINKSPEED_1000;
- break;
- case IFM_2500_SX:
- case IFM_2500_KX:
- rv = LACP_LINKSPEED_2500;
- break;
- case IFM_5000_T:
- rv = LACP_LINKSPEED_5000;
- break;
- case IFM_10G_LR:
- case IFM_10G_SR:
- case IFM_10G_CX4:
- case IFM_10G_TWINAX:
- case IFM_10G_TWINAX_LONG:
- case IFM_10G_LRM:
- case IFM_10G_T:
- rv = LACP_LINKSPEED_10G;
- break;
- default:
- rv = LACP_LINKSPEED_UNKNOWN;
- }
-
- if (IFM_TYPE(ifmedia) == IFM_ETHER)
- SET(rv, LACP_MEDIA_ETHER);
- if ((ifmedia & IFM_FDX) != 0)
- SET(rv, LACP_MEDIA_FDX);
-
- return rv;
-}
-
static void
lacp_linkstate(struct lagg_proto_softc *xlsc, struct lagg_port *lp)
{
@@ -2743,3 +2697,31 @@ lacp_linkstate(struct lagg_proto_softc *
lacp_linkstate_ifnet_locked(xlsc, lp);
IFNET_UNLOCK(lp->lp_ifp);
}
+
+static void
+lacp_linkspeed_work(struct lagg_work *lw __unused, void *xlsc)
+{
+ struct lacp_softc *lsc = (struct lacp_softc *)xlsc;
+ struct lagg_softc *sc = lsc->lsc_softc;
+ struct lacp_portmap *pm;
+ struct lagg_port *lp;
+ struct lacp_port *lacpp;
+ uint64_t linkspeed;
+ size_t act, i;
+
+ linkspeed = 0;
+
+ LACP_LOCK(lsc);
+ act = LACP_PORTMAP_ACTIVE(lsc);
+ pm = &lsc->lsc_portmaps[act];
+ for (i = 0; i < pm->pm_count; i++) {
+ lp = pm->pm_ports[i];
+ lacpp = lp->lp_proto_ctx;
+ linkspeed = MAX(linkspeed, lacpp->lp_linkspeed);
+ }
+ LACP_UNLOCK(lsc);
+
+ LAGG_LOCK(sc);
+ lagg_set_linkspeed(sc, linkspeed);
+ LAGG_UNLOCK(sc);
+}
Index: src/sys/net/lagg/if_lagg_lacp.h
diff -u src/sys/net/lagg/if_lagg_lacp.h:1.4 src/sys/net/lagg/if_lagg_lacp.h:1.5
--- src/sys/net/lagg/if_lagg_lacp.h:1.4 Thu Mar 31 02:04:50 2022
+++ src/sys/net/lagg/if_lagg_lacp.h Wed Nov 22 03:49:13 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: if_lagg_lacp.h,v 1.4 2022/03/31 02:04:50 yamaguchi Exp $ */
+/* $NetBSD: if_lagg_lacp.h,v 1.5 2023/11/22 03:49:13 yamaguchi Exp $ */
/*
* Copyright (c) 2021 Internet Initiative Japan Inc.
@@ -129,35 +129,4 @@ struct markerdu {
struct tlvhdr mdu_tlv_term;
uint8_t mdu_resv[90];
} __packed;
-
-/*
- * lacp media:
- * 1byte
- * +-------+-------+-------+-------+
- * | media | speed |
- * +-------+-------+-------+-------+
- */
-
-enum lacp_linkspeed {
- LACP_LINKSPEED_UNKNOWN = 0,
- LACP_LINKSPEED_10,
- LACP_LINKSPEED_100,
- LACP_LINKSPEED_1000,
- LACP_LINKSPEED_2500,
- LACP_LINKSPEED_5000,
- LACP_LINKSPEED_10G,
- LACP_LINKSPEED_25G,
- LACP_LINKSPEED_40G,
- LACP_LINKSPEED_50G,
- LACP_LINKSPEED_56G,
- LACP_LINKSPEED_100G,
- LACP_LINKSPEED_200G,
-};
-
-#define LACP_MEDIA_OFFSET 24
-#define LACP_MEDIA_MASK 0xff000000U
-#define LACP_MEDIA_ETHER (__BIT(0) << LACP_MEDIA_OFFSET)
-#define LACP_MEDIA_FDX (__BIT(1) << LACP_MEDIA_OFFSET)
-#define LACP_MEDIA_DEFAULT (LACP_LINKSPEED_UNKNOWN | \
- LACP_MEDIA_ETHER | LACP_MEDIA_FDX)
#endif
Index: src/sys/net/lagg/if_laggproto.c
diff -u src/sys/net/lagg/if_laggproto.c:1.6 src/sys/net/lagg/if_laggproto.c:1.7
--- src/sys/net/lagg/if_laggproto.c:1.6 Thu Mar 31 07:59:05 2022
+++ src/sys/net/lagg/if_laggproto.c Wed Nov 22 03:49:13 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: if_laggproto.c,v 1.6 2022/03/31 07:59:05 yamaguchi Exp $ */
+/* $NetBSD: if_laggproto.c,v 1.7 2023/11/22 03:49:13 yamaguchi Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause-NetBSD
@@ -29,7 +29,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if_laggproto.c,v 1.6 2022/03/31 07:59:05 yamaguchi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if_laggproto.c,v 1.7 2023/11/22 03:49:13 yamaguchi Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -57,6 +57,8 @@ struct lagg_proto_softc {
size_t psc_ctxsiz;
void *psc_ctx;
size_t psc_nactports;
+ struct workqueue *psc_workq;
+ struct lagg_work psc_work_linkspeed;
};
/*
@@ -90,7 +92,9 @@ struct lagg_lb {
struct lagg_proto_port {
struct pslist_entry lpp_entry;
struct lagg_port *lpp_laggport;
+ uint64_t lpp_linkspeed;
bool lpp_active;
+ bool lpp_running;
};
#define LAGG_PROTO_LOCK(_psc) mutex_enter(&(_psc)->psc_lock)
@@ -107,6 +111,9 @@ static void lagg_proto_remove_port(struc
static struct lagg_port *
lagg_link_active(struct lagg_proto_softc *psc,
struct lagg_proto_port *, struct psref *);
+static void lagg_fail_linkspeed_work(struct lagg_work *, void *);
+static void lagg_lb_linkspeed_work(struct lagg_work*,
+ void *);
static inline struct lagg_portmap *
lagg_portmap_active(struct lagg_portmaps *maps)
@@ -146,6 +153,7 @@ static struct lagg_proto_softc *
lagg_proto_alloc(lagg_proto pr, struct lagg_softc *sc)
{
struct lagg_proto_softc *psc;
+ char xnamebuf[MAXCOMLEN];
size_t ctxsiz;
switch (pr) {
@@ -163,9 +171,18 @@ lagg_proto_alloc(lagg_proto pr, struct l
if (psc == NULL)
return NULL;
+ psc->psc_workq = lagg_workq_create(xnamebuf,
+ PRI_SOFTNET, IPL_SOFTNET, WQ_MPSAFE);
+ if (psc->psc_workq == NULL) {
+ LAGG_LOG(sc, LOG_ERR, "workqueue create failed\n");
+ kmem_free(psc, sizeof(*psc));
+ return NULL;
+ }
+
if (ctxsiz > 0) {
psc->psc_ctx = kmem_zalloc(ctxsiz, KM_NOSLEEP);
if (psc->psc_ctx == NULL) {
+ lagg_workq_destroy(psc->psc_workq);
kmem_free(psc, sizeof(*psc));
return NULL;
}
@@ -185,8 +202,10 @@ static void
lagg_proto_free(struct lagg_proto_softc *psc)
{
+ lagg_workq_wait(psc->psc_workq, &psc->psc_work_linkspeed);
pserialize_destroy(psc->psc_psz);
mutex_destroy(&psc->psc_lock);
+ lagg_workq_destroy(psc->psc_workq);
if (psc->psc_ctxsiz > 0)
kmem_free(psc->psc_ctx, psc->psc_ctxsiz);
@@ -251,6 +270,7 @@ lagg_common_freeport(struct lagg_proto_s
struct lagg_proto_port *pport;
pport = lp->lp_proto_ctx;
+ KASSERT(!pport->lpp_running);
lp->lp_proto_ctx = NULL;
kmem_free(pport, sizeof(*pport));
@@ -311,6 +331,10 @@ lagg_common_startport(struct lagg_proto_
pport = lp->lp_proto_ctx;
lagg_proto_insert_port(psc, pport);
+ LAGG_PROTO_LOCK(psc);
+ pport->lpp_running = true;
+ LAGG_PROTO_UNLOCK(psc);
+
lagg_common_linkstate(psc, lp);
}
@@ -321,6 +345,11 @@ lagg_common_stopport(struct lagg_proto_s
struct ifnet *ifp;
pport = lp->lp_proto_ctx;
+
+ LAGG_PROTO_LOCK(psc);
+ pport->lpp_running = false;
+ LAGG_PROTO_UNLOCK(psc);
+
lagg_proto_remove_port(psc, pport);
if (pport->lpp_active) {
@@ -340,16 +369,26 @@ void
lagg_common_linkstate(struct lagg_proto_softc *psc, struct lagg_port *lp)
{
struct lagg_proto_port *pport;
- struct ifnet *ifp;
+ struct ifnet *ifp, *ifp_port;
+ struct ifmediareq ifmr;
+ uint64_t linkspeed;
bool is_active;
+ int error;
pport = lp->lp_proto_ctx;
is_active = lagg_portactive(lp);
+ ifp_port = lp->lp_ifp;
- if (pport->lpp_active == is_active)
+ LAGG_PROTO_LOCK(psc);
+ if (!pport->lpp_running ||
+ pport->lpp_active == is_active) {
+ LAGG_PROTO_UNLOCK(psc);
return;
+ }
ifp = &psc->psc_softc->sc_if;
+ pport->lpp_active = is_active;
+
if (is_active) {
psc->psc_nactports++;
if (psc->psc_nactports == 1)
@@ -361,8 +400,20 @@ lagg_common_linkstate(struct lagg_proto_
if (psc->psc_nactports == 0)
if_link_state_change(ifp, LINK_STATE_DOWN);
}
+ LAGG_PROTO_UNLOCK(psc);
+
+ memset(&ifmr, 0, sizeof(ifmr));
+ error = if_ioctl(ifp_port, SIOCGIFMEDIA, (void *)&ifmr);
+ if (error == 0) {
+ linkspeed = ifmedia_baudrate(ifmr.ifm_active);
+ } else {
+ linkspeed = 0;
+ }
- atomic_store_relaxed(&pport->lpp_active, is_active);
+ LAGG_PROTO_LOCK(psc);
+ pport->lpp_linkspeed = linkspeed;
+ LAGG_PROTO_UNLOCK(psc);
+ lagg_workq_add(psc->psc_workq, &psc->psc_work_linkspeed);
}
void
@@ -392,6 +443,8 @@ lagg_fail_attach(struct lagg_softc *sc,
fovr = psc->psc_ctx;
fovr->fo_rx_all = true;
+ lagg_work_set(&psc->psc_work_linkspeed,
+ lagg_fail_linkspeed_work, psc);
*xpsc = psc;
return 0;
@@ -510,6 +563,33 @@ lagg_fail_ioctl(struct lagg_proto_softc
return error;
}
+void
+lagg_fail_linkspeed_work(struct lagg_work *_lw __unused, void *xpsc)
+{
+ struct lagg_proto_softc *psc = xpsc;
+ struct lagg_proto_port *pport;
+ struct lagg_port *lp;
+ struct psref psref;
+ uint64_t linkspeed;
+
+ kpreempt_disable();
+ lp = lagg_link_active(psc, NULL, &psref);
+ if (lp != NULL) {
+ pport = lp->lp_proto_ctx;
+ LAGG_PROTO_LOCK(psc);
+ linkspeed = pport->lpp_linkspeed;
+ LAGG_PROTO_UNLOCK(psc);
+ lagg_port_putref(lp, &psref);
+ } else {
+ linkspeed = 0;
+ }
+ kpreempt_enable();
+
+ LAGG_LOCK(psc->psc_softc);
+ lagg_set_linkspeed(psc->psc_softc, linkspeed);
+ LAGG_UNLOCK(psc->psc_softc);
+}
+
int
lagg_lb_attach(struct lagg_softc *sc, struct lagg_proto_softc **xpsc)
{
@@ -522,6 +602,8 @@ lagg_lb_attach(struct lagg_softc *sc, st
lb = psc->psc_ctx;
lb->lb_pmaps.maps_activepmap = 0;
+ lagg_work_set(&psc->psc_work_linkspeed,
+ lagg_lb_linkspeed_work, psc);
*xpsc = psc;
return 0;
@@ -640,3 +722,30 @@ lagg_lb_portstat(struct lagg_proto_softc
LAGG_PORT_COLLECTING | LAGG_PORT_DISTRIBUTING);
}
}
+
+static void
+lagg_lb_linkspeed_work(struct lagg_work *_lw __unused, void *xpsc)
+{
+ struct lagg_proto_softc *psc = xpsc;
+ struct lagg_proto_port *pport;
+ uint64_t linkspeed, l;
+ int s;
+
+ linkspeed = 0;
+
+ s = pserialize_read_enter();
+ PSLIST_READER_FOREACH(pport, &psc->psc_ports,
+ struct lagg_proto_port, lpp_entry) {
+ if (pport->lpp_active) {
+ LAGG_PROTO_LOCK(psc);
+ l = pport->lpp_linkspeed;
+ LAGG_PROTO_UNLOCK(psc);
+ linkspeed = MAX(linkspeed, l);
+ }
+ }
+ pserialize_read_exit(s);
+
+ LAGG_LOCK(psc->psc_softc);
+ lagg_set_linkspeed(psc->psc_softc, linkspeed);
+ LAGG_UNLOCK(psc->psc_softc);
+}
Index: src/sys/net/lagg/if_laggproto.h
diff -u src/sys/net/lagg/if_laggproto.h:1.18 src/sys/net/lagg/if_laggproto.h:1.19
--- src/sys/net/lagg/if_laggproto.h:1.18 Sun Jun 26 17:55:24 2022
+++ src/sys/net/lagg/if_laggproto.h Wed Nov 22 03:49:13 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: if_laggproto.h,v 1.18 2022/06/26 17:55:24 riastradh Exp $ */
+/* $NetBSD: if_laggproto.h,v 1.19 2023/11/22 03:49:13 yamaguchi Exp $ */
/*
* Copyright (c) 2021 Internet Initiative Japan Inc.
@@ -146,6 +146,7 @@ struct lagg_vlantag {
struct lagg_softc {
kmutex_t sc_lock;
struct ifmedia sc_media;
+ uint64_t sc_media_active;
u_char sc_iftype;
/* interface link-layer address */
@@ -286,6 +287,7 @@ void lagg_port_putref(struct lagg_port
void lagg_output(struct lagg_softc *,
struct lagg_port *, struct mbuf *);
uint32_t lagg_hashmbuf(struct lagg_softc *, struct mbuf *);
+void lagg_set_linkspeed(struct lagg_softc *, uint64_t);
void lagg_common_detach(struct lagg_proto_softc *);
int lagg_common_allocport(struct lagg_proto_softc *,