Download raw body.
move aggr/trunk input processing into ether_input
currently aggr and trunk (and my switch chip drivers) replace the
if_input handler (which is ether_input) on interfaces they take over.
this changes it so these drivers operate like the bridge drivers where
an "ether_port" struct is given to arpcom that ether_input will look at
and allow input packets to be filtered with.
i want this for two reasons. firstly, the old "swap if_input" semantic
assumes that if_input is run while holding NET_LOCK in some way, and i
want the freedom to call it without NET_LOCK in the future. secondly, it
makes it hard to make an ethernet driver that has some extra encap you
have to remove before calling ether_input. such a driver will mess up if
you try to use aggr or trunk with them and their own if_input handling
has been swapped with aggr_input or trunk_input.
ive tested aggr and veb with this change. anyone want to test the trunk
changes before i put this in?
Index: net/if_aggr.c
===================================================================
RCS file: /cvs/src/sys/net/if_aggr.c,v
diff -u -p -r1.50 if_aggr.c
--- net/if_aggr.c 7 Jul 2025 02:28:50 -0000 1.50
+++ net/if_aggr.c 22 Nov 2025 09:28:42 -0000
@@ -346,12 +346,13 @@ struct aggr_port {
struct ifnet *p_ifp0;
struct kstat *p_kstat;
struct mutex p_mtx;
+ struct ether_port p_ether_port;
+ struct refcnt p_refs;
uint8_t p_lladdr[ETHER_ADDR_LEN];
uint32_t p_mtu;
int (*p_ioctl)(struct ifnet *, u_long, caddr_t);
- void (*p_input)(struct ifnet *, struct mbuf *, struct netstack *);
int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
@@ -743,75 +744,93 @@ aggr_start(struct ifqueue *ifq)
smr_read_leave();
}
+static void
+aggr_port_take(void *port)
+{
+ struct aggr_port *p = port;
+ refcnt_take(&p->p_refs);
+}
+
+static void
+aggr_port_rele(void *port)
+{
+ struct aggr_port *p = port;
+ refcnt_rele_wake(&p->p_refs);
+}
+
+static inline int
+aggr_is_lldp(struct mbuf *m, uint64_t dst)
+{
+ struct ether_header *eh = mtod(m, struct ether_header *);
+
+ if (eh->ether_type == htons(ETHERTYPE_LLDP) &&
+ ETH64_IS_8021_RSVD(dst)) {
+ /* look at the last nibble of the 802.1 reserved address */
+ switch (dst & 0xf) {
+ case 0x0: /* Nearest Customer Bridge */
+ case 0x3: /* Non-TPMR Bridge */
+ case 0xe: /* Nearest Bridge */
+ return (1);
+ default:
+ break;
+ }
+ }
+
+ return (0);
+}
+
static inline struct mbuf *
-aggr_input_control(struct aggr_port *p, struct mbuf *m, struct netstack *ns)
+aggr_input_control(struct aggr_port *p, struct mbuf *m, uint64_t dst)
{
struct ether_header *eh;
int hlen = sizeof(*eh);
- uint16_t etype;
- uint64_t dst;
+ unsigned int rx_proto = AGGR_PROTO_RX_LACP;
+ struct ether_slowproto_hdr *sph;
+ int drop = 0;
if (ISSET(m->m_flags, M_VLANTAG))
return (m);
eh = mtod(m, struct ether_header *);
- etype = eh->ether_type;
- dst = ether_addr_to_e64((struct ether_addr *)eh->ether_dhost);
-
- if (__predict_false(etype == htons(ETHERTYPE_SLOW) &&
- dst == LACP_ADDR_SLOW_E64)) {
- unsigned int rx_proto = AGGR_PROTO_RX_LACP;
- struct ether_slowproto_hdr *sph;
- int drop = 0;
-
- hlen += sizeof(*sph);
- if (m->m_len < hlen) {
- m = m_pullup(m, hlen);
- if (m == NULL) {
- /* short++ */
- return (NULL);
- }
- eh = mtod(m, struct ether_header *);
- }
-
- sph = (struct ether_slowproto_hdr *)(eh + 1);
- switch (sph->sph_subtype) {
- case SLOWPROTOCOLS_SUBTYPE_LACP_MARKER:
- rx_proto = AGGR_PROTO_RX_MARKER;
- /* FALLTHROUGH */
- case SLOWPROTOCOLS_SUBTYPE_LACP:
- mtx_enter(&p->p_mtx);
- p->p_proto_counts[rx_proto].c_pkts++;
- p->p_proto_counts[rx_proto].c_bytes += m->m_pkthdr.len;
-
- if (ml_len(&p->p_rxm_ml) < AGGR_MAX_SLOW_PKTS)
- ml_enqueue(&p->p_rxm_ml, m);
- else {
- p->p_rx_drops++;
- drop = 1;
- }
- mtx_leave(&p->p_mtx);
+ if (__predict_true(eh->ether_type != htons(ETHERTYPE_SLOW) ||
+ dst != LACP_ADDR_SLOW_E64))
+ return (m);
- if (drop)
- goto drop;
- else
- task_add(systq, &p->p_rxm_task);
+ hlen += sizeof(*sph);
+ if (m->m_len < hlen) {
+ m = m_pullup(m, hlen);
+ if (m == NULL) {
+ /* short++ */
return (NULL);
- default:
- break;
}
- } else if (__predict_false(etype == htons(ETHERTYPE_LLDP) &&
- ETH64_IS_8021_RSVD(dst))) {
- /* look at the last nibble of the 802.1 reserved address */
- switch (dst & 0xf) {
- case 0x0: /* Nearest Customer Bridge */
- case 0x3: /* Non-TPMR Bridge */
- case 0xe: /* Nearest Bridge */
- p->p_input(p->p_ifp0, m, ns);
- return (NULL);
- default:
- break;
+ eh = mtod(m, struct ether_header *);
+ }
+
+ sph = (struct ether_slowproto_hdr *)(eh + 1);
+ switch (sph->sph_subtype) {
+ case SLOWPROTOCOLS_SUBTYPE_LACP_MARKER:
+ rx_proto = AGGR_PROTO_RX_MARKER;
+ /* FALLTHROUGH */
+ case SLOWPROTOCOLS_SUBTYPE_LACP:
+ mtx_enter(&p->p_mtx);
+ p->p_proto_counts[rx_proto].c_pkts++;
+ p->p_proto_counts[rx_proto].c_bytes += m->m_pkthdr.len;
+
+ if (ml_len(&p->p_rxm_ml) < AGGR_MAX_SLOW_PKTS)
+ ml_enqueue(&p->p_rxm_ml, m);
+ else {
+ p->p_rx_drops++;
+ drop = 1;
}
+ mtx_leave(&p->p_mtx);
+
+ if (drop)
+ goto drop;
+ else
+ task_add(systq, &p->p_rxm_task);
+ return (NULL);
+ default:
+ break;
}
return (m);
@@ -821,20 +840,23 @@ drop:
return (NULL);
}
-static void
-aggr_input(struct ifnet *ifp0, struct mbuf *m, struct netstack *ns)
+static struct mbuf *
+aggr_port_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *port,
+ struct netstack *ns)
{
- struct arpcom *ac0 = (struct arpcom *)ifp0;
- struct aggr_port *p = ac0->ac_trunkport;
+ struct aggr_port *p = port;
struct aggr_softc *sc = p->p_aggr;
struct ifnet *ifp = &sc->sc_if;
+ if (__predict_false(aggr_is_lldp(m, dst)))
+ return (m);
+
if (!ISSET(ifp->if_flags, IFF_RUNNING))
goto drop;
- m = aggr_input_control(p, m, ns);
+ m = aggr_input_control(p, m, dst);
if (m == NULL)
- return;
+ return (NULL);
if (__predict_false(!p->p_collecting))
goto drop;
@@ -844,10 +866,11 @@ aggr_input(struct ifnet *ifp0, struct mb
if_vinput(ifp, m, ns);
- return;
+ return (NULL);
drop:
m_freem(m);
+ return (NULL);
}
static int
@@ -1168,7 +1191,7 @@ aggr_add_port(struct aggr_softc *sc, con
}
ac0 = (struct arpcom *)ifp0;
- if (ac0->ac_trunkport != NULL) {
+ if (SMR_PTR_GET_LOCKED(&ac0->ac_trport) != NULL) {
error = EBUSY;
goto put;
}
@@ -1188,11 +1211,16 @@ aggr_add_port(struct aggr_softc *sc, con
p->p_aggr = sc;
p->p_mtu = ifp0->if_mtu;
mtx_init(&p->p_mtx, IPL_SOFTNET);
+ refcnt_init(&p->p_refs);
+
+ p->p_ether_port.ep_input = aggr_port_input;
+ p->p_ether_port.ep_port_take = aggr_port_take;
+ p->p_ether_port.ep_port_rele = aggr_port_rele;
+ p->p_ether_port.ep_port = p;
CTASSERT(sizeof(p->p_lladdr) == sizeof(ac0->ac_enaddr));
memcpy(p->p_lladdr, ac0->ac_enaddr, sizeof(p->p_lladdr));
p->p_ioctl = ifp0->if_ioctl;
- p->p_input = ifp0->if_input;
p->p_output = ifp0->if_output;
error = aggr_group(sc, p, SIOCADDMULTI);
@@ -1256,16 +1284,16 @@ aggr_add_port(struct aggr_softc *sc, con
aggr_update_capabilities(sc);
/*
- * use (and modification) of ifp->if_input and ac->ac_trunkport
- * is protected by NET_LOCK.
+ * modification of ac->ac_trport is protected by NET_LOCK.
*/
- ac0->ac_trunkport = p;
+ KASSERT(SMR_PTR_GET_LOCKED(&ac0->ac_trport) == NULL);
+ aggr_port_take(p); /* for the SMR ptr */
+ SMR_PTR_SET_LOCKED(&ac0->ac_trport, &p->p_ether_port);
/* make sure p is visible before handlers can run */
membar_producer();
ifp0->if_ioctl = aggr_p_ioctl;
- ifp0->if_input = aggr_input;
ifp0->if_output = aggr_p_output;
aggr_mux(sc, p, LACP_MUX_E_BEGIN);
@@ -1399,10 +1427,20 @@ static int
aggr_p_ioctl(struct ifnet *ifp0, u_long cmd, caddr_t data)
{
struct arpcom *ac0 = (struct arpcom *)ifp0;
- struct aggr_port *p = ac0->ac_trunkport;
+ const struct ether_port *ep = SMR_PTR_GET_LOCKED(&ac0->ac_trport);
+ struct aggr_port *p;
struct ifreq *ifr = (struct ifreq *)data;
int error = 0;
+ KASSERTMSG(ep != NULL,
+ "%s: %s called without an ether_port set",
+ ifp0->if_xname, __func__);
+ KASSERTMSG(ep->ep_input == aggr_port_input,
+ "%s called %s, but ep_input (%p) seems wrong",
+ ifp0->if_xname, __func__, ep->ep_input);
+
+ p = ep->ep_port;
+
switch (cmd) {
case SIOCGTRUNKPORT: {
struct trunk_reqport *rp = (struct trunk_reqport *)data;
@@ -1449,8 +1487,10 @@ static int
aggr_p_output(struct ifnet *ifp0, struct mbuf *m, struct sockaddr *dst,
struct rtentry *rt)
{
+ int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
+ struct rtentry *) = NULL;
struct arpcom *ac0 = (struct arpcom *)ifp0;
- struct aggr_port *p = ac0->ac_trunkport;
+ const struct ether_port *ep;
/* restrict transmission to bpf only */
if (m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL) {
@@ -1458,7 +1498,20 @@ aggr_p_output(struct ifnet *ifp0, struct
return (EBUSY);
}
- return ((*p->p_output)(ifp0, m, dst, rt));
+ smr_read_enter();
+ ep = SMR_PTR_GET(&ac0->ac_trport);
+ if (ep != NULL && ep->ep_input == aggr_port_input) {
+ struct aggr_port *p = ep->ep_port;
+ p_output = p->p_output; /* code doesn't go away */
+ }
+ smr_read_leave();
+
+ if (p_output == NULL) {
+ m_freem(m);
+ return (ENXIO);
+ }
+
+ return ((*p_output)(ifp0, m, dst, rt));
}
static void
@@ -1469,6 +1522,7 @@ aggr_p_dtor(struct aggr_softc *sc, struc
struct arpcom *ac0 = (struct arpcom *)ifp0;
struct aggr_multiaddr *ma;
enum aggr_port_selected selected;
+ struct smr_entry smrdtor;
int error;
DPRINTF(sc, "%s %s %s: destroying port\n",
@@ -1486,14 +1540,19 @@ aggr_p_dtor(struct aggr_softc *sc, struc
timeout_del(&p->p_wait_while_timer);
/*
- * use (and modification) of ifp->if_input and ac->ac_trunkport
- * is protected by NET_LOCK.
+ * modification of ac->ac_trport is protected by NET_LOCK.
*/
- ac0->ac_trunkport = NULL;
- ifp0->if_input = p->p_input;
+ NET_ASSERT_LOCKED();
+ KASSERT(SMR_PTR_GET_LOCKED(&ac0->ac_trport) == &p->p_ether_port);
+ smr_init(&smrdtor);
+
ifp0->if_ioctl = p->p_ioctl;
ifp0->if_output = p->p_output;
+ SMR_PTR_SET_LOCKED(&ac0->ac_trport, NULL);
+ smr_call(&smrdtor, aggr_port_rele, p);
+
+ refcnt_finalize(&p->p_refs, "aggrdtor");
#if NKSTAT > 0
aggr_port_kstat_detach(p);
Index: net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
diff -u -p -r1.380 if_bridge.c
--- net/if_bridge.c 3 Nov 2025 23:50:57 -0000 1.380
+++ net/if_bridge.c 22 Nov 2025 09:28:42 -0000
@@ -149,7 +149,7 @@ struct niqueue bridgeintrq = NIQUEUE_INI
struct if_clone bridge_cloner =
IF_CLONE_INITIALIZER("bridge", bridge_clone_create, bridge_clone_destroy);
-const struct ether_brport bridge_brport = {
+const struct ether_port bridge_brport = {
bridge_input,
bridge_take,
bridge_rele,
Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
diff -u -p -r1.304 if_ethersubr.c
--- net/if_ethersubr.c 3 Nov 2025 23:50:57 -0000 1.304
+++ net/if_ethersubr.c 22 Nov 2025 09:28:42 -0000
@@ -375,20 +375,31 @@ ether_output(struct ifnet *ifp, struct m
return (if_enqueue(ifp, m));
}
+static struct mbuf *
+ether_port_input(struct ifnet *ifp, struct mbuf *m, uint64_t dst,
+ const struct ether_port **epp, struct netstack *ns)
+{
+ const struct ether_port *ep;
+
+ smr_read_enter();
+ ep = SMR_PTR_GET(epp);
+ if (ep != NULL)
+ ep->ep_port_take(ep->ep_port);
+ smr_read_leave();
+ if (ep != NULL) {
+ m = (*ep->ep_input)(ifp, m, dst, ep->ep_port, ns);
+ ep->ep_port_rele(ep->ep_port);
+ }
+
+ return (m);
+}
+
/*
* Process a received Ethernet packet.
*
* Ethernet input has several "phases" of filtering packets to
* support virtual/pseudo interfaces before actual layer 3 protocol
* handling.
- *
- * First phase:
- *
- * The first phase supports drivers that aggregate multiple Ethernet
- * ports into a single logical interface, ie, aggr(4) and trunk(4).
- * These drivers intercept packets by swapping out the if_input handler
- * on the "port" interfaces to steal the packets before they get here
- * to ether_input().
*/
void
ether_input(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
@@ -396,8 +407,7 @@ ether_input(struct ifnet *ifp, struct mb
struct ether_header *eh;
void (*input)(struct ifnet *, struct mbuf *, struct netstack *);
u_int16_t etype;
- struct arpcom *ac;
- const struct ether_brport *eb;
+ struct arpcom *ac = (struct arpcom *)ifp;
unsigned int sdelim = 0;
uint64_t dst, self;
@@ -405,6 +415,20 @@ ether_input(struct ifnet *ifp, struct mb
if (m->m_len < ETHER_HDR_LEN)
goto dropanyway;
+ eh = mtod(m, struct ether_header *);
+ dst = ether_addr_to_e64((struct ether_addr *)eh->ether_dhost);
+
+ /*
+ * First phase:
+ *
+ * The first phase supports drivers that aggregate multiple
+ * Ethernet ports into a single logical interface, ie, aggr(4)
+ * and trunk(4).
+ */
+ m = ether_port_input(ifp, m, dst, &ac->ac_trport, ns);
+ if (m == NULL)
+ return;
+
/*
* Second phase: service delimited packet filtering.
*
@@ -414,8 +438,6 @@ ether_input(struct ifnet *ifp, struct mb
* bridge can have a go at forwarding them.
*/
- eh = mtod(m, struct ether_header *);
- dst = ether_addr_to_e64((struct ether_addr *)eh->ether_dhost);
etype = ntohs(eh->ether_type);
if (ISSET(m->m_flags, M_VLANTAG) ||
@@ -438,21 +460,9 @@ ether_input(struct ifnet *ifp, struct mb
* may return it here to ether_input() to support local
* delivery to this port.
*/
-
- ac = (struct arpcom *)ifp;
-
- smr_read_enter();
- eb = SMR_PTR_GET(&ac->ac_brport);
- if (eb != NULL)
- eb->eb_port_take(eb->eb_port);
- smr_read_leave();
- if (eb != NULL) {
- m = (*eb->eb_input)(ifp, m, dst, eb->eb_port, ns);
- eb->eb_port_rele(eb->eb_port);
- if (m == NULL) {
- return;
- }
- }
+ m = ether_port_input(ifp, m, dst, &ac->ac_brport, ns);
+ if (m == NULL)
+ return;
/*
* Fourth phase: drop service delimited packets.
@@ -606,7 +616,7 @@ ether_brport_isset(struct ifnet *ifp)
}
void
-ether_brport_set(struct ifnet *ifp, const struct ether_brport *eb)
+ether_brport_set(struct ifnet *ifp, const struct ether_port *ep)
{
struct arpcom *ac = (struct arpcom *)ifp;
@@ -614,7 +624,7 @@ ether_brport_set(struct ifnet *ifp, cons
KASSERTMSG(SMR_PTR_GET_LOCKED(&ac->ac_brport) == NULL,
"%s setting an already set brport", ifp->if_xname);
- SMR_PTR_SET_LOCKED(&ac->ac_brport, eb);
+ SMR_PTR_SET_LOCKED(&ac->ac_brport, ep);
}
void
@@ -629,7 +639,7 @@ ether_brport_clr(struct ifnet *ifp)
SMR_PTR_SET_LOCKED(&ac->ac_brport, NULL);
}
-const struct ether_brport *
+const struct ether_port *
ether_brport_get(struct ifnet *ifp)
{
struct arpcom *ac = (struct arpcom *)ifp;
@@ -637,7 +647,7 @@ ether_brport_get(struct ifnet *ifp)
return (SMR_PTR_GET(&ac->ac_brport));
}
-const struct ether_brport *
+const struct ether_port *
ether_brport_get_locked(struct ifnet *ifp)
{
struct arpcom *ac = (struct arpcom *)ifp;
Index: net/if_tpmr.c
===================================================================
RCS file: /cvs/src/sys/net/if_tpmr.c,v
diff -u -p -r1.38 if_tpmr.c
--- net/if_tpmr.c 4 Nov 2025 12:12:00 -0000 1.38
+++ net/if_tpmr.c 22 Nov 2025 09:28:42 -0000
@@ -81,7 +81,7 @@ struct tpmr_port {
int p_refcnt;
- struct ether_brport p_brport;
+ struct ether_port p_brport;
};
struct tpmr_softc {
@@ -545,10 +545,10 @@ tpmr_add_port(struct tpmr_softc *sc, con
task_set(&p->p_dtask, tpmr_p_detach, p);
if_detachhook_add(ifp0, &p->p_dtask);
- p->p_brport.eb_input = tpmr_input;
- p->p_brport.eb_port_take = tpmr_p_take;
- p->p_brport.eb_port_rele = tpmr_p_rele;
- p->p_brport.eb_port = p;
+ p->p_brport.ep_input = tpmr_input;
+ p->p_brport.ep_port_take = tpmr_p_take;
+ p->p_brport.ep_port_rele = tpmr_p_rele;
+ p->p_brport.ep_port = p;
/* commit */
DPRINTF(sc, "%s %s trunkport: creating port\n",
@@ -661,18 +661,18 @@ done:
static int
tpmr_p_ioctl(struct ifnet *ifp0, u_long cmd, caddr_t data)
{
- const struct ether_brport *eb = ether_brport_get_locked(ifp0);
+ const struct ether_port *ep = ether_brport_get_locked(ifp0);
struct tpmr_port *p;
int error = 0;
- KASSERTMSG(eb != NULL,
+ KASSERTMSG(ep != NULL,
"%s: %s called without an ether_brport set",
ifp0->if_xname, __func__);
- KASSERTMSG(eb->eb_input == tpmr_input,
- "%s: %s called, but eb_input seems wrong (%p != tpmr_input())",
- ifp0->if_xname, __func__, eb->eb_input);
+ KASSERTMSG(ep->ep_input == tpmr_input,
+ "%s: %s called, but ep_input seems wrong (%p != tpmr_input())",
+ ifp0->if_xname, __func__, ep->ep_input);
- p = eb->eb_port;
+ p = ep->ep_port;
switch (cmd) {
case SIOCSIFADDR:
@@ -693,7 +693,7 @@ tpmr_p_output(struct ifnet *ifp0, struct
{
int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *) = NULL;
- const struct ether_brport *eb;
+ const struct ether_port *ep;
/* restrict transmission to bpf only */
if ((m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) {
@@ -702,9 +702,9 @@ tpmr_p_output(struct ifnet *ifp0, struct
}
smr_read_enter();
- eb = ether_brport_get(ifp0);
- if (eb != NULL && eb->eb_input == tpmr_input) {
- struct tpmr_port *p = eb->eb_port;
+ ep = ether_brport_get(ifp0);
+ if (ep != NULL && ep->ep_input == tpmr_input) {
+ struct tpmr_port *p = ep->ep_port;
p_output = p->p_output; /* code doesn't go away */
}
smr_read_leave();
Index: net/if_trunk.c
===================================================================
RCS file: /cvs/src/sys/net/if_trunk.c,v
diff -u -p -r1.157 if_trunk.c
--- net/if_trunk.c 7 Jul 2025 02:28:50 -0000 1.157
+++ net/if_trunk.c 22 Nov 2025 09:28:42 -0000
@@ -24,6 +24,7 @@
#include <sys/sockio.h>
#include <sys/systm.h>
#include <sys/task.h>
+#include <sys/smr.h>
#include <crypto/siphash.h>
@@ -72,7 +73,11 @@ int trunk_ether_delmulti(struct trunk_s
void trunk_ether_purgemulti(struct trunk_softc *);
int trunk_ether_cmdmulti(struct trunk_port *, u_long);
int trunk_ioctl_allports(struct trunk_softc *, u_long, caddr_t);
-void trunk_input(struct ifnet *, struct mbuf *, struct netstack *);
+void trunk_port_take(void *);
+void trunk_port_rele(void *);
+struct mbuf *
+ trunk_input(struct ifnet *, struct mbuf *, uint64_t, void *,
+ struct netstack *);
void trunk_start(struct ifnet *);
void trunk_init(struct ifnet *);
void trunk_stop(struct ifnet *);
@@ -296,7 +301,7 @@ trunk_port_create(struct trunk_softc *tr
return (EPROTONOSUPPORT);
ac0 = (struct arpcom *)ifp;
- if (ac0->ac_trunkport != NULL)
+ if (SMR_PTR_GET_LOCKED(&ac0->ac_trport) != NULL)
return (EBUSY);
/* Take MTU from the first member port */
@@ -318,6 +323,12 @@ trunk_port_create(struct trunk_softc *tr
if ((tp = malloc(sizeof *tp, M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
return (ENOMEM);
+ refcnt_init(&tp->tp_refs);
+ tp->tp_ether_port.ep_input = trunk_input;
+ tp->tp_ether_port.ep_port_take = trunk_port_take;
+ tp->tp_ether_port.ep_port_rele = trunk_port_rele;
+ tp->tp_ether_port.ep_port = tp;
+
/* Check if port is a stacked trunk */
SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) {
if (ifp == &tr_ptr->tr_ac.ac_if) {
@@ -377,11 +388,9 @@ trunk_port_create(struct trunk_softc *tr
if (tr->tr_port_create != NULL)
error = (*tr->tr_port_create)(tp);
- /* Change input handler of the physical interface. */
- tp->tp_input = ifp->if_input;
+ /* Assing input handler of the physical interface. */
NET_ASSERT_LOCKED();
- ac0->ac_trunkport = tp;
- ifp->if_input = trunk_input;
+ SMR_PTR_SET_LOCKED(&ac0->ac_trport, &tp->tp_ether_port);
return (error);
}
@@ -413,8 +422,10 @@ trunk_port_destroy(struct trunk_port *tp
/* Restore previous input handler. */
NET_ASSERT_LOCKED();
- ifp->if_input = tp->tp_input;
- ac0->ac_trunkport = NULL;
+ KASSERT(SMR_PTR_GET_LOCKED(&ac0->ac_trport) == &tp->tp_ether_port);
+ SMR_PTR_SET_LOCKED(&ac0->ac_trport, NULL);
+ smr_barrier();
+ refcnt_finalize(&tp->tp_refs, "trdtor");
/* Remove multicast addresses from this port */
trunk_ether_cmdmulti(tp, SIOCDELMULTI);
@@ -664,9 +675,12 @@ trunk_ioctl(struct ifnet *ifp, u_long cm
*/
NET_ASSERT_LOCKED();
SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
- /* if_ih_remove(tp->tp_if, trunk_input, tp); */
- tp->tp_if->if_input = tp->tp_input;
+ struct arpcom *ac = (struct arpcom *)tp->tp_if;
+ SMR_PTR_SET_LOCKED(&ac->ac_trport, NULL);
}
+ SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
+ refcnt_finalize(&tp->tp_refs, "trunkset");
+ smr_barrier();
if (tr->tr_proto != TRUNK_PROTO_NONE)
error = tr->tr_detach(tr);
if (error != 0)
@@ -681,9 +695,11 @@ trunk_ioctl(struct ifnet *ifp, u_long cm
if (tr->tr_proto != TRUNK_PROTO_NONE)
error = trunk_protos[i].ti_attach(tr);
SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
- /* if_ih_insert(tp->tp_if,
- trunk_input, tp); */
- tp->tp_if->if_input = trunk_input;
+ struct arpcom *ac =
+ (struct arpcom *)tp->tp_if;
+ refcnt_init(&tp->tp_refs);
+ SMR_PTR_SET_LOCKED(&ac->ac_trport,
+ &tp->tp_ether_port);
}
/* Update trunk capabilities */
tr->tr_capabilities = trunk_capabilities(tr);
@@ -1144,10 +1160,24 @@ trunk_stop(struct ifnet *ifp)
}
void
-trunk_input(struct ifnet *ifp, struct mbuf *m, struct netstack *ns)
+trunk_port_take(void *port)
{
- struct arpcom *ac0 = (struct arpcom *)ifp;
- struct trunk_port *tp;
+ struct trunk_port *tp = port;
+ refcnt_take(&tp->tp_refs);
+}
+
+void
+trunk_port_rele(void *port)
+{
+ struct trunk_port *tp = port;
+ refcnt_rele_wake(&tp->tp_refs);
+}
+
+struct mbuf *
+trunk_input(struct ifnet *ifp, struct mbuf *m, uint64_t dst, void *port,
+ struct netstack *ns)
+{
+ struct trunk_port *tp = port;
struct trunk_softc *tr;
struct ifnet *trifp = NULL;
struct ether_header *eh;
@@ -1163,7 +1193,6 @@ trunk_input(struct ifnet *ifp, struct mb
if (ifp->if_type != IFT_IEEE8023ADLAG)
goto bad;
- tp = (struct trunk_port *)ac0->ac_trunkport;
if ((tr = (struct trunk_softc *)tp->tp_trunk) == NULL)
goto bad;
@@ -1176,7 +1205,7 @@ trunk_input(struct ifnet *ifp, struct mb
* We stop here if the packet has been consumed
* by the protocol routine.
*/
- return;
+ return (NULL);
}
if ((trifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
@@ -1190,20 +1219,19 @@ trunk_input(struct ifnet *ifp, struct mb
(ifp->if_flags & IFF_PROMISC) &&
(trifp->if_flags & IFF_PROMISC) == 0) {
if (bcmp(&tr->tr_ac.ac_enaddr, eh->ether_dhost,
- ETHER_ADDR_LEN)) {
- m_freem(m);
- return;
- }
+ ETHER_ADDR_LEN))
+ goto drop;
}
-
if_vinput(trifp, m, ns);
- return;
+ return (NULL);
bad:
if (trifp != NULL)
trifp->if_ierrors++;
+drop:
m_freem(m);
+ return (NULL);
}
int
Index: net/if_trunk.h
===================================================================
RCS file: /cvs/src/sys/net/if_trunk.h,v
diff -u -p -r1.32 if_trunk.h
--- net/if_trunk.h 2 Mar 2025 21:28:32 -0000 1.32
+++ net/if_trunk.h 22 Nov 2025 09:28:42 -0000
@@ -159,6 +159,8 @@ struct trunk_softc;
struct trunk_port {
struct ifnet *tp_if; /* physical interface */
struct trunk_softc *tp_trunk; /* parent trunk */
+ struct refcnt tp_refs;
+ struct ether_port tp_ether_port;
u_int8_t tp_lladdr[ETHER_ADDR_LEN];
caddr_t tp_psc; /* protocol data */
@@ -172,7 +174,6 @@ struct trunk_port {
int (*tp_ioctl)(struct ifnet *, u_long, caddr_t);
int (*tp_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
- void (*tp_input)(struct ifnet *, struct mbuf *, struct netstack *);
SLIST_ENTRY(trunk_port) tp_entries;
};
Index: net/if_veb.c
===================================================================
RCS file: /cvs/src/sys/net/if_veb.c,v
diff -u -p -r1.54 if_veb.c
--- net/if_veb.c 22 Nov 2025 06:07:36 -0000 1.54
+++ net/if_veb.c 22 Nov 2025 09:28:42 -0000
@@ -117,7 +117,7 @@ struct veb_port {
struct veb_softc *p_veb;
- struct ether_brport p_brport;
+ struct ether_port p_brport;
unsigned int p_link_state;
unsigned int p_bif_flags;
@@ -289,8 +289,8 @@ static void veb_eb_port_rele(void *, vo
static size_t veb_eb_port_ifname(void *, char *, size_t, void *);
static void veb_eb_port_sa(void *, struct sockaddr_storage *, void *);
-static void veb_eb_brport_take(void *);
-static void veb_eb_brport_rele(void *);
+static void veb_ep_brport_take(void *);
+static void veb_ep_brport_rele(void *);
static const struct etherbridge_ops veb_etherbridge_ops = {
veb_eb_port_cmp,
@@ -1660,6 +1660,10 @@ veb_add_port(struct veb_softc *sc, const
p->p_ioctl = ifp0->if_ioctl;
p->p_output = ifp0->if_output;
+ p->p_brport.ep_port = p;
+ p->p_brport.ep_port_take = veb_ep_brport_take;
+ p->p_brport.ep_port_rele = veb_ep_brport_rele;
+
if (span) {
ports_ptr = &sc->sc_spans;
@@ -1668,7 +1672,7 @@ veb_add_port(struct veb_softc *sc, const
goto free;
}
- p->p_brport.eb_input = veb_span_input;
+ p->p_brport.ep_input = veb_span_input;
p->p_bif_flags = IFBIF_SPAN;
} else {
ports_ptr = &sc->sc_ports;
@@ -1678,13 +1682,10 @@ veb_add_port(struct veb_softc *sc, const
goto free;
p->p_bif_flags = IFBIF_LEARNING | IFBIF_DISCOVER;
- p->p_brport.eb_input = isvport ?
+ p->p_brport.ep_input = isvport ?
veb_vport_input : veb_port_input;
}
- p->p_brport.eb_port_take = veb_eb_brport_take;
- p->p_brport.eb_port_rele = veb_eb_brport_rele;
-
om = SMR_PTR_GET_LOCKED(ports_ptr);
nm = veb_ports_insert(om, p);
@@ -1699,8 +1700,6 @@ veb_add_port(struct veb_softc *sc, const
task_set(&p->p_dtask, veb_p_detach, p);
if_detachhook_add(ifp0, &p->p_dtask);
- p->p_brport.eb_port = p;
-
/* commit */
SMR_PTR_SET_LOCKED(ports_ptr, nm);
@@ -2970,19 +2969,19 @@ veb_del_vid_addr(struct veb_softc *sc, c
static int
veb_p_ioctl(struct ifnet *ifp0, u_long cmd, caddr_t data)
{
- const struct ether_brport *eb = ether_brport_get_locked(ifp0);
+ const struct ether_port *ep = ether_brport_get_locked(ifp0);
struct veb_port *p;
int error = 0;
- KASSERTMSG(eb != NULL,
+ KASSERTMSG(ep != NULL,
"%s: %s called without an ether_brport set",
ifp0->if_xname, __func__);
- KASSERTMSG((eb->eb_input == veb_port_input) ||
- (eb->eb_input == veb_span_input),
- "%s called %s, but eb_input (%p) seems wrong",
- ifp0->if_xname, __func__, eb->eb_input);
+ KASSERTMSG((ep->ep_input == veb_port_input) ||
+ (ep->ep_input == veb_span_input),
+ "%s called %s, but ep_input (%p) seems wrong",
+ ifp0->if_xname, __func__, ep->ep_input);
- p = eb->eb_port;
+ p = ep->ep_port;
switch (cmd) {
case SIOCSIFADDR:
@@ -3003,7 +3002,7 @@ veb_p_output(struct ifnet *ifp0, struct
{
int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *) = NULL;
- const struct ether_brport *eb;
+ const struct ether_port *ep;
/* restrict transmission to bpf only */
if ((m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) {
@@ -3012,9 +3011,9 @@ veb_p_output(struct ifnet *ifp0, struct
}
smr_read_enter();
- eb = ether_brport_get(ifp0);
- if (eb != NULL && eb->eb_input == veb_port_input) {
- struct veb_port *p = eb->eb_port;
+ ep = ether_brport_get(ifp0);
+ if (ep != NULL && ep->ep_input == veb_port_input) {
+ struct veb_port *p = ep->ep_port;
p_output = p->p_output; /* code doesn't go away */
}
smr_read_leave();
@@ -3189,13 +3188,13 @@ veb_eb_port_rele(void *arg, void *port)
}
static void
-veb_eb_brport_take(void *port)
+veb_ep_brport_take(void *port)
{
veb_eb_port_take(NULL, port);
}
static void
-veb_eb_brport_rele(void *port)
+veb_ep_brport_rele(void *port)
{
veb_eb_port_rele(NULL, port);
}
@@ -3377,7 +3376,7 @@ static int
vport_enqueue(struct ifnet *ifp, struct mbuf *m)
{
struct arpcom *ac;
- const struct ether_brport *eb;
+ const struct ether_port *ep;
int error = ENETDOWN;
#if NBPFILTER > 0
caddr_t if_bpf;
@@ -3399,13 +3398,13 @@ vport_enqueue(struct ifnet *ifp, struct
ac = (struct arpcom *)ifp;
smr_read_enter();
- eb = SMR_PTR_GET(&ac->ac_brport);
- if (eb != NULL)
- eb->eb_port_take(eb->eb_port);
+ ep = SMR_PTR_GET(&ac->ac_brport);
+ if (ep != NULL)
+ ep->ep_port_take(ep->ep_port);
smr_read_leave();
- if (eb != NULL) {
+ if (ep != NULL) {
struct mbuf *(*input)(struct ifnet *, struct mbuf *,
- uint64_t, void *, struct netstack *) = eb->eb_input;
+ uint64_t, void *, struct netstack *) = ep->ep_input;
struct ether_header *eh;
uint64_t dst;
@@ -3423,11 +3422,11 @@ vport_enqueue(struct ifnet *ifp, struct
if (input == veb_vport_input)
input = veb_port_input;
- m = (*input)(ifp, m, dst, eb->eb_port, NULL);
+ m = (*input)(ifp, m, dst, ep->ep_port, NULL);
error = 0;
- eb->eb_port_rele(eb->eb_port);
+ ep->ep_port_rele(ep->ep_port);
}
m_freem(m);
Index: netinet/if_ether.h
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.h,v
diff -u -p -r1.97 if_ether.h
--- netinet/if_ether.h 3 Nov 2025 23:50:57 -0000 1.97
+++ netinet/if_ether.h 22 Nov 2025 09:28:42 -0000
@@ -131,6 +131,10 @@ struct ether_vlan_header {
#define ETH64_IS_8021_RSVD(_e64) \
(((_e64) & ETH64_8021_RSVD_MASK) == ETH64_8021_RSVD_PREFIX)
+#define ETH64_8021_NEAREST_CUSTOMER_BR 0x0180c2000000ULL
+#define ETH64_8021_NON_TPMR_BR 0x0180c2000003ULL
+#define ETH64_8021_NEAREST_BR 0x0180c200000eULL
+
/*
* Ethernet MTU constants.
*/
@@ -220,12 +224,12 @@ do { \
#include <net/if_var.h> /* for "struct ifnet" */
-struct ether_brport {
- struct mbuf *(*eb_input)(struct ifnet *, struct mbuf *,
+struct ether_port {
+ struct mbuf *(*ep_input)(struct ifnet *, struct mbuf *,
uint64_t, void *, struct netstack *);
- void (*eb_port_take)(void *);
- void (*eb_port_rele)(void *);
- void *eb_port;
+ void (*ep_port_take)(void *);
+ void (*ep_port_rele)(void *);
+ void *ep_port;
};
/*
@@ -241,8 +245,8 @@ struct arpcom {
int ac_multicnt; /* length of ac_multiaddrs */
int ac_multirangecnt; /* number of mcast ranges */
- void *ac_trunkport;
- const struct ether_brport *ac_brport;
+ const struct ether_port *ac_trport;
+ const struct ether_port *ac_brport;
};
extern int arpt_keep; /* arp resolved cache expire */
@@ -289,11 +293,11 @@ void ether_rtrequest(struct ifnet *, int
char *ether_sprintf(u_char *);
int ether_brport_isset(struct ifnet *);
-void ether_brport_set(struct ifnet *, const struct ether_brport *);
+void ether_brport_set(struct ifnet *, const struct ether_port *);
void ether_brport_clr(struct ifnet *);
-const struct ether_brport *
+const struct ether_port *
ether_brport_get(struct ifnet *);
-const struct ether_brport *
+const struct ether_port *
ether_brport_get_locked(struct ifnet *);
uint64_t ether_addr_to_e64(const struct ether_addr *);
move aggr/trunk input processing into ether_input