On Mon, Aug 06, 2018 at 08:18:23PM -0700, Carlos Cardenas wrote: > Howdy. > > Attached is a patch from my work that started at g2k18 on adding > administrative knobs to our LACP driver. > > The driver now has a new ioctl (SIOCxTRUNKOPTS), which for now only > has options for LACP: > * Mode - Active or Passive (default Active) > * Timeout - Fast or Slow (default Slow) > * System Priority - 1(high) to 65535(low) (default 32768) > * Port Priority - 1(high) to 65535(low) (default 32768) > * IFQ Priority - 0 to NUM_QUEUES (default 6) > > At the moment, ifconfig only has options for lacpmode and lacptimeout > plumbed as those are the immediate need. > > The approach taken for the options was to make them on a "trunk" vs a > "port" as what's typically seen on various NOSes (JunOS, NXOS, etc...) > as it's uncommon for a host to have one link "Passive" and the other > "Active" in a given trunk. > > Just like on a NOS, when applying lacpmode or lacptimeout, the settings > are immediately applied to all existing ports in the trunk and to all > future ports brought into the trunk. > > When using lacpmode/lacptimeout, they can be used on the same line > creating the trunk. > > Here's an example hostname.trunk0: > trunkproto lacp lacptimeout fast > trunkport em0 > trunkport em1 > dhcp > inet6 autoconf > > Testing done: > Arch - amd64 > - Kernel: bsd.rd and GENERIC.MP > - NIC Driver: em and oce > - NOS: JunOS 18.1 > - MLAG-SETUP: No > > I would like to solicit testers with additional NIC drivers, NOSes, and > MLAG setups to ensure there's no regressions. > > Comments? Ok?
I've updated the ifconfig piece to be a bit cleaner (prompted by deraadt). +--+ Carlos
Index: sbin/ifconfig/ifconfig.8 =================================================================== RCS file: /home/los/cvs/src/sbin/ifconfig/ifconfig.8,v retrieving revision 1.312 diff -u -p -r1.312 ifconfig.8 --- sbin/ifconfig/ifconfig.8 19 Jul 2018 19:16:36 -0000 1.312 +++ sbin/ifconfig/ifconfig.8 8 Aug 2018 17:42:56 -0000 @@ -1627,6 +1627,16 @@ Set the trunk protocol. Refer to .Xr trunk 4 for a complete list of the available protocols. +.It Cm lacpmode Ar mode +Set the LACP trunk mode to either +.Ar active +or +.Ar passive . +.It Cm lacptimeout Ar speed +Set the LACP timeout speed to either +.Ar fast +or +.Ar slow . .El .Sh TUNNEL .nr nS 1 Index: sbin/ifconfig/ifconfig.c =================================================================== RCS file: /home/los/cvs/src/sbin/ifconfig/ifconfig.c,v retrieving revision 1.369 diff -u -p -r1.369 ifconfig.c --- sbin/ifconfig/ifconfig.c 13 Jul 2018 08:41:32 -0000 1.369 +++ sbin/ifconfig/ifconfig.c 8 Aug 2018 17:42:56 -0000 @@ -170,7 +170,12 @@ int shownet80211chans; int shownet80211nodes; int showclasses; -struct ifencap; +struct ifencap; + +const char *lacpmodeactive = "active"; +const char *lacpmodepassive = "passive"; +const char *lacptimeoutfast = "fast"; +const char *lacptimeoutslow = "slow"; void notealias(const char *, int); void setifaddr(const char *, int); @@ -252,6 +257,8 @@ void setautoconf(const char *, int); void settrunkport(const char *, int); void unsettrunkport(const char *, int); void settrunkproto(const char *, int); +void settrunklacpmode(const char *, int); +void settrunklacptimeout(const char *, int); void trunk_status(void); void list_cloners(void); @@ -408,6 +415,8 @@ const struct cmd { { "trunkport", NEXTARG, 0, settrunkport }, { "-trunkport", NEXTARG, 0, unsettrunkport }, { "trunkproto", NEXTARG, 0, settrunkproto }, + { "lacpmode", NEXTARG, 0, settrunklacpmode }, + { "lacptimeout", NEXTARG, 0, settrunklacptimeout }, { "anycast", IN6_IFF_ANYCAST, 0, setia6flags }, { "-anycast", -IN6_IFF_ANYCAST, 0, setia6flags }, { "tentative", IN6_IFF_TENTATIVE, 0, setia6flags }, @@ -3990,6 +3999,72 @@ settrunkproto(const char *val, int d) strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname)); if (ioctl(s, SIOCSTRUNK, &ra) != 0) err(1, "SIOCSTRUNK"); +} + +void +settrunklacpmode(const char *val, int d) +{ + struct trunk_reqall ra; + struct trunk_opts tops; + + bzero(&ra, sizeof(ra)); + strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname)); + + if (ioctl(s, SIOCGTRUNK, &ra) != 0) + err(1, "SIOCGTRUNK"); + + if (ra.ra_proto != TRUNK_PROTO_LACP) + errx(1, "Invalid option for trunk: %s", name); + + if (strcmp(val, lacpmodeactive) != 0 && + strcmp(val, lacpmodepassive) != 0) + errx(1, "Invalid lacpmode option for trunk: %s", name); + + bzero(&tops, sizeof(tops)); + strlcpy(tops.to_ifname, name, sizeof(tops.to_ifname)); + tops.to_proto = TRUNK_PROTO_LACP; + tops.to_opts |= TRUNK_OPT_LACP_MODE; + + if (strcmp(val, lacpmodeactive) == 0) + tops.to_lacpopts.lacp_mode = 1; + else + tops.to_lacpopts.lacp_mode = 0; + + if (ioctl(s, SIOCSTRUNKOPTS, &tops) != 0) + err(1, "SIOCSTRUNKOPTS"); +} + +void +settrunklacptimeout(const char *val, int d) +{ + struct trunk_reqall ra; + struct trunk_opts tops; + + bzero(&ra, sizeof(ra)); + strlcpy(ra.ra_ifname, name, sizeof(ra.ra_ifname)); + + if (ioctl(s, SIOCGTRUNK, &ra) != 0) + err(1, "SIOCGTRUNK"); + + if (ra.ra_proto != TRUNK_PROTO_LACP) + errx(1, "Invalid option for trunk: %s", name); + + if (strcmp(val, lacptimeoutfast) != 0 && + strcmp(val, lacptimeoutslow) != 0) + errx(1, "Invalid lacptimeout option for trunk: %s", name); + + bzero(&tops, sizeof(tops)); + strlcpy(tops.to_ifname, name, sizeof(tops.to_ifname)); + tops.to_proto = TRUNK_PROTO_LACP; + tops.to_opts |= TRUNK_OPT_LACP_TIMEOUT; + + if (strcmp(val, lacptimeoutfast) == 0) + tops.to_lacpopts.lacp_timeout = 1; + else + tops.to_lacpopts.lacp_timeout = 0; + + if (ioctl(s, SIOCSTRUNKOPTS, &tops) != 0) + err(1, "SIOCSTRUNKOPTS"); } void Index: sys/net/if_trunk.c =================================================================== RCS file: /home/los/cvs/src/sys/net/if_trunk.c,v retrieving revision 1.136 diff -u -p -r1.136 if_trunk.c --- sys/net/if_trunk.c 19 Feb 2018 08:59:52 -0000 1.136 +++ sys/net/if_trunk.c 8 Aug 2018 17:42:56 -0000 @@ -604,8 +604,11 @@ 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; @@ -670,6 +673,94 @@ trunk_ioctl(struct ifnet *ifp, u_long cm } } error = EPROTONOSUPPORT; + 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; + break; + case SIOCSTRUNKOPTS: + if ((error = suser(curproc)) != 0) { + error = EPERM; + 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; + } break; case SIOCGTRUNKPORT: if (rp->rp_portname[0] == '\0' || Index: sys/net/if_trunk.h =================================================================== RCS file: /home/los/cvs/src/sys/net/if_trunk.h,v retrieving revision 1.25 diff -u -p -r1.25 if_trunk.h --- sys/net/if_trunk.h 23 Sep 2015 12:40:12 -0000 1.25 +++ sys/net/if_trunk.h 8 Aug 2018 17:42:56 -0000 @@ -121,6 +121,36 @@ struct trunk_reqall { #define SIOCGTRUNK _IOWR('i', 143, struct trunk_reqall) #define SIOCSTRUNK _IOW('i', 144, struct trunk_reqall) +/* LACP administrative options */ +struct lacp_adminopts { + u_int8_t lacp_mode; /* active or passive */ + u_int8_t lacp_timeout; /* fast or slow */ + u_int16_t lacp_prio; /* system priority */ + u_int16_t lacp_portprio; /* port priority */ + u_int8_t lacp_ifqprio; /* ifq priority */ +}; + +/* Trunk administrative options */ +struct trunk_opts { + char to_ifname[IFNAMSIZ]; /* name of the trunk */ + u_int to_proto; /* trunk protocol */ + int to_opts; /* option bitmap */ +#define TRUNK_OPT_NONE 0x00 +#define TRUNK_OPT_LACP_MODE 0x01 /* set active bit */ +#define TRUNK_OPT_LACP_TIMEOUT 0x02 /* set timeout bit */ +#define TRUNK_OPT_LACP_SYS_PRIO 0x04 /* set sys_prio bit */ +#define TRUNK_OPT_LACP_PORT_PRIO 0x08 /* set port_prio bit */ +#define TRUNK_OPT_LACP_IFQ_PRIO 0x10 /* set ifq_prio bit */ + + union { + struct lacp_adminopts rpsc_lacp; + } to_psc; +#define to_lacpopts to_psc.rpsc_lacp +}; + +#define SIOCGTRUNKOPTS _IOWR('i', 145, struct trunk_opts) +#define SIOCSTRUNKOPTS _IOW('i', 146, struct trunk_opts) + #ifdef _KERNEL /* * Internal kernel part Index: sys/net/trunklacp.c =================================================================== RCS file: /home/los/cvs/src/sys/net/trunklacp.c,v retrieving revision 1.29 diff -u -p -r1.29 trunklacp.c --- sys/net/trunklacp.c 24 Jan 2017 10:08:30 -0000 1.29 +++ sys/net/trunklacp.c 8 Aug 2018 17:42:56 -0000 @@ -58,14 +58,6 @@ #include <net/bpf.h> #endif -/* - * actor system priority and port priority. - * XXX should be configurable. - */ -#define LACP_SYSTEM_PRIO 0x8000 -#define LACP_PORT_PRIO 0x8000 -#define LACP_IFQ_PRIO 6 - const u_int8_t ethermulticastaddr_slowprotocols[ETHER_ADDR_LEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 }; @@ -93,6 +85,8 @@ const struct tlv_template marker_respons typedef void (*lacp_timer_func_t)(struct lacp_port *); +void lacp_default_partner(struct lacp_softc *, + struct lacp_peerinfo *); void lacp_fill_actorinfo(struct lacp_port *, struct lacp_peerinfo *); void lacp_fill_markerinfo(struct lacp_port *, struct lacp_markerinfo *); @@ -197,31 +191,22 @@ void lacp_dprintf(const struct lacp_por #define LACP_DPRINTF(a) /* nothing */ #endif -/* - * partner administration variables. - * XXX should be configurable. - */ - -const struct lacp_peerinfo lacp_partner_admin = { - { 0xffff }, /* lip_systemid.lsi_prio */ - 0, /* lip_key */ - { 0xffff }, /* lip_portid.lpi_prio */ -#if 1 - /* optimistic lip_state */ - LACP_STATE_SYNC | LACP_STATE_AGGREGATION | - LACP_STATE_COLLECTING | LACP_STATE_DISTRIBUTING -#else - /* pessimistic lip_state */ - 0 -#endif -}; - const lacp_timer_func_t lacp_timer_funcs[LACP_NTIMER] = { [LACP_TIMER_CURRENT_WHILE] = lacp_sm_rx_timer, [LACP_TIMER_PERIODIC] = lacp_sm_ptx_timer, [LACP_TIMER_WAIT_WHILE] = lacp_sm_mux_timer, }; +void +lacp_default_partner(struct lacp_softc *lsc, struct lacp_peerinfo *peer) +{ + peer->lip_systemid.lsi_prio = lsc->lsc_sys_prio; + peer->lip_key = 0; + peer->lip_portid.lpi_prio = lsc->lsc_port_prio; + peer->lip_state = LACP_STATE_SYNC | LACP_STATE_AGGREGATION | + LACP_STATE_COLLECTING | LACP_STATE_DISTRIBUTING; +} + int lacp_input(struct trunk_port *tp, struct mbuf *m) { @@ -351,13 +336,14 @@ bad: void lacp_fill_actorinfo(struct lacp_port *lp, struct lacp_peerinfo *info) { + struct lacp_softc *lsc = lp->lp_lsc; struct trunk_port *tp = lp->lp_trunk; struct trunk_softc *sc = tp->tp_trunk; - info->lip_systemid.lsi_prio = htons(LACP_SYSTEM_PRIO); + info->lip_systemid.lsi_prio = htons(lsc->lsc_sys_prio); memcpy(&info->lip_systemid.lsi_mac, sc->tr_ac.ac_enaddr, ETHER_ADDR_LEN); - info->lip_portid.lpi_prio = htons(LACP_PORT_PRIO); + info->lip_portid.lpi_prio = htons(lsc->lsc_port_prio); info->lip_portid.lpi_portno = htons(lp->lp_ifp->if_index); info->lip_state = lp->lp_state; } @@ -376,6 +362,7 @@ lacp_fill_markerinfo(struct lacp_port *l int lacp_xmit_lacpdu(struct lacp_port *lp) { + struct lacp_softc *lsc = lp->lp_lsc; struct trunk_port *tp = lp->lp_trunk; struct mbuf *m; struct lacpdu *du; @@ -385,7 +372,7 @@ lacp_xmit_lacpdu(struct lacp_port *lp) if (m == NULL) return (ENOMEM); m->m_len = m->m_pkthdr.len = sizeof(*du); - m->m_pkthdr.pf.prio = LACP_IFQ_PRIO; + m->m_pkthdr.pf.prio = lsc->lsc_ifq_prio; du = mtod(m, struct lacpdu *); memset(du, 0, sizeof(*du)); @@ -427,6 +414,7 @@ lacp_xmit_lacpdu(struct lacp_port *lp) int lacp_xmit_marker(struct lacp_port *lp) { + struct lacp_softc *lsc = lp->lp_lsc; struct trunk_port *tp = lp->lp_trunk; struct mbuf *m; struct markerdu *mdu; @@ -436,7 +424,7 @@ lacp_xmit_marker(struct lacp_port *lp) if (m == NULL) return (ENOMEM); m->m_len = m->m_pkthdr.len = sizeof(*mdu); - m->m_pkthdr.pf.prio = LACP_IFQ_PRIO; + m->m_pkthdr.pf.prio = lsc->lsc_ifq_prio; mdu = mtod(m, struct markerdu *); memset(mdu, 0, sizeof(*mdu)); @@ -522,9 +510,6 @@ lacp_port_create(struct trunk_port *tp) struct ifreq ifr; int error; - int active = 1; /* XXX should be configurable */ - int fast = 0; /* XXX should be configurable */ - bzero(&ifr, sizeof(ifr)); ifr.ifr_addr.sa_family = AF_UNSPEC; ifr.ifr_addr.sa_len = ETHER_ADDR_LEN; @@ -554,8 +539,8 @@ lacp_port_create(struct trunk_port *tp) lacp_fill_actorinfo(lp, &lp->lp_actor); lacp_fill_markerinfo(lp, &lp->lp_marker); lp->lp_state = - (active ? LACP_STATE_ACTIVITY : 0) | - (fast ? LACP_STATE_TIMEOUT : 0); + (lsc->lsc_mode ? LACP_STATE_ACTIVITY : 0) | + (lsc->lsc_timeout ? LACP_STATE_TIMEOUT : 0); lp->lp_aggregator = NULL; lacp_sm_rx_set_expired(lp); @@ -764,6 +749,13 @@ lacp_attach(struct trunk_softc *sc) TAILQ_INIT(&lsc->lsc_aggregators); LIST_INIT(&lsc->lsc_ports); + /* set default admin values */ + lsc->lsc_mode = LACP_DEFAULT_MODE; + lsc->lsc_timeout = LACP_DEFAULT_TIMEOUT; + lsc->lsc_sys_prio = LACP_DEFAULT_SYSTEM_PRIO; + lsc->lsc_port_prio = LACP_DEFAULT_PORT_PRIO; + lsc->lsc_ifq_prio = LACP_DEFAULT_IFQ_PRIO; + timeout_set(&lsc->lsc_transit_callout, lacp_transit_expire, lsc); timeout_set(&lsc->lsc_callout, lacp_tick, lsc); task_set(&lsc->lsc_input, lacp_input_process, lsc); @@ -1555,12 +1547,15 @@ lacp_sm_rx_update_ntt(struct lacp_port * void lacp_sm_rx_record_default(struct lacp_port *lp) { + struct lacp_softc *lsc; u_int8_t oldpstate; + lsc = lp->lp_lsc; + /* LACP_DPRINTF((lp, "%s\n", __func__)); */ oldpstate = lp->lp_partner.lip_state; - lp->lp_partner = lacp_partner_admin; + lacp_default_partner(lsc, &(lp->lp_partner)); lp->lp_state |= LACP_STATE_DEFAULTED; lacp_sm_ptx_update_timeout(lp, oldpstate); } @@ -1590,9 +1585,14 @@ lacp_sm_rx_update_selected(struct lacp_p void lacp_sm_rx_update_default_selected(struct lacp_port *lp) { + struct lacp_softc *lsc; + struct lacp_peerinfo peer; + + lsc = lp->lp_lsc; + lacp_default_partner(lsc, &peer); /* LACP_DPRINTF((lp, "%s\n", __func__)); */ - lacp_sm_rx_update_selected_from_peerinfo(lp, &lacp_partner_admin); + lacp_sm_rx_update_selected_from_peerinfo(lp, &peer); } /* transmit machine */ Index: sys/net/trunklacp.h =================================================================== RCS file: /home/los/cvs/src/sys/net/trunklacp.h,v retrieving revision 1.13 diff -u -p -r1.13 trunklacp.h --- sys/net/trunklacp.h 12 May 2018 02:02:34 -0000 1.13 +++ sys/net/trunklacp.h 8 Aug 2018 17:42:56 -0000 @@ -39,6 +39,19 @@ #define SLOWPROTOCOLS_SUBTYPE_LACP 1 #define SLOWPROTOCOLS_SUBTYPE_MARKER 2 +/* + * default administrative values + */ +#define LACP_DEFAULT_MODE 1 /* Active Mode */ +#define LACP_DEFAULT_TIMEOUT 0 /* Slow Timeout */ +#define LACP_DEFAULT_SYSTEM_PRIO 0x8000 /* Medium Priority */ +#define LACP_LOW_SYSTEM_PRIO 0xffff +#define LACP_HIGH_SYSTEM_PRIO 0x0001 +#define LACP_DEFAULT_PORT_PRIO 0x8000 /* Medium Priority */ +#define LACP_LOW_PORT_PRIO 0xffff +#define LACP_HIGH_PORT_PRIO 0x0001 +#define LACP_DEFAULT_IFQ_PRIO 6 + struct slowprothdr { u_int8_t sph_subtype; u_int8_t sph_version; @@ -221,6 +234,14 @@ struct lacp_aggregator { int la_pending; /* number of ports in wait_while */ }; +struct lacp_admin_def { + u_int8_t lad_mode; /* active or passive */ + u_int8_t lad_timeout; /* fast or slow */ + u_int16_t lad_prio; /* system priority */ + u_int16_t lad_portprio; /* port priority */ + u_int8_t lad_ifqprio; /* ifq priority */ +}; + struct lacp_softc { struct trunk_softc *lsc_softc; struct lacp_aggregator *lsc_active_aggregator; @@ -233,6 +254,12 @@ struct lacp_softc { volatile u_int lsc_activemap; SIPHASH_KEY lsc_hashkey; struct task lsc_input; + struct lacp_admin_def lsc_admin_defaults; +#define lsc_mode lsc_admin_defaults.lad_mode +#define lsc_timeout lsc_admin_defaults.lad_timeout +#define lsc_sys_prio lsc_admin_defaults.lad_prio +#define lsc_port_prio lsc_admin_defaults.lad_portprio +#define lsc_ifq_prio lsc_admin_defaults.lad_ifqprio }; #define LACP_TYPE_ACTORINFO 1 Index: share/man/man4/trunk.4 =================================================================== RCS file: /home/los/cvs/src/share/man/man4/trunk.4,v retrieving revision 1.29 diff -u -p -r1.29 trunk.4 --- share/man/man4/trunk.4 13 Mar 2015 19:58:41 -0000 1.29 +++ share/man/man4/trunk.4 8 Aug 2018 17:42:56 -0000 @@ -144,10 +144,8 @@ such as duplicate address detection (DAD) cannot properly deal with duplicate packets. .Pp -There is no way to configure LACP administrative variables, including -system and port priorities. -The current implementation always performs active-mode LACP and uses -0x8000 as system and port priorities. +The current LACP implementation defaults to active-mode LACP, slow timeout, +and uses 0x8000 (medium priority) as system and port priorities. .Pp The .Nm