| 1 | /*	$NetBSD: ieee8023ad_impl.h,v 1.2 2005/12/10 23:21:39 elad Exp $	*/ |
| 2 | |
| 3 | /*- |
| 4 | * SPDX-License-Identifier: BSD-2-Clause |
| 5 | * |
| 6 | * Copyright (c)2005 YAMAMOTO Takashi, |
| 7 | * All rights reserved. |
| 8 | * |
| 9 | * Redistribution and use in source and binary forms, with or without |
| 10 | * modification, are permitted provided that the following conditions |
| 11 | * are met: |
| 12 | * 1. Redistributions of source code must retain the above copyright |
| 13 | * notice, this list of conditions and the following disclaimer. |
| 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| 15 | * notice, this list of conditions and the following disclaimer in the |
| 16 | * documentation and/or other materials provided with the distribution. |
| 17 | * |
| 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
| 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE |
| 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 28 | * SUCH DAMAGE. |
| 29 | */ |
| 30 | |
| 31 | /* |
| 32 | * IEEE802.3ad LACP |
| 33 | * |
| 34 | * implementation details. |
| 35 | */ |
| 36 | |
| 37 | #define	LACP_TIMER_CURRENT_WHILE	0 |
| 38 | #define	LACP_TIMER_PERIODIC		1 |
| 39 | #define	LACP_TIMER_WAIT_WHILE		2 |
| 40 | #define	LACP_NTIMER			3 |
| 41 | |
| 42 | #define	LACP_TIMER_ARM(port, timer, val) \ |
| 43 | 	(port)->lp_timer[(timer)] = (val) |
| 44 | #define	LACP_TIMER_DISARM(port, timer) \ |
| 45 | 	(port)->lp_timer[(timer)] = 0 |
| 46 | #define	LACP_TIMER_ISARMED(port, timer) \ |
| 47 | 	((port)->lp_timer[(timer)] > 0) |
| 48 | |
| 49 | /* |
| 50 | * IEEE802.3ad LACP |
| 51 | * |
| 52 | * protocol definitions. |
| 53 | */ |
| 54 | |
| 55 | #define	LACP_STATE_ACTIVITY	(1<<0) |
| 56 | #define	LACP_STATE_TIMEOUT	(1<<1) |
| 57 | #define	LACP_STATE_AGGREGATION	(1<<2) |
| 58 | #define	LACP_STATE_SYNC		(1<<3) |
| 59 | #define	LACP_STATE_COLLECTING	(1<<4) |
| 60 | #define	LACP_STATE_DISTRIBUTING	(1<<5) |
| 61 | #define	LACP_STATE_DEFAULTED	(1<<6) |
| 62 | #define	LACP_STATE_EXPIRED	(1<<7) |
| 63 | |
| 64 | #define	LACP_PORT_NTT		0x00000001 |
| 65 | #define	LACP_PORT_MARK		0x00000002 |
| 66 | |
| 67 | #define	LACP_STATE_BITS		\ |
| 68 | 	"\020"			\ |
| 69 | 	"\001ACTIVITY"		\ |
| 70 | 	"\002TIMEOUT"		\ |
| 71 | 	"\003AGGREGATION"	\ |
| 72 | 	"\004SYNC"		\ |
| 73 | 	"\005COLLECTING"	\ |
| 74 | 	"\006DISTRIBUTING"	\ |
| 75 | 	"\007DEFAULTED"		\ |
| 76 | 	"\010EXPIRED" |
| 77 | |
| 78 | #ifdef _KERNEL |
| 79 | /* |
| 80 | * IEEE802.3 slow protocols |
| 81 | * |
| 82 | * protocol (on-wire) definitions. |
| 83 | * |
| 84 | * XXX should be elsewhere. |
| 85 | */ |
| 86 | |
| 87 | #define	SLOWPROTOCOLS_SUBTYPE_LACP	1 |
| 88 | #define	SLOWPROTOCOLS_SUBTYPE_MARKER	2 |
| 89 | |
| 90 | struct slowprothdr { |
| 91 | 	uint8_t		sph_subtype; |
| 92 | 	uint8_t		sph_version; |
| 93 | } __packed; |
| 94 | |
| 95 | /* |
| 96 | * TLV on-wire structure. |
| 97 | */ |
| 98 | |
| 99 | struct tlvhdr { |
| 100 | 	uint8_t		tlv_type; |
| 101 | 	uint8_t		tlv_length; |
| 102 | 	/* uint8_t tlv_value[]; */ |
| 103 | } __packed; |
| 104 | |
| 105 | /* |
| 106 | * ... and our implementation. |
| 107 | */ |
| 108 | |
| 109 | #define	TLV_SET(tlv, type, length) \ |
| 110 | 	do { \ |
| 111 | 		(tlv)->tlv_type = (type); \ |
| 112 | 		(tlv)->tlv_length = sizeof(*tlv) + (length); \ |
| 113 | 	} while (/*CONSTCOND*/0) |
| 114 | |
| 115 | struct tlv_template { |
| 116 | 	uint8_t			tmpl_type; |
| 117 | 	uint8_t			tmpl_length; |
| 118 | }; |
| 119 | |
| 120 | struct lacp_systemid { |
| 121 | 	uint16_t		lsi_prio; |
| 122 | 	uint8_t			lsi_mac[6]; |
| 123 | } __packed; |
| 124 | |
| 125 | struct lacp_portid { |
| 126 | 	uint16_t		lpi_prio; |
| 127 | 	uint16_t		lpi_portno; |
| 128 | } __packed; |
| 129 | |
| 130 | struct lacp_peerinfo { |
| 131 | 	struct lacp_systemid	lip_systemid; |
| 132 | 	uint16_t		lip_key; |
| 133 | 	struct lacp_portid	lip_portid; |
| 134 | 	uint8_t			lip_state; |
| 135 | 	uint8_t			lip_resv[3]; |
| 136 | } __packed; |
| 137 | |
| 138 | struct lacp_collectorinfo { |
| 139 | 	uint16_t		lci_maxdelay; |
| 140 | 	uint8_t			lci_resv[12]; |
| 141 | } __packed; |
| 142 | |
| 143 | struct lacpdu { |
| 144 | 	struct ether_header	ldu_eh; |
| 145 | 	struct slowprothdr	ldu_sph; |
| 146 | |
| 147 | 	struct tlvhdr		ldu_tlv_actor; |
| 148 | 	struct lacp_peerinfo	ldu_actor; |
| 149 | 	struct tlvhdr		ldu_tlv_partner; |
| 150 | 	struct lacp_peerinfo	ldu_partner; |
| 151 | 	struct tlvhdr		ldu_tlv_collector; |
| 152 | 	struct lacp_collectorinfo ldu_collector; |
| 153 | 	struct tlvhdr		ldu_tlv_term; |
| 154 | 	uint8_t			ldu_resv[50]; |
| 155 | } __packed; |
| 156 | |
| 157 | /* |
| 158 | * IEEE802.3ad marker protocol |
| 159 | * |
| 160 | * protocol (on-wire) definitions. |
| 161 | */ |
| 162 | struct lacp_markerinfo { |
| 163 | 	uint16_t		mi_rq_port; |
| 164 | 	uint8_t			mi_rq_system[ETHER_ADDR_LEN]; |
| 165 | 	uint32_t		mi_rq_xid; |
| 166 | 	uint8_t			mi_pad[2]; |
| 167 | } __packed; |
| 168 | |
| 169 | struct markerdu { |
| 170 | 	struct ether_header	mdu_eh; |
| 171 | 	struct slowprothdr	mdu_sph; |
| 172 | |
| 173 | 	struct tlvhdr		mdu_tlv; |
| 174 | 	struct lacp_markerinfo	mdu_info; |
| 175 | 	struct tlvhdr		mdu_tlv_term; |
| 176 | 	uint8_t			mdu_resv[90]; |
| 177 | } __packed; |
| 178 | |
| 179 | #define	MARKER_TYPE_INFO	0x01 |
| 180 | #define	MARKER_TYPE_RESPONSE	0x02 |
| 181 | |
| 182 | enum lacp_selected { |
| 183 | 	LACP_UNSELECTED, |
| 184 | 	LACP_STANDBY,	/* not used in this implementation */ |
| 185 | 	LACP_SELECTED, |
| 186 | }; |
| 187 | |
| 188 | enum lacp_mux_state { |
| 189 | 	LACP_MUX_DETACHED, |
| 190 | 	LACP_MUX_WAITING, |
| 191 | 	LACP_MUX_ATTACHED, |
| 192 | 	LACP_MUX_COLLECTING, |
| 193 | 	LACP_MUX_DISTRIBUTING, |
| 194 | }; |
| 195 | |
| 196 | #define	LACP_MAX_PORTS		32 |
| 197 | |
| 198 | struct lacp_numa { |
| 199 | 	int			count; |
| 200 | 	struct lacp_port	*map[LACP_MAX_PORTS]; |
| 201 | }; |
| 202 | |
| 203 | struct lacp_portmap { |
| 204 | 	int			pm_count; |
| 205 | 	int			pm_num_dom; |
| 206 | 	struct lacp_numa	pm_numa[MAXMEMDOM]; |
| 207 | 	struct lacp_port	*pm_map[LACP_MAX_PORTS]; |
| 208 | }; |
| 209 | |
| 210 | struct lacp_port { |
| 211 | 	TAILQ_ENTRY(lacp_port)	lp_dist_q; |
| 212 | 	LIST_ENTRY(lacp_port)	lp_next; |
| 213 | 	struct lacp_softc	*lp_lsc; |
| 214 | 	struct lagg_port	*lp_lagg; |
| 215 | 	struct ifnet		*lp_ifp; |
| 216 | 	struct lacp_peerinfo	lp_partner; |
| 217 | 	struct lacp_peerinfo	lp_actor; |
| 218 | 	struct lacp_markerinfo	lp_marker; |
| 219 | #define	lp_state	lp_actor.lip_state |
| 220 | #define	lp_key		lp_actor.lip_key |
| 221 | #define	lp_systemid	lp_actor.lip_systemid |
| 222 | 	struct timeval		lp_last_lacpdu; |
| 223 | 	struct timeval		lp_last_lacpdu_rx; |
| 224 | 	int			lp_lacpdu_sent; |
| 225 | 	enum lacp_mux_state	lp_mux_state; |
| 226 | 	enum lacp_selected	lp_selected; |
| 227 | 	int			lp_flags; |
| 228 | 	u_int			lp_media; /* XXX redundant */ |
| 229 | 	int			lp_timer[LACP_NTIMER]; |
| 230 | 	struct ifmultiaddr	*lp_ifma; |
| 231 | |
| 232 | 	struct lacp_aggregator	*lp_aggregator; |
| 233 | }; |
| 234 | |
| 235 | struct lacp_aggregator { |
| 236 | 	TAILQ_ENTRY(lacp_aggregator)	la_q; |
| 237 | 	int			la_refcnt; /* num of ports which selected us */ |
| 238 | 	int			la_nports; /* num of distributing ports */ |
| 239 | 	TAILQ_HEAD(, lacp_port)	la_ports; /* distributing ports */ |
| 240 | 	struct lacp_peerinfo	la_partner; |
| 241 | 	struct lacp_peerinfo	la_actor; |
| 242 | 	int			la_pending; /* number of ports in wait_while */ |
| 243 | }; |
| 244 | |
| 245 | struct lacp_softc { |
| 246 | 	struct lagg_softc	*lsc_softc; |
| 247 | 	struct mtx		lsc_mtx; |
| 248 | 	struct lacp_aggregator	*lsc_active_aggregator; |
| 249 | 	TAILQ_HEAD(, lacp_aggregator) lsc_aggregators; |
| 250 | 	boolean_t		lsc_suppress_distributing; |
| 251 | 	struct callout		lsc_transit_callout; |
| 252 | 	struct callout		lsc_callout; |
| 253 | 	LIST_HEAD(, lacp_port)	lsc_ports; |
| 254 | 	struct lacp_portmap	lsc_pmap[2]; |
| 255 | 	volatile u_int		lsc_activemap; |
| 256 | 	u_int32_t		lsc_hashkey; |
| 257 | 	struct { |
| 258 | 		u_int32_t	lsc_rx_test; |
| 259 | 		u_int32_t	lsc_tx_test; |
| 260 | 	} lsc_debug; |
| 261 | 	u_int32_t		lsc_strict_mode; |
| 262 | 	boolean_t		lsc_fast_timeout; /* if set, fast timeout */ |
| 263 | }; |
| 264 | |
| 265 | #define	LACP_TYPE_ACTORINFO	1 |
| 266 | #define	LACP_TYPE_PARTNERINFO	2 |
| 267 | #define	LACP_TYPE_COLLECTORINFO	3 |
| 268 | |
| 269 | /* timeout values (in sec) */ |
| 270 | #define	LACP_FAST_PERIODIC_TIME		(1) |
| 271 | #define	LACP_SLOW_PERIODIC_TIME		(30) |
| 272 | #define	LACP_SHORT_TIMEOUT_TIME		(3 * LACP_FAST_PERIODIC_TIME) |
| 273 | #define	LACP_LONG_TIMEOUT_TIME		(3 * LACP_SLOW_PERIODIC_TIME) |
| 274 | #define	LACP_CHURN_DETECTION_TIME	(60) |
| 275 | #define	LACP_AGGREGATE_WAIT_TIME	(2) |
| 276 | #define	LACP_TRANSIT_DELAY		3000	/* in msec */ |
| 277 | |
| 278 | #define	LACP_STATE_EQ(s1, s2, mask)	\ |
| 279 | 	((((s1) ^ (s2)) & (mask)) == 0) |
| 280 | |
| 281 | #define	LACP_SYS_PRI(peer)	(peer).lip_systemid.lsi_prio |
| 282 | |
| 283 | #define	LACP_PORT(_lp)	((struct lacp_port *)(_lp)->lp_psc) |
| 284 | #define	LACP_SOFTC(_sc)	((struct lacp_softc *)(_sc)->sc_psc) |
| 285 | |
| 286 | #define LACP_LOCK_INIT(_lsc)		mtx_init(&(_lsc)->lsc_mtx, \ |
| 287 | 					 "lacp mtx", NULL, MTX_DEF) |
| 288 | #define LACP_LOCK_DESTROY(_lsc)		mtx_destroy(&(_lsc)->lsc_mtx) |
| 289 | #define LACP_LOCK(_lsc)			mtx_lock(&(_lsc)->lsc_mtx) |
| 290 | #define LACP_UNLOCK(_lsc)		mtx_unlock(&(_lsc)->lsc_mtx) |
| 291 | #define LACP_LOCK_ASSERT(_lsc)		mtx_assert(&(_lsc)->lsc_mtx, MA_OWNED) |
| 292 | |
| 293 | struct mbuf	*lacp_input(struct lagg_port *, struct mbuf *); |
| 294 | struct lagg_port *lacp_select_tx_port(struct lagg_softc *, struct mbuf *, |
| 295 | int *); |
| 296 | struct lagg_port *lacp_select_tx_port_by_hash(struct lagg_softc *, uint32_t, |
| 297 | uint8_t, int *); |
| 298 | void		lacp_attach(struct lagg_softc *); |
| 299 | void		lacp_detach(void *); |
| 300 | void		lacp_init(struct lagg_softc *); |
| 301 | void		lacp_stop(struct lagg_softc *); |
| 302 | int		lacp_port_create(struct lagg_port *); |
| 303 | void		lacp_port_destroy(struct lagg_port *); |
| 304 | void		lacp_linkstate(struct lagg_port *); |
| 305 | void		lacp_req(struct lagg_softc *, void *); |
| 306 | void		lacp_portreq(struct lagg_port *, void *); |
| 307 | |
| 308 | static __inline bool |
| 309 | lacp_isactive(struct lagg_port *lgp) |
| 310 | { |
| 311 | 	struct lacp_port *lp = LACP_PORT(lgp); |
| 312 | 	struct lacp_softc *lsc = lp->lp_lsc; |
| 313 | 	struct lacp_aggregator *la = lp->lp_aggregator; |
| 314 | |
| 315 | 	/* This port is joined to the active aggregator */ |
| 316 | 	return (la != NULL && la == lsc->lsc_active_aggregator); |
| 317 | } |
| 318 | |
| 319 | static __inline bool |
| 320 | lacp_iscollecting(struct lagg_port *lgp) |
| 321 | { |
| 322 | 	struct lacp_port *lp = LACP_PORT(lgp); |
| 323 | |
| 324 | 	return (lp->lp_state & LACP_STATE_COLLECTING); |
| 325 | } |
| 326 | |
| 327 | static __inline bool |
| 328 | lacp_isdistributing(struct lagg_port *lgp) |
| 329 | { |
| 330 | 	struct lacp_port *lp = LACP_PORT(lgp); |
| 331 | |
| 332 | 	return (lp->lp_state & LACP_STATE_DISTRIBUTING); |
| 333 | } |
| 334 | |
| 335 | /* following constants don't include terminating NUL */ |
| 336 | #define	LACP_MACSTR_MAX		(2*6 + 5) |
| 337 | #define	LACP_SYSTEMPRIOSTR_MAX	(4) |
| 338 | #define	LACP_SYSTEMIDSTR_MAX	(LACP_SYSTEMPRIOSTR_MAX + 1 + LACP_MACSTR_MAX) |
| 339 | #define	LACP_PORTPRIOSTR_MAX	(4) |
| 340 | #define	LACP_PORTNOSTR_MAX	(4) |
| 341 | #define	LACP_PORTIDSTR_MAX	(LACP_PORTPRIOSTR_MAX + 1 + LACP_PORTNOSTR_MAX) |
| 342 | #define	LACP_KEYSTR_MAX		(4) |
| 343 | #define	LACP_PARTNERSTR_MAX	\ |
| 344 | 	(1 + LACP_SYSTEMIDSTR_MAX + 1 + LACP_KEYSTR_MAX + 1 \ |
| 345 | 	+ LACP_PORTIDSTR_MAX + 1) |
| 346 | #define	LACP_LAGIDSTR_MAX	\ |
| 347 | 	(1 + LACP_PARTNERSTR_MAX + 1 + LACP_PARTNERSTR_MAX + 1) |
| 348 | #define	LACP_STATESTR_MAX	(255) /* XXX */ |
| 349 | #endif	/* _KERNEL */ |