From: Chaz Kettleson Subject: Re: trunk(4): deprecate LACP mode To: David Gwynne Cc: tech@openbsd.org Date: Tue, 2 Dec 2025 06:09:09 -0500 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