From: Chaz Kettleson Subject: Re: trunk(4): deprecate LACP mode To: David Gwynne Cc: tech@openbsd.org Date: Tue, 2 Dec 2025 19:46:08 -0500 On Tue, Dec 02, 2025 at 06:09:09AM -0500, Chaz Kettleson wrote: > On Tue, Dec 02, 2025 at 05:14:58PM +1000, David Gwynne wrote: > > aggr(4) is a better option for LACP for several reasons: > > > > - in my experience aggr is better at following the standard > > > > it doesn't get into weird states that blackhole traffic at the worst > > possible times. > > > > - aggr is mpsafe > > > > the last time i looked at trying to make the lacp code mpsafe in > > trunk(4) i ended up writing aggr(4). this lack of mpsafety is now > > making it hard to unlock more of the network stack. > > > > - aggr is faster than trunk > > > > looking at the benchmarking we did when i first introduced aggr, > > it looks like using trunk(4) more than halved the pps you can > > forward through a box, while aggr was more like a 10 to 15% hit. > > switching from trunk to aggr in our environment doubled our firewall > > performance. > > > > apart from these implementation differences, there's a few operational > > ones too that sthen@ has pointed out: > > > > - aggr uses a random MAC by default, trunk uses the MAC of the first- > > added child port. > > > > - aggr does not bring the interface up automatically, you must use "up". > > > > anyone still using trunk(4) for LACP links will need to do at least the > > following: > > > > # mv hostname.trunk0 hostname.aggr0 > > # echo up >> hostname.aggr0 > > > > if you want a predictable MAC address on an aggr interface, you'll need > > to specify the lladdr before bringing it up. for example, my configs > > looks like this: > > > > lladdr fe:e1:ba:d0:e8:43 > > trunkport ixl0 > > trunkport ixl1 > > up > > > > a bunch of vlan interfaces sit on top of this, which is why it doesnt > > have address config of its own. > > > > an example with ips: > > > > lladdr fe:e1:ba:d0:7c:ff > > trunkproto lacp > > trunkport ix0 > > trunkport ix1 > > inet 192.0.2.216 255.255.255.0 > > inet6 2001:db8:230f:bc24:d3d8:7b58:f17c:f96e 64 > > up > > > > Index: share/man/man4/trunk.4 > > =================================================================== > > RCS file: /cvs/src/share/man/man4/trunk.4,v > > diff -u -p -r1.31 trunk.4 > > --- share/man/man4/trunk.4 24 Aug 2020 07:34:00 -0000 1.31 > > +++ share/man/man4/trunk.4 2 Dec 2025 05:05:16 -0000 > > @@ -38,7 +38,6 @@ command. > > The driver currently supports the trunk protocols > > .Ic broadcast , > > .Ic failover , > > -.Ic lacp , > > .Ic loadbalance , > > .Ic none , > > and > > @@ -58,17 +57,6 @@ If the master port becomes unavailable, > > the next active port is used. > > The first interface added is the master port; > > any interfaces added after that are used as failover devices. > > -.It Ic lacp > > -Uses the IEEE 802.3ad (renamed to 802.1AX in 2014) > > -Link Aggregation Control Protocol (LACP) > > -and the Marker Protocol > > -to increase link speed and provide redundancy. > > -LACP trunk groups are composed of ports of the same speed, > > -set to full-duplex operation. > > -This protocol requires a switch which supports LACP. > > -By default, the LACP implementation uses active-mode LACP, > > -slow timeout, and 0x8000 (medium) priority as system and port > > -priorities. > > .It Ic loadbalance > > Distributes outgoing traffic through all active ports > > and accepts incoming traffic from any active port. > > @@ -90,6 +78,12 @@ The configuration can be done at runtime > > .Xr hostname.if 5 > > configuration file for > > .Xr netstart 8 . > > +.Pp > > +.Nm > > +does not implement > > +IEEE 802.1AX (formerly 802.3ad) Link Aggregation, > > +it is supported by > > +.Xr aggr 4 . > > .Sh EXAMPLES > > Create a simple round robin trunk with two > > .Xr bge 4 > > @@ -113,6 +107,7 @@ device will be used: > > 192.168.1.1 netmask 255.255.255.0 > > .Ed > > .Sh SEE ALSO > > +.Xr aggr 4 , > > .Xr inet 4 , > > .Xr hostname.if 5 , > > .Xr ifconfig 8 , > > @@ -122,6 +117,10 @@ The > > .Nm > > device first appeared in > > .Ox 3.8 . > > +Support for 802.3ad Link Aggregation was added in > > +.Ox 4.4 > > +and removed in > > +.Ox 7.9 . > > .Sh AUTHORS > > The > > .Nm > > Index: sys/conf/files > > =================================================================== > > RCS file: /cvs/src/sys/conf/files,v > > diff -u -p -r1.748 files > > --- sys/conf/files 14 Nov 2025 01:55:07 -0000 1.748 > > +++ sys/conf/files 2 Dec 2025 05:05:16 -0000 > > @@ -868,7 +872,6 @@ file net/slcompress.c ppp > > file net/if_enc.c enc > > file net/if_gre.c gre needs-count > > file net/if_trunk.c trunk > > -file net/trunklacp.c trunk > > file net/if_aggr.c aggr > > file net/if_tpmr.c tpmr > > file net/if_mpe.c mpe > > Index: sys/net/if_trunk.c > > =================================================================== > > RCS file: /cvs/src/sys/net/if_trunk.c,v > > diff -u -p -r1.159 if_trunk.c > > --- sys/net/if_trunk.c 2 Dec 2025 03:24:19 -0000 1.159 > > +++ sys/net/if_trunk.c 2 Dec 2025 05:05:16 -0000 > > @@ -42,7 +42,6 @@ > > #endif > > > > #include > > -#include > > > > #include "bpfilter.h" > > #if NBPFILTER > 0 > > @@ -125,13 +124,6 @@ int trunk_bcast_start(struct trunk_soft > > int trunk_bcast_input(struct trunk_softc *, struct trunk_port *, > > struct mbuf *); > > > > -/* 802.3ad LACP */ > > -int trunk_lacp_attach(struct trunk_softc *); > > -int trunk_lacp_detach(struct trunk_softc *); > > -int trunk_lacp_start(struct trunk_softc *, struct mbuf *); > > -int trunk_lacp_input(struct trunk_softc *, struct trunk_port *, > > - struct mbuf *); > > - > > /* Trunk protocol table */ > > static const struct { > > enum trunk_proto ti_proto; > > @@ -141,7 +133,6 @@ static const struct { > > { TRUNK_PROTO_FAILOVER, trunk_fail_attach }, > > { TRUNK_PROTO_LOADBALANCE, trunk_lb_attach }, > > { TRUNK_PROTO_BROADCAST, trunk_bcast_attach }, > > - { TRUNK_PROTO_LACP, trunk_lacp_attach }, > > { TRUNK_PROTO_NONE, NULL } > > }; > > > > @@ -606,11 +597,6 @@ trunk_port2req(struct trunk_port *tp, st > > if (TRUNK_PORTACTIVE(tp)) > > rp->rp_flags |= TRUNK_PORT_ACTIVE; > > break; > > - > > - case TRUNK_PROTO_LACP: > > - /* LACP has a different definition of active */ > > - rp->rp_flags = lacp_port_status(tp); > > - break; > > default: > > break; > > } > > @@ -622,11 +608,8 @@ trunk_ioctl(struct ifnet *ifp, u_long cm > > struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc; > > struct trunk_reqall *ra = (struct trunk_reqall *)data; > > struct trunk_reqport *rp = (struct trunk_reqport *)data, rpbuf; > > - struct trunk_opts *tro = (struct trunk_opts *)data; > > struct ifreq *ifr = (struct ifreq *)data; > > - struct lacp_softc *lsc; > > struct trunk_port *tp; > > - struct lacp_port *lp; > > struct ifnet *tpif; > > int i, error = 0; > > > > @@ -710,16 +693,7 @@ trunk_ioctl(struct ifnet *ifp, u_long cm > > break; > > case SIOCGTRUNKOPTS: > > /* Only LACP trunks have options atm */ > > - if (tro->to_proto != TRUNK_PROTO_LACP) { > > - error = EPROTONOSUPPORT; > > - break; > > - } > > - lsc = LACP_SOFTC(tr); > > - tro->to_lacpopts.lacp_mode = lsc->lsc_mode; > > - tro->to_lacpopts.lacp_timeout = lsc->lsc_timeout; > > - tro->to_lacpopts.lacp_prio = lsc->lsc_sys_prio; > > - tro->to_lacpopts.lacp_portprio = lsc->lsc_port_prio; > > - tro->to_lacpopts.lacp_ifqprio = lsc->lsc_ifq_prio; > > + error = EPROTONOSUPPORT; > > break; > > case SIOCSTRUNKOPTS: > > if ((error = suser(curproc)) != 0) { > > @@ -727,74 +701,7 @@ trunk_ioctl(struct ifnet *ifp, u_long cm > > break; > > } > > /* Only LACP trunks have options atm */ > > - if (tro->to_proto != TRUNK_PROTO_LACP) { > > - error = EPROTONOSUPPORT; > > - break; > > - } > > - lsc = LACP_SOFTC(tr); > > - switch(tro->to_opts) { > > - case TRUNK_OPT_LACP_MODE: > > - /* > > - * Ensure mode changes occur immediately > > - * on all ports > > - */ > > - lsc->lsc_mode = tro->to_lacpopts.lacp_mode; > > - if (lsc->lsc_mode == 0) { > > - LIST_FOREACH(lp, &lsc->lsc_ports, > > - lp_next) > > - lp->lp_state &= > > - ~LACP_STATE_ACTIVITY; > > - } else { > > - LIST_FOREACH(lp, &lsc->lsc_ports, > > - lp_next) > > - lp->lp_state |= > > - LACP_STATE_ACTIVITY; > > - } > > - break; > > - case TRUNK_OPT_LACP_TIMEOUT: > > - /* > > - * Ensure timeout changes occur immediately > > - * on all ports > > - */ > > - lsc->lsc_timeout = > > - tro->to_lacpopts.lacp_timeout; > > - if (lsc->lsc_timeout == 0) { > > - LIST_FOREACH(lp, &lsc->lsc_ports, > > - lp_next) > > - lp->lp_state &= > > - ~LACP_STATE_TIMEOUT; > > - } else { > > - LIST_FOREACH(lp, &lsc->lsc_ports, > > - lp_next) > > - lp->lp_state |= > > - LACP_STATE_TIMEOUT; > > - } > > - break; > > - case TRUNK_OPT_LACP_SYS_PRIO: > > - if (tro->to_lacpopts.lacp_prio == 0) { > > - error = EINVAL; > > - break; > > - } > > - lsc->lsc_sys_prio = tro->to_lacpopts.lacp_prio; > > - break; > > - case TRUNK_OPT_LACP_PORT_PRIO: > > - if (tro->to_lacpopts.lacp_portprio == 0) { > > - error = EINVAL; > > - break; > > - } > > - lsc->lsc_port_prio = > > - tro->to_lacpopts.lacp_portprio; > > - break; > > - case TRUNK_OPT_LACP_IFQ_PRIO: > > - if (tro->to_lacpopts.lacp_ifqprio > > > - IFQ_MAXPRIO) { > > - error = EINVAL; > > - break; > > - } > > - lsc->lsc_ifq_prio = > > - tro->to_lacpopts.lacp_ifqprio; > > - break; > > - } > > + error = EPROTONOSUPPORT; > > break; > > case SIOCGTRUNKPORT: > > if (rp->rp_portname[0] == '\0' || > > @@ -1681,70 +1588,4 @@ int > > trunk_bcast_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) > > { > > return (0); > > -} > > - > > -/* > > - * 802.3ad LACP > > - */ > > - > > -int > > -trunk_lacp_attach(struct trunk_softc *tr) > > -{ > > - struct trunk_port *tp; > > - int error; > > - > > - tr->tr_detach = trunk_lacp_detach; > > - tr->tr_port_create = lacp_port_create; > > - tr->tr_port_destroy = lacp_port_destroy; > > - tr->tr_linkstate = lacp_linkstate; > > - tr->tr_start = trunk_lacp_start; > > - tr->tr_input = trunk_lacp_input; > > - tr->tr_init = lacp_init; > > - tr->tr_stop = lacp_stop; > > - tr->tr_req = lacp_req; > > - tr->tr_portreq = lacp_portreq; > > - > > - error = lacp_attach(tr); > > - if (error) > > - return (error); > > - > > - SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) > > - lacp_port_create(tp); > > - > > - return (error); > > -} > > - > > -int > > -trunk_lacp_detach(struct trunk_softc *tr) > > -{ > > - struct trunk_port *tp; > > - int error; > > - > > - SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) > > - lacp_port_destroy(tp); > > - > > - /* unlocking is safe here */ > > - error = lacp_detach(tr); > > - > > - return (error); > > -} > > - > > -int > > -trunk_lacp_start(struct trunk_softc *tr, struct mbuf *m) > > -{ > > - struct trunk_port *tp; > > - > > - tp = lacp_select_tx_port(tr, m); > > - if (tp == NULL) { > > - m_freem(m); > > - return (EBUSY); > > - } > > - > > - return (if_enqueue(tp->tp_if, m)); > > -} > > - > > -int > > -trunk_lacp_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m) > > -{ > > - return (lacp_input(tp, m)); > > } > > > > Hello, > > Do you know of any cases where aggr is _not_ a complete replacement for > trunk? A few years ago I setup a Dell PowerConnect 5224 in LACP and was > unable to get aggr to work, however, the following does work for me: > > cat /etc/hostname.trunk0 > trunkproto lacp > trunkport bnx0 > trunkport bnx1 > trunkport bge0 > up > > I can give it a shot again tonight to see if I missed something when I > initially tried aggr. > > -- > Chaz > Hello, Good news, everything appears to work. 1. mv /etc/hostname.trunk0 /etc/hostname.aggr0 2. removed trunkproto lacp (no longer needed) 3. updated all hostname.vlan* with parent aggr0 Not sure if something changed since 6.9/7.0 to now, or if I messed something up when I originally tried -- but everything is working as expected now! Thanks for the motivation to change this. -- Chaz