git: 85967694b459 - main - bridge: store a bridge_iflist pointer in ifnet
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 09 Apr 2025 08:17:43 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=85967694b4590a436c56a061b397620e342784ae commit 85967694b4590a436c56a061b397620e342784ae Author: Lexi Winter <lexi@hemlock.eden.le-fay.org> AuthorDate: 2025-04-05 14:04:21 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2025-04-09 07:39:01 +0000 bridge: store a bridge_iflist pointer in ifnet currently, bridge stores a pointer to its softc in ifnet. this means that when processing a packet, it needs to walk the bridge's member list to find the bridge_iflist for the interface the packet came from. instead, store a pointer to the bridge_iflist in ifnet, and add a pointer from bridge_iflist back to the bridge_softc. this means given an ifnet, we always have both the softc and the bridge_iflist without a list walk. there are two places outside if_bridge that treat ifnet->if_bridge as something other than an opaque pointer: bridgestp, and netinet. add two function pointers exported from if_bridge to handle those cases. bump __FreeBSD_version as this is technically a KABI break. Reviewed by: kp --- sys/net/bridgestp.c | 4 +- sys/net/if_bridge.c | 132 ++++++++++++++++++++++++++++++++++--------------- sys/net/if_bridgevar.h | 2 + sys/net/if_ethersubr.c | 2 + sys/netinet/if_ether.c | 7 +-- sys/sys/param.h | 2 +- 6 files changed, 103 insertions(+), 46 deletions(-) diff --git a/sys/net/bridgestp.c b/sys/net/bridgestp.c index c67f1efe3d88..b5a863641de7 100644 --- a/sys/net/bridgestp.c +++ b/sys/net/bridgestp.c @@ -57,6 +57,7 @@ #include <net/if_types.h> #include <net/if_llc.h> #include <net/if_media.h> +#include <net/if_bridgevar.h> #include <net/vnet.h> #include <netinet/in.h> @@ -2059,6 +2060,7 @@ bstp_reinit(struct bstp_state *bs) mif = NULL; bridgeptr = LIST_FIRST(&bs->bs_bplist)->bp_ifp->if_bridge; KASSERT(bridgeptr != NULL, ("Invalid bridge pointer")); + KASSERT(bridge_same_p != NULL, ("if_bridge not loaded")); /* * Search through the Ethernet adapters and find the one with the * lowest value. Make sure the adapter which we take the MAC address @@ -2070,7 +2072,7 @@ bstp_reinit(struct bstp_state *bs) if (ifp->if_type != IFT_ETHER && ifp->if_type != IFT_L2VLAN) continue; /* Not Ethernet */ - if (ifp->if_bridge != bridgeptr) + if (!bridge_same_p(ifp->if_bridge, bridgeptr)) continue; /* Not part of our bridge */ if (bstp_addr_cmp(IF_LLADDR(ifp), llzero) == 0) diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index 5cb4a033e325..fdfec024ef07 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -238,12 +238,15 @@ #define BRIDGE_RT_LOCK_OR_NET_EPOCH_ASSERT(_sc) \ MPASS(in_epoch(net_epoch_preempt) || mtx_owned(&(_sc)->sc_rt_mtx)) +struct bridge_softc; + /* * Bridge interface list entry. */ struct bridge_iflist { CK_LIST_ENTRY(bridge_iflist) bif_next; struct ifnet *bif_ifp; /* member if */ + struct bridge_softc *bif_sc; /* parent bridge */ struct bstp_port bif_stp; /* STP state */ uint32_t bif_flags; /* member if flags */ int bif_savedcaps; /* saved capabilities */ @@ -314,6 +317,8 @@ static void bridge_set_ifcap(struct bridge_softc *, struct bridge_iflist *, static void bridge_ifdetach(void *arg __unused, struct ifnet *); static void bridge_init(void *); static void bridge_dummynet(struct mbuf *, struct ifnet *); +static bool bridge_same(const void *, const void *); +static void *bridge_get_softc(struct ifnet *); static void bridge_stop(struct ifnet *, int); static int bridge_transmit(struct ifnet *, struct mbuf *); #ifdef ALTQ @@ -658,6 +663,8 @@ bridge_modevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: bridge_dn_p = bridge_dummynet; + bridge_same_p = bridge_same; + bridge_get_softc_p = bridge_get_softc; bridge_detach_cookie = EVENTHANDLER_REGISTER( ifnet_departure_event, bridge_ifdetach, NULL, EVENTHANDLER_PRI_ANY); @@ -666,6 +673,8 @@ bridge_modevent(module_t mod, int type, void *data) EVENTHANDLER_DEREGISTER(ifnet_departure_event, bridge_detach_cookie); bridge_dn_p = NULL; + bridge_same_p = NULL; + bridge_get_softc_p = NULL; break; default: return (EOPNOTSUPP); @@ -740,6 +749,43 @@ bridge_reassign(struct ifnet *ifp, struct vnet *newvnet, char *arg) } #endif +/* + * bridge_get_softc: + * + * Return the bridge softc for an ifnet. + */ +static void * +bridge_get_softc(struct ifnet *ifp) +{ + struct bridge_iflist *bif; + + NET_EPOCH_ASSERT(); + + bif = ifp->if_bridge; + if (bif == NULL) + return (NULL); + return (bif->bif_sc); +} + +/* + * bridge_same: + * + * Return true if two interfaces are in the same bridge. This is only used by + * bridgestp via bridge_same_p. + */ +static bool +bridge_same(const void *bifap, const void *bifbp) +{ + const struct bridge_iflist *bifa = bifap, *bifb = bifbp; + + NET_EPOCH_ASSERT(); + + if (bifa == NULL || bifb == NULL) + return (false); + + return (bifa->bif_sc == bifb->bif_sc); +} + /* * bridge_clone_create: * @@ -1116,16 +1162,8 @@ bridge_lookup_member(struct bridge_softc *sc, const char *name) static struct bridge_iflist * bridge_lookup_member_if(struct bridge_softc *sc, struct ifnet *member_ifp) { - struct bridge_iflist *bif; - BRIDGE_LOCK_OR_NET_EPOCH_ASSERT(sc); - - CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) { - if (bif->bif_ifp == member_ifp) - return (bif); - } - - return (NULL); + return (member_ifp->if_bridge); } static void @@ -1257,11 +1295,13 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) if (ifs == bif->bif_ifp) return (EBUSY); - if (ifs->if_bridge == sc) - return (EEXIST); + if (ifs->if_bridge) { + struct bridge_iflist *sbif = ifs->if_bridge; + if (sbif->bif_sc == sc) + return (EEXIST); - if (ifs->if_bridge != NULL) return (EBUSY); + } switch (ifs->if_type) { case IFT_ETHER: @@ -1336,6 +1376,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) if (bif == NULL) return (ENOMEM); + bif->bif_sc = sc; bif->bif_ifp = ifs; bif->bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER; bif->bif_savedcaps = ifs->if_capenable; @@ -1352,7 +1393,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg) EVENTHANDLER_INVOKE(iflladdr_event, sc->sc_ifp); } - ifs->if_bridge = sc; + ifs->if_bridge = bif; ifs->if_bridge_output = bridge_output; ifs->if_bridge_input = bridge_input; ifs->if_bridge_linkstate = bridge_linkstate; @@ -1979,8 +2020,11 @@ bridge_ioctl_stxhc(struct bridge_softc *sc, void *arg) static void bridge_ifdetach(void *arg __unused, struct ifnet *ifp) { - struct bridge_softc *sc = ifp->if_bridge; - struct bridge_iflist *bif; + struct bridge_iflist *bif = ifp->if_bridge; + struct bridge_softc *sc = NULL; + + if (bif) + sc = bif->bif_sc; if (ifp->if_flags & IFF_RENAMING) return; @@ -1994,11 +2038,7 @@ bridge_ifdetach(void *arg __unused, struct ifnet *ifp) /* Check if the interface is a bridge member */ if (sc != NULL) { BRIDGE_LOCK(sc); - - bif = bridge_lookup_member_if(sc, ifp); - if (bif != NULL) - bridge_delete_member(sc, bif, 1); - + bridge_delete_member(sc, bif, 1); BRIDGE_UNLOCK(sc); return; } @@ -2136,9 +2176,11 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m) static void bridge_dummynet(struct mbuf *m, struct ifnet *ifp) { - struct bridge_softc *sc; + struct bridge_iflist *bif = ifp->if_bridge; + struct bridge_softc *sc = NULL; - sc = ifp->if_bridge; + if (bif) + sc = bif->bif_sc; /* * The packet didnt originate from a member interface. This should only @@ -2175,6 +2217,7 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, struct rtentry *rt) { struct ether_header *eh; + struct bridge_iflist *sbif; struct ifnet *bifp, *dst_if; struct bridge_softc *sc; uint16_t vlan; @@ -2187,12 +2230,13 @@ bridge_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *sa, return (0); } + sbif = ifp->if_bridge; + sc = sbif->bif_sc; + bifp = sc->sc_ifp; + eh = mtod(m, struct ether_header *); - sc = ifp->if_bridge; vlan = VLANTAGOF(m); - bifp = sc->sc_ifp; - /* * If bridge is down, but the original output interface is up, * go ahead and send out that interface. Otherwise, the packet @@ -2503,7 +2547,7 @@ drop: static struct mbuf * bridge_input(struct ifnet *ifp, struct mbuf *m) { - struct bridge_softc *sc; + struct bridge_softc *sc = NULL; struct bridge_iflist *bif, *bif2; struct ifnet *bifp; struct ether_header *eh; @@ -2516,7 +2560,10 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) eh = mtod(m, struct ether_header *); vlan = VLANTAGOF(m); - sc = ifp->if_bridge; + bif = ifp->if_bridge; + if (bif) + sc = bif->bif_sc; + if (sc == NULL) { /* * This packet originated from the bridge itself, so it must @@ -2553,10 +2600,6 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) m_freem(m); return (NULL); } - bif = bridge_lookup_member_if(sc, ifp); - if (bif == NULL) { - return (m); - } bridge_span(sc, m); @@ -3329,10 +3372,16 @@ bridge_rtnode_destroy(struct bridge_softc *sc, struct bridge_rtnode *brt) static void bridge_rtable_expire(struct ifnet *ifp, int age) { - struct bridge_softc *sc = ifp->if_bridge; + struct bridge_iflist *bif = NULL; + struct bridge_softc *sc = NULL; struct bridge_rtnode *brt; CURVNET_SET(ifp->if_vnet); + + bif = ifp->if_bridge; + if (bif) + sc = bif->bif_sc; + MPASS(sc != NULL); BRIDGE_RT_LOCK(sc); /* @@ -3362,7 +3411,8 @@ bridge_rtable_expire(struct ifnet *ifp, int age) static void bridge_state_change(struct ifnet *ifp, int state) { - struct bridge_softc *sc = ifp->if_bridge; + struct bridge_iflist *bif = ifp->if_bridge; + struct bridge_softc *sc = bif->bif_sc; static const char *stpstates[] = { "disabled", "listening", @@ -3877,20 +3927,20 @@ dropit: static void bridge_linkstate(struct ifnet *ifp) { - struct bridge_softc *sc = ifp->if_bridge; + struct bridge_softc *sc = NULL; struct bridge_iflist *bif; struct epoch_tracker et; NET_EPOCH_ENTER(et); - bif = bridge_lookup_member_if(sc, ifp); - if (bif == NULL) { - NET_EPOCH_EXIT(et); - return; - } - bridge_linkcheck(sc); + bif = ifp->if_bridge; + if (bif) + sc = bif->bif_sc; - bstp_linkstate(&bif->bif_stp); + if (sc != NULL) { + bridge_linkcheck(sc); + bstp_linkstate(&bif->bif_stp); + } NET_EPOCH_EXIT(et); } diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h index 01ac96e8d5b0..1f762bc4ecf9 100644 --- a/sys/net/if_bridgevar.h +++ b/sys/net/if_bridgevar.h @@ -320,5 +320,7 @@ struct ifbpstpconf { } while (0) extern void (*bridge_dn_p)(struct mbuf *, struct ifnet *); +extern bool (*bridge_same_p)(const void *, const void *); +extern void *(*bridge_get_softc_p)(struct ifnet *); #endif /* _KERNEL */ diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index ddaa94414ca5..2397b5ff2090 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -110,6 +110,8 @@ void (*vlan_input_p)(struct ifnet *, struct mbuf *); /* if_bridge(4) support */ void (*bridge_dn_p)(struct mbuf *, struct ifnet *); +bool (*bridge_same_p)(const void *, const void *); +void *(*bridge_get_softc_p)(struct ifnet *); /* if_lagg(4) support */ struct mbuf *(*lagg_input_ethernet_p)(struct ifnet *, struct mbuf *); diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c index 88da1b139b1f..dc6ef343662d 100644 --- a/sys/netinet/if_ether.c +++ b/sys/netinet/if_ether.c @@ -56,6 +56,7 @@ #include <net/if_dl.h> #include <net/if_private.h> #include <net/if_types.h> +#include <net/if_bridgevar.h> #include <net/netisr.h> #include <net/ethernet.h> #include <net/route.h> @@ -832,7 +833,7 @@ in_arpinput(struct mbuf *m) * when we have clusters of interfaces). */ CK_LIST_FOREACH(ia, INADDR_HASH(itaddr.s_addr), ia_hash) { - if (((bridged && ia->ia_ifp->if_bridge == ifp->if_bridge) || + if (((bridged && bridge_same_p(ia->ia_ifp->if_bridge, ifp->if_bridge)) || ia->ia_ifp == ifp) && itaddr.s_addr == ia->ia_addr.sin_addr.s_addr && (ia->ia_ifa.ifa_carp == NULL || @@ -842,7 +843,7 @@ in_arpinput(struct mbuf *m) } } CK_LIST_FOREACH(ia, INADDR_HASH(isaddr.s_addr), ia_hash) - if (((bridged && ia->ia_ifp->if_bridge == ifp->if_bridge) || + if (((bridged && bridge_same_p(ia->ia_ifp->if_bridge, ifp->if_bridge)) || ia->ia_ifp == ifp) && isaddr.s_addr == ia->ia_addr.sin_addr.s_addr) { ifa_ref(&ia->ia_ifa); @@ -850,7 +851,7 @@ in_arpinput(struct mbuf *m) } #define BDG_MEMBER_MATCHES_ARP(addr, ifp, ia) \ - (ia->ia_ifp->if_bridge == ifp->if_softc && \ + (bridge_get_softc_p(ia->ia_ifp) == ifp->if_softc && \ !bcmp(IF_LLADDR(ia->ia_ifp), IF_LLADDR(ifp), ifp->if_addrlen) && \ addr == ia->ia_addr.sin_addr.s_addr) /* diff --git a/sys/sys/param.h b/sys/sys/param.h index b08a83ccc25b..4b7b4853e19d 100644 --- a/sys/sys/param.h +++ b/sys/sys/param.h @@ -73,7 +73,7 @@ * cannot include sys/param.h and should only be updated here. */ #undef __FreeBSD_version -#define __FreeBSD_version 1500035 +#define __FreeBSD_version 1500036 /* * __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,