diff options
author | ccardenas <ccardenas@cvs.openbsd.org> | 2018-08-12 23:50:32 +0000 |
---|---|---|
committer | ccardenas <ccardenas@cvs.openbsd.org> | 2018-08-12 23:50:32 +0000 |
commit | 812322fbfc21e66ff5e13cd48878b3148086cecc (patch) | |
tree | 9d2e91f5ad9d100446c7028fcf972348dfd1dc84 /sys | |
parent | ed4ba547919184d93efa4623461e0a5bf3056aa3 (diff) |
Add administrative options to LACP trunk implementation.
The trunk 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/0x8000)
* Port Priority - 1(high) to 65535(low) (default 32768/0x8000)
* 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.
Tested by many on a plethora of NIC drivers and switches.
Ok remi@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/if_trunk.c | 93 | ||||
-rw-r--r-- | sys/net/if_trunk.h | 32 | ||||
-rw-r--r-- | sys/net/trunklacp.c | 78 | ||||
-rw-r--r-- | sys/net/trunklacp.h | 29 |
4 files changed, 190 insertions, 42 deletions
diff --git a/sys/net/if_trunk.c b/sys/net/if_trunk.c index 49d2dbecbbe..6887002a863 100644 --- a/sys/net/if_trunk.c +++ b/sys/net/if_trunk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_trunk.c,v 1.136 2018/02/19 08:59:52 mpi Exp $ */ +/* $OpenBSD: if_trunk.c,v 1.137 2018/08/12 23:50:31 ccardenas Exp $ */ /* * Copyright (c) 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org> @@ -604,8 +604,11 @@ trunk_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 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; @@ -671,6 +674,94 @@ trunk_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) } 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' || (tpif = ifunit(rp->rp_portname)) == NULL) { diff --git a/sys/net/if_trunk.h b/sys/net/if_trunk.h index 05d731a3307..c4408dc5e5d 100644 --- a/sys/net/if_trunk.h +++ b/sys/net/if_trunk.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_trunk.h,v 1.25 2015/09/23 12:40:12 mikeb Exp $ */ +/* $OpenBSD: if_trunk.h,v 1.26 2018/08/12 23:50:31 ccardenas Exp $ */ /* * Copyright (c) 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org> @@ -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 diff --git a/sys/net/trunklacp.c b/sys/net/trunklacp.c index 52ca84f6514..8d5b7bcadbf 100644 --- a/sys/net/trunklacp.c +++ b/sys/net/trunklacp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trunklacp.c,v 1.29 2017/01/24 10:08:30 krw Exp $ */ +/* $OpenBSD: trunklacp.c,v 1.30 2018/08/12 23:50:31 ccardenas Exp $ */ /* $NetBSD: ieee8023ad_lacp.c,v 1.3 2005/12/11 12:24:54 christos Exp $ */ /* $FreeBSD:ieee8023ad_lacp.c,v 1.15 2008/03/16 19:25:30 thompsa Exp $ */ @@ -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_response_tlv_template[] = { 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_port *, const char *, ...) #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 *lp, struct lacp_markerinfo *info) 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 *lp, const struct lacpdu *du) 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_port *lp, const struct lacpdu *du) 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 */ diff --git a/sys/net/trunklacp.h b/sys/net/trunklacp.h index 869076aa4ea..1abc67f279e 100644 --- a/sys/net/trunklacp.h +++ b/sys/net/trunklacp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: trunklacp.h,v 1.13 2018/05/12 02:02:34 ccardenas Exp $ */ +/* $OpenBSD: trunklacp.h,v 1.14 2018/08/12 23:50:31 ccardenas Exp $ */ /* $NetBSD: ieee8023ad_impl.h,v 1.2 2005/12/10 23:21:39 elad Exp $ */ /* @@ -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 |