xref: /openbsd/sys/net/if_aggr.c (revision 2fbde403)
1 /*	$OpenBSD: if_aggr.c,v 1.47 2024/12/18 01:56:05 dlg Exp $ */
2 
3 /*
4  * Copyright (c) 2019 The University of Queensland
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * This driver implements 802.1AX Link Aggregation (formerly 802.3ad)
21  *
22  * The specification describes systems with multiple ports that that
23  * can dynamically form aggregations. The relationships between ports
24  * and aggregations is such that arbitrary ports connected to ports
25  * on other systems may move between aggregations, and there can be
26  * as many aggregations as ports. An aggregation in this model is
27  * effectively an interface, and becomes the point that Ethernet traffic
28  * enters and leaves the system. The spec also contains a description
29  * of the Link Aggregation Control Protocol (LACP) for use on the wire,
30  * and how to process it and select ports and aggregations based on
31  * it.
32  *
33  * This driver implements a simplified or constrained model where each
34  * aggr(4) interface is effectively an independent system, and will
35  * only support one aggregation. This supports the use of the kernel
36  * interface as a static entity that is created and configured once,
37  * and has the link "come up" when that one aggregation is selected
38  * by the LACP protocol.
39  */
40 
41 /*
42  * This code was written by David Gwynne <dlg@uq.edu.au> as part
43  * of the Information Technology Infrastructure Group (ITIG) in the
44  * Faculty of Engineering, Architecture and Information Technology
45  * (EAIT).
46  */
47 
48 /*
49  * TODO:
50  *
51  * - add locking
52  * - figure out the Ready_N and Ready logic
53  */
54 
55 #include "bpfilter.h"
56 #include "kstat.h"
57 
58 #include <sys/param.h>
59 #include <sys/kernel.h>
60 #include <sys/malloc.h>
61 #include <sys/mbuf.h>
62 #include <sys/queue.h>
63 #include <sys/socket.h>
64 #include <sys/sockio.h>
65 #include <sys/systm.h>
66 #include <sys/syslog.h>
67 #include <sys/rwlock.h>
68 #include <sys/percpu.h>
69 #include <sys/smr.h>
70 #include <sys/task.h>
71 #include <sys/kstat.h>
72 
73 #include <net/if.h>
74 #include <net/if_dl.h>
75 #include <net/if_types.h>
76 
77 #include <net/if_media.h>
78 
79 #include <netinet/in.h>
80 #include <netinet/if_ether.h>
81 
82 #include <crypto/siphash.h> /* if_trunk.h uses siphash bits */
83 #include <net/if_trunk.h>
84 
85 #if NBPFILTER > 0
86 #include <net/bpf.h>
87 #endif
88 
89 /*
90  * Link Aggregation Control Protocol (LACP)
91  */
92 
93 struct ether_slowproto_hdr {
94 	uint8_t		sph_subtype;
95 	uint8_t		sph_version;
96 } __packed;
97 
98 #define SLOWPROTOCOLS_SUBTYPE_LACP	1
99 #define SLOWPROTOCOLS_SUBTYPE_LACP_MARKER \
100 					2
101 
102 #define LACP_VERSION			1
103 
104 #define LACP_FAST_PERIODIC_TIME		1
105 #define LACP_SLOW_PERIODIC_TIME		30
106 #define LACP_TIMEOUT_FACTOR		3
107 #define LACP_AGGREGATION_WAIT_TIME	2
108 
109 #define LACP_TX_MACHINE_RATE		3 /* per LACP_FAST_PERIODIC_TIME */
110 
111 #define LACP_ADDR_C_BRIDGE		{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }
112 #define LACP_ADDR_SLOW			{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 }
113 #define LACP_ADDR_SLOW_E64		0x0180c2000002ULL
114 #define LACP_ADDR_NON_TPMR_BRIDGE	{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }
115 
116 struct lacp_tlv_hdr {
117 	uint8_t			lacp_tlv_type;
118 	uint8_t			lacp_tlv_length;
119 } __packed __aligned(2);
120 
121 /* LACP TLV types */
122 
123 #define LACP_T_TERMINATOR		0x00
124 #define LACP_T_ACTOR			0x01
125 #define LACP_T_PARTNER			0x02
126 #define LACP_T_COLLECTOR		0x03
127 
128 /* LACPv2 TLV types */
129 
130 #define LACP_T_PORT_ALGORITHM		0x04
131 #define LACP_T_PORT_CONVERSATION_ID_DIGEST \
132 					0x05
133 #define LACP_T_PORT_CONVERSATION_MASK	0x06
134 #define LACP_T_PORT_CONVERSATION_SERVICE_MAPPING \
135 					0x0a
136 
137 struct lacp_sysid {
138 	uint16_t		lacp_sysid_priority;
139 	uint8_t			lacp_sysid_mac[ETHER_ADDR_LEN];
140 } __packed __aligned(2);
141 
142 struct lacp_portid {
143 	uint16_t		lacp_portid_priority;
144 	uint16_t		lacp_portid_number;
145 } __packed __aligned(2);
146 
147 struct lacp_port_info {
148 	struct lacp_sysid	lacp_sysid;
149 	uint16_t		lacp_key;
150 	struct lacp_portid	lacp_portid;
151 	uint8_t			lacp_state;
152 	uint8_t			lacp_reserved[3];
153 } __packed __aligned(2);
154 
155 #define LACP_STATE_ACTIVITY		(1 << 0)
156 #define LACP_STATE_TIMEOUT		(1 << 1)
157 #define LACP_STATE_AGGREGATION		(1 << 2)
158 #define LACP_STATE_SYNC			(1 << 3)
159 #define LACP_STATE_COLLECTING		(1 << 4)
160 #define LACP_STATE_DISTRIBUTING		(1 << 5)
161 #define LACP_STATE_DEFAULTED		(1 << 6)
162 #define LACP_STATE_EXPIRED		(1 << 7)
163 
164 struct lacp_collector_info {
165 	uint16_t		lacp_maxdelay;
166 	uint8_t			lacp_reserved[12];
167 } __packed __aligned(2);
168 
169 struct lacp_du {
170 	struct ether_slowproto_hdr
171 				lacp_du_sph;
172 	struct lacp_tlv_hdr	lacp_actor_info_tlv;
173 	struct lacp_port_info	lacp_actor_info;
174 	struct lacp_tlv_hdr	lacp_partner_info_tlv;
175 	struct lacp_port_info	lacp_partner_info;
176 	struct lacp_tlv_hdr	lacp_collector_info_tlv;
177 	struct lacp_collector_info
178 				lacp_collector_info;
179 	/* other TLVs go here */
180 	struct lacp_tlv_hdr	lacp_terminator;
181 	uint8_t			lacp_pad[50];
182 } __packed __aligned(2);
183 
184 /* Marker TLV types */
185 
186 #define MARKER_T_INFORMATION		0x01
187 #define MARKER_T_RESPONSE		0x02
188 
189 struct marker_info {
190 	uint16_t		marker_requester_port;
191 	uint8_t			marker_requester_system[ETHER_ADDR_LEN];
192 	uint8_t			marker_requester_txid[4];
193 	uint8_t			marker_pad[2];
194 } __packed __aligned(2);
195 
196 struct marker_pdu {
197 	struct ether_slowproto_hdr
198 				marker_sph;
199 
200 	struct lacp_tlv_hdr	marker_info_tlv;
201 	struct marker_info	marker_info;
202 	struct lacp_tlv_hdr	marker_terminator;
203 	uint8_t			marker_pad[90];
204 } __packed __aligned(2);
205 
206 enum lacp_rxm_state {
207 	LACP_RXM_S_BEGIN = 0,
208 	LACP_RXM_S_INITIALIZE,
209 	LACP_RXM_S_PORT_DISABLED,
210 	LACP_RXM_S_EXPIRED,
211 	LACP_RXM_S_LACP_DISABLED,
212 	LACP_RXM_S_DEFAULTED,
213 	LACP_RXM_S_CURRENT,
214 };
215 
216 enum lacp_rxm_event {
217 	LACP_RXM_E_BEGIN,
218 	LACP_RXM_E_UCT,
219 	LACP_RXM_E_PORT_MOVED,
220 	LACP_RXM_E_NOT_PORT_MOVED,
221 	LACP_RXM_E_PORT_ENABLED,
222 	LACP_RXM_E_NOT_PORT_ENABLED,
223 	LACP_RXM_E_LACP_ENABLED,
224 	LACP_RXM_E_NOT_LACP_ENABLED,
225 	LACP_RXM_E_LACPDU, /* CtrlMuxN:M_UNITDATA.indication(LACPDU) */
226 	LACP_RXM_E_TIMER_EXPIRED, /* current_while_timer expired */
227 };
228 
229 enum lacp_mux_state {
230 	LACP_MUX_S_BEGIN = 0,
231 	LACP_MUX_S_DETACHED,
232 	LACP_MUX_S_WAITING,
233 	LACP_MUX_S_ATTACHED,
234 	LACP_MUX_S_DISTRIBUTING,
235 	LACP_MUX_S_COLLECTING,
236 };
237 
238 enum lacp_mux_event {
239 	LACP_MUX_E_BEGIN,
240 	LACP_MUX_E_SELECTED,
241 	LACP_MUX_E_STANDBY,
242 	LACP_MUX_E_UNSELECTED,
243 	LACP_MUX_E_READY,
244 	LACP_MUX_E_SYNC,
245 	LACP_MUX_E_NOT_SYNC,
246 	LACP_MUX_E_COLLECTING,
247 	LACP_MUX_E_NOT_COLLECTING,
248 };
249 
250 /*
251  * LACP variables
252  */
253 
254 static const uint8_t lacp_address_slow[ETHER_ADDR_LEN] = LACP_ADDR_SLOW;
255 
256 static const char *lacp_rxm_state_names[] = {
257 	"BEGIN",
258 	"INITIALIZE",
259 	"PORT_DISABLED",
260 	"EXPIRED",
261 	"LACP_DISABLED",
262 	"DEFAULTED",
263 	"CURRENT",
264 };
265 
266 static const char *lacp_rxm_event_names[] = {
267 	"BEGIN",
268 	"UCT",
269 	"port_moved",
270 	"!port_moved",
271 	"port_enabled",
272 	"!port_enabled",
273 	"LACP_Enabled",
274 	"!LACP_Enabled",
275 	"LACPDU",
276 	"current_while_timer expired",
277 };
278 
279 static const char *lacp_mux_state_names[] = {
280 	"BEGIN",
281 	"DETACHED",
282 	"WAITING",
283 	"ATTACHED",
284 	"DISTRIBUTING",
285 	"COLLECTING",
286 };
287 
288 static const char *lacp_mux_event_names[] = {
289 	"BEGIN",
290 	"Selected == SELECTED",
291 	"Selected == STANDBY",
292 	"Selected == UNSELECTED",
293 	"Ready",
294 	"Partner.Sync",
295 	"! Partner.Sync",
296 	"Partner.Collecting",
297 	"! Partner.Collecting",
298 };
299 
300 /*
301  * aggr interface
302  */
303 
304 #define AGGR_PORT_BITS		5
305 #define AGGR_FLOWID_SHIFT	(16 - AGGR_PORT_BITS)
306 
307 #define AGGR_MAX_PORTS		(1 << AGGR_PORT_BITS)
308 #define AGGR_MAX_SLOW_PKTS	3
309 
310 struct aggr_multiaddr {
311 	TAILQ_ENTRY(aggr_multiaddr)
312 				m_entry;
313 	unsigned int		m_refs;
314 	uint8_t			m_addrlo[ETHER_ADDR_LEN];
315 	uint8_t			m_addrhi[ETHER_ADDR_LEN];
316 	struct sockaddr_storage m_addr;
317 };
318 TAILQ_HEAD(aggr_multiaddrs, aggr_multiaddr);
319 
320 struct aggr_softc;
321 
322 enum aggr_port_selected {
323 	AGGR_PORT_UNSELECTED,
324 	AGGR_PORT_SELECTED,
325 	AGGR_PORT_STANDBY,
326 };
327 
328 static const char *aggr_port_selected_names[] = {
329 	"UNSELECTED",
330 	"SELECTED",
331 	"STANDBY",
332 };
333 
334 struct aggr_proto_count {
335 	uint64_t		c_pkts;
336 	uint64_t		c_bytes;
337 };
338 
339 #define AGGR_PROTO_TX_LACP	0
340 #define AGGR_PROTO_TX_MARKER	1
341 #define AGGR_PROTO_RX_LACP	2
342 #define AGGR_PROTO_RX_MARKER	3
343 
344 #define AGGR_PROTO_COUNT	4
345 
346 struct aggr_port {
347 	struct ifnet		*p_ifp0;
348 	struct kstat		*p_kstat;
349 	struct mutex		 p_mtx;
350 
351 	uint8_t			 p_lladdr[ETHER_ADDR_LEN];
352 	uint32_t		 p_mtu;
353 
354 	int (*p_ioctl)(struct ifnet *, u_long, caddr_t);
355 	void (*p_input)(struct ifnet *, struct mbuf *);
356 	int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
357 	    struct rtentry *);
358 
359 	struct task		 p_lhook;
360 	struct task		 p_dhook;
361 
362 	struct aggr_softc	*p_aggr;
363 	TAILQ_ENTRY(aggr_port)	 p_entry;
364 
365 	unsigned int		 p_collecting;
366 	unsigned int		 p_distributing;
367 	TAILQ_ENTRY(aggr_port)	 p_entry_distributing;
368 	TAILQ_ENTRY(aggr_port)	 p_entry_muxen;
369 
370 	/* Partner information */
371 	enum aggr_port_selected	 p_muxed;
372 	enum aggr_port_selected	 p_selected;		/* Selected */
373 	struct lacp_port_info	 p_partner;
374 #define p_partner_state		 p_partner.lacp_state
375 
376 	uint8_t			 p_actor_state;
377 	uint8_t			 p_lacp_timeout;
378 
379 	struct timeout		 p_current_while_timer;
380 	struct timeout		 p_wait_while_timer;
381 
382 	/* Receive machine */
383 	enum lacp_rxm_state	 p_rxm_state;
384 	struct mbuf_list	 p_rxm_ml;
385 	struct task		 p_rxm_task;
386 
387 	/* Periodic Transmission machine */
388 	struct timeout		 p_ptm_tx;
389 
390 	/* Mux machine */
391 	enum lacp_mux_state	 p_mux_state;
392 
393 	/* Transmit machine */
394 	int			 p_txm_log[LACP_TX_MACHINE_RATE];
395 	unsigned int		 p_txm_slot;
396 	struct timeout		 p_txm_ntt;
397 
398 	/* Counters */
399 	struct aggr_proto_count	 p_proto_counts[AGGR_PROTO_COUNT];
400 	uint64_t		 p_rx_drops;
401 	uint32_t		 p_nselectch;
402 };
403 
404 TAILQ_HEAD(aggr_port_list, aggr_port);
405 
406 struct aggr_map {
407 	struct ifnet		*m_ifp0s[AGGR_MAX_PORTS];
408 };
409 
410 struct aggr_softc {
411 	struct arpcom		 sc_ac;
412 #define sc_if			 sc_ac.ac_if
413 	unsigned int		 sc_dead;
414 	unsigned int		 sc_promisc;
415 	struct ifmedia		 sc_media;
416 
417 	struct aggr_multiaddrs	 sc_multiaddrs;
418 
419 	unsigned int		 sc_mix;
420 
421 	struct aggr_map		 sc_maps[2];
422 	unsigned int		 sc_map_gen;
423 	struct aggr_map		*sc_map;
424 
425 	struct rwlock		 sc_lock;
426 	struct aggr_port_list	 sc_ports;
427 	struct aggr_port_list	 sc_distributing;
428 	struct aggr_port_list	 sc_muxen;
429 	unsigned int		 sc_nports;
430 	unsigned int		 sc_ndistributing;
431 
432 	struct timeout		 sc_tick;
433 
434 	uint8_t			 sc_lacp_mode;
435 #define AGGR_LACP_MODE_PASSIVE		0
436 #define AGGR_LACP_MODE_ACTIVE		1
437 	uint8_t			 sc_lacp_timeout;
438 #define AGGR_LACP_TIMEOUT_SLOW		0
439 #define AGGR_LACP_TIMEOUT_FAST		1
440 	uint16_t		 sc_lacp_prio;
441 	uint16_t		 sc_lacp_port_prio;
442 
443 	struct lacp_sysid	 sc_partner_system;
444 	uint16_t		 sc_partner_key;
445 };
446 
447 #define DPRINTF(_sc, fmt...)	do { \
448 	if (ISSET((_sc)->sc_if.if_flags, IFF_DEBUG)) \
449 		printf(fmt); \
450 } while (0)
451 
452 static const unsigned int aggr_periodic_times[] = {
453 	[AGGR_LACP_TIMEOUT_SLOW] = LACP_SLOW_PERIODIC_TIME,
454 	[AGGR_LACP_TIMEOUT_FAST] = LACP_FAST_PERIODIC_TIME,
455 };
456 
457 static int	aggr_clone_create(struct if_clone *, int);
458 static int	aggr_clone_destroy(struct ifnet *);
459 
460 static int	aggr_ioctl(struct ifnet *, u_long, caddr_t);
461 static void	aggr_start(struct ifqueue *);
462 static int	aggr_enqueue(struct ifnet *, struct mbuf *);
463 
464 static int	aggr_media_change(struct ifnet *);
465 static void	aggr_media_status(struct ifnet *, struct ifmediareq *);
466 
467 static int	aggr_up(struct aggr_softc *);
468 static int	aggr_down(struct aggr_softc *);
469 static int	aggr_iff(struct aggr_softc *);
470 
471 static void	aggr_p_linkch(void *);
472 static void	aggr_p_detach(void *);
473 static int	aggr_p_ioctl(struct ifnet *, u_long, caddr_t);
474 static int	aggr_p_output(struct ifnet *, struct mbuf *,
475 		    struct sockaddr *, struct rtentry *);
476 
477 static int	aggr_get_trunk(struct aggr_softc *, struct trunk_reqall *);
478 static int	aggr_set_options(struct aggr_softc *,
479 		    const struct trunk_opts *);
480 static int	aggr_get_options(struct aggr_softc *, struct trunk_opts *);
481 static int	aggr_set_lladdr(struct aggr_softc *, const struct ifreq *);
482 static int	aggr_set_mtu(struct aggr_softc *, uint32_t);
483 static void	aggr_p_dtor(struct aggr_softc *, struct aggr_port *,
484 		    const char *);
485 static int	aggr_p_setlladdr(struct aggr_port *, const uint8_t *);
486 static int	aggr_p_set_mtu(struct aggr_port *, uint32_t);
487 static int	aggr_add_port(struct aggr_softc *,
488 		    const struct trunk_reqport *);
489 static int	aggr_get_port(struct aggr_softc *, struct trunk_reqport *);
490 static int	aggr_del_port(struct aggr_softc *,
491 		    const struct trunk_reqport *);
492 static int	aggr_group(struct aggr_softc *, struct aggr_port *, u_long);
493 static int	aggr_multi(struct aggr_softc *, struct aggr_port *,
494 		    const struct aggr_multiaddr *, u_long);
495 static void	aggr_update_capabilities(struct aggr_softc *);
496 static void	aggr_set_lacp_mode(struct aggr_softc *, int);
497 static void	aggr_set_lacp_timeout(struct aggr_softc *, int);
498 static int	aggr_multi_add(struct aggr_softc *, struct ifreq *);
499 static int	aggr_multi_del(struct aggr_softc *, struct ifreq *);
500 
501 static void	aggr_map(struct aggr_softc *);
502 
503 static void	aggr_record_default(struct aggr_softc *, struct aggr_port *);
504 static void	aggr_current_while_timer(void *);
505 static void	aggr_wait_while_timer(void *);
506 static void	aggr_rx(void *);
507 static void	aggr_rxm_ev(struct aggr_softc *, struct aggr_port *,
508 		    enum lacp_rxm_event, const struct lacp_du *);
509 #define aggr_rxm(_sc, _p, _ev) \
510 		aggr_rxm_ev((_sc), (_p), (_ev), NULL)
511 #define aggr_rxm_lacpdu(_sc, _p, _lacpdu) \
512 		aggr_rxm_ev((_sc), (_p), LACP_RXM_E_LACPDU, (_lacpdu))
513 
514 static void	aggr_mux(struct aggr_softc *, struct aggr_port *,
515 		    enum lacp_mux_event);
516 static int	aggr_mux_ev(struct aggr_softc *, struct aggr_port *,
517 		    enum lacp_mux_event, int *);
518 
519 static void	aggr_set_partner_timeout(struct aggr_port *, int);
520 
521 static void	aggr_ptm_tx(void *);
522 
523 static void	aggr_transmit_machine(void *);
524 static void	aggr_ntt(struct aggr_port *);
525 static void	aggr_ntt_transmit(struct aggr_port *);
526 
527 static void	aggr_set_selected(struct aggr_port *, enum aggr_port_selected,
528 		    enum lacp_mux_event);
529 static void	aggr_unselected(struct aggr_port *);
530 
531 static void	aggr_selection_logic(struct aggr_softc *, struct aggr_port *);
532 
533 #if NKSTAT > 0
534 static void	aggr_port_kstat_attach(struct aggr_port *);
535 static void	aggr_port_kstat_detach(struct aggr_port *);
536 #endif
537 
538 static struct if_clone aggr_cloner =
539     IF_CLONE_INITIALIZER("aggr", aggr_clone_create, aggr_clone_destroy);
540 
541 void
aggrattach(int count)542 aggrattach(int count)
543 {
544 	if_clone_attach(&aggr_cloner);
545 }
546 
547 static int
aggr_clone_create(struct if_clone * ifc,int unit)548 aggr_clone_create(struct if_clone *ifc, int unit)
549 {
550 	struct aggr_softc *sc;
551 	struct ifnet *ifp;
552 
553 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO|M_CANFAIL);
554 	if (sc == NULL)
555 		return (ENOMEM);
556 
557 	sc->sc_mix = arc4random();
558 
559 	ifp = &sc->sc_if;
560 
561 	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
562 	    ifc->ifc_name, unit);
563 
564 	TAILQ_INIT(&sc->sc_multiaddrs);
565 	rw_init(&sc->sc_lock, "aggrlk");
566 	TAILQ_INIT(&sc->sc_ports);
567 	sc->sc_nports = 0;
568 	TAILQ_INIT(&sc->sc_distributing);
569 	sc->sc_ndistributing = 0;
570 	TAILQ_INIT(&sc->sc_muxen);
571 
572 	sc->sc_map_gen = 0;
573 	sc->sc_map = NULL; /* no links yet */
574 
575 	sc->sc_lacp_mode = AGGR_LACP_MODE_ACTIVE;
576 	sc->sc_lacp_timeout = AGGR_LACP_TIMEOUT_SLOW;
577 	sc->sc_lacp_prio = 0x8000; /* medium */
578 	sc->sc_lacp_port_prio = 0x8000; /* medium */
579 
580 	ifmedia_init(&sc->sc_media, 0, aggr_media_change, aggr_media_status);
581 	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
582 	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
583 
584 	ifp->if_softc = sc;
585 	ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN;
586 	ifp->if_ioctl = aggr_ioctl;
587 	ifp->if_qstart = aggr_start;
588 	ifp->if_enqueue = aggr_enqueue;
589 	ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX;
590 	ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE;
591 	ifp->if_link_state = LINK_STATE_DOWN;
592 	ether_fakeaddr(ifp);
593 
594 	if_counters_alloc(ifp);
595 	if_attach(ifp);
596 	ether_ifattach(ifp);
597 
598 	ifp->if_llprio = IFQ_MAXPRIO;
599 
600 	return (0);
601 }
602 
603 static int
aggr_clone_destroy(struct ifnet * ifp)604 aggr_clone_destroy(struct ifnet *ifp)
605 {
606 	struct aggr_softc *sc = ifp->if_softc;
607 	struct aggr_port *p;
608 
609 	NET_LOCK();
610 	sc->sc_dead = 1;
611 
612 	if (ISSET(ifp->if_flags, IFF_RUNNING))
613 		aggr_down(sc);
614 	NET_UNLOCK();
615 
616 	ether_ifdetach(ifp);
617 	if_detach(ifp);
618 
619 	/* last ref, no need to lock. aggr_p_dtor locks anyway */
620 	NET_LOCK();
621 	while ((p = TAILQ_FIRST(&sc->sc_ports)) != NULL)
622 		aggr_p_dtor(sc, p, "destroy");
623 	NET_UNLOCK();
624 
625 	free(sc, M_DEVBUF, sizeof(*sc));
626 
627 	return (0);
628 }
629 
630 /*
631  * LACP_Enabled
632  */
633 static inline int
aggr_lacp_enabled(struct aggr_softc * sc)634 aggr_lacp_enabled(struct aggr_softc *sc)
635 {
636 	struct ifnet *ifp = &sc->sc_if;
637 	return (ISSET(ifp->if_flags, IFF_RUNNING));
638 }
639 
640 /*
641  * port_enabled
642  */
643 static int
aggr_port_enabled(struct aggr_port * p)644 aggr_port_enabled(struct aggr_port *p)
645 {
646 	struct ifnet *ifp0 = p->p_ifp0;
647 
648 	if (!ISSET(ifp0->if_flags, IFF_RUNNING))
649 		return (0);
650 
651 	if (!LINK_STATE_IS_UP(ifp0->if_link_state))
652 		return (0);
653 
654 	return (1);
655 }
656 
657 /*
658  * port_moved
659  *
660  * This variable is set to TRUE if the Receive machine for an Aggregation
661  * Port is in the PORT_DISABLED state, and the combination of
662  * Partner_Oper_System and Partner_Oper_Port_Number in use by that
663  * Aggregation Port has been received in an incoming LACPDU on a
664  * different Aggregation Port. This variable is set to FALSE once the
665  * INITIALIZE state of the Receive machine has set the Partner information
666  * for the Aggregation Port to administrative default values.
667  *
668  * Value: Boolean
669 */
670 static int
aggr_port_moved(struct aggr_softc * sc,struct aggr_port * p)671 aggr_port_moved(struct aggr_softc *sc, struct aggr_port *p)
672 {
673 	return (0);
674 }
675 
676 static void
aggr_transmit(struct aggr_softc * sc,const struct aggr_map * map,struct mbuf * m)677 aggr_transmit(struct aggr_softc *sc, const struct aggr_map *map, struct mbuf *m)
678 {
679 	struct ifnet *ifp = &sc->sc_if;
680 	struct ifnet *ifp0;
681 	uint16_t flow = 0;
682 
683 #if NBPFILTER > 0
684 	{
685 		caddr_t if_bpf = ifp->if_bpf;
686 		if (if_bpf)
687 			bpf_mtap_ether(if_bpf, m, BPF_DIRECTION_OUT);
688 	}
689 #endif
690 
691 	if (ISSET(m->m_pkthdr.csum_flags, M_FLOWID))
692 		flow = m->m_pkthdr.ph_flowid >> AGGR_FLOWID_SHIFT;
693 
694 	ifp0 = map->m_ifp0s[flow % AGGR_MAX_PORTS];
695 
696 	if (if_enqueue(ifp0, m) != 0)
697 		counters_inc(ifp->if_counters, ifc_oerrors);
698 }
699 
700 static int
aggr_enqueue(struct ifnet * ifp,struct mbuf * m)701 aggr_enqueue(struct ifnet *ifp, struct mbuf *m)
702 {
703 	struct aggr_softc *sc;
704 	const struct aggr_map *map;
705 	int error = 0;
706 
707 	if (!ifq_is_priq(&ifp->if_snd))
708 		return (if_enqueue_ifq(ifp, m));
709 
710 	sc = ifp->if_softc;
711 
712 	smr_read_enter();
713 	map = SMR_PTR_GET(&sc->sc_map);
714 	if (__predict_false(map == NULL)) {
715 		m_freem(m);
716 		error = ENETDOWN;
717 	} else {
718 		counters_pkt(ifp->if_counters,
719 		    ifc_opackets, ifc_obytes, m->m_pkthdr.len);
720 		aggr_transmit(sc, map, m);
721 	}
722 	smr_read_leave();
723 
724 	return (error);
725 }
726 
727 static void
aggr_start(struct ifqueue * ifq)728 aggr_start(struct ifqueue *ifq)
729 {
730 	struct ifnet *ifp = ifq->ifq_if;
731 	struct aggr_softc *sc = ifp->if_softc;
732 	const struct aggr_map *map;
733 
734 	smr_read_enter();
735 	map = SMR_PTR_GET(&sc->sc_map);
736 	if (__predict_false(map == NULL))
737 		ifq_purge(ifq);
738 	else {
739 		struct mbuf *m;
740 
741 		while ((m = ifq_dequeue(ifq)) != NULL)
742 			aggr_transmit(sc, map, m);
743 	}
744 	smr_read_leave();
745 }
746 
747 static inline struct mbuf *
aggr_input_control(struct aggr_port * p,struct mbuf * m)748 aggr_input_control(struct aggr_port *p, struct mbuf *m)
749 {
750 	struct ether_header *eh;
751 	int hlen = sizeof(*eh);
752 	uint16_t etype;
753 	uint64_t dst;
754 
755 	if (ISSET(m->m_flags, M_VLANTAG))
756 		return (m);
757 
758 	eh = mtod(m, struct ether_header *);
759 	etype = eh->ether_type;
760 	dst = ether_addr_to_e64((struct ether_addr *)eh->ether_dhost);
761 
762 	if (__predict_false(etype == htons(ETHERTYPE_SLOW) &&
763 	    dst == LACP_ADDR_SLOW_E64)) {
764 		unsigned int rx_proto = AGGR_PROTO_RX_LACP;
765 		struct ether_slowproto_hdr *sph;
766 		int drop = 0;
767 
768 		hlen += sizeof(*sph);
769 		if (m->m_len < hlen) {
770 			m = m_pullup(m, hlen);
771 			if (m == NULL) {
772 				/* short++ */
773 				return (NULL);
774 			}
775 			eh = mtod(m, struct ether_header *);
776 		}
777 
778 		sph = (struct ether_slowproto_hdr *)(eh + 1);
779 		switch (sph->sph_subtype) {
780 		case SLOWPROTOCOLS_SUBTYPE_LACP_MARKER:
781 			rx_proto = AGGR_PROTO_RX_MARKER;
782 			/* FALLTHROUGH */
783 		case SLOWPROTOCOLS_SUBTYPE_LACP:
784 			mtx_enter(&p->p_mtx);
785 			p->p_proto_counts[rx_proto].c_pkts++;
786 			p->p_proto_counts[rx_proto].c_bytes += m->m_pkthdr.len;
787 
788 			if (ml_len(&p->p_rxm_ml) < AGGR_MAX_SLOW_PKTS)
789 				ml_enqueue(&p->p_rxm_ml, m);
790 			else {
791 				p->p_rx_drops++;
792 				drop = 1;
793 			}
794 			mtx_leave(&p->p_mtx);
795 
796 			if (drop)
797 				goto drop;
798 			else
799 				task_add(systq, &p->p_rxm_task);
800 			return (NULL);
801 		default:
802 			break;
803 		}
804 	} else if (__predict_false(etype == htons(ETHERTYPE_LLDP) &&
805 	    ETH64_IS_8021_RSVD(dst))) {
806 		/* look at the last nibble of the 802.1 reserved address */
807 		switch (dst & 0xf) {
808 		case 0x0: /* Nearest Customer Bridge */
809 		case 0x3: /* Non-TPMR Bridge */
810 		case 0xe: /* Nearest Bridge */
811 			p->p_input(p->p_ifp0, m);
812 			return (NULL);
813 		default:
814 			break;
815 		}
816 	}
817 
818 	return (m);
819 
820 drop:
821 	m_freem(m);
822 	return (NULL);
823 }
824 
825 static void
aggr_input(struct ifnet * ifp0,struct mbuf * m)826 aggr_input(struct ifnet *ifp0, struct mbuf *m)
827 {
828 	struct arpcom *ac0 = (struct arpcom *)ifp0;
829 	struct aggr_port *p = ac0->ac_trunkport;
830 	struct aggr_softc *sc = p->p_aggr;
831 	struct ifnet *ifp = &sc->sc_if;
832 
833 	if (!ISSET(ifp->if_flags, IFF_RUNNING))
834 		goto drop;
835 
836 	m = aggr_input_control(p, m);
837 	if (m == NULL)
838 		return;
839 
840 	if (__predict_false(!p->p_collecting))
841 		goto drop;
842 
843 	if (!ISSET(m->m_pkthdr.csum_flags, M_FLOWID))
844 		m->m_pkthdr.ph_flowid = ifp0->if_index ^ sc->sc_mix;
845 
846 	if_vinput(ifp, m);
847 
848 	return;
849 
850 drop:
851 	m_freem(m);
852 }
853 
854 static int
aggr_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)855 aggr_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
856 {
857 	struct aggr_softc *sc = ifp->if_softc;
858 	struct ifreq *ifr = (struct ifreq *)data;
859 	int error = 0;
860 
861 	if (sc->sc_dead)
862 		return (ENXIO);
863 
864 	switch (cmd) {
865 	case SIOCSIFADDR:
866 		break;
867 
868 	case SIOCSIFFLAGS:
869 		if (ISSET(ifp->if_flags, IFF_UP)) {
870 			if (!ISSET(ifp->if_flags, IFF_RUNNING))
871 				error = aggr_up(sc);
872 			else
873 				error = ENETRESET;
874 		} else {
875 			if (ISSET(ifp->if_flags, IFF_RUNNING))
876 				error = aggr_down(sc);
877 		}
878 		break;
879 
880 	case SIOCSIFLLADDR:
881 		error = aggr_set_lladdr(sc, ifr);
882 		break;
883 
884 	case SIOCSTRUNK:
885 		error = suser(curproc);
886 		if (error != 0)
887 			break;
888 
889 		if (((struct trunk_reqall *)data)->ra_proto !=
890 		    TRUNK_PROTO_LACP) {
891 			error = EPROTONOSUPPORT;
892 			break;
893 		}
894 
895 		/* nop */
896 		break;
897 	case SIOCGTRUNK:
898 		error = aggr_get_trunk(sc, (struct trunk_reqall *)data);
899 		break;
900 
901 	case SIOCSTRUNKOPTS:
902 		error = suser(curproc);
903 		if (error != 0)
904 			break;
905 
906 		error = aggr_set_options(sc, (struct trunk_opts *)data);
907 		break;
908 
909 	case SIOCGTRUNKOPTS:
910 		error = aggr_get_options(sc, (struct trunk_opts *)data);
911 		break;
912 
913 	case SIOCGTRUNKPORT:
914 		error = aggr_get_port(sc, (struct trunk_reqport *)data);
915 		break;
916 	case SIOCSTRUNKPORT:
917 		error = suser(curproc);
918 		if (error != 0)
919 			break;
920 
921 		error = aggr_add_port(sc, (struct trunk_reqport *)data);
922 		break;
923 	case SIOCSTRUNKDELPORT:
924 		error = suser(curproc);
925 		if (error != 0)
926 			break;
927 
928 		error = aggr_del_port(sc, (struct trunk_reqport *)data);
929 		break;
930 
931 	case SIOCSIFMTU:
932 		error = aggr_set_mtu(sc, ifr->ifr_mtu);
933 		break;
934 
935 	case SIOCADDMULTI:
936 		error = aggr_multi_add(sc, ifr);
937 		break;
938 	case SIOCDELMULTI:
939 		error = aggr_multi_del(sc, ifr);
940 		break;
941 
942 	case SIOCSIFMEDIA:
943 		error = EOPNOTSUPP;
944 		break;
945 	case SIOCGIFMEDIA:
946 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
947 		break;
948 
949 	default:
950 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
951 		break;
952 	}
953 
954 	if (error == ENETRESET)
955 		error = aggr_iff(sc);
956 
957 	return (error);
958 }
959 
960 static int
aggr_get_trunk(struct aggr_softc * sc,struct trunk_reqall * ra)961 aggr_get_trunk(struct aggr_softc *sc, struct trunk_reqall *ra)
962 {
963 	struct ifnet *ifp = &sc->sc_if;
964 	struct trunk_reqport rp;
965 	struct aggr_port *p;
966 	size_t size = ra->ra_size;
967 	caddr_t ubuf = (caddr_t)ra->ra_port;
968 	struct lacp_opreq *req;
969 	uint8_t state = 0;
970 	int error = 0;
971 
972 	if (sc->sc_lacp_mode == AGGR_LACP_MODE_ACTIVE)
973 		SET(state, LACP_STATE_ACTIVITY);
974 	if (sc->sc_lacp_timeout == AGGR_LACP_TIMEOUT_FAST)
975 		SET(state, LACP_STATE_TIMEOUT);
976 
977 	ra->ra_proto = TRUNK_PROTO_LACP;
978 	memset(&ra->ra_psc, 0, sizeof(ra->ra_psc));
979 
980 	/*
981 	 * aggr(4) does not support Individual links so don't bother
982 	 * with portprio, portno, and state, as per the spec.
983 	 */
984 
985 	req = &ra->ra_lacpreq;
986 	req->actor_prio = sc->sc_lacp_prio;
987 	CTASSERT(sizeof(req->actor_mac) == sizeof(sc->sc_ac.ac_enaddr));
988 	memcpy(req->actor_mac, &sc->sc_ac.ac_enaddr, sizeof(req->actor_mac));
989 	req->actor_key = ifp->if_index;
990 	req->actor_state = state;
991 
992 	req->partner_prio = ntohs(sc->sc_partner_system.lacp_sysid_priority);
993 	CTASSERT(sizeof(req->partner_mac) ==
994 	    sizeof(sc->sc_partner_system.lacp_sysid_mac));
995 	memcpy(req->partner_mac, sc->sc_partner_system.lacp_sysid_mac,
996 	    sizeof(req->partner_mac));
997 	req->partner_key = ntohs(sc->sc_partner_key);
998 
999 	ra->ra_ports = sc->sc_nports;
1000 	TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
1001 		struct ifnet *ifp0;
1002 		struct lacp_opreq *opreq;
1003 
1004 		if (size < sizeof(rp))
1005 			break;
1006 
1007 		ifp0 = p->p_ifp0;
1008 
1009 		CTASSERT(sizeof(rp.rp_ifname) == sizeof(ifp->if_xname));
1010 		CTASSERT(sizeof(rp.rp_portname) == sizeof(ifp0->if_xname));
1011 
1012 		memset(&rp, 0, sizeof(rp));
1013 		memcpy(rp.rp_ifname, ifp->if_xname, sizeof(rp.rp_ifname));
1014 		memcpy(rp.rp_portname, ifp0->if_xname, sizeof(rp.rp_portname));
1015 
1016 		if (p->p_muxed)
1017 			SET(rp.rp_flags, TRUNK_PORT_ACTIVE);
1018 		if (p->p_collecting)
1019 			SET(rp.rp_flags, TRUNK_PORT_COLLECTING);
1020 		if (p->p_distributing)
1021 			SET(rp.rp_flags, TRUNK_PORT_DISTRIBUTING);
1022 		if (!aggr_port_enabled(p))
1023 			SET(rp.rp_flags, TRUNK_PORT_DISABLED);
1024 
1025 		opreq = &rp.rp_lacpreq;
1026 
1027 		opreq->actor_prio = sc->sc_lacp_prio;
1028 		memcpy(opreq->actor_mac, &sc->sc_ac.ac_enaddr,
1029 		    sizeof(req->actor_mac));
1030 		opreq->actor_key = ifp->if_index;
1031 		opreq->actor_portprio = sc->sc_lacp_port_prio;
1032 		opreq->actor_portno = ifp0->if_index;
1033 		opreq->actor_state = state | p->p_actor_state;
1034 
1035 		opreq->partner_prio =
1036 		    ntohs(p->p_partner.lacp_sysid.lacp_sysid_priority);
1037 		CTASSERT(sizeof(opreq->partner_mac) ==
1038 		    sizeof(p->p_partner.lacp_sysid.lacp_sysid_mac));
1039 		memcpy(opreq->partner_mac,
1040 		    p->p_partner.lacp_sysid.lacp_sysid_mac,
1041 		    sizeof(opreq->partner_mac));
1042 		opreq->partner_key = ntohs(p->p_partner.lacp_key);
1043 		opreq->partner_portprio =
1044 		    ntohs(p->p_partner.lacp_portid.lacp_portid_priority);
1045 		opreq->partner_portno =
1046 		    ntohs(p->p_partner.lacp_portid.lacp_portid_number);
1047 		opreq->partner_state = p->p_partner_state;
1048 
1049 		error = copyout(&rp, ubuf, sizeof(rp));
1050 		if (error != 0)
1051 			break;
1052 
1053 		ubuf += sizeof(rp);
1054 		size -= sizeof(rp);
1055 	}
1056 
1057 	return (error);
1058 }
1059 
1060 static int
aggr_get_options(struct aggr_softc * sc,struct trunk_opts * tro)1061 aggr_get_options(struct aggr_softc *sc, struct trunk_opts *tro)
1062 {
1063 	struct lacp_adminopts *opt = &tro->to_lacpopts;
1064 
1065 	if (tro->to_proto != TRUNK_PROTO_LACP)
1066 		return (EPROTONOSUPPORT);
1067 
1068 	opt->lacp_mode = sc->sc_lacp_mode;
1069 	opt->lacp_timeout = sc->sc_lacp_timeout;
1070 	opt->lacp_prio = sc->sc_lacp_prio;
1071 	opt->lacp_portprio = sc->sc_lacp_port_prio;
1072 	opt->lacp_ifqprio = sc->sc_if.if_llprio;
1073 
1074 	return (0);
1075 }
1076 
1077 static int
aggr_set_options(struct aggr_softc * sc,const struct trunk_opts * tro)1078 aggr_set_options(struct aggr_softc *sc, const struct trunk_opts *tro)
1079 {
1080 	const struct lacp_adminopts *opt = &tro->to_lacpopts;
1081 
1082 	if (tro->to_proto != TRUNK_PROTO_LACP)
1083 		return (EPROTONOSUPPORT);
1084 
1085 	switch (tro->to_opts) {
1086 	case TRUNK_OPT_LACP_MODE:
1087 		switch (opt->lacp_mode) {
1088 		case AGGR_LACP_MODE_PASSIVE:
1089 		case AGGR_LACP_MODE_ACTIVE:
1090 			break;
1091 		default:
1092 			return (EINVAL);
1093 		}
1094 
1095 		aggr_set_lacp_mode(sc, opt->lacp_mode);
1096 		break;
1097 
1098 	case TRUNK_OPT_LACP_TIMEOUT:
1099 		if (opt->lacp_timeout >= nitems(aggr_periodic_times))
1100 			return (EINVAL);
1101 
1102 		aggr_set_lacp_timeout(sc, opt->lacp_timeout);
1103 		break;
1104 
1105 	case TRUNK_OPT_LACP_SYS_PRIO:
1106 		if (opt->lacp_prio == 0)
1107 			return (EINVAL);
1108 
1109 		sc->sc_lacp_prio = opt->lacp_prio;
1110 		break;
1111 
1112 	case TRUNK_OPT_LACP_PORT_PRIO:
1113 		if (opt->lacp_portprio == 0)
1114 			return (EINVAL);
1115 
1116 		sc->sc_lacp_port_prio = opt->lacp_portprio;
1117 		break;
1118 
1119 	default:
1120 		return (ENODEV);
1121 	}
1122 
1123 	return (0);
1124 }
1125 
1126 static int
aggr_add_port(struct aggr_softc * sc,const struct trunk_reqport * rp)1127 aggr_add_port(struct aggr_softc *sc, const struct trunk_reqport *rp)
1128 {
1129 	struct ifnet *ifp = &sc->sc_if;
1130 	struct ifnet *ifp0;
1131 	struct arpcom *ac0;
1132 	struct aggr_port *p;
1133 	struct aggr_multiaddr *ma;
1134 	int past = ticks - (hz * LACP_TIMEOUT_FACTOR);
1135 	int i;
1136 	int error;
1137 
1138 	NET_ASSERT_LOCKED();
1139 	if (sc->sc_nports > AGGR_MAX_PORTS)
1140 		return (ENOSPC);
1141 
1142 	ifp0 = if_unit(rp->rp_portname);
1143 	if (ifp0 == NULL)
1144 		return (EINVAL);
1145 
1146 	if (ifp0->if_index == ifp->if_index) {
1147 		error = EINVAL;
1148 		goto put;
1149 	}
1150 
1151 	if (ifp0->if_type != IFT_ETHER) {
1152 		error = EPROTONOSUPPORT;
1153 		goto put;
1154 	}
1155 
1156 	error = ether_brport_isset(ifp0);
1157 	if (error != 0)
1158 		goto put;
1159 
1160 	if (ifp0->if_hardmtu < ifp->if_mtu) {
1161 		error = ENOBUFS;
1162 		goto put;
1163 	}
1164 
1165 	ac0 = (struct arpcom *)ifp0;
1166 	if (ac0->ac_trunkport != NULL) {
1167 		error = EBUSY;
1168 		goto put;
1169 	}
1170 
1171 	/* let's try */
1172 
1173 	p = malloc(sizeof(*p), M_DEVBUF, M_WAITOK|M_ZERO|M_CANFAIL);
1174 	if (p == NULL) {
1175 		error = ENOMEM;
1176 		goto put;
1177 	}
1178 
1179 	for (i = 0; i < nitems(p->p_txm_log); i++)
1180 		p->p_txm_log[i] = past;
1181 
1182 	p->p_ifp0 = ifp0;
1183 	p->p_aggr = sc;
1184 	p->p_mtu = ifp0->if_mtu;
1185 	mtx_init(&p->p_mtx, IPL_SOFTNET);
1186 
1187 	CTASSERT(sizeof(p->p_lladdr) == sizeof(ac0->ac_enaddr));
1188 	memcpy(p->p_lladdr, ac0->ac_enaddr, sizeof(p->p_lladdr));
1189 	p->p_ioctl = ifp0->if_ioctl;
1190 	p->p_input = ifp0->if_input;
1191 	p->p_output = ifp0->if_output;
1192 
1193 	error = aggr_group(sc, p, SIOCADDMULTI);
1194 	if (error != 0)
1195 		goto free;
1196 
1197 	error = aggr_p_setlladdr(p, sc->sc_ac.ac_enaddr);
1198 	if (error != 0)
1199 		goto ungroup;
1200 
1201 	error = aggr_p_set_mtu(p, ifp->if_mtu);
1202 	if (error != 0)
1203 		goto resetlladdr;
1204 
1205 	if (sc->sc_promisc) {
1206 		error = ifpromisc(ifp0, 1);
1207 		if (error != 0)
1208 			goto unmtu;
1209 	}
1210 
1211 	TAILQ_FOREACH(ma, &sc->sc_multiaddrs, m_entry) {
1212 		if (aggr_multi(sc, p, ma, SIOCADDMULTI) != 0) {
1213 			log(LOG_WARNING, "%s %s: "
1214 			    "unable to add multicast address\n",
1215 			    ifp->if_xname, ifp0->if_xname);
1216 		}
1217 	}
1218 
1219 	task_set(&p->p_lhook, aggr_p_linkch, p);
1220 	if_linkstatehook_add(ifp0, &p->p_lhook);
1221 
1222 	task_set(&p->p_dhook, aggr_p_detach, p);
1223 	if_detachhook_add(ifp0, &p->p_dhook);
1224 
1225 	task_set(&p->p_rxm_task, aggr_rx, p);
1226 	ml_init(&p->p_rxm_ml);
1227 
1228 	timeout_set_proc(&p->p_ptm_tx, aggr_ptm_tx, p);
1229 	timeout_set_proc(&p->p_txm_ntt, aggr_transmit_machine, p);
1230 	timeout_set_proc(&p->p_current_while_timer,
1231 	    aggr_current_while_timer, p);
1232 	timeout_set_proc(&p->p_wait_while_timer, aggr_wait_while_timer, p);
1233 
1234 	p->p_muxed = 0;
1235 	p->p_collecting = 0;
1236 	p->p_distributing = 0;
1237 	p->p_selected = AGGR_PORT_UNSELECTED;
1238 	p->p_actor_state = LACP_STATE_AGGREGATION;
1239 
1240 	/* commit */
1241 	DPRINTF(sc, "%s %s trunkport: creating port\n",
1242 	    ifp->if_xname, ifp0->if_xname);
1243 
1244 #if NKSTAT > 0
1245 	aggr_port_kstat_attach(p); /* this prints warnings itself */
1246 #endif
1247 
1248 	TAILQ_INSERT_TAIL(&sc->sc_ports, p, p_entry);
1249 	sc->sc_nports++;
1250 
1251 	aggr_update_capabilities(sc);
1252 
1253 	/*
1254 	 * use (and modification) of ifp->if_input and ac->ac_trunkport
1255 	 * is protected by NET_LOCK.
1256 	 */
1257 
1258 	ac0->ac_trunkport = p;
1259 
1260 	/* make sure p is visible before handlers can run */
1261 	membar_producer();
1262 	ifp0->if_ioctl = aggr_p_ioctl;
1263 	ifp0->if_input = aggr_input;
1264 	ifp0->if_output = aggr_p_output;
1265 
1266 	aggr_mux(sc, p, LACP_MUX_E_BEGIN);
1267 	aggr_rxm(sc, p, LACP_RXM_E_BEGIN);
1268 	aggr_p_linkch(p);
1269 
1270 	return (0);
1271 
1272 unmtu:
1273 	if (aggr_p_set_mtu(p, p->p_mtu) != 0) {
1274 		log(LOG_WARNING, "%s add %s: unable to reset mtu %u\n",
1275 		    ifp->if_xname, ifp0->if_xname, p->p_mtu);
1276 	}
1277 resetlladdr:
1278 	if (aggr_p_setlladdr(p, p->p_lladdr) != 0) {
1279 		log(LOG_WARNING, "%s add %s: unable to reset lladdr\n",
1280 		    ifp->if_xname, ifp0->if_xname);
1281 	}
1282 ungroup:
1283 	if (aggr_group(sc, p, SIOCDELMULTI) != 0) {
1284 		log(LOG_WARNING, "%s add %s: "
1285 		    "unable to remove LACP group address\n",
1286 		    ifp->if_xname, ifp0->if_xname);
1287 	}
1288 free:
1289 	free(p, M_DEVBUF, sizeof(*p));
1290 put:
1291 	if_put(ifp0);
1292 	return (error);
1293 }
1294 
1295 static struct aggr_port *
aggr_trunkport(struct aggr_softc * sc,const char * name)1296 aggr_trunkport(struct aggr_softc *sc, const char *name)
1297 {
1298 	struct aggr_port *p;
1299 
1300 	TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
1301 		if (strcmp(p->p_ifp0->if_xname, name) == 0)
1302 			return (p);
1303 	}
1304 
1305 	return (NULL);
1306 }
1307 
1308 static int
aggr_get_port(struct aggr_softc * sc,struct trunk_reqport * rp)1309 aggr_get_port(struct aggr_softc *sc, struct trunk_reqport *rp)
1310 {
1311 	struct aggr_port *p;
1312 
1313 	NET_ASSERT_LOCKED();
1314 	p = aggr_trunkport(sc, rp->rp_portname);
1315 	if (p == NULL)
1316 		return (EINVAL);
1317 
1318 	/* XXX */
1319 
1320 	return (0);
1321 }
1322 
1323 static int
aggr_del_port(struct aggr_softc * sc,const struct trunk_reqport * rp)1324 aggr_del_port(struct aggr_softc *sc, const struct trunk_reqport *rp)
1325 {
1326 	struct aggr_port *p;
1327 
1328 	NET_ASSERT_LOCKED();
1329 	p = aggr_trunkport(sc, rp->rp_portname);
1330 	if (p == NULL)
1331 		return (EINVAL);
1332 
1333 	aggr_p_dtor(sc, p, "del");
1334 
1335 	return (0);
1336 }
1337 
1338 static int
aggr_p_setlladdr(struct aggr_port * p,const uint8_t * addr)1339 aggr_p_setlladdr(struct aggr_port *p, const uint8_t *addr)
1340 {
1341 	struct ifnet *ifp0 = p->p_ifp0;
1342 	struct ifreq ifr;
1343 	struct sockaddr *sa;
1344 	int error;
1345 
1346 	memset(&ifr, 0, sizeof(ifr));
1347 
1348 	CTASSERT(sizeof(ifr.ifr_name) == sizeof(ifp0->if_xname));
1349 	memcpy(ifr.ifr_name, ifp0->if_xname, sizeof(ifr.ifr_name));
1350 
1351 	sa = &ifr.ifr_addr;
1352 
1353 	/* wtf is this? */
1354 	sa->sa_len = ETHER_ADDR_LEN;
1355 	sa->sa_family = AF_LINK;
1356 	CTASSERT(sizeof(sa->sa_data) >= ETHER_ADDR_LEN);
1357 	memcpy(sa->sa_data, addr, ETHER_ADDR_LEN);
1358 
1359 	error = (*p->p_ioctl)(ifp0, SIOCSIFLLADDR, (caddr_t)&ifr);
1360 	switch (error) {
1361 	case ENOTTY:
1362 	case 0:
1363 		break;
1364 	default:
1365 		return (error);
1366 	}
1367 
1368 	error = if_setlladdr(ifp0, addr);
1369 	if (error != 0)
1370 		return (error);
1371 
1372 	ifnewlladdr(ifp0);
1373 
1374 	return (0);
1375 }
1376 
1377 static int
aggr_p_set_mtu(struct aggr_port * p,uint32_t mtu)1378 aggr_p_set_mtu(struct aggr_port *p, uint32_t mtu)
1379 {
1380 	struct ifnet *ifp0 = p->p_ifp0;
1381 	struct ifreq ifr;
1382 
1383 	memset(&ifr, 0, sizeof(ifr));
1384 
1385 	CTASSERT(sizeof(ifr.ifr_name) == sizeof(ifp0->if_xname));
1386 	memcpy(ifr.ifr_name, ifp0->if_xname, sizeof(ifr.ifr_name));
1387 
1388 	ifr.ifr_mtu = mtu;
1389 
1390 	return ((*p->p_ioctl)(ifp0, SIOCSIFMTU, (caddr_t)&ifr));
1391 }
1392 
1393 static int
aggr_p_ioctl(struct ifnet * ifp0,u_long cmd,caddr_t data)1394 aggr_p_ioctl(struct ifnet *ifp0, u_long cmd, caddr_t data)
1395 {
1396 	struct arpcom *ac0 = (struct arpcom *)ifp0;
1397 	struct aggr_port *p = ac0->ac_trunkport;
1398 	struct ifreq *ifr = (struct ifreq *)data;
1399 	int error = 0;
1400 
1401 	switch (cmd) {
1402 	case SIOCGTRUNKPORT: {
1403 		struct trunk_reqport *rp = (struct trunk_reqport *)data;
1404 		struct aggr_softc *sc = p->p_aggr;
1405 		struct ifnet *ifp = &sc->sc_if;
1406 
1407 		if (strncmp(rp->rp_ifname, rp->rp_portname,
1408 		    sizeof(rp->rp_ifname)) != 0)
1409 			return (EINVAL);
1410 
1411 		CTASSERT(sizeof(rp->rp_ifname) == sizeof(ifp->if_xname));
1412 		memcpy(rp->rp_ifname, ifp->if_xname, sizeof(rp->rp_ifname));
1413 		break;
1414 	}
1415 
1416 	case SIOCSIFMTU:
1417 		if (ifr->ifr_mtu == ifp0->if_mtu)
1418 			break; /* nop */
1419 
1420 		/* FALLTHROUGH */
1421 	case SIOCSIFLLADDR:
1422 		error = EBUSY;
1423 		break;
1424 
1425 	case SIOCSIFFLAGS:
1426 		if (!ISSET(ifp0->if_flags, IFF_UP) &&
1427 		    ISSET(ifp0->if_flags, IFF_RUNNING)) {
1428 			/* port is going down */
1429 			if (p->p_selected == AGGR_PORT_SELECTED) {
1430 				aggr_unselected(p);
1431 				aggr_ntt_transmit(p); /* XXX */
1432 			}
1433 		}
1434 		/* FALLTHROUGH */
1435 	default:
1436 		error = (*p->p_ioctl)(ifp0, cmd, data);
1437 		break;
1438 	}
1439 
1440 	return (error);
1441 }
1442 
1443 static int
aggr_p_output(struct ifnet * ifp0,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)1444 aggr_p_output(struct ifnet *ifp0, struct mbuf *m, struct sockaddr *dst,
1445     struct rtentry *rt)
1446 {
1447 	struct arpcom *ac0 = (struct arpcom *)ifp0;
1448 	struct aggr_port *p = ac0->ac_trunkport;
1449 
1450 	/* restrict transmission to bpf only */
1451 	if (m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL) {
1452 		m_freem(m);
1453 		return (EBUSY);
1454 	}
1455 
1456 	return ((*p->p_output)(ifp0, m, dst, rt));
1457 }
1458 
1459 static void
aggr_p_dtor(struct aggr_softc * sc,struct aggr_port * p,const char * op)1460 aggr_p_dtor(struct aggr_softc *sc, struct aggr_port *p, const char *op)
1461 {
1462 	struct ifnet *ifp = &sc->sc_if;
1463 	struct ifnet *ifp0 = p->p_ifp0;
1464 	struct arpcom *ac0 = (struct arpcom *)ifp0;
1465 	struct aggr_multiaddr *ma;
1466 	enum aggr_port_selected selected;
1467 	int error;
1468 
1469 	DPRINTF(sc, "%s %s %s: destroying port\n",
1470 	    ifp->if_xname, ifp0->if_xname, op);
1471 
1472 	selected = p->p_selected;
1473 	aggr_rxm(sc, p, LACP_RXM_E_NOT_PORT_ENABLED);
1474 	aggr_unselected(p);
1475 	if (aggr_port_enabled(p) && selected == AGGR_PORT_SELECTED)
1476 		aggr_ntt_transmit(p);
1477 
1478 	timeout_del(&p->p_ptm_tx);
1479 	timeout_del_barrier(&p->p_txm_ntt); /* XXX */
1480 	timeout_del(&p->p_current_while_timer);
1481 	timeout_del(&p->p_wait_while_timer);
1482 
1483 	/*
1484 	 * use (and modification) of ifp->if_input and ac->ac_trunkport
1485 	 * is protected by NET_LOCK.
1486 	 */
1487 
1488 	ac0->ac_trunkport = NULL;
1489 	ifp0->if_input = p->p_input;
1490 	ifp0->if_ioctl = p->p_ioctl;
1491 	ifp0->if_output = p->p_output;
1492 
1493 #if NKSTAT > 0
1494 	aggr_port_kstat_detach(p);
1495 #endif
1496 
1497 	TAILQ_REMOVE(&sc->sc_ports, p, p_entry);
1498 	sc->sc_nports--;
1499 
1500 	TAILQ_FOREACH(ma, &sc->sc_multiaddrs, m_entry) {
1501 		error = aggr_multi(sc, p, ma, SIOCDELMULTI);
1502 		if (error != 0) {
1503 			log(LOG_WARNING, "%s %s %s: "
1504 			    "unable to remove multicast address (%d)\n",
1505 			    ifp->if_xname, op, ifp0->if_xname, error);
1506 		}
1507 	}
1508 
1509 	if (sc->sc_promisc) {
1510 		error = ifpromisc(ifp0, 0);
1511 		if (error != 0) {
1512 			log(LOG_WARNING, "%s %s %s: "
1513 			    "unable to disable promisc (%d)\n",
1514 			    ifp->if_xname, op, ifp0->if_xname, error);
1515 		}
1516 	}
1517 
1518 	error = aggr_p_set_mtu(p, p->p_mtu);
1519 	if (error != 0) {
1520 		log(LOG_WARNING, "%s %s %s: unable to restore mtu %u (%d)\n",
1521 		    ifp->if_xname, op, ifp0->if_xname, p->p_mtu, error);
1522 	}
1523 
1524 	error = aggr_p_setlladdr(p, p->p_lladdr);
1525 	if (error != 0) {
1526 		log(LOG_WARNING, "%s %s %s: unable to restore lladdr (%d)\n",
1527 		    ifp->if_xname, op, ifp0->if_xname, error);
1528 	}
1529 
1530 	error = aggr_group(sc, p, SIOCDELMULTI);
1531 	if (error != 0) {
1532 		log(LOG_WARNING, "%s %s %s: "
1533 		    "unable to remove LACP group address (%d)\n",
1534 		    ifp->if_xname, op, ifp0->if_xname, error);
1535 	}
1536 
1537 	if_detachhook_del(ifp0, &p->p_dhook);
1538 	if_linkstatehook_del(ifp0, &p->p_lhook);
1539 	if_put(ifp0);
1540 	free(p, M_DEVBUF, sizeof(*p));
1541 
1542 	/* XXX this is a pretty ugly place to update this */
1543 	aggr_update_capabilities(sc);
1544 }
1545 
1546 static void
aggr_p_detach(void * arg)1547 aggr_p_detach(void *arg)
1548 {
1549 	struct aggr_port *p = arg;
1550 	struct aggr_softc *sc = p->p_aggr;
1551 
1552 	aggr_p_dtor(sc, p, "detach");
1553 
1554 	NET_ASSERT_LOCKED();
1555 }
1556 
1557 static void
aggr_p_linkch(void * arg)1558 aggr_p_linkch(void *arg)
1559 {
1560 	struct aggr_port *p = arg;
1561 	struct aggr_softc *sc = p->p_aggr;
1562 
1563 	NET_ASSERT_LOCKED();
1564 
1565 	if (aggr_port_enabled(p)) {
1566 		aggr_rxm(sc, p, LACP_RXM_E_PORT_ENABLED);
1567 
1568 		if (aggr_lacp_enabled(sc)) {
1569 			timeout_add_sec(&p->p_ptm_tx,
1570 			    aggr_periodic_times[AGGR_LACP_TIMEOUT_FAST]);
1571 		}
1572 	} else {
1573 		aggr_rxm(sc, p, LACP_RXM_E_NOT_PORT_ENABLED);
1574 		aggr_unselected(p);
1575 		aggr_record_default(sc, p);
1576 		timeout_del(&p->p_ptm_tx);
1577 	}
1578 }
1579 
1580 static void
aggr_map(struct aggr_softc * sc)1581 aggr_map(struct aggr_softc *sc)
1582 {
1583 	struct ifnet *ifp = &sc->sc_if;
1584 	struct aggr_map *map = NULL;
1585 	struct aggr_port *p;
1586 	unsigned int gen;
1587 	unsigned int i;
1588 	int link_state = LINK_STATE_DOWN;
1589 
1590 	p = TAILQ_FIRST(&sc->sc_distributing);
1591 	if (p != NULL) {
1592 		gen = sc->sc_map_gen++;
1593 		map = &sc->sc_maps[gen % nitems(sc->sc_maps)];
1594 
1595 		for (i = 0; i < nitems(map->m_ifp0s); i++) {
1596 			map->m_ifp0s[i] = p->p_ifp0;
1597 
1598 			p = TAILQ_NEXT(p, p_entry_distributing);
1599 			if (p == NULL)
1600 				p = TAILQ_FIRST(&sc->sc_distributing);
1601 		}
1602 
1603 		link_state = LINK_STATE_FULL_DUPLEX;
1604 	}
1605 
1606 	SMR_PTR_SET_LOCKED(&sc->sc_map, map);
1607 	smr_barrier();
1608 
1609 	if (ifp->if_link_state != link_state) {
1610 		ifp->if_link_state = link_state;
1611 		if_link_state_change(ifp);
1612 	}
1613 }
1614 
1615 static void
aggr_current_while_timer(void * arg)1616 aggr_current_while_timer(void *arg)
1617 {
1618 	struct aggr_port *p = arg;
1619 	struct aggr_softc *sc = p->p_aggr;
1620 
1621 	aggr_rxm(sc, p, LACP_RXM_E_TIMER_EXPIRED);
1622 }
1623 
1624 static void
aggr_wait_while_timer(void * arg)1625 aggr_wait_while_timer(void *arg)
1626 {
1627 	struct aggr_port *p = arg;
1628 	struct aggr_softc *sc = p->p_aggr;
1629 
1630 	aggr_selection_logic(sc, p);
1631 }
1632 
1633 static void
aggr_start_current_while_timer(struct aggr_port * p,unsigned int t)1634 aggr_start_current_while_timer(struct aggr_port *p, unsigned int t)
1635 {
1636 	timeout_add_sec(&p->p_current_while_timer,
1637 		aggr_periodic_times[t] * LACP_TIMEOUT_FACTOR);
1638 }
1639 
1640 static void
aggr_input_lacpdu(struct aggr_port * p,struct mbuf * m)1641 aggr_input_lacpdu(struct aggr_port *p, struct mbuf *m)
1642 {
1643 	struct aggr_softc *sc = p->p_aggr;
1644 	struct lacp_du *lacpdu;
1645 
1646 	if (m->m_len < sizeof(*lacpdu)) {
1647 		m = m_pullup(m, sizeof(*lacpdu));
1648 		if (m == NULL)
1649 			return;
1650 	}
1651 
1652 	/*
1653 	 * In the process of executing the recordPDU function, a Receive
1654 	 * machine compliant to this standard shall not validate the
1655 	 * Version Number, TLV_type, or Reserved fields in received
1656 	 * LACPDUs. The same actions are taken regardless of the values
1657 	 * received in these fields. A Receive machine may validate
1658 	 * the Actor_Information_Length, Partner_Information_Length,
1659 	 * Collector_Information_Length, or Terminator_Length fields.
1660 	 */
1661 
1662 	lacpdu = mtod(m, struct lacp_du *);
1663 	aggr_rxm_lacpdu(sc, p, lacpdu);
1664 
1665 	m_freem(m);
1666 }
1667 
1668 static void
aggr_update_selected(struct aggr_softc * sc,struct aggr_port * p,const struct lacp_du * lacpdu)1669 aggr_update_selected(struct aggr_softc *sc, struct aggr_port *p,
1670     const struct lacp_du *lacpdu)
1671 {
1672 	const struct lacp_port_info *rpi = &lacpdu->lacp_actor_info;
1673 	const struct lacp_port_info *lpi = &p->p_partner;
1674 
1675 	if ((rpi->lacp_portid.lacp_portid_number ==
1676 	     lpi->lacp_portid.lacp_portid_number) &&
1677 	    (rpi->lacp_portid.lacp_portid_priority ==
1678 	     lpi->lacp_portid.lacp_portid_priority) &&
1679 	    ETHER_IS_EQ(rpi->lacp_sysid.lacp_sysid_mac,
1680 	     lpi->lacp_sysid.lacp_sysid_mac) &&
1681 	    (rpi->lacp_sysid.lacp_sysid_priority ==
1682 	     lpi->lacp_sysid.lacp_sysid_priority) &&
1683 	    (rpi->lacp_key == lpi->lacp_key) &&
1684 	    (ISSET(rpi->lacp_state, LACP_STATE_AGGREGATION) ==
1685 	     ISSET(lpi->lacp_state, LACP_STATE_AGGREGATION)))
1686 		return;
1687 
1688 	aggr_unselected(p);
1689 }
1690 
1691 static void
aggr_record_default(struct aggr_softc * sc,struct aggr_port * p)1692 aggr_record_default(struct aggr_softc *sc, struct aggr_port *p)
1693 {
1694 	struct lacp_port_info *pi = &p->p_partner;
1695 
1696 	pi->lacp_sysid.lacp_sysid_priority = htons(0);
1697 	memset(pi->lacp_sysid.lacp_sysid_mac, 0,
1698 	    sizeof(pi->lacp_sysid.lacp_sysid_mac));
1699 
1700 	pi->lacp_key = htons(0);
1701 
1702 	pi->lacp_portid.lacp_portid_priority = htons(0);
1703 	pi->lacp_portid.lacp_portid_number = htons(0);
1704 
1705 	SET(p->p_actor_state, LACP_STATE_DEFAULTED);
1706 
1707 	pi->lacp_state = LACP_STATE_AGGREGATION | LACP_STATE_SYNC;
1708 	if (sc->sc_lacp_timeout == AGGR_LACP_TIMEOUT_FAST)
1709 		SET(pi->lacp_state, LACP_STATE_TIMEOUT);
1710 	if (sc->sc_lacp_mode == AGGR_LACP_MODE_ACTIVE)
1711 		SET(pi->lacp_state, LACP_STATE_ACTIVITY);
1712 
1713 	/* notify Mux */
1714 	aggr_mux(sc, p, LACP_MUX_E_NOT_COLLECTING);
1715 	aggr_mux(sc, p, LACP_MUX_E_SYNC);
1716 }
1717 
1718 static void
aggr_update_default_selected(struct aggr_softc * sc,struct aggr_port * p)1719 aggr_update_default_selected(struct aggr_softc *sc, struct aggr_port *p)
1720 {
1721 	const struct lacp_port_info *pi = &p->p_partner;
1722 
1723 	if ((pi->lacp_portid.lacp_portid_number == htons(0)) &&
1724 	    (pi->lacp_portid.lacp_portid_priority == htons(0)) &&
1725 	    ETHER_IS_ANYADDR(pi->lacp_sysid.lacp_sysid_mac) &&
1726 	    (pi->lacp_sysid.lacp_sysid_priority == htons(0)) &&
1727 	    (pi->lacp_key == htons(0)) &&
1728 	    ISSET(pi->lacp_state, LACP_STATE_AGGREGATION))
1729 		return;
1730 
1731 	aggr_unselected(p);
1732 	aggr_selection_logic(sc, p); /* restart */
1733 }
1734 
1735 static int
aggr_update_ntt(struct aggr_port * p,const struct lacp_du * lacpdu)1736 aggr_update_ntt(struct aggr_port *p, const struct lacp_du *lacpdu)
1737 {
1738 	struct aggr_softc *sc = p->p_aggr;
1739 	struct arpcom *ac = &sc->sc_ac;
1740 	struct ifnet *ifp = &ac->ac_if;
1741 	struct ifnet *ifp0 = p->p_ifp0;
1742 	const struct lacp_port_info *pi = &lacpdu->lacp_partner_info;
1743 	uint8_t bits = LACP_STATE_ACTIVITY | LACP_STATE_TIMEOUT |
1744 	    LACP_STATE_SYNC | LACP_STATE_AGGREGATION;
1745 	uint8_t state = p->p_actor_state;
1746 	int sync = 0;
1747 
1748 	if (pi->lacp_portid.lacp_portid_number != htons(ifp0->if_index))
1749 		goto ntt;
1750 	if (pi->lacp_portid.lacp_portid_priority !=
1751 	    htons(sc->sc_lacp_port_prio))
1752 		goto ntt;
1753 	if (!ETHER_IS_EQ(pi->lacp_sysid.lacp_sysid_mac, ac->ac_enaddr))
1754 		goto ntt;
1755 	if (pi->lacp_sysid.lacp_sysid_priority !=
1756 	    htons(sc->sc_lacp_prio))
1757 		goto ntt;
1758 	if (pi->lacp_key != htons(ifp->if_index))
1759 		goto ntt;
1760 	if (ISSET(pi->lacp_state, LACP_STATE_SYNC) !=
1761 	    ISSET(state, LACP_STATE_SYNC))
1762 		goto ntt;
1763 	sync = 1;
1764 
1765 	if (sc->sc_lacp_timeout == AGGR_LACP_TIMEOUT_FAST)
1766 		SET(state, LACP_STATE_TIMEOUT);
1767 	if (sc->sc_lacp_mode == AGGR_LACP_MODE_ACTIVE)
1768 		SET(state, LACP_STATE_ACTIVITY);
1769 
1770 	if (ISSET(pi->lacp_state, bits) != ISSET(state, bits))
1771 		goto ntt;
1772 
1773 	return (1);
1774 
1775 ntt:
1776 	aggr_ntt(p);
1777 
1778 	return (sync);
1779 }
1780 
1781 static void
aggr_recordpdu(struct aggr_port * p,const struct lacp_du * lacpdu,int sync)1782 aggr_recordpdu(struct aggr_port *p, const struct lacp_du *lacpdu, int sync)
1783 {
1784 	struct aggr_softc *sc = p->p_aggr;
1785 	const struct lacp_port_info *rpi = &lacpdu->lacp_actor_info;
1786 	struct lacp_port_info *lpi = &p->p_partner;
1787 	int active = ISSET(rpi->lacp_state, LACP_STATE_ACTIVITY) ||
1788 	    (ISSET(p->p_actor_state, LACP_STATE_ACTIVITY) &&
1789 	     ISSET(lacpdu->lacp_partner_info.lacp_state, LACP_STATE_ACTIVITY));
1790 
1791 	lpi->lacp_portid.lacp_portid_number =
1792 	    rpi->lacp_portid.lacp_portid_number;
1793 	lpi->lacp_portid.lacp_portid_priority =
1794 	    rpi->lacp_portid.lacp_portid_priority;
1795 	memcpy(lpi->lacp_sysid.lacp_sysid_mac,
1796 	    rpi->lacp_sysid.lacp_sysid_mac,
1797 	    sizeof(lpi->lacp_sysid.lacp_sysid_mac));
1798 	lpi->lacp_sysid.lacp_sysid_priority =
1799 	    rpi->lacp_sysid.lacp_sysid_priority;
1800 	lpi->lacp_key = rpi->lacp_key;
1801 	lpi->lacp_state = rpi->lacp_state & ~LACP_STATE_SYNC;
1802 
1803 	CLR(p->p_actor_state, LACP_STATE_DEFAULTED);
1804 
1805 	if (active && ISSET(rpi->lacp_state, LACP_STATE_SYNC) && sync) {
1806 		SET(p->p_partner_state, LACP_STATE_SYNC);
1807 		aggr_mux(sc, p, LACP_MUX_E_SYNC);
1808 	} else {
1809 		CLR(p->p_partner_state, LACP_STATE_SYNC);
1810 		aggr_mux(sc, p, LACP_MUX_E_NOT_SYNC);
1811 	}
1812 }
1813 
1814 static void
aggr_marker_response(struct aggr_port * p,struct mbuf * m)1815 aggr_marker_response(struct aggr_port *p, struct mbuf *m)
1816 {
1817 	struct aggr_softc *sc = p->p_aggr;
1818 	struct arpcom *ac = &sc->sc_ac;
1819 	struct ifnet *ifp0 = p->p_ifp0;
1820 	struct marker_pdu *mpdu;
1821 	struct ether_header *eh;
1822 
1823 	mpdu = mtod(m, struct marker_pdu *);
1824 	mpdu->marker_info_tlv.lacp_tlv_type = MARKER_T_RESPONSE;
1825 
1826 	m = m_prepend(m, sizeof(*eh), M_DONTWAIT);
1827 	if (m == NULL)
1828 		return;
1829 
1830 	eh = mtod(m, struct ether_header *);
1831 	memcpy(eh->ether_dhost, lacp_address_slow, sizeof(eh->ether_dhost));
1832 	memcpy(eh->ether_shost, ac->ac_enaddr, sizeof(eh->ether_shost));
1833 	eh->ether_type = htons(ETHERTYPE_SLOW);
1834 
1835 	mtx_enter(&p->p_mtx);
1836 	p->p_proto_counts[AGGR_PROTO_TX_MARKER].c_pkts++;
1837 	p->p_proto_counts[AGGR_PROTO_TX_MARKER].c_bytes += m->m_pkthdr.len;
1838 	mtx_leave(&p->p_mtx);
1839 
1840 	(void)if_enqueue(ifp0, m);
1841 }
1842 
1843 static void
aggr_input_marker(struct aggr_port * p,struct mbuf * m)1844 aggr_input_marker(struct aggr_port *p, struct mbuf *m)
1845 {
1846 	struct marker_pdu *mpdu;
1847 
1848 	if (m->m_len < sizeof(*mpdu)) {
1849 		m = m_pullup(m, sizeof(*mpdu));
1850 		if (m == NULL)
1851 			return;
1852 	}
1853 
1854 	mpdu = mtod(m, struct marker_pdu *);
1855 	switch (mpdu->marker_info_tlv.lacp_tlv_type) {
1856 	case MARKER_T_INFORMATION:
1857 		aggr_marker_response(p, m);
1858 		break;
1859 	default:
1860 		m_freem(m);
1861 		break;
1862 	}
1863 }
1864 
1865 static void
aggr_rx(void * arg)1866 aggr_rx(void *arg)
1867 {
1868 	struct aggr_port *p = arg;
1869 	struct mbuf_list ml;
1870 	struct mbuf *m;
1871 
1872 	mtx_enter(&p->p_mtx);
1873 	ml = p->p_rxm_ml;
1874 	ml_init(&p->p_rxm_ml);
1875 	mtx_leave(&p->p_mtx);
1876 
1877 	while ((m = ml_dequeue(&ml)) != NULL) {
1878 		struct ether_slowproto_hdr *sph;
1879 
1880 		/* aggr_input has checked eh already */
1881 		m_adj(m, sizeof(struct ether_header));
1882 
1883 		sph = mtod(m, struct ether_slowproto_hdr *);
1884 		switch (sph->sph_subtype) {
1885 		case SLOWPROTOCOLS_SUBTYPE_LACP:
1886 			aggr_input_lacpdu(p, m);
1887 			break;
1888 		case SLOWPROTOCOLS_SUBTYPE_LACP_MARKER:
1889 			aggr_input_marker(p, m);
1890 			break;
1891 		default:
1892 			panic("unexpected slow protocol subtype");
1893 			/* NOTREACHED */
1894 		}
1895 	}
1896 }
1897 
1898 static void
aggr_set_selected(struct aggr_port * p,enum aggr_port_selected s,enum lacp_mux_event ev)1899 aggr_set_selected(struct aggr_port *p, enum aggr_port_selected s,
1900     enum lacp_mux_event ev)
1901 {
1902 	struct aggr_softc *sc = p->p_aggr;
1903 
1904 	if (p->p_selected != s) {
1905 		DPRINTF(sc, "%s %s: Selected %s -> %s\n",
1906 		    sc->sc_if.if_xname, p->p_ifp0->if_xname,
1907 		    aggr_port_selected_names[p->p_selected],
1908 		    aggr_port_selected_names[s]);
1909 
1910 		/*
1911 		 * setting p_selected doesn't need the mtx except to
1912 		 * coordinate with a kstat read.
1913 		 */
1914 
1915 		mtx_enter(&p->p_mtx);
1916 		p->p_selected = s;
1917 		p->p_nselectch++;
1918 		mtx_leave(&p->p_mtx);
1919 	}
1920 	aggr_mux(sc, p, ev);
1921 }
1922 
1923 static void
aggr_unselected(struct aggr_port * p)1924 aggr_unselected(struct aggr_port *p)
1925 {
1926 	aggr_set_selected(p, AGGR_PORT_UNSELECTED, LACP_MUX_E_UNSELECTED);
1927 }
1928 
1929 static inline void
aggr_selected(struct aggr_port * p)1930 aggr_selected(struct aggr_port *p)
1931 {
1932 	aggr_set_selected(p, AGGR_PORT_SELECTED, LACP_MUX_E_SELECTED);
1933 }
1934 
1935 #ifdef notyet
1936 static inline void
aggr_standby(struct aggr_port * p)1937 aggr_standby(struct aggr_port *p)
1938 {
1939 	aggr_set_selected(p, AGGR_PORT_STANDBY, LACP_MUX_E_STANDBY);
1940 }
1941 #endif
1942 
1943 static void
aggr_selection_logic(struct aggr_softc * sc,struct aggr_port * p)1944 aggr_selection_logic(struct aggr_softc *sc, struct aggr_port *p)
1945 {
1946 	const struct lacp_port_info *pi;
1947 	struct arpcom *ac = &sc->sc_ac;
1948 	struct ifnet *ifp = &ac->ac_if;
1949 	const uint8_t *mac;
1950 
1951 	if (p->p_rxm_state != LACP_RXM_S_CURRENT) {
1952 		DPRINTF(sc, "%s %s: selection logic: unselected (rxm !%s)\n",
1953 		    ifp->if_xname, p->p_ifp0->if_xname,
1954 		    lacp_rxm_state_names[LACP_RXM_S_CURRENT]);
1955 		goto unselected;
1956 	}
1957 
1958 	pi = &p->p_partner;
1959 	if (pi->lacp_key == htons(0)) {
1960 		DPRINTF(sc, "%s %s: selection logic: unselected "
1961 		    "(partner key == 0)\n",
1962 		    ifp->if_xname, p->p_ifp0->if_xname);
1963 		goto unselected;
1964 	}
1965 
1966 	/*
1967 	 * aggr(4) does not support individual interfaces
1968 	 */
1969 	if (!ISSET(pi->lacp_state, LACP_STATE_AGGREGATION)) {
1970 		DPRINTF(sc, "%s %s: selection logic: unselected "
1971 		    "(partner state is Individual)\n",
1972 		    ifp->if_xname, p->p_ifp0->if_xname);
1973 		goto unselected;
1974 	}
1975 
1976 	/*
1977 	 * Any pair of Aggregation Ports that are members of the same
1978 	 * LAG, but are connected together by the same link, shall not
1979 	 * select the same Aggregator
1980 	 */
1981 
1982 	mac = pi->lacp_sysid.lacp_sysid_mac;
1983 	if (ETHER_IS_EQ(mac, ac->ac_enaddr) &&
1984 	    pi->lacp_key == htons(ifp->if_index)) {
1985 		DPRINTF(sc, "%s %s: selection logic: unselected "
1986 		    "(partner sysid !eq)\n",
1987 		    ifp->if_xname, p->p_ifp0->if_xname);
1988 		goto unselected;
1989 	}
1990 
1991 	if (!TAILQ_EMPTY(&sc->sc_muxen)) {
1992 		/* an aggregation has already been selected */
1993 		if (!ETHER_IS_EQ(mac, sc->sc_partner_system.lacp_sysid_mac) ||
1994 		    sc->sc_partner_key != pi->lacp_key) {
1995 			DPRINTF(sc, "%s %s: selection logic: unselected "
1996 			    "(partner sysid != selection)\n",
1997 			    ifp->if_xname, p->p_ifp0->if_xname);
1998 			goto unselected;
1999 		}
2000 	}
2001 
2002 	aggr_selected(p);
2003 	return;
2004 
2005 unselected:
2006 	aggr_unselected(p);
2007 }
2008 
2009 static void
aggr_mux(struct aggr_softc * sc,struct aggr_port * p,enum lacp_mux_event ev)2010 aggr_mux(struct aggr_softc *sc, struct aggr_port *p, enum lacp_mux_event ev)
2011 {
2012 	int ntt = 0;
2013 
2014 	/*
2015 	 * the mux can move through multiple states based on a
2016 	 * single event, so loop until the event is completely consumed.
2017 	 * debounce NTT = TRUE through the multiple state transitions.
2018 	 */
2019 
2020 	while (aggr_mux_ev(sc, p, ev, &ntt) != 0)
2021 		;
2022 
2023 	if (ntt)
2024 		aggr_ntt(p);
2025 }
2026 
2027 #ifdef notyet
2028 static int
aggr_ready_n(struct aggr_port * p)2029 aggr_ready_n(struct aggr_port *p)
2030 {
2031 	return (p->p_mux_state == LACP_MUX_S_WAITING &&
2032 	    !timeout_pending(&p->p_wait_while_timer));
2033 }
2034 #endif
2035 
2036 static inline int
aggr_ready(struct aggr_softc * sc)2037 aggr_ready(struct aggr_softc *sc)
2038 {
2039 	return (1);
2040 }
2041 
2042 static void
aggr_disable_distributing(struct aggr_softc * sc,struct aggr_port * p)2043 aggr_disable_distributing(struct aggr_softc *sc, struct aggr_port *p)
2044 {
2045 	if (!p->p_distributing)
2046 		return;
2047 
2048 	sc->sc_ndistributing--;
2049 	TAILQ_REMOVE(&sc->sc_distributing, p, p_entry_distributing);
2050 	p->p_distributing = 0;
2051 
2052 	aggr_map(sc);
2053 
2054 	DPRINTF(sc, "%s %s: distributing disabled\n",
2055 	    sc->sc_if.if_xname, p->p_ifp0->if_xname);
2056 }
2057 
2058 static void
aggr_enable_distributing(struct aggr_softc * sc,struct aggr_port * p)2059 aggr_enable_distributing(struct aggr_softc *sc, struct aggr_port *p)
2060 {
2061 	if (p->p_distributing)
2062 		return;
2063 
2064 	/* check the LAG ID? */
2065 
2066 	p->p_distributing = 1;
2067 	TAILQ_INSERT_TAIL(&sc->sc_distributing, p, p_entry_distributing);
2068 	sc->sc_ndistributing++;
2069 
2070 	aggr_map(sc);
2071 
2072 	DPRINTF(sc, "%s %s: distributing enabled\n",
2073 	    sc->sc_if.if_xname, p->p_ifp0->if_xname);
2074 }
2075 
2076 static void
aggr_disable_collecting(struct aggr_softc * sc,struct aggr_port * p)2077 aggr_disable_collecting(struct aggr_softc *sc, struct aggr_port *p)
2078 {
2079 	if (!p->p_collecting)
2080 		return;
2081 
2082 	p->p_collecting = 0;
2083 
2084 	DPRINTF(sc, "%s %s: collecting disabled\n",
2085 	    sc->sc_if.if_xname, p->p_ifp0->if_xname);
2086 }
2087 
2088 static void
aggr_enable_collecting(struct aggr_softc * sc,struct aggr_port * p)2089 aggr_enable_collecting(struct aggr_softc *sc, struct aggr_port *p)
2090 {
2091 	if (p->p_collecting)
2092 		return;
2093 
2094 	p->p_collecting = 1;
2095 
2096 	DPRINTF(sc, "%s %s: collecting enabled\n",
2097 	    sc->sc_if.if_xname, p->p_ifp0->if_xname);
2098 }
2099 
2100 static void
aggr_attach_mux(struct aggr_softc * sc,struct aggr_port * p)2101 aggr_attach_mux(struct aggr_softc *sc, struct aggr_port *p)
2102 {
2103 	const struct lacp_port_info *pi = &p->p_partner;
2104 
2105 	if (p->p_muxed)
2106 		return;
2107 
2108 	p->p_muxed = 1;
2109 	if (TAILQ_EMPTY(&sc->sc_muxen)) {
2110 		KASSERT(sc->sc_partner_key == htons(0));
2111 		sc->sc_partner_system = pi->lacp_sysid;
2112 		sc->sc_partner_key = pi->lacp_key;
2113 	}
2114 
2115 	TAILQ_INSERT_TAIL(&sc->sc_muxen, p, p_entry_muxen);
2116 
2117 	DPRINTF(sc, "%s %s: mux attached\n",
2118 	    sc->sc_if.if_xname, p->p_ifp0->if_xname);
2119 }
2120 
2121 static void
aggr_detach_mux(struct aggr_softc * sc,struct aggr_port * p)2122 aggr_detach_mux(struct aggr_softc *sc, struct aggr_port *p)
2123 {
2124 	if (!p->p_muxed)
2125 		return;
2126 
2127 	p->p_muxed = 0;
2128 
2129 	TAILQ_REMOVE(&sc->sc_muxen, p, p_entry_muxen);
2130 	if (TAILQ_EMPTY(&sc->sc_muxen)) {
2131 		memset(&sc->sc_partner_system.lacp_sysid_mac, 0,
2132 		    sizeof(sc->sc_partner_system.lacp_sysid_mac));
2133 		sc->sc_partner_system.lacp_sysid_priority = htons(0);
2134 		sc->sc_partner_key = htons(0);
2135 	}
2136 
2137 	DPRINTF(sc, "%s %s: mux detached\n",
2138 	    sc->sc_if.if_xname, p->p_ifp0->if_xname);
2139 }
2140 
2141 static int
aggr_mux_ev(struct aggr_softc * sc,struct aggr_port * p,enum lacp_mux_event ev,int * ntt)2142 aggr_mux_ev(struct aggr_softc *sc, struct aggr_port *p, enum lacp_mux_event ev,
2143     int *ntt)
2144 {
2145 	enum lacp_mux_state nstate = LACP_MUX_S_DETACHED;
2146 
2147 	switch (p->p_mux_state) {
2148 	case LACP_MUX_S_BEGIN:
2149 		KASSERT(ev == LACP_MUX_E_BEGIN);
2150 		nstate = LACP_MUX_S_DETACHED;
2151 		break;
2152 	case LACP_MUX_S_DETACHED:
2153 		switch (ev) {
2154 		case LACP_MUX_E_SELECTED:
2155 		case LACP_MUX_E_STANDBY:
2156 			nstate = LACP_MUX_S_WAITING;
2157 			break;
2158 		default:
2159 			return (0);
2160 		}
2161 		break;
2162 	case LACP_MUX_S_WAITING:
2163 		switch (ev) {
2164 		case LACP_MUX_E_UNSELECTED:
2165 			nstate = LACP_MUX_S_DETACHED;
2166 			break;
2167 		case LACP_MUX_E_SELECTED:
2168 		case LACP_MUX_E_READY:
2169 			if (aggr_ready(sc) &&
2170 			    p->p_selected == AGGR_PORT_SELECTED) {
2171 				nstate = LACP_MUX_S_ATTACHED;
2172 				break;
2173 			}
2174 			/* FALLTHROUGH */
2175 		default:
2176 			return (0);
2177 		}
2178 		break;
2179 	case LACP_MUX_S_ATTACHED:
2180 		switch (ev) {
2181 		case LACP_MUX_E_UNSELECTED:
2182 		case LACP_MUX_E_STANDBY:
2183 			nstate = LACP_MUX_S_DETACHED;
2184 			break;
2185 		case LACP_MUX_E_SELECTED:
2186 		case LACP_MUX_E_SYNC:
2187 			if (p->p_selected == AGGR_PORT_SELECTED &&
2188 			    ISSET(p->p_partner_state, LACP_STATE_SYNC)) {
2189 				nstate = LACP_MUX_S_COLLECTING;
2190 				break;
2191 			}
2192 			/* FALLTHROUGH */
2193 		default:
2194 			return (0);
2195 		}
2196 		break;
2197 	case LACP_MUX_S_COLLECTING:
2198 		switch (ev) {
2199 		case LACP_MUX_E_UNSELECTED:
2200 		case LACP_MUX_E_STANDBY:
2201 		case LACP_MUX_E_NOT_SYNC:
2202 			nstate = LACP_MUX_S_ATTACHED;
2203 			break;
2204 		case LACP_MUX_E_SELECTED:
2205 		case LACP_MUX_E_SYNC:
2206 		case LACP_MUX_E_COLLECTING:
2207 			if (p->p_selected == AGGR_PORT_SELECTED &&
2208 			    ISSET(p->p_partner_state, LACP_STATE_SYNC) &&
2209 			    ISSET(p->p_partner_state, LACP_STATE_COLLECTING)) {
2210 				nstate = LACP_MUX_S_DISTRIBUTING;
2211 				break;
2212 			}
2213 			/* FALLTHROUGH */
2214 		default:
2215 			return (0);
2216 		}
2217 		break;
2218 	case LACP_MUX_S_DISTRIBUTING:
2219 		switch (ev) {
2220 		case LACP_MUX_E_UNSELECTED:
2221 		case LACP_MUX_E_STANDBY:
2222 		case LACP_MUX_E_NOT_SYNC:
2223 		case LACP_MUX_E_NOT_COLLECTING:
2224 			nstate = LACP_MUX_S_COLLECTING;
2225 			break;
2226 		default:
2227 			return (0);
2228 		}
2229 		break;
2230 	}
2231 
2232 	DPRINTF(sc, "%s %s mux: %s (%s) -> %s\n",
2233 	    sc->sc_if.if_xname, p->p_ifp0->if_xname,
2234 	    lacp_mux_state_names[p->p_mux_state], lacp_mux_event_names[ev],
2235 	    lacp_mux_state_names[nstate]);
2236 
2237 	/* act on the new state */
2238 	switch (nstate) {
2239 	case LACP_MUX_S_BEGIN:
2240 		panic("unexpected mux nstate BEGIN");
2241 		/* NOTREACHED */
2242 	case LACP_MUX_S_DETACHED:
2243 		/*
2244 		 * Detach_Mux_From_Aggregator();
2245 		 * Actor.Sync = FALSE;
2246 		 * Disable_Distributing();
2247 		 * Actor.Distributing = FALSE;
2248 		 * Actor.Collecting = FALSE;
2249 		 * Disable_Collecting();
2250 		 * NTT = TRUE;
2251 		 */
2252 		aggr_detach_mux(sc, p);
2253 		CLR(p->p_actor_state, LACP_STATE_SYNC);
2254 		aggr_disable_distributing(sc, p);
2255 		CLR(p->p_actor_state, LACP_STATE_DISTRIBUTING);
2256 		CLR(p->p_actor_state, LACP_STATE_COLLECTING);
2257 		aggr_disable_collecting(sc, p);
2258 		*ntt = 1;
2259 		break;
2260 	case LACP_MUX_S_WAITING:
2261 		/*
2262 		 * Start wait_while_timer
2263 		 */
2264 		timeout_add_sec(&p->p_wait_while_timer,
2265 		    LACP_AGGREGATION_WAIT_TIME);
2266 		break;
2267 	case LACP_MUX_S_ATTACHED:
2268 		/*
2269 		 * Attach_Mux_To_Aggregator();
2270 		 * Actor.Sync = TRUE;
2271 		 * Actor.Collecting = FALSE;
2272 		 * Disable_Collecting();
2273 		 * NTT = TRUE;
2274 		 */
2275 		aggr_attach_mux(sc, p);
2276 		SET(p->p_actor_state, LACP_STATE_SYNC);
2277 		CLR(p->p_actor_state, LACP_STATE_COLLECTING);
2278 		aggr_disable_collecting(sc, p);
2279 		*ntt = 1;
2280 		break;
2281 
2282 	case LACP_MUX_S_COLLECTING:
2283 		/*
2284 		 * Enable_Collecting();
2285 		 * Actor.Collecting = TRUE;
2286 		 * Disable_Distributing();
2287 		 * Actor.Distributing = FALSE;
2288 		 * NTT = TRUE;
2289 		 */
2290 		aggr_enable_collecting(sc, p);
2291 		SET(p->p_actor_state, LACP_STATE_COLLECTING);
2292 		aggr_disable_distributing(sc, p);
2293 		CLR(p->p_actor_state, LACP_STATE_DISTRIBUTING);
2294 		*ntt = 1;
2295 		break;
2296 	case LACP_MUX_S_DISTRIBUTING:
2297 		/*
2298 		 * Actor.Distributing = TRUE;
2299 		 * Enable_Distributing();
2300 		 */
2301 		SET(p->p_actor_state, LACP_STATE_DISTRIBUTING);
2302 		aggr_enable_distributing(sc, p);
2303 		break;
2304 	}
2305 
2306 	p->p_mux_state = nstate;
2307 
2308 	return (1);
2309 }
2310 
2311 static void
aggr_rxm_ev(struct aggr_softc * sc,struct aggr_port * p,enum lacp_rxm_event ev,const struct lacp_du * lacpdu)2312 aggr_rxm_ev(struct aggr_softc *sc, struct aggr_port *p,
2313     enum lacp_rxm_event ev, const struct lacp_du *lacpdu)
2314 {
2315 	unsigned int port_disabled = 0;
2316 	enum lacp_rxm_state nstate = LACP_RXM_S_BEGIN;
2317 
2318 	KASSERT((ev == LACP_RXM_E_LACPDU) == (lacpdu != NULL));
2319 
2320 	/* global transitions */
2321 
2322 	switch (ev) {
2323 	case LACP_RXM_E_NOT_PORT_ENABLED:
2324 		port_disabled = !aggr_port_moved(sc, p);
2325 		break;
2326 	case LACP_RXM_E_NOT_PORT_MOVED:
2327 		port_disabled = !aggr_port_enabled(p);
2328 		break;
2329 	default:
2330 		break;
2331 	}
2332 
2333 	if (port_disabled)
2334 		nstate = LACP_RXM_S_PORT_DISABLED;
2335 	else switch (p->p_rxm_state) { /* local state transitions */
2336 	case LACP_RXM_S_BEGIN:
2337 		KASSERT(ev == LACP_RXM_E_BEGIN);
2338 		nstate = LACP_RXM_S_INITIALIZE;
2339 		break;
2340 	case LACP_RXM_S_INITIALIZE:
2341 		/* this should only be handled via UCT in nstate handling */
2342 		panic("unexpected rxm state INITIALIZE");
2343 
2344 	case LACP_RXM_S_PORT_DISABLED:
2345 		switch (ev) {
2346 		case LACP_RXM_E_PORT_MOVED:
2347 			nstate = LACP_RXM_S_INITIALIZE;
2348 			break;
2349 		case LACP_RXM_E_PORT_ENABLED:
2350 			nstate = aggr_lacp_enabled(sc) ?
2351 			    LACP_RXM_S_EXPIRED : LACP_RXM_S_LACP_DISABLED;
2352 			break;
2353 		case LACP_RXM_E_LACP_ENABLED:
2354 			if (!aggr_port_enabled(p))
2355 				return;
2356 			nstate = LACP_RXM_S_EXPIRED;
2357 			break;
2358 		case LACP_RXM_E_NOT_LACP_ENABLED:
2359 			if (!aggr_port_enabled(p))
2360 				return;
2361 			nstate = LACP_RXM_S_LACP_DISABLED;
2362 			break;
2363 		default:
2364 			return;
2365 		}
2366 		break;
2367 	case LACP_RXM_S_EXPIRED:
2368 		switch (ev) {
2369 		case LACP_RXM_E_LACPDU:
2370 			nstate = LACP_RXM_S_CURRENT;
2371 			break;
2372 		case LACP_RXM_E_TIMER_EXPIRED:
2373 			nstate = LACP_RXM_S_DEFAULTED;
2374 			break;
2375 		default:
2376 			return;
2377 		}
2378 		break;
2379 	case LACP_RXM_S_LACP_DISABLED:
2380 		switch (ev) {
2381 		case LACP_RXM_E_LACP_ENABLED:
2382 			nstate = LACP_RXM_S_PORT_DISABLED;
2383 			break;
2384 		default:
2385 			return;
2386 		}
2387 		break;
2388 	case LACP_RXM_S_DEFAULTED:
2389 		switch (ev) {
2390 		case LACP_RXM_E_LACPDU:
2391 			nstate = LACP_RXM_S_CURRENT;
2392 			break;
2393 		default:
2394 			return;
2395 		}
2396 		break;
2397 	case LACP_RXM_S_CURRENT:
2398 		switch (ev) {
2399 		case LACP_RXM_E_TIMER_EXPIRED:
2400 			nstate = LACP_RXM_S_EXPIRED;
2401 			break;
2402 		case LACP_RXM_E_LACPDU:
2403 			nstate = LACP_RXM_S_CURRENT;
2404 			break;
2405 		default:
2406 			return;
2407 		}
2408 		break;
2409 	}
2410 
2411 uct:
2412 	if (p->p_rxm_state != nstate) {
2413 		DPRINTF(sc, "%s %s rxm: %s (%s) -> %s\n",
2414 		    sc->sc_if.if_xname, p->p_ifp0->if_xname,
2415 		    lacp_rxm_state_names[p->p_rxm_state],
2416 		    lacp_rxm_event_names[ev],
2417 		    lacp_rxm_state_names[nstate]);
2418 	}
2419 
2420 	/* record the new state */
2421 	p->p_rxm_state = nstate;
2422 
2423 	/* act on the new state */
2424 	switch (nstate) {
2425 	case LACP_RXM_S_BEGIN:
2426 		panic("unexpected rxm nstate BEGIN");
2427 		/* NOTREACHED */
2428 	case LACP_RXM_S_INITIALIZE:
2429 		/*
2430 		 * Selected = UNSELECTED;
2431 		 * recordDefault();
2432 		 * Actor_Oper_Port_State.Expired = FALSE;
2433 		 * port_moved = FALSE;
2434 		 */
2435 		aggr_unselected(p);
2436 		aggr_record_default(sc, p);
2437 		CLR(p->p_actor_state, LACP_STATE_EXPIRED);
2438 
2439 		ev = LACP_RXM_E_UCT;
2440 		nstate = LACP_RXM_S_PORT_DISABLED;
2441 		goto uct;
2442 		/* NOTREACHED */
2443 	case LACP_RXM_S_PORT_DISABLED:
2444 		/*
2445 		 * Partner_Oper_Port_State.Synchronization = FALSE;
2446 		 */
2447 		CLR(p->p_partner_state, LACP_STATE_SYNC);
2448 		aggr_mux(sc, p, LACP_MUX_E_NOT_SYNC);
2449 		break;
2450 	case LACP_RXM_S_EXPIRED:
2451 		/*
2452 		 * Partner_Oper_Port_State.Synchronization = FALSE;
2453 		 * Partner_Oper_Port_State.LACP_Timeout = Short Timeout;
2454 		 * start current_while_timer(Short Timeout);
2455 		 * Actor_Oper_Port_State.Expired = TRUE;
2456 		 */
2457 
2458 		CLR(p->p_partner_state, LACP_STATE_SYNC);
2459 		aggr_mux(sc, p, LACP_MUX_E_NOT_SYNC);
2460 		aggr_set_partner_timeout(p, AGGR_LACP_TIMEOUT_FAST);
2461 		aggr_start_current_while_timer(p, AGGR_LACP_TIMEOUT_FAST);
2462 		SET(p->p_actor_state, LACP_STATE_EXPIRED);
2463 
2464 		break;
2465 	case LACP_RXM_S_LACP_DISABLED:
2466 		/*
2467 		 * Selected = UNSELECTED;
2468 		 * recordDefault();
2469 		 * Partner_Oper_Port_State.Aggregation = FALSE;
2470 		 * Actor_Oper_Port_State.Expired = FALSE;
2471 		 */
2472 		aggr_unselected(p);
2473 		aggr_record_default(sc, p);
2474 		CLR(p->p_partner_state, LACP_STATE_AGGREGATION);
2475 		CLR(p->p_actor_state, LACP_STATE_EXPIRED);
2476 		break;
2477 	case LACP_RXM_S_DEFAULTED:
2478 		/*
2479 		 * update_Default_Selected();
2480 		 * recordDefault();
2481 		 * Actor_Oper_Port_State.Expired = FALSE;
2482 		 */
2483 		aggr_update_default_selected(sc, p);
2484 		aggr_record_default(sc, p);
2485 		CLR(p->p_actor_state, LACP_STATE_EXPIRED);
2486 		break;
2487 	case LACP_RXM_S_CURRENT: {
2488 		/*
2489 		 * update_Selected();
2490 		 * update_NTT();
2491 		 * if (Actor_System_LACP_Version >=2 ) recordVersionNumber();
2492 		 * recordPDU();
2493 		 * start current_while_timer(
2494 		 *     Actor_Oper_Port_State.LACP_Timeout);
2495 		 * Actor_Oper_Port_State.Expired = FALSE;
2496 		 */
2497 		int sync;
2498 
2499 		aggr_update_selected(sc, p, lacpdu);
2500 		sync = aggr_update_ntt(p, lacpdu);
2501 		/* don't support v2 yet */
2502 		aggr_recordpdu(p, lacpdu, sync);
2503 		aggr_start_current_while_timer(p, sc->sc_lacp_timeout);
2504 		CLR(p->p_actor_state, LACP_STATE_EXPIRED);
2505 
2506 		if (p->p_selected == AGGR_PORT_UNSELECTED)
2507 			aggr_selection_logic(sc, p); /* restart */
2508 
2509 		}
2510 		break;
2511 	}
2512 }
2513 
2514 static int
aggr_up(struct aggr_softc * sc)2515 aggr_up(struct aggr_softc *sc)
2516 {
2517 	struct ifnet *ifp = &sc->sc_if;
2518 	struct aggr_port *p;
2519 
2520 	NET_ASSERT_LOCKED();
2521 	KASSERT(!ISSET(ifp->if_flags, IFF_RUNNING));
2522 
2523 	SET(ifp->if_flags, IFF_RUNNING); /* LACP_Enabled = TRUE */
2524 
2525 	TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
2526 		aggr_rxm(sc, p, LACP_RXM_E_LACP_ENABLED);
2527 		aggr_p_linkch(p);
2528 	}
2529 
2530 	/* start the Periodic Transmission machine */
2531 	if (sc->sc_lacp_mode == AGGR_LACP_MODE_ACTIVE) {
2532 		TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
2533 			if (!aggr_port_enabled(p))
2534 				continue;
2535 
2536 			timeout_add_sec(&p->p_ptm_tx,
2537 			    aggr_periodic_times[sc->sc_lacp_timeout]);
2538 		}
2539 	}
2540 
2541 	return (ENETRESET);
2542 }
2543 
2544 static int
aggr_iff(struct aggr_softc * sc)2545 aggr_iff(struct aggr_softc *sc)
2546 {
2547 	struct ifnet *ifp = &sc->sc_if;
2548 	unsigned int promisc = ISSET(ifp->if_flags, IFF_PROMISC);
2549 
2550 	NET_ASSERT_LOCKED();
2551 
2552 	if (promisc != sc->sc_promisc) {
2553 		struct aggr_port *p;
2554 
2555 		rw_enter_read(&sc->sc_lock);
2556 		TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
2557 			struct ifnet *ifp0 = p->p_ifp0;
2558 			if (ifpromisc(ifp0, promisc) != 0) {
2559 				log(LOG_WARNING, "%s iff %s: "
2560 				    "unable to turn promisc %s\n",
2561 				    ifp->if_xname, ifp0->if_xname,
2562 				    promisc ? "on" : "off");
2563 			}
2564 		}
2565 		rw_exit_read(&sc->sc_lock);
2566 
2567 		sc->sc_promisc = promisc;
2568 	}
2569 
2570 	return (0);
2571 }
2572 
2573 static int
aggr_down(struct aggr_softc * sc)2574 aggr_down(struct aggr_softc *sc)
2575 {
2576 	struct ifnet *ifp = &sc->sc_if;
2577 	struct aggr_port *p;
2578 
2579 	NET_ASSERT_LOCKED();
2580 	CLR(ifp->if_flags, IFF_RUNNING); /* LACP_Enabled = FALSE */
2581 
2582 	TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
2583 		aggr_rxm(sc, p, LACP_RXM_E_NOT_LACP_ENABLED);
2584 
2585 		/* stop the Periodic Transmission machine */
2586 		timeout_del(&p->p_ptm_tx);
2587 
2588 		/* stop the Mux machine */
2589 		aggr_mux(sc, p, LACP_MUX_E_UNSELECTED);
2590 
2591 		/* stop the Transmit machine */
2592 		timeout_del(&p->p_txm_ntt);
2593 	}
2594 
2595 	KASSERT(TAILQ_EMPTY(&sc->sc_distributing));
2596 	KASSERT(sc->sc_ndistributing == 0);
2597 	KASSERT(SMR_PTR_GET_LOCKED(&sc->sc_map) == NULL);
2598 
2599 	return (ENETRESET);
2600 }
2601 
2602 static int
aggr_set_lladdr(struct aggr_softc * sc,const struct ifreq * ifr)2603 aggr_set_lladdr(struct aggr_softc *sc, const struct ifreq *ifr)
2604 {
2605 	struct ifnet *ifp = &sc->sc_if;
2606 	struct aggr_port *p;
2607 	const uint8_t *lladdr = ifr->ifr_addr.sa_data;
2608 
2609 	rw_enter_read(&sc->sc_lock);
2610 	TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
2611 		if (aggr_p_setlladdr(p, lladdr) != 0) {
2612 			struct ifnet *ifp0 = p->p_ifp0;
2613 			log(LOG_WARNING, "%s setlladdr %s: "
2614 			    "unable to set lladdr\n",
2615 			    ifp->if_xname, ifp0->if_xname);
2616 		}
2617 	}
2618 	rw_exit_read(&sc->sc_lock);
2619 
2620 	return (0);
2621 }
2622 
2623 static int
aggr_set_mtu(struct aggr_softc * sc,uint32_t mtu)2624 aggr_set_mtu(struct aggr_softc *sc, uint32_t mtu)
2625 {
2626 	struct ifnet *ifp = &sc->sc_if;
2627 	struct aggr_port *p;
2628 
2629 	if (mtu < ETHERMIN || mtu > ifp->if_hardmtu)
2630 		return (EINVAL);
2631 
2632 	ifp->if_mtu = mtu;
2633 
2634 	TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
2635 		if (aggr_p_set_mtu(p, mtu) != 0) {
2636 			struct ifnet *ifp0 = p->p_ifp0;
2637 			log(LOG_WARNING, "%s %s: unable to set mtu %u\n",
2638 			    ifp->if_xname, ifp0->if_xname, mtu);
2639 		}
2640 	}
2641 
2642 	return (0);
2643 }
2644 
2645 static int
aggr_group(struct aggr_softc * sc,struct aggr_port * p,u_long cmd)2646 aggr_group(struct aggr_softc *sc, struct aggr_port *p, u_long cmd)
2647 {
2648 	struct ifnet *ifp0 = p->p_ifp0;
2649 	struct ifreq ifr;
2650 	struct sockaddr *sa;
2651 
2652 	memset(&ifr, 0, sizeof(ifr));
2653 
2654 	/* make it convincing */
2655 	CTASSERT(sizeof(ifr.ifr_name) == sizeof(ifp0->if_xname));
2656 	memcpy(ifr.ifr_name, ifp0->if_xname, sizeof(ifr.ifr_name));
2657 
2658 	sa = &ifr.ifr_addr;
2659 	CTASSERT(sizeof(sa->sa_data) >= sizeof(lacp_address_slow));
2660 
2661 	sa->sa_family = AF_UNSPEC;
2662 	memcpy(sa->sa_data, lacp_address_slow, sizeof(lacp_address_slow));
2663 
2664 	return ((*p->p_ioctl)(ifp0, cmd, (caddr_t)&ifr));
2665 }
2666 
2667 static int
aggr_multi(struct aggr_softc * sc,struct aggr_port * p,const struct aggr_multiaddr * ma,u_long cmd)2668 aggr_multi(struct aggr_softc *sc, struct aggr_port *p,
2669     const struct aggr_multiaddr *ma, u_long cmd)
2670 {
2671 	struct ifnet *ifp0 = p->p_ifp0;
2672 	struct {
2673 		char			if_name[IFNAMSIZ];
2674 		struct sockaddr_storage if_addr;
2675 	} ifr;
2676 
2677 	memset(&ifr, 0, sizeof(ifr));
2678 
2679 	/* make it convincing */
2680 	CTASSERT(sizeof(ifr.if_name) == sizeof(ifp0->if_xname));
2681 	memcpy(ifr.if_name, ifp0->if_xname, sizeof(ifr.if_name));
2682 
2683 	ifr.if_addr = ma->m_addr;
2684 
2685 	return ((*p->p_ioctl)(ifp0, cmd, (caddr_t)&ifr));
2686 }
2687 
2688 static void
aggr_media_status(struct ifnet * ifp,struct ifmediareq * imr)2689 aggr_media_status(struct ifnet *ifp, struct ifmediareq *imr)
2690 {
2691 	struct aggr_softc *sc = ifp->if_softc;
2692 
2693 	imr->ifm_status = IFM_AVALID;
2694 	imr->ifm_active = IFM_ETHER | IFM_AUTO;
2695 
2696 	smr_read_enter(); /* there's no reason to block... */
2697 	if (SMR_PTR_GET(&sc->sc_map) != NULL)
2698 		imr->ifm_status |= IFM_ACTIVE;
2699 	smr_read_leave();
2700 }
2701 
2702 static int
aggr_media_change(struct ifnet * ifp)2703 aggr_media_change(struct ifnet *ifp)
2704 {
2705 	return (EOPNOTSUPP);
2706 }
2707 
2708 static void
aggr_update_capabilities(struct aggr_softc * sc)2709 aggr_update_capabilities(struct aggr_softc *sc)
2710 {
2711 	struct aggr_port *p;
2712 	uint32_t hardmtu = ETHER_MAX_HARDMTU_LEN;
2713 	uint32_t capabilities = ~0;
2714 	int set = 0;
2715 
2716 	/* Do not inherit LRO capabilities. */
2717 	CLR(capabilities, IFCAP_LRO);
2718 
2719 	rw_enter_read(&sc->sc_lock);
2720 	TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
2721 		struct ifnet *ifp0 = p->p_ifp0;
2722 
2723 		set = 1;
2724 		capabilities &= ifp0->if_capabilities;
2725 		if (ifp0->if_hardmtu < hardmtu)
2726 			hardmtu = ifp0->if_hardmtu;
2727 	}
2728 	rw_exit_read(&sc->sc_lock);
2729 
2730 	sc->sc_if.if_hardmtu = hardmtu;
2731 	sc->sc_if.if_capabilities = (set ? capabilities : 0);
2732 }
2733 
2734 static void
aggr_ptm_tx(void * arg)2735 aggr_ptm_tx(void *arg)
2736 {
2737 	struct aggr_port *p = arg;
2738 	unsigned int timeout;
2739 
2740 	aggr_ntt(p);
2741 
2742 	timeout = ISSET(p->p_partner_state, LACP_STATE_TIMEOUT) ?
2743 	    AGGR_LACP_TIMEOUT_FAST : AGGR_LACP_TIMEOUT_SLOW;
2744 	timeout_add_sec(&p->p_ptm_tx, aggr_periodic_times[timeout]);
2745 }
2746 
2747 static inline void
aggr_lacp_tlv_set(struct lacp_tlv_hdr * tlv,uint8_t type,uint8_t len)2748 aggr_lacp_tlv_set(struct lacp_tlv_hdr *tlv, uint8_t type, uint8_t len)
2749 {
2750 	tlv->lacp_tlv_type = type;
2751 	tlv->lacp_tlv_length = sizeof(*tlv) + len;
2752 }
2753 
2754 static void
aggr_ntt_transmit(struct aggr_port * p)2755 aggr_ntt_transmit(struct aggr_port *p)
2756 {
2757 	struct aggr_softc *sc = p->p_aggr;
2758 	struct arpcom *ac = &sc->sc_ac;
2759 	struct ifnet *ifp = &sc->sc_if;
2760 	struct ifnet *ifp0 = p->p_ifp0;
2761 	struct mbuf *m;
2762 	struct lacp_du *lacpdu;
2763 	struct lacp_port_info *pi;
2764 	struct lacp_collector_info *ci;
2765 	struct ether_header *eh;
2766 	int linkhdr = max_linkhdr + ETHER_ALIGN;
2767 	int len = linkhdr + sizeof(*eh) + sizeof(*lacpdu);
2768 
2769 	m = m_gethdr(M_DONTWAIT, MT_DATA);
2770 	if (m == NULL)
2771 		return;
2772 
2773 	if (len > MHLEN) {
2774 		MCLGETL(m, M_DONTWAIT, len);
2775 		if (!ISSET(m->m_flags, M_EXT)) {
2776 			m_freem(m);
2777 			return;
2778 		}
2779 	}
2780 
2781 	m->m_pkthdr.pf.prio = sc->sc_if.if_llprio;
2782 	m->m_pkthdr.len = m->m_len = len;
2783 	memset(m->m_data, 0, m->m_len);
2784 	m_adj(m, linkhdr);
2785 
2786 	eh = mtod(m, struct ether_header *);
2787 
2788 	CTASSERT(sizeof(eh->ether_dhost) == sizeof(lacp_address_slow));
2789 	CTASSERT(sizeof(eh->ether_shost) == sizeof(ac->ac_enaddr));
2790 
2791 	memcpy(eh->ether_dhost, lacp_address_slow, sizeof(eh->ether_dhost));
2792 	memcpy(eh->ether_shost, ac->ac_enaddr, sizeof(eh->ether_shost));
2793 	eh->ether_type = htons(ETHERTYPE_SLOW);
2794 
2795 	lacpdu = (struct lacp_du *)(eh + 1);
2796 	lacpdu->lacp_du_sph.sph_subtype = SLOWPROTOCOLS_SUBTYPE_LACP;
2797 	lacpdu->lacp_du_sph.sph_version = LACP_VERSION;
2798 
2799 	pi = &lacpdu->lacp_actor_info;
2800 	aggr_lacp_tlv_set(&lacpdu->lacp_actor_info_tlv,
2801 	    LACP_T_ACTOR, sizeof(*pi));
2802 
2803 	pi->lacp_sysid.lacp_sysid_priority = htons(sc->sc_lacp_prio);
2804 	CTASSERT(sizeof(pi->lacp_sysid.lacp_sysid_mac) ==
2805 	    sizeof(ac->ac_enaddr));
2806 	memcpy(pi->lacp_sysid.lacp_sysid_mac, ac->ac_enaddr,
2807 	    sizeof(pi->lacp_sysid.lacp_sysid_mac));
2808 
2809 	pi->lacp_key = htons(ifp->if_index);
2810 
2811 	pi->lacp_portid.lacp_portid_priority = htons(sc->sc_lacp_port_prio);
2812 	pi->lacp_portid.lacp_portid_number = htons(ifp0->if_index);
2813 
2814 	pi->lacp_state = p->p_actor_state;
2815 	if (sc->sc_lacp_mode)
2816 		SET(pi->lacp_state, LACP_STATE_ACTIVITY);
2817 	if (sc->sc_lacp_timeout)
2818 		SET(pi->lacp_state, LACP_STATE_TIMEOUT);
2819 
2820 	pi = &lacpdu->lacp_partner_info;
2821 	aggr_lacp_tlv_set(&lacpdu->lacp_partner_info_tlv,
2822 	    LACP_T_PARTNER, sizeof(*pi));
2823 
2824 	*pi = p->p_partner;
2825 
2826 	ci = &lacpdu->lacp_collector_info;
2827 	aggr_lacp_tlv_set(&lacpdu->lacp_collector_info_tlv,
2828 	    LACP_T_COLLECTOR, sizeof(*ci));
2829 	ci->lacp_maxdelay = htons(0);
2830 
2831 	lacpdu->lacp_terminator.lacp_tlv_type = LACP_T_TERMINATOR;
2832 	lacpdu->lacp_terminator.lacp_tlv_length = 0;
2833 
2834 	mtx_enter(&p->p_mtx);
2835 	p->p_proto_counts[AGGR_PROTO_TX_LACP].c_pkts++;
2836 	p->p_proto_counts[AGGR_PROTO_TX_LACP].c_bytes += m->m_pkthdr.len;
2837 	mtx_leave(&p->p_mtx);
2838 
2839 	(void)if_enqueue(ifp0, m);
2840 }
2841 
2842 static void
aggr_ntt(struct aggr_port * p)2843 aggr_ntt(struct aggr_port *p)
2844 {
2845 	if (!timeout_pending(&p->p_txm_ntt))
2846 		timeout_add(&p->p_txm_ntt, 0);
2847 }
2848 
2849 static void
aggr_transmit_machine(void * arg)2850 aggr_transmit_machine(void *arg)
2851 {
2852 	struct aggr_port *p = arg;
2853 	struct aggr_softc *sc = p->p_aggr;
2854 	unsigned int slot;
2855 	int *log;
2856 	int period = hz * LACP_FAST_PERIODIC_TIME;
2857 	int diff;
2858 
2859 	if (!aggr_lacp_enabled(sc) || !aggr_port_enabled(p))
2860 		return;
2861 
2862 	slot = p->p_txm_slot;
2863 	log = &p->p_txm_log[slot % nitems(p->p_txm_log)];
2864 
2865 	diff = ticks - *log;
2866 	if (diff < period) {
2867 		timeout_add(&p->p_txm_ntt, period - diff);
2868 		return;
2869 	}
2870 
2871 	*log = ticks;
2872 	p->p_txm_slot = ++slot;
2873 
2874 #if 0
2875 	DPRINTF(sc, "%s %s ntt\n", sc->sc_if.if_xname, p->p_ifp0->if_xname);
2876 #endif
2877 
2878 	aggr_ntt_transmit(p);
2879 }
2880 
2881 static void
aggr_set_lacp_mode(struct aggr_softc * sc,int mode)2882 aggr_set_lacp_mode(struct aggr_softc *sc, int mode)
2883 {
2884 	sc->sc_lacp_mode = mode;
2885 
2886 	if (mode == AGGR_LACP_MODE_PASSIVE) {
2887 		struct aggr_port *p;
2888 
2889 		TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
2890 			if (!ISSET(p->p_partner_state, LACP_STATE_ACTIVITY))
2891 				timeout_del(&p->p_ptm_tx);
2892 		}
2893 	}
2894 }
2895 
2896 static void
aggr_set_partner_timeout(struct aggr_port * p,int timeout)2897 aggr_set_partner_timeout(struct aggr_port *p, int timeout)
2898 {
2899 	uint8_t ostate = ISSET(p->p_partner_state, LACP_STATE_TIMEOUT);
2900 	uint8_t nstate = (timeout == AGGR_LACP_TIMEOUT_FAST) ?
2901 	    LACP_STATE_TIMEOUT : 0;
2902 
2903 	if (ostate == nstate)
2904 		return;
2905 
2906 	if (timeout == AGGR_LACP_TIMEOUT_FAST) {
2907 		SET(p->p_partner_state, LACP_STATE_TIMEOUT);
2908 		timeout_add_sec(&p->p_ptm_tx,
2909 		    aggr_periodic_times[AGGR_LACP_TIMEOUT_FAST]);
2910 	} else
2911 		CLR(p->p_partner_state, LACP_STATE_TIMEOUT);
2912 }
2913 
2914 static void
aggr_set_lacp_timeout(struct aggr_softc * sc,int timeout)2915 aggr_set_lacp_timeout(struct aggr_softc *sc, int timeout)
2916 {
2917 	struct aggr_port *p;
2918 
2919 	sc->sc_lacp_timeout = timeout;
2920 
2921 	TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
2922 		if (!ISSET(p->p_actor_state, LACP_STATE_DEFAULTED))
2923 			continue;
2924 
2925 		aggr_set_partner_timeout(p, timeout);
2926 	}
2927 }
2928 
2929 static int
aggr_multi_eq(const struct aggr_multiaddr * ma,const uint8_t * addrlo,const uint8_t * addrhi)2930 aggr_multi_eq(const struct aggr_multiaddr *ma,
2931     const uint8_t *addrlo, const uint8_t *addrhi)
2932 {
2933 	return (ETHER_IS_EQ(ma->m_addrlo, addrlo) &&
2934 	    ETHER_IS_EQ(ma->m_addrhi, addrhi));
2935 }
2936 
2937 static int
aggr_multi_add(struct aggr_softc * sc,struct ifreq * ifr)2938 aggr_multi_add(struct aggr_softc *sc, struct ifreq *ifr)
2939 {
2940 	struct ifnet *ifp = &sc->sc_if;
2941 	struct aggr_port *p;
2942 	struct aggr_multiaddr *ma;
2943 	uint8_t addrlo[ETHER_ADDR_LEN];
2944 	uint8_t addrhi[ETHER_ADDR_LEN];
2945 	int error;
2946 
2947 	error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
2948 	if (error != 0)
2949 		return (error);
2950 
2951 	TAILQ_FOREACH(ma, &sc->sc_multiaddrs, m_entry) {
2952 		if (aggr_multi_eq(ma, addrlo, addrhi)) {
2953 			ma->m_refs++;
2954 			return (0);
2955 		}
2956 	}
2957 
2958 	ma = malloc(sizeof(*ma), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
2959 	if (ma == NULL)
2960 		return (ENOMEM);
2961 
2962 	ma->m_refs = 1;
2963 	memcpy(&ma->m_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
2964 	memcpy(ma->m_addrlo, addrlo, sizeof(ma->m_addrlo));
2965 	memcpy(ma->m_addrhi, addrhi, sizeof(ma->m_addrhi));
2966 	TAILQ_INSERT_TAIL(&sc->sc_multiaddrs, ma, m_entry);
2967 
2968 	TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
2969 		struct ifnet *ifp0 = p->p_ifp0;
2970 
2971 		if (aggr_multi(sc, p, ma, SIOCADDMULTI) != 0) {
2972 			log(LOG_WARNING, "%s %s: "
2973 			    "unable to add multicast address\n",
2974 			    ifp->if_xname, ifp0->if_xname);
2975 		}
2976 	}
2977 
2978 	return (0);
2979 }
2980 
2981 int
aggr_multi_del(struct aggr_softc * sc,struct ifreq * ifr)2982 aggr_multi_del(struct aggr_softc *sc, struct ifreq *ifr)
2983 {
2984 	struct ifnet *ifp = &sc->sc_if;
2985 	struct aggr_port *p;
2986 	struct aggr_multiaddr *ma;
2987 	uint8_t addrlo[ETHER_ADDR_LEN];
2988 	uint8_t addrhi[ETHER_ADDR_LEN];
2989 	int error;
2990 
2991 	error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
2992 	if (error != 0)
2993 		return (error);
2994 
2995 	TAILQ_FOREACH(ma, &sc->sc_multiaddrs, m_entry) {
2996 		if (aggr_multi_eq(ma, addrlo, addrhi))
2997 			break;
2998 	}
2999 
3000 	if (ma == NULL)
3001 		return (EINVAL);
3002 
3003 	if (--ma->m_refs > 0)
3004 		return (0);
3005 
3006 	TAILQ_REMOVE(&sc->sc_multiaddrs, ma, m_entry);
3007 
3008 	TAILQ_FOREACH(p, &sc->sc_ports, p_entry) {
3009 		struct ifnet *ifp0 = p->p_ifp0;
3010 
3011 		if (aggr_multi(sc, p, ma, SIOCDELMULTI) != 0) {
3012 			log(LOG_WARNING, "%s %s: "
3013 			    "unable to delete multicast address\n",
3014 			    ifp->if_xname, ifp0->if_xname);
3015 		}
3016 	}
3017 
3018 	free(ma, M_DEVBUF, sizeof(*ma));
3019 
3020 	return (0);
3021 }
3022 
3023 #if NKSTAT > 0
3024 static const char *aggr_proto_names[AGGR_PROTO_COUNT] = {
3025 	[AGGR_PROTO_TX_LACP] = "tx-lacp",
3026 	[AGGR_PROTO_TX_MARKER] = "tx-marker",
3027 	[AGGR_PROTO_RX_LACP] = "rx-lacp",
3028 	[AGGR_PROTO_RX_MARKER] = "rx-marker",
3029 };
3030 
3031 struct aggr_port_kstat {
3032 	struct kstat_kv		interface;
3033 
3034 	struct {
3035 		struct kstat_kv		pkts;
3036 		struct kstat_kv		bytes;
3037 	}			protos[AGGR_PROTO_COUNT];
3038 
3039 	struct kstat_kv		rx_drops;
3040 
3041 	struct kstat_kv		selected;
3042 	struct kstat_kv		nselectch;
3043 };
3044 
3045 static int
aggr_port_kstat_read(struct kstat * ks)3046 aggr_port_kstat_read(struct kstat *ks)
3047 {
3048 	struct aggr_port *p = ks->ks_softc;
3049 	struct aggr_port_kstat *pk = ks->ks_data;
3050 	unsigned int proto;
3051 
3052 	mtx_enter(&p->p_mtx);
3053 	for (proto = 0; proto < AGGR_PROTO_COUNT; proto++) {
3054 		kstat_kv_u64(&pk->protos[proto].pkts) =
3055 		    p->p_proto_counts[proto].c_pkts;
3056 		kstat_kv_u64(&pk->protos[proto].bytes) =
3057 		    p->p_proto_counts[proto].c_bytes;
3058 	}
3059 	kstat_kv_u64(&pk->rx_drops) = p->p_rx_drops;
3060 
3061 	kstat_kv_bool(&pk->selected) = p->p_selected == AGGR_PORT_SELECTED;
3062 	kstat_kv_u32(&pk->nselectch) = p->p_nselectch;
3063 	mtx_leave(&p->p_mtx);
3064 
3065 	nanouptime(&ks->ks_updated);
3066 
3067 	return (0);
3068 }
3069 
3070 static void
aggr_port_kstat_attach(struct aggr_port * p)3071 aggr_port_kstat_attach(struct aggr_port *p)
3072 {
3073 	struct aggr_softc *sc = p->p_aggr;
3074 	struct ifnet *ifp = &sc->sc_if;
3075 	struct ifnet *ifp0 = p->p_ifp0;
3076 	struct kstat *ks;
3077 	struct aggr_port_kstat *pk;
3078 	unsigned int proto;
3079 
3080 	pk = malloc(sizeof(*pk), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
3081 	if (pk == NULL) {
3082 		log(LOG_WARNING, "%s %s: unable to allocate aggr-port kstat\n",
3083 		    ifp->if_xname, ifp0->if_xname);
3084 		return;
3085 	}
3086 
3087 	ks = kstat_create(ifp->if_xname, 0, "aggr-port", ifp0->if_index,
3088 	    KSTAT_T_KV, 0);
3089 	if (ks == NULL) {
3090 		log(LOG_WARNING, "%s %s: unable to create aggr-port kstat\n",
3091 		    ifp->if_xname, ifp0->if_xname);
3092 		free(pk, M_DEVBUF, sizeof(*pk));
3093 		return;
3094 	}
3095 
3096 	kstat_kv_init(&pk->interface, "interface", KSTAT_KV_T_ISTR);
3097 	strlcpy(kstat_kv_istr(&pk->interface), ifp0->if_xname,
3098 	    sizeof(kstat_kv_istr(&pk->interface)));
3099 
3100 	for (proto = 0; proto < AGGR_PROTO_COUNT; proto++) {
3101 		char kvname[KSTAT_KV_NAMELEN];
3102 
3103 		snprintf(kvname, sizeof(kvname),
3104 		    "%s-pkts", aggr_proto_names[proto]);
3105 		kstat_kv_unit_init(&pk->protos[proto].pkts,
3106 		    kvname, KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS);
3107 
3108 		snprintf(kvname, sizeof(kvname),
3109 		    "%s-bytes", aggr_proto_names[proto]);
3110 		kstat_kv_unit_init(&pk->protos[proto].bytes,
3111 		    kvname, KSTAT_KV_T_COUNTER64, KSTAT_KV_U_BYTES);
3112 	}
3113 
3114 	kstat_kv_unit_init(&pk->rx_drops, "rx-drops",
3115 	    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS);
3116 
3117 	kstat_kv_init(&pk->selected, "selected", KSTAT_KV_T_BOOL);
3118 	kstat_kv_init(&pk->nselectch, "select-changes", KSTAT_KV_T_COUNTER32);
3119 
3120 	ks->ks_softc = p;
3121 	ks->ks_data = pk;
3122 	ks->ks_datalen = sizeof(*pk);
3123 	ks->ks_read = aggr_port_kstat_read;
3124 
3125 	kstat_install(ks);
3126 
3127 	p->p_kstat = ks;
3128 }
3129 
3130 static void
aggr_port_kstat_detach(struct aggr_port * p)3131 aggr_port_kstat_detach(struct aggr_port *p)
3132 {
3133 	struct kstat *ks = p->p_kstat;
3134 	struct aggr_port_kstat *pk;
3135 
3136 	if (ks == NULL)
3137 		return;
3138 
3139 	p->p_kstat = NULL;
3140 
3141 	kstat_remove(ks);
3142 	pk = ks->ks_data;
3143 	kstat_destroy(ks);
3144 
3145 	free(pk, M_DEVBUF, sizeof(*pk));
3146 }
3147 #endif
3148