Index | Thread | Search

From:
Chaz Kettleson <chaz@pyr3x.com>
Subject:
Re: trunk(4): deprecate LACP mode
To:
David Gwynne <david@gwynne.id.au>
Cc:
tech@openbsd.org
Date:
Tue, 2 Dec 2025 19:46:08 -0500

Download raw body.

Thread
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 <net/if_trunk.h>
> > -#include <net/trunklacp.h>
> >  
> >  #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