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 <r...@openbsd.org> @@ -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 *,