xref: /openbsd-src/sys/net/if_trunk.c (revision 505ee9ea3b177e2387d907a91ca7da069f3f14d8)
1 /*	$OpenBSD: if_trunk.c,v 1.147 2020/07/10 13:22:22 patrick Exp $	*/
2 
3 /*
4  * Copyright (c) 2005, 2006, 2007 Reyk Floeter <reyk@openbsd.org>
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 #include <sys/param.h>
20 #include <sys/kernel.h>
21 #include <sys/malloc.h>
22 #include <sys/mbuf.h>
23 #include <sys/queue.h>
24 #include <sys/socket.h>
25 #include <sys/sockio.h>
26 #include <sys/systm.h>
27 #include <sys/task.h>
28 #include <sys/timeout.h>
29 
30 #include <crypto/siphash.h>
31 
32 #include <net/if.h>
33 #include <net/if_dl.h>
34 #include <net/if_media.h>
35 #include <net/if_types.h>
36 #include <net/route.h>
37 
38 #include <netinet/in.h>
39 #include <netinet/if_ether.h>
40 #include <netinet/ip.h>
41 
42 #ifdef INET6
43 #include <netinet/ip6.h>
44 #endif
45 
46 #include <net/if_vlan_var.h>
47 #include <net/if_trunk.h>
48 #include <net/trunklacp.h>
49 
50 #include "bpfilter.h"
51 #if NBPFILTER > 0
52 #include <net/bpf.h>
53 #endif
54 
55 SLIST_HEAD(__trhead, trunk_softc) trunk_list;	/* list of trunks */
56 
57 void	 trunkattach(int);
58 int	 trunk_clone_create(struct if_clone *, int);
59 int	 trunk_clone_destroy(struct ifnet *);
60 void	 trunk_lladdr(struct arpcom *, u_int8_t *);
61 int	 trunk_capabilities(struct trunk_softc *);
62 void	 trunk_port_lladdr(struct trunk_port *, u_int8_t *);
63 int	 trunk_port_create(struct trunk_softc *, struct ifnet *);
64 int	 trunk_port_destroy(struct trunk_port *);
65 void	 trunk_port_state(void *);
66 void	 trunk_port_ifdetach(void *);
67 int	 trunk_port_ioctl(struct ifnet *, u_long, caddr_t);
68 int	 trunk_port_output(struct ifnet *, struct mbuf *, struct sockaddr *,
69 	    struct rtentry *);
70 struct trunk_port *trunk_port_get(struct trunk_softc *, struct ifnet *);
71 int	 trunk_port_checkstacking(struct trunk_softc *);
72 void	 trunk_port2req(struct trunk_port *, struct trunk_reqport *);
73 int	 trunk_ioctl(struct ifnet *, u_long, caddr_t);
74 int	 trunk_ether_addmulti(struct trunk_softc *, struct ifreq *);
75 int	 trunk_ether_delmulti(struct trunk_softc *, struct ifreq *);
76 void	 trunk_ether_purgemulti(struct trunk_softc *);
77 int	 trunk_ether_cmdmulti(struct trunk_port *, u_long);
78 int	 trunk_ioctl_allports(struct trunk_softc *, u_long, caddr_t);
79 int	 trunk_input(struct ifnet *, struct mbuf *, void *);
80 void	 trunk_start(struct ifnet *);
81 void	 trunk_init(struct ifnet *);
82 void	 trunk_stop(struct ifnet *);
83 int	 trunk_media_change(struct ifnet *);
84 void	 trunk_media_status(struct ifnet *, struct ifmediareq *);
85 struct trunk_port *trunk_link_active(struct trunk_softc *,
86 	    struct trunk_port *);
87 const void *trunk_gethdr(struct mbuf *, u_int, u_int, void *);
88 
89 struct if_clone trunk_cloner =
90     IF_CLONE_INITIALIZER("trunk", trunk_clone_create, trunk_clone_destroy);
91 
92 /* Simple round robin */
93 int	 trunk_rr_attach(struct trunk_softc *);
94 int	 trunk_rr_detach(struct trunk_softc *);
95 void	 trunk_rr_port_destroy(struct trunk_port *);
96 int	 trunk_rr_start(struct trunk_softc *, struct mbuf *);
97 int	 trunk_rr_input(struct trunk_softc *, struct trunk_port *,
98 	    struct mbuf *);
99 
100 /* Active failover */
101 int	 trunk_fail_attach(struct trunk_softc *);
102 int	 trunk_fail_detach(struct trunk_softc *);
103 int	 trunk_fail_port_create(struct trunk_port *);
104 void	 trunk_fail_port_destroy(struct trunk_port *);
105 int	 trunk_fail_start(struct trunk_softc *, struct mbuf *);
106 int	 trunk_fail_input(struct trunk_softc *, struct trunk_port *,
107 	    struct mbuf *);
108 void	 trunk_fail_linkstate(struct trunk_port *);
109 
110 /* Loadbalancing */
111 int	 trunk_lb_attach(struct trunk_softc *);
112 int	 trunk_lb_detach(struct trunk_softc *);
113 int	 trunk_lb_port_create(struct trunk_port *);
114 void	 trunk_lb_port_destroy(struct trunk_port *);
115 int	 trunk_lb_start(struct trunk_softc *, struct mbuf *);
116 int	 trunk_lb_input(struct trunk_softc *, struct trunk_port *,
117 	    struct mbuf *);
118 int	 trunk_lb_porttable(struct trunk_softc *, struct trunk_port *);
119 
120 /* Broadcast mode */
121 int	 trunk_bcast_attach(struct trunk_softc *);
122 int	 trunk_bcast_detach(struct trunk_softc *);
123 int	 trunk_bcast_start(struct trunk_softc *, struct mbuf *);
124 int	 trunk_bcast_input(struct trunk_softc *, struct trunk_port *,
125 	    struct mbuf *);
126 
127 /* 802.3ad LACP */
128 int	 trunk_lacp_attach(struct trunk_softc *);
129 int	 trunk_lacp_detach(struct trunk_softc *);
130 int	 trunk_lacp_start(struct trunk_softc *, struct mbuf *);
131 int	 trunk_lacp_input(struct trunk_softc *, struct trunk_port *,
132 	    struct mbuf *);
133 
134 /* Trunk protocol table */
135 static const struct {
136 	enum trunk_proto	ti_proto;
137 	int			(*ti_attach)(struct trunk_softc *);
138 } trunk_protos[] = {
139 	{ TRUNK_PROTO_ROUNDROBIN,	trunk_rr_attach },
140 	{ TRUNK_PROTO_FAILOVER,		trunk_fail_attach },
141 	{ TRUNK_PROTO_LOADBALANCE,	trunk_lb_attach },
142 	{ TRUNK_PROTO_BROADCAST,	trunk_bcast_attach },
143 	{ TRUNK_PROTO_LACP,		trunk_lacp_attach },
144 	{ TRUNK_PROTO_NONE,		NULL }
145 };
146 
147 void
148 trunkattach(int count)
149 {
150 	SLIST_INIT(&trunk_list);
151 	if_clone_attach(&trunk_cloner);
152 }
153 
154 int
155 trunk_clone_create(struct if_clone *ifc, int unit)
156 {
157 	struct trunk_softc *tr;
158 	struct ifnet *ifp;
159 	int i, error = 0;
160 
161 	tr = malloc(sizeof(*tr), M_DEVBUF, M_WAITOK|M_ZERO);
162 	tr->tr_proto = TRUNK_PROTO_NONE;
163 	for (i = 0; trunk_protos[i].ti_proto != TRUNK_PROTO_NONE; i++) {
164 		if (trunk_protos[i].ti_proto == TRUNK_PROTO_DEFAULT) {
165 			tr->tr_proto = trunk_protos[i].ti_proto;
166 			if ((error = trunk_protos[i].ti_attach(tr)) != 0) {
167 				free(tr, M_DEVBUF, sizeof *tr);
168 				return (error);
169 			}
170 			break;
171 		}
172 	}
173 	SLIST_INIT(&tr->tr_ports);
174 
175 	/* Initialise pseudo media types */
176 	ifmedia_init(&tr->tr_media, 0, trunk_media_change,
177 	    trunk_media_status);
178 	ifmedia_add(&tr->tr_media, IFM_ETHER | IFM_AUTO, 0, NULL);
179 	ifmedia_set(&tr->tr_media, IFM_ETHER | IFM_AUTO);
180 
181 	ifp = &tr->tr_ac.ac_if;
182 	ifp->if_softc = tr;
183 	ifp->if_start = trunk_start;
184 	ifp->if_ioctl = trunk_ioctl;
185 	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
186 	ifp->if_capabilities = trunk_capabilities(tr);
187 
188 	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
189 	    ifc->ifc_name, unit);
190 
191 	/*
192 	 * Attach as an ordinary ethernet device, children will be attached
193 	 * as special device IFT_IEEE8023ADLAG.
194 	 */
195 	if_counters_alloc(ifp);
196 	if_attach(ifp);
197 	ether_ifattach(ifp);
198 
199 	/* Insert into the global list of trunks */
200 	SLIST_INSERT_HEAD(&trunk_list, tr, tr_entries);
201 
202 	return (0);
203 }
204 
205 int
206 trunk_clone_destroy(struct ifnet *ifp)
207 {
208 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
209 	struct trunk_port *tp;
210 	int error;
211 
212 	/* Remove any multicast groups that we may have joined. */
213 	trunk_ether_purgemulti(tr);
214 
215 	/* Shutdown and remove trunk ports, return on error */
216 	NET_LOCK();
217 	while ((tp = SLIST_FIRST(&tr->tr_ports)) != NULL) {
218 		if ((error = trunk_port_destroy(tp)) != 0) {
219 			NET_UNLOCK();
220 			return (error);
221 		}
222 	}
223 	NET_UNLOCK();
224 
225 	ifmedia_delete_instance(&tr->tr_media, IFM_INST_ANY);
226 	ether_ifdetach(ifp);
227 	if_detach(ifp);
228 
229 	SLIST_REMOVE(&trunk_list, tr, trunk_softc, tr_entries);
230 	free(tr, M_DEVBUF, sizeof *tr);
231 
232 	return (0);
233 }
234 
235 void
236 trunk_lladdr(struct arpcom *ac, u_int8_t *lladdr)
237 {
238 	struct ifnet *ifp = &ac->ac_if;
239 	struct sockaddr_dl *sdl;
240 
241 	sdl = ifp->if_sadl;
242 	sdl->sdl_type = IFT_ETHER;
243 	sdl->sdl_alen = ETHER_ADDR_LEN;
244 	bcopy(lladdr, LLADDR(sdl), ETHER_ADDR_LEN);
245 	bcopy(lladdr, ac->ac_enaddr, ETHER_ADDR_LEN);
246 }
247 
248 int
249 trunk_capabilities(struct trunk_softc *tr)
250 {
251 	struct trunk_port *tp;
252 	int cap = ~0, priv;
253 
254 	/* Preserve private capabilities */
255 	priv = tr->tr_capabilities & IFCAP_TRUNK_MASK;
256 
257 	/* Get capabilities from the trunk ports */
258 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
259 		cap &= tp->tp_capabilities;
260 
261 	if (tr->tr_ifflags & IFF_DEBUG) {
262 		printf("%s: capabilities 0x%08x\n",
263 		    tr->tr_ifname, cap == ~0 ? priv : (cap | priv));
264 	}
265 
266 	return (cap == ~0 ? priv : (cap | priv));
267 }
268 
269 void
270 trunk_port_lladdr(struct trunk_port *tp, u_int8_t *lladdr)
271 {
272 	struct ifnet *ifp = tp->tp_if;
273 
274 	/* Set the link layer address */
275 	trunk_lladdr((struct arpcom *)ifp, lladdr);
276 
277 	/* Reset the port to update the lladdr */
278 	ifnewlladdr(ifp);
279 }
280 
281 int
282 trunk_port_create(struct trunk_softc *tr, struct ifnet *ifp)
283 {
284 	struct trunk_softc *tr_ptr;
285 	struct trunk_port *tp;
286 	struct arpcom *ac0;
287 	int error = 0;
288 
289 	/* Limit the maximal number of trunk ports */
290 	if (tr->tr_count >= TRUNK_MAX_PORTS)
291 		return (ENOSPC);
292 
293 	/* Check if port has already been associated to a trunk */
294 	if (trunk_port_get(NULL, ifp) != NULL)
295 		return (EBUSY);
296 
297 	/* XXX Disallow non-ethernet interfaces (this should be any of 802) */
298 	if (ifp->if_type != IFT_ETHER)
299 		return (EPROTONOSUPPORT);
300 
301 	ac0 = (struct arpcom *)ifp;
302 	if (ac0->ac_trunkport != NULL)
303 		return (EBUSY);
304 
305 	/* Take MTU from the first member port */
306 	if (SLIST_EMPTY(&tr->tr_ports)) {
307 		if (tr->tr_ifflags & IFF_DEBUG)
308 			printf("%s: first port, setting trunk mtu %u\n",
309 			    tr->tr_ifname, ifp->if_mtu);
310 		tr->tr_ac.ac_if.if_mtu = ifp->if_mtu;
311 		tr->tr_ac.ac_if.if_hardmtu = ifp->if_hardmtu;
312 	} else if (tr->tr_ac.ac_if.if_mtu != ifp->if_mtu) {
313 		printf("%s: adding %s failed, MTU %u != %u\n", tr->tr_ifname,
314 		    ifp->if_xname, ifp->if_mtu, tr->tr_ac.ac_if.if_mtu);
315 		return (EINVAL);
316 	}
317 
318 	if ((error = ifpromisc(ifp, 1)) != 0)
319 		return (error);
320 
321 	if ((tp = malloc(sizeof *tp, M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
322 		return (ENOMEM);
323 
324 	/* Check if port is a stacked trunk */
325 	SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) {
326 		if (ifp == &tr_ptr->tr_ac.ac_if) {
327 			tp->tp_flags |= TRUNK_PORT_STACK;
328 			if (trunk_port_checkstacking(tr_ptr) >=
329 			    TRUNK_MAX_STACKING) {
330 				free(tp, M_DEVBUF, sizeof *tp);
331 				return (E2BIG);
332 			}
333 		}
334 	}
335 
336 	/* Change the interface type */
337 	tp->tp_iftype = ifp->if_type;
338 	ifp->if_type = IFT_IEEE8023ADLAG;
339 
340 	tp->tp_ioctl = ifp->if_ioctl;
341 	ifp->if_ioctl = trunk_port_ioctl;
342 
343 	tp->tp_output = ifp->if_output;
344 	ifp->if_output = trunk_port_output;
345 
346 	tp->tp_if = ifp;
347 	tp->tp_trunk = tr;
348 
349 	/* Save port link layer address */
350 	bcopy(((struct arpcom *)ifp)->ac_enaddr, tp->tp_lladdr, ETHER_ADDR_LEN);
351 
352 	if (SLIST_EMPTY(&tr->tr_ports)) {
353 		tr->tr_primary = tp;
354 		tp->tp_flags |= TRUNK_PORT_MASTER;
355 		trunk_lladdr(&tr->tr_ac, tp->tp_lladdr);
356 	}
357 
358 	/* Insert into the list of ports */
359 	SLIST_INSERT_HEAD(&tr->tr_ports, tp, tp_entries);
360 	tr->tr_count++;
361 
362 	/* Update link layer address for this port */
363 	trunk_port_lladdr(tp,
364 	    ((struct arpcom *)(tr->tr_primary->tp_if))->ac_enaddr);
365 
366 	/* Update trunk capabilities */
367 	tr->tr_capabilities = trunk_capabilities(tr);
368 
369 	/* Add multicast addresses to this port */
370 	trunk_ether_cmdmulti(tp, SIOCADDMULTI);
371 
372 	/* Register callback for physical link state changes */
373 	task_set(&tp->tp_ltask, trunk_port_state, tp);
374 	if_linkstatehook_add(ifp, &tp->tp_ltask);
375 
376 	/* Register callback if parent wants to unregister */
377 	task_set(&tp->tp_dtask, trunk_port_ifdetach, tp);
378 	if_detachhook_add(ifp, &tp->tp_dtask);
379 
380 	if (tr->tr_port_create != NULL)
381 		error = (*tr->tr_port_create)(tp);
382 
383 	ac0->ac_trunkport = tp;
384 	/* Change input handler of the physical interface. */
385 	if_ih_insert(ifp, trunk_input, tp);
386 
387 	return (error);
388 }
389 
390 int
391 trunk_port_checkstacking(struct trunk_softc *tr)
392 {
393 	struct trunk_softc *tr_ptr;
394 	struct trunk_port *tp;
395 	int m = 0;
396 
397 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
398 		if (tp->tp_flags & TRUNK_PORT_STACK) {
399 			tr_ptr = (struct trunk_softc *)tp->tp_if->if_softc;
400 			m = MAX(m, trunk_port_checkstacking(tr_ptr));
401 		}
402 	}
403 
404 	return (m + 1);
405 }
406 
407 int
408 trunk_port_destroy(struct trunk_port *tp)
409 {
410 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
411 	struct trunk_port *tp_ptr;
412 	struct ifnet *ifp = tp->tp_if;
413 	struct arpcom *ac0 = (struct arpcom *)ifp;
414 
415 	/* Restore previous input handler. */
416 	if_ih_remove(ifp, trunk_input, tp);
417 	ac0->ac_trunkport = NULL;
418 
419 	/* Remove multicast addresses from this port */
420 	trunk_ether_cmdmulti(tp, SIOCDELMULTI);
421 
422 	/* Port has to be down */
423 	if (ifp->if_flags & IFF_UP)
424 		if_down(ifp);
425 
426 	ifpromisc(ifp, 0);
427 
428 	if (tr->tr_port_destroy != NULL)
429 		(*tr->tr_port_destroy)(tp);
430 
431 	/* Restore interface type. */
432 	ifp->if_type = tp->tp_iftype;
433 
434 	ifp->if_ioctl = tp->tp_ioctl;
435 	ifp->if_output = tp->tp_output;
436 
437 	if_detachhook_del(ifp, &tp->tp_dtask);
438 	if_linkstatehook_del(ifp, &tp->tp_ltask);
439 
440 	/* Finally, remove the port from the trunk */
441 	SLIST_REMOVE(&tr->tr_ports, tp, trunk_port, tp_entries);
442 	tr->tr_count--;
443 
444 	/* Update the primary interface */
445 	if (tp == tr->tr_primary) {
446 		u_int8_t lladdr[ETHER_ADDR_LEN];
447 
448 		if ((tp_ptr = SLIST_FIRST(&tr->tr_ports)) == NULL) {
449 			bzero(&lladdr, ETHER_ADDR_LEN);
450 		} else {
451 			bcopy(((struct arpcom *)tp_ptr->tp_if)->ac_enaddr,
452 			    lladdr, ETHER_ADDR_LEN);
453 			tp_ptr->tp_flags = TRUNK_PORT_MASTER;
454 		}
455 		trunk_lladdr(&tr->tr_ac, lladdr);
456 		tr->tr_primary = tp_ptr;
457 
458 		/* Update link layer address for each port */
459 		SLIST_FOREACH(tp_ptr, &tr->tr_ports, tp_entries)
460 			trunk_port_lladdr(tp_ptr, lladdr);
461 	}
462 
463 	/* Reset the port lladdr */
464 	trunk_port_lladdr(tp, tp->tp_lladdr);
465 
466 	free(tp, M_DEVBUF, sizeof *tp);
467 
468 	/* Update trunk capabilities */
469 	tr->tr_capabilities = trunk_capabilities(tr);
470 
471 	return (0);
472 }
473 
474 int
475 trunk_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
476 {
477 	struct trunk_reqport *rp = (struct trunk_reqport *)data;
478 	struct trunk_softc *tr;
479 	struct trunk_port *tp = NULL;
480 	int error = 0;
481 
482 	/* Should be checked by the caller */
483 	if (ifp->if_type != IFT_IEEE8023ADLAG ||
484 	    (tp = trunk_port_get(NULL, ifp)) == NULL ||
485 	    (tr = (struct trunk_softc *)tp->tp_trunk) == NULL) {
486 		error = EINVAL;
487 		goto fallback;
488 	}
489 
490 	switch (cmd) {
491 	case SIOCGTRUNKPORT:
492 		if (rp->rp_portname[0] == '\0' ||
493 		    ifunit(rp->rp_portname) != ifp) {
494 			error = EINVAL;
495 			break;
496 		}
497 
498 		/* Search in all trunks if the global flag is set */
499 		if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
500 		    NULL : tr, ifp)) == NULL) {
501 			error = ENOENT;
502 			break;
503 		}
504 
505 		trunk_port2req(tp, rp);
506 		break;
507 	case SIOCSIFMTU:
508 		/* Do not allow the MTU to be changed once joined */
509 		error = EINVAL;
510 		break;
511 	default:
512 		error = ENOTTY;
513 		goto fallback;
514 	}
515 
516 	return (error);
517 
518  fallback:
519 	if (tp != NULL)
520 		error = (*tp->tp_ioctl)(ifp, cmd, data);
521 
522 	return (error);
523 }
524 
525 int
526 trunk_port_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
527     struct rtentry *rt)
528 {
529 	/* restrict transmission on trunk members to bpf only */
530 	if (ifp->if_type == IFT_IEEE8023ADLAG &&
531 	    (m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) {
532 		m_freem(m);
533 		return (EBUSY);
534 	}
535 
536 	return (ether_output(ifp, m, dst, rt));
537 }
538 
539 void
540 trunk_port_ifdetach(void *arg)
541 {
542 	struct trunk_port *tp = (struct trunk_port *)arg;
543 
544 	trunk_port_destroy(tp);
545 }
546 
547 struct trunk_port *
548 trunk_port_get(struct trunk_softc *tr, struct ifnet *ifp)
549 {
550 	struct trunk_port *tp;
551 	struct trunk_softc *tr_ptr;
552 
553 	if (tr != NULL) {
554 		/* Search port in specified trunk */
555 		SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
556 			if (tp->tp_if == ifp)
557 				return (tp);
558 		}
559 	} else {
560 		/* Search all trunks for the selected port */
561 		SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) {
562 			SLIST_FOREACH(tp, &tr_ptr->tr_ports, tp_entries) {
563 				if (tp->tp_if == ifp)
564 					return (tp);
565 			}
566 		}
567 	}
568 
569 	return (NULL);
570 }
571 
572 void
573 trunk_port2req(struct trunk_port *tp, struct trunk_reqport *rp)
574 {
575 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
576 
577 	strlcpy(rp->rp_ifname, tr->tr_ifname, sizeof(rp->rp_ifname));
578 	strlcpy(rp->rp_portname, tp->tp_if->if_xname, sizeof(rp->rp_portname));
579 	rp->rp_prio = tp->tp_prio;
580 	if (tr->tr_portreq != NULL)
581 		(*tr->tr_portreq)(tp, (caddr_t)&rp->rp_psc);
582 
583 	/* Add protocol specific flags */
584 	switch (tr->tr_proto) {
585 	case TRUNK_PROTO_FAILOVER:
586 		rp->rp_flags = tp->tp_flags;
587 		if (tp == trunk_link_active(tr, tr->tr_primary))
588 			rp->rp_flags |= TRUNK_PORT_ACTIVE;
589 		break;
590 
591 	case TRUNK_PROTO_ROUNDROBIN:
592 	case TRUNK_PROTO_LOADBALANCE:
593 	case TRUNK_PROTO_BROADCAST:
594 		rp->rp_flags = tp->tp_flags;
595 		if (TRUNK_PORTACTIVE(tp))
596 			rp->rp_flags |= TRUNK_PORT_ACTIVE;
597 		break;
598 
599 	case TRUNK_PROTO_LACP:
600 		/* LACP has a different definition of active */
601 		rp->rp_flags = lacp_port_status(tp);
602 		break;
603 	default:
604 		break;
605 	}
606 }
607 
608 int
609 trunk_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
610 {
611 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
612 	struct trunk_reqall *ra = (struct trunk_reqall *)data;
613 	struct trunk_reqport *rp = (struct trunk_reqport *)data, rpbuf;
614 	struct trunk_opts *tro = (struct trunk_opts *)data;
615 	struct ifreq *ifr = (struct ifreq *)data;
616 	struct lacp_softc *lsc;
617 	struct trunk_port *tp;
618 	struct lacp_port *lp;
619 	struct ifnet *tpif;
620 	int i, error = 0;
621 
622 	bzero(&rpbuf, sizeof(rpbuf));
623 
624 	switch (cmd) {
625 	case SIOCGTRUNK:
626 		ra->ra_proto = tr->tr_proto;
627 		if (tr->tr_req != NULL)
628 			(*tr->tr_req)(tr, (caddr_t)&ra->ra_psc);
629 		ra->ra_ports = i = 0;
630 		tp = SLIST_FIRST(&tr->tr_ports);
631 		while (tp && ra->ra_size >=
632 		    i + sizeof(struct trunk_reqport)) {
633 			trunk_port2req(tp, &rpbuf);
634 			error = copyout(&rpbuf, (caddr_t)ra->ra_port + i,
635 			    sizeof(struct trunk_reqport));
636 			if (error)
637 				break;
638 			i += sizeof(struct trunk_reqport);
639 			ra->ra_ports++;
640 			tp = SLIST_NEXT(tp, tp_entries);
641 		}
642 		break;
643 	case SIOCSTRUNK:
644 		if ((error = suser(curproc)) != 0) {
645 			error = EPERM;
646 			break;
647 		}
648 		if (ra->ra_proto >= TRUNK_PROTO_MAX) {
649 			error = EPROTONOSUPPORT;
650 			break;
651 		}
652 		/*
653 		 * Serialize modifications to the trunk and trunk
654 		 * ports via the ifih SRP: detaching trunk_input
655 		 * from the trunk port will require all currently
656 		 * running trunk_input's on this port to finish
657 		 * granting us an exclusive access to it.
658 		 */
659 		SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
660 			if_ih_remove(tp->tp_if, trunk_input, tp);
661 		if (tr->tr_proto != TRUNK_PROTO_NONE)
662 			error = tr->tr_detach(tr);
663 		if (error != 0)
664 			break;
665 		for (i = 0; i < nitems(trunk_protos); i++) {
666 			if (trunk_protos[i].ti_proto == ra->ra_proto) {
667 				if (tr->tr_ifflags & IFF_DEBUG)
668 					printf("%s: using proto %u\n",
669 					    tr->tr_ifname,
670 					    trunk_protos[i].ti_proto);
671 				tr->tr_proto = trunk_protos[i].ti_proto;
672 				if (tr->tr_proto != TRUNK_PROTO_NONE)
673 					error = trunk_protos[i].ti_attach(tr);
674 				SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
675 					if_ih_insert(tp->tp_if,
676 					    trunk_input, tp);
677 				/* Update trunk capabilities */
678 				tr->tr_capabilities = trunk_capabilities(tr);
679 				goto out;
680 			}
681 		}
682 		error = EPROTONOSUPPORT;
683 		break;
684 	case SIOCGTRUNKOPTS:
685 		/* Only LACP trunks have options atm */
686 		if (tro->to_proto != TRUNK_PROTO_LACP) {
687 			error = EPROTONOSUPPORT;
688 			break;
689 		}
690 		lsc = LACP_SOFTC(tr);
691 		tro->to_lacpopts.lacp_mode = lsc->lsc_mode;
692 		tro->to_lacpopts.lacp_timeout = lsc->lsc_timeout;
693 		tro->to_lacpopts.lacp_prio = lsc->lsc_sys_prio;
694 		tro->to_lacpopts.lacp_portprio = lsc->lsc_port_prio;
695 		tro->to_lacpopts.lacp_ifqprio = lsc->lsc_ifq_prio;
696 		break;
697 	case SIOCSTRUNKOPTS:
698 		if ((error = suser(curproc)) != 0) {
699 			error = EPERM;
700 			break;
701 		}
702 		/* Only LACP trunks have options atm */
703 		if (tro->to_proto != TRUNK_PROTO_LACP) {
704 			error = EPROTONOSUPPORT;
705 			break;
706 		}
707 		lsc = LACP_SOFTC(tr);
708 		switch(tro->to_opts) {
709 			case TRUNK_OPT_LACP_MODE:
710 				/*
711 				 * Ensure mode changes occur immediately
712 				 * on all ports
713 				 */
714 				lsc->lsc_mode = tro->to_lacpopts.lacp_mode;
715 				if (lsc->lsc_mode == 0) {
716 					LIST_FOREACH(lp, &lsc->lsc_ports,
717 					    lp_next)
718 						lp->lp_state &=
719 						    ~LACP_STATE_ACTIVITY;
720 				} else {
721 					LIST_FOREACH(lp, &lsc->lsc_ports,
722 					    lp_next)
723 						lp->lp_state |=
724 						    LACP_STATE_ACTIVITY;
725 				}
726 				break;
727 			case TRUNK_OPT_LACP_TIMEOUT:
728 				/*
729 				 * Ensure timeout changes occur immediately
730 				 * on all ports
731 				 */
732 				lsc->lsc_timeout =
733 				    tro->to_lacpopts.lacp_timeout;
734 				if (lsc->lsc_timeout == 0) {
735 					LIST_FOREACH(lp, &lsc->lsc_ports,
736 					    lp_next)
737 						lp->lp_state &=
738 						    ~LACP_STATE_TIMEOUT;
739 				} else {
740 					LIST_FOREACH(lp, &lsc->lsc_ports,
741 					    lp_next)
742 						lp->lp_state |=
743 						    LACP_STATE_TIMEOUT;
744 				}
745 				break;
746 			case TRUNK_OPT_LACP_SYS_PRIO:
747 				if (tro->to_lacpopts.lacp_prio == 0) {
748 					error = EINVAL;
749 					break;
750 				}
751 				lsc->lsc_sys_prio = tro->to_lacpopts.lacp_prio;
752 				break;
753 			case TRUNK_OPT_LACP_PORT_PRIO:
754 				if (tro->to_lacpopts.lacp_portprio == 0) {
755 					error = EINVAL;
756 					break;
757 				}
758 				lsc->lsc_port_prio =
759 				    tro->to_lacpopts.lacp_portprio;
760 				break;
761 			case TRUNK_OPT_LACP_IFQ_PRIO:
762 				if (tro->to_lacpopts.lacp_ifqprio >
763 				    IFQ_MAXPRIO) {
764 					error = EINVAL;
765 					break;
766 				}
767 				lsc->lsc_ifq_prio =
768 				    tro->to_lacpopts.lacp_ifqprio;
769 				break;
770 		}
771 		break;
772 	case SIOCGTRUNKPORT:
773 		if (rp->rp_portname[0] == '\0' ||
774 		    (tpif = ifunit(rp->rp_portname)) == NULL) {
775 			error = EINVAL;
776 			break;
777 		}
778 
779 		/* Search in all trunks if the global flag is set */
780 		if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
781 		    NULL : tr, tpif)) == NULL) {
782 			error = ENOENT;
783 			break;
784 		}
785 
786 		trunk_port2req(tp, rp);
787 		break;
788 	case SIOCSTRUNKPORT:
789 		if ((error = suser(curproc)) != 0) {
790 			error = EPERM;
791 			break;
792 		}
793 		if (rp->rp_portname[0] == '\0' ||
794 		    (tpif = ifunit(rp->rp_portname)) == NULL) {
795 			error = EINVAL;
796 			break;
797 		}
798 		error = trunk_port_create(tr, tpif);
799 		break;
800 	case SIOCSTRUNKDELPORT:
801 		if ((error = suser(curproc)) != 0) {
802 			error = EPERM;
803 			break;
804 		}
805 		if (rp->rp_portname[0] == '\0' ||
806 		    (tpif = ifunit(rp->rp_portname)) == NULL) {
807 			error = EINVAL;
808 			break;
809 		}
810 
811 		/* Search in all trunks if the global flag is set */
812 		if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
813 		    NULL : tr, tpif)) == NULL) {
814 			error = ENOENT;
815 			break;
816 		}
817 
818 		error = trunk_port_destroy(tp);
819 		break;
820 	case SIOCSIFADDR:
821 		ifp->if_flags |= IFF_UP;
822 		/* FALLTHROUGH */
823 	case SIOCSIFFLAGS:
824 		error = ENETRESET;
825 		break;
826 	case SIOCADDMULTI:
827 		error = trunk_ether_addmulti(tr, ifr);
828 		break;
829 	case SIOCDELMULTI:
830 		error = trunk_ether_delmulti(tr, ifr);
831 		break;
832 	case SIOCSIFMEDIA:
833 	case SIOCGIFMEDIA:
834 		error = ifmedia_ioctl(ifp, ifr, &tr->tr_media, cmd);
835 		break;
836 	case SIOCSIFLLADDR:
837 		/* Update the port lladdrs as well */
838 		SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
839 			trunk_port_lladdr(tp, ifr->ifr_addr.sa_data);
840 		error = ENETRESET;
841 		break;
842 	default:
843 		error = ether_ioctl(ifp, &tr->tr_ac, cmd, data);
844 	}
845 
846 	if (error == ENETRESET) {
847 		if (ifp->if_flags & IFF_UP) {
848 			if ((ifp->if_flags & IFF_RUNNING) == 0)
849 				trunk_init(ifp);
850 		} else {
851 			if (ifp->if_flags & IFF_RUNNING)
852 				trunk_stop(ifp);
853 		}
854 		error = 0;
855 	}
856 
857  out:
858 	return (error);
859 }
860 
861 int
862 trunk_ether_addmulti(struct trunk_softc *tr, struct ifreq *ifr)
863 {
864 	struct trunk_mc *mc;
865 	u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
866 	int error;
867 
868 	/* Ignore ENETRESET error code */
869 	if ((error = ether_addmulti(ifr, &tr->tr_ac)) != ENETRESET)
870 		return (error);
871 
872 	if ((mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT)) == NULL) {
873 		error = ENOMEM;
874 		goto failed;
875 	}
876 
877 	ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
878 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, mc->mc_enm);
879 	bcopy(&ifr->ifr_addr, &mc->mc_addr, ifr->ifr_addr.sa_len);
880 	SLIST_INSERT_HEAD(&tr->tr_mc_head, mc, mc_entries);
881 
882 	if ((error = trunk_ioctl_allports(tr, SIOCADDMULTI,
883 	    (caddr_t)ifr)) != 0) {
884 		trunk_ether_delmulti(tr, ifr);
885 		return (error);
886 	}
887 
888 	return (error);
889 
890  failed:
891 	ether_delmulti(ifr, &tr->tr_ac);
892 
893 	return (error);
894 }
895 
896 int
897 trunk_ether_delmulti(struct trunk_softc *tr, struct ifreq *ifr)
898 {
899 	struct ether_multi *enm;
900 	struct trunk_mc *mc;
901 	u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
902 	int error;
903 
904 	if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
905 		return (error);
906 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, enm);
907 	if (enm == NULL)
908 		return (EINVAL);
909 
910 	SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries)
911 		if (mc->mc_enm == enm)
912 			break;
913 
914 	/* We won't delete entries we didn't add */
915 	if (mc == NULL)
916 		return (EINVAL);
917 
918 	if ((error = ether_delmulti(ifr, &tr->tr_ac)) != ENETRESET)
919 		return (error);
920 
921 	/* We no longer use this multicast address.  Tell parent so. */
922 	error = trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr);
923 	if (error == 0) {
924 		SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries);
925 		free(mc, M_DEVBUF, sizeof(*mc));
926 	} else {
927 		/* XXX At least one port failed to remove the address */
928 		if (tr->tr_ifflags & IFF_DEBUG) {
929 			printf("%s: failed to remove multicast address "
930 			    "on all ports (%d)\n", tr->tr_ifname, error);
931 		}
932 		(void)ether_addmulti(ifr, &tr->tr_ac);
933 	}
934 
935 	return (0);
936 }
937 
938 void
939 trunk_ether_purgemulti(struct trunk_softc *tr)
940 {
941 	struct trunk_mc *mc;
942 	struct trunk_ifreq ifs;
943 	struct ifreq *ifr = &ifs.ifreq.ifreq;
944 
945 	while ((mc = SLIST_FIRST(&tr->tr_mc_head)) != NULL) {
946 		bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len);
947 
948 		/* Try to remove multicast address on all ports */
949 		trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr);
950 
951 		SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries);
952 		free(mc, M_DEVBUF, sizeof(*mc));
953 	}
954 }
955 
956 int
957 trunk_ether_cmdmulti(struct trunk_port *tp, u_long cmd)
958 {
959 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
960 	struct trunk_mc *mc;
961 	struct trunk_ifreq ifs;
962 	struct ifreq *ifr = &ifs.ifreq.ifreq;
963 	int ret, error = 0;
964 
965 	bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ);
966 	SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) {
967 		bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len);
968 
969 		if ((ret = tp->tp_ioctl(tp->tp_if, cmd, (caddr_t)ifr)) != 0) {
970 			if (tr->tr_ifflags & IFF_DEBUG) {
971 				printf("%s: ioctl %lu failed on %s: %d\n",
972 				    tr->tr_ifname, cmd, tp->tp_ifname, ret);
973 			}
974 			/* Store last known error and continue */
975 			error = ret;
976 		}
977 	}
978 
979 	return (error);
980 }
981 
982 int
983 trunk_ioctl_allports(struct trunk_softc *tr, u_long cmd, caddr_t data)
984 {
985 	struct ifreq *ifr = (struct ifreq *)data;
986 	struct trunk_port *tp;
987 	int ret, error = 0;
988 
989 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
990 		bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ);
991 		if ((ret = tp->tp_ioctl(tp->tp_if, cmd, data)) != 0) {
992 			if (tr->tr_ifflags & IFF_DEBUG) {
993 				printf("%s: ioctl %lu failed on %s: %d\n",
994 				    tr->tr_ifname, cmd, tp->tp_ifname, ret);
995 			}
996 			/* Store last known error and continue */
997 			error = ret;
998 		}
999 	}
1000 
1001 	return (error);
1002 }
1003 
1004 void
1005 trunk_start(struct ifnet *ifp)
1006 {
1007 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1008 	struct mbuf *m;
1009 	int error;
1010 
1011 	for (;;) {
1012 		m = ifq_dequeue(&ifp->if_snd);
1013 		if (m == NULL)
1014 			break;
1015 
1016 #if NBPFILTER > 0
1017 		if (ifp->if_bpf)
1018 			bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
1019 #endif
1020 
1021 		if (tr->tr_proto != TRUNK_PROTO_NONE && tr->tr_count) {
1022 			error = (*tr->tr_start)(tr, m);
1023 			if (error != 0)
1024 				ifp->if_oerrors++;
1025 		} else {
1026 			m_freem(m);
1027 			if (tr->tr_proto != TRUNK_PROTO_NONE)
1028 				ifp->if_oerrors++;
1029 		}
1030 	}
1031 }
1032 
1033 u_int32_t
1034 trunk_hashmbuf(struct mbuf *m, SIPHASH_KEY *key)
1035 {
1036 	u_int16_t etype, ether_vtag;
1037 	u_int32_t p = 0;
1038 	u_int16_t *vlan, vlanbuf[2];
1039 	int off;
1040 	struct ether_header *eh;
1041 	struct ip *ip, ipbuf;
1042 #ifdef INET6
1043 	u_int32_t flow;
1044 	struct ip6_hdr *ip6, ip6buf;
1045 #endif
1046 	SIPHASH_CTX ctx;
1047 
1048 	if (m->m_pkthdr.csum_flags & M_FLOWID)
1049 		return (m->m_pkthdr.ph_flowid);
1050 
1051 	SipHash24_Init(&ctx, key);
1052 	off = sizeof(*eh);
1053 	if (m->m_len < off)
1054 		goto done;
1055 	eh = mtod(m, struct ether_header *);
1056 	etype = ntohs(eh->ether_type);
1057 	SipHash24_Update(&ctx, &eh->ether_shost, ETHER_ADDR_LEN);
1058 	SipHash24_Update(&ctx, &eh->ether_dhost, ETHER_ADDR_LEN);
1059 
1060 	/* Special handling for encapsulating VLAN frames */
1061 	if (m->m_flags & M_VLANTAG) {
1062 		ether_vtag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
1063 		SipHash24_Update(&ctx, &ether_vtag, sizeof(ether_vtag));
1064 	} else if (etype == ETHERTYPE_VLAN) {
1065 		if ((vlan = (u_int16_t *)
1066 		    trunk_gethdr(m, off, EVL_ENCAPLEN, &vlanbuf)) == NULL)
1067 			return (p);
1068 		ether_vtag = EVL_VLANOFTAG(*vlan);
1069 		SipHash24_Update(&ctx, &ether_vtag, sizeof(ether_vtag));
1070 		etype = ntohs(vlan[1]);
1071 		off += EVL_ENCAPLEN;
1072 	}
1073 
1074 	switch (etype) {
1075 	case ETHERTYPE_IP:
1076 		if ((ip = (struct ip *)
1077 		    trunk_gethdr(m, off, sizeof(*ip), &ipbuf)) == NULL)
1078 			return (p);
1079 		SipHash24_Update(&ctx, &ip->ip_src, sizeof(struct in_addr));
1080 		SipHash24_Update(&ctx, &ip->ip_dst, sizeof(struct in_addr));
1081 		break;
1082 #ifdef INET6
1083 	case ETHERTYPE_IPV6:
1084 		if ((ip6 = (struct ip6_hdr *)
1085 		    trunk_gethdr(m, off, sizeof(*ip6), &ip6buf)) == NULL)
1086 			return (p);
1087 		SipHash24_Update(&ctx, &ip6->ip6_src, sizeof(struct in6_addr));
1088 		SipHash24_Update(&ctx, &ip6->ip6_dst, sizeof(struct in6_addr));
1089 		flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
1090 		SipHash24_Update(&ctx, &flow, sizeof(flow)); /* IPv6 flow label */
1091 		break;
1092 #endif
1093 	}
1094 
1095 done:
1096 	return SipHash24_End(&ctx);
1097 }
1098 
1099 void
1100 trunk_init(struct ifnet *ifp)
1101 {
1102 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1103 
1104 	ifp->if_flags |= IFF_RUNNING;
1105 
1106 	if (tr->tr_init != NULL)
1107 		(*tr->tr_init)(tr);
1108 }
1109 
1110 void
1111 trunk_stop(struct ifnet *ifp)
1112 {
1113 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1114 
1115 	ifp->if_flags &= ~IFF_RUNNING;
1116 
1117 	if (tr->tr_stop != NULL)
1118 		(*tr->tr_stop)(tr);
1119 }
1120 
1121 int
1122 trunk_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
1123 {
1124 	struct trunk_softc *tr;
1125 	struct trunk_port *tp;
1126 	struct ifnet *trifp = NULL;
1127 	struct ether_header *eh;
1128 
1129 	eh = mtod(m, struct ether_header *);
1130 	if (ETHER_IS_MULTICAST(eh->ether_dhost))
1131 		ifp->if_imcasts++;
1132 
1133 	/* Should be checked by the caller */
1134 	if (ifp->if_type != IFT_IEEE8023ADLAG)
1135 		goto bad;
1136 
1137 	tp = (struct trunk_port *)cookie;
1138 	if ((tr = (struct trunk_softc *)tp->tp_trunk) == NULL)
1139 		goto bad;
1140 
1141 	trifp = &tr->tr_ac.ac_if;
1142 	if (tr->tr_proto == TRUNK_PROTO_NONE)
1143 		goto bad;
1144 
1145 	if ((*tr->tr_input)(tr, tp, m)) {
1146 		/*
1147 		 * We stop here if the packet has been consumed
1148 		 * by the protocol routine.
1149 		 */
1150 		return (1);
1151 	}
1152 
1153 	if ((trifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
1154 		goto bad;
1155 
1156 	/*
1157 	 * Drop promiscuously received packets if we are not in
1158 	 * promiscuous mode.
1159 	 */
1160 	if (!ETHER_IS_MULTICAST(eh->ether_dhost) &&
1161 	    (ifp->if_flags & IFF_PROMISC) &&
1162 	    (trifp->if_flags & IFF_PROMISC) == 0) {
1163 		if (bcmp(&tr->tr_ac.ac_enaddr, eh->ether_dhost,
1164 		    ETHER_ADDR_LEN)) {
1165 			m_freem(m);
1166 			return (1);
1167 		}
1168 	}
1169 
1170 
1171 	if_vinput(trifp, m);
1172 	return (1);
1173 
1174  bad:
1175 	if (trifp != NULL)
1176 		trifp->if_ierrors++;
1177 	m_freem(m);
1178 	return (1);
1179 }
1180 
1181 int
1182 trunk_media_change(struct ifnet *ifp)
1183 {
1184 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1185 
1186 	if (tr->tr_ifflags & IFF_DEBUG)
1187 		printf("%s\n", __func__);
1188 
1189 	/* Ignore */
1190 	return (0);
1191 }
1192 
1193 void
1194 trunk_media_status(struct ifnet *ifp, struct ifmediareq *imr)
1195 {
1196 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1197 	struct trunk_port *tp;
1198 
1199 	imr->ifm_status = IFM_AVALID;
1200 	imr->ifm_active = IFM_ETHER | IFM_AUTO;
1201 
1202 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
1203 		if (TRUNK_PORTACTIVE(tp))
1204 			imr->ifm_status |= IFM_ACTIVE;
1205 	}
1206 }
1207 
1208 void
1209 trunk_port_state(void *arg)
1210 {
1211 	struct trunk_port *tp = (struct trunk_port *)arg;
1212 	struct trunk_softc *tr = NULL;
1213 
1214 	if (tp != NULL)
1215 		tr = (struct trunk_softc *)tp->tp_trunk;
1216 	if (tr == NULL)
1217 		return;
1218 	if (tr->tr_linkstate != NULL)
1219 		(*tr->tr_linkstate)(tp);
1220 	trunk_link_active(tr, tp);
1221 	rtm_ifchg(&tr->tr_ac.ac_if);
1222 }
1223 
1224 struct trunk_port *
1225 trunk_link_active(struct trunk_softc *tr, struct trunk_port *tp)
1226 {
1227 	struct trunk_port *tp_next, *rval = NULL;
1228 	int new_link = LINK_STATE_DOWN;
1229 
1230 	/*
1231 	 * Search a port which reports an active link state.
1232 	 */
1233 
1234 	if (tp == NULL)
1235 		goto search;
1236 	if (TRUNK_PORTACTIVE(tp)) {
1237 		rval = tp;
1238 		goto found;
1239 	}
1240 	if ((tp_next = SLIST_NEXT(tp, tp_entries)) != NULL &&
1241 	    TRUNK_PORTACTIVE(tp_next)) {
1242 		rval = tp_next;
1243 		goto found;
1244 	}
1245 
1246  search:
1247 	SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) {
1248 		if (TRUNK_PORTACTIVE(tp_next)) {
1249 			rval = tp_next;
1250 			goto found;
1251 		}
1252 	}
1253 
1254  found:
1255 	if (rval != NULL) {
1256 		/*
1257 		 * The IEEE 802.1D standard assumes that a trunk with
1258 		 * multiple ports is always full duplex. This is valid
1259 		 * for load sharing trunks and if at least two links
1260 		 * are active. Unfortunately, checking the latter would
1261 		 * be too expensive at this point.
1262 		 */
1263 		if ((tr->tr_capabilities & IFCAP_TRUNK_FULLDUPLEX) &&
1264 		    (tr->tr_count > 1))
1265 			new_link = LINK_STATE_FULL_DUPLEX;
1266 		else
1267 			new_link = rval->tp_link_state;
1268 	}
1269 
1270 	if (tr->tr_ac.ac_if.if_link_state != new_link) {
1271 		tr->tr_ac.ac_if.if_link_state = new_link;
1272 		if_link_state_change(&tr->tr_ac.ac_if);
1273 	}
1274 
1275 	return (rval);
1276 }
1277 
1278 const void *
1279 trunk_gethdr(struct mbuf *m, u_int off, u_int len, void *buf)
1280 {
1281 	if (m->m_pkthdr.len < (off + len))
1282 		return (NULL);
1283 	else if (m->m_len < (off + len)) {
1284 		m_copydata(m, off, len, buf);
1285 		return (buf);
1286 	}
1287 	return (mtod(m, caddr_t) + off);
1288 }
1289 
1290 /*
1291  * Simple round robin trunking
1292  */
1293 
1294 int
1295 trunk_rr_attach(struct trunk_softc *tr)
1296 {
1297 	struct trunk_port *tp;
1298 
1299 	tr->tr_detach = trunk_rr_detach;
1300 	tr->tr_start = trunk_rr_start;
1301 	tr->tr_input = trunk_rr_input;
1302 	tr->tr_init = NULL;
1303 	tr->tr_stop = NULL;
1304 	tr->tr_linkstate = NULL;
1305 	tr->tr_port_create = NULL;
1306 	tr->tr_port_destroy = trunk_rr_port_destroy;
1307 	tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX;
1308 	tr->tr_req = NULL;
1309 	tr->tr_portreq = NULL;
1310 
1311 	tp = SLIST_FIRST(&tr->tr_ports);
1312 	tr->tr_psc = (caddr_t)tp;
1313 
1314 	return (0);
1315 }
1316 
1317 int
1318 trunk_rr_detach(struct trunk_softc *tr)
1319 {
1320 	tr->tr_psc = NULL;
1321 	return (0);
1322 }
1323 
1324 void
1325 trunk_rr_port_destroy(struct trunk_port *tp)
1326 {
1327 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
1328 
1329 	if (tp == (struct trunk_port *)tr->tr_psc)
1330 		tr->tr_psc = NULL;
1331 }
1332 
1333 int
1334 trunk_rr_start(struct trunk_softc *tr, struct mbuf *m)
1335 {
1336 	struct trunk_port *tp = (struct trunk_port *)tr->tr_psc, *tp_next;
1337 	int error = 0;
1338 
1339 	if (tp == NULL && (tp = trunk_link_active(tr, NULL)) == NULL) {
1340 		m_freem(m);
1341 		return (ENOENT);
1342 	}
1343 
1344 	if ((error = if_enqueue(tp->tp_if, m)) != 0)
1345 		return (error);
1346 
1347 	/* Get next active port */
1348 	tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries));
1349 	tr->tr_psc = (caddr_t)tp_next;
1350 
1351 	return (0);
1352 }
1353 
1354 int
1355 trunk_rr_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m)
1356 {
1357 	/* Just pass in the packet to our trunk device */
1358 	return (0);
1359 }
1360 
1361 /*
1362  * Active failover
1363  */
1364 
1365 int
1366 trunk_fail_attach(struct trunk_softc *tr)
1367 {
1368 	tr->tr_detach = trunk_fail_detach;
1369 	tr->tr_start = trunk_fail_start;
1370 	tr->tr_input = trunk_fail_input;
1371 	tr->tr_init = NULL;
1372 	tr->tr_stop = NULL;
1373 	tr->tr_port_create = trunk_fail_port_create;
1374 	tr->tr_port_destroy = trunk_fail_port_destroy;
1375 	tr->tr_linkstate = trunk_fail_linkstate;
1376 	tr->tr_req = NULL;
1377 	tr->tr_portreq = NULL;
1378 
1379 	/* Get primary or the next active port */
1380 	tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary);
1381 
1382 	return (0);
1383 }
1384 
1385 int
1386 trunk_fail_detach(struct trunk_softc *tr)
1387 {
1388 	tr->tr_psc = NULL;
1389 	return (0);
1390 }
1391 
1392 int
1393 trunk_fail_port_create(struct trunk_port *tp)
1394 {
1395 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
1396 
1397 	/* Get primary or the next active port */
1398 	tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary);
1399 	return (0);
1400 }
1401 
1402 void
1403 trunk_fail_port_destroy(struct trunk_port *tp)
1404 {
1405 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
1406 	struct trunk_port *tp_next;
1407 
1408 	if ((caddr_t)tp == tr->tr_psc) {
1409 		/* Get the next active port */
1410 		tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries));
1411 		if (tp_next == tp)
1412 			tr->tr_psc = NULL;
1413 		else
1414 			tr->tr_psc = (caddr_t)tp_next;
1415 	} else {
1416 		/* Get primary or the next active port */
1417 		tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary);
1418 	}
1419 }
1420 
1421 int
1422 trunk_fail_start(struct trunk_softc *tr, struct mbuf *m)
1423 {
1424 	struct trunk_port *tp = (struct trunk_port *)tr->tr_psc;
1425 
1426 	/* Use the master port if active or the next available port */
1427 	if (tp == NULL) {
1428 		m_freem(m);
1429 		return (ENOENT);
1430 	}
1431 
1432 	return (if_enqueue(tp->tp_if, m));
1433 }
1434 
1435 int
1436 trunk_fail_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m)
1437 {
1438 	if ((caddr_t)tp == tr->tr_psc)
1439 		return (0);
1440 	m_freem(m);
1441 	return (-1);
1442 }
1443 
1444 void
1445 trunk_fail_linkstate(struct trunk_port *tp)
1446 {
1447 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
1448 
1449 	tr->tr_psc = (caddr_t)trunk_link_active(tr, tr->tr_primary);
1450 }
1451 
1452 /*
1453  * Loadbalancing
1454  */
1455 
1456 int
1457 trunk_lb_attach(struct trunk_softc *tr)
1458 {
1459 	struct trunk_lb *lb;
1460 
1461 	if ((lb = malloc(sizeof(*lb), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
1462 		return (ENOMEM);
1463 
1464 	tr->tr_detach = trunk_lb_detach;
1465 	tr->tr_start = trunk_lb_start;
1466 	tr->tr_input = trunk_lb_input;
1467 	tr->tr_port_create = trunk_lb_port_create;
1468 	tr->tr_port_destroy = trunk_lb_port_destroy;
1469 	tr->tr_linkstate = NULL;
1470 	tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX;
1471 	tr->tr_req = NULL;
1472 	tr->tr_portreq = NULL;
1473 	tr->tr_init = NULL;
1474 	tr->tr_stop = NULL;
1475 
1476 	arc4random_buf(&lb->lb_key, sizeof(lb->lb_key));
1477 	tr->tr_psc = (caddr_t)lb;
1478 
1479 	return (0);
1480 }
1481 
1482 int
1483 trunk_lb_detach(struct trunk_softc *tr)
1484 {
1485 	struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
1486 
1487 	free(lb, M_DEVBUF, sizeof *lb);
1488 	return (0);
1489 }
1490 
1491 int
1492 trunk_lb_porttable(struct trunk_softc *tr, struct trunk_port *tp)
1493 {
1494 	struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
1495 	struct trunk_port *tp_next;
1496 	int i = 0;
1497 
1498 	bzero(&lb->lb_ports, sizeof(lb->lb_ports));
1499 	SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) {
1500 		if (tp_next == tp)
1501 			continue;
1502 		if (i >= TRUNK_MAX_PORTS)
1503 			return (EINVAL);
1504 		if (tr->tr_ifflags & IFF_DEBUG)
1505 			printf("%s: port %s at index %d\n",
1506 			    tr->tr_ifname, tp_next->tp_ifname, i);
1507 		lb->lb_ports[i++] = tp_next;
1508 	}
1509 
1510 	return (0);
1511 }
1512 
1513 int
1514 trunk_lb_port_create(struct trunk_port *tp)
1515 {
1516 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
1517 	return (trunk_lb_porttable(tr, NULL));
1518 }
1519 
1520 void
1521 trunk_lb_port_destroy(struct trunk_port *tp)
1522 {
1523 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
1524 	trunk_lb_porttable(tr, tp);
1525 }
1526 
1527 int
1528 trunk_lb_start(struct trunk_softc *tr, struct mbuf *m)
1529 {
1530 	struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
1531 	struct trunk_port *tp = NULL;
1532 	u_int32_t p = 0;
1533 
1534 	p = trunk_hashmbuf(m, &lb->lb_key);
1535 	p %= tr->tr_count;
1536 	tp = lb->lb_ports[p];
1537 
1538 	/*
1539 	 * Check the port's link state. This will return the next active
1540 	 * port if the link is down or the port is NULL.
1541 	 */
1542 	if ((tp = trunk_link_active(tr, tp)) == NULL) {
1543 		m_freem(m);
1544 		return (ENOENT);
1545 	}
1546 
1547 	return (if_enqueue(tp->tp_if, m));
1548 }
1549 
1550 int
1551 trunk_lb_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m)
1552 {
1553 	/* Just pass in the packet to our trunk device */
1554 	return (0);
1555 }
1556 
1557 /*
1558  * Broadcast mode
1559  */
1560 
1561 int
1562 trunk_bcast_attach(struct trunk_softc *tr)
1563 {
1564 	tr->tr_detach = trunk_bcast_detach;
1565 	tr->tr_start = trunk_bcast_start;
1566 	tr->tr_input = trunk_bcast_input;
1567 	tr->tr_init = NULL;
1568 	tr->tr_stop = NULL;
1569 	tr->tr_port_create = NULL;
1570 	tr->tr_port_destroy = NULL;
1571 	tr->tr_linkstate = NULL;
1572 	tr->tr_req = NULL;
1573 	tr->tr_portreq = NULL;
1574 
1575 	return (0);
1576 }
1577 
1578 int
1579 trunk_bcast_detach(struct trunk_softc *tr)
1580 {
1581 	return (0);
1582 }
1583 
1584 int
1585 trunk_bcast_start(struct trunk_softc *tr, struct mbuf *m0)
1586 {
1587 	int			 active_ports = 0;
1588 	int			 errors = 0;
1589 	struct trunk_port	*tp, *last = NULL;
1590 	struct mbuf		*m;
1591 
1592 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
1593 		if (!TRUNK_PORTACTIVE(tp))
1594 			continue;
1595 
1596 		active_ports++;
1597 
1598 		if (last != NULL) {
1599 			m = m_copym(m0, 0, M_COPYALL, M_DONTWAIT);
1600 			if (m == NULL) {
1601 				errors++;
1602 				break;
1603 			}
1604 
1605 			if (if_enqueue(last->tp_if, m) != 0)
1606 				errors++;
1607 		}
1608 		last = tp;
1609 	}
1610 	if (last == NULL) {
1611 		m_freem(m0);
1612 		return (ENOENT);
1613 	}
1614 
1615 	if (if_enqueue(last->tp_if, m0) != 0)
1616 		errors++;
1617 
1618 	if (errors == active_ports)
1619 		return (ENOBUFS);
1620 
1621 	return (0);
1622 }
1623 
1624 int
1625 trunk_bcast_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m)
1626 {
1627 	return (0);
1628 }
1629 
1630 /*
1631  * 802.3ad LACP
1632  */
1633 
1634 int
1635 trunk_lacp_attach(struct trunk_softc *tr)
1636 {
1637 	struct trunk_port *tp;
1638 	int error;
1639 
1640 	tr->tr_detach = trunk_lacp_detach;
1641 	tr->tr_port_create = lacp_port_create;
1642 	tr->tr_port_destroy = lacp_port_destroy;
1643 	tr->tr_linkstate = lacp_linkstate;
1644 	tr->tr_start = trunk_lacp_start;
1645 	tr->tr_input = trunk_lacp_input;
1646 	tr->tr_init = lacp_init;
1647 	tr->tr_stop = lacp_stop;
1648 	tr->tr_req = lacp_req;
1649 	tr->tr_portreq = lacp_portreq;
1650 
1651 	error = lacp_attach(tr);
1652 	if (error)
1653 		return (error);
1654 
1655 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
1656 		lacp_port_create(tp);
1657 
1658 	return (error);
1659 }
1660 
1661 int
1662 trunk_lacp_detach(struct trunk_softc *tr)
1663 {
1664 	struct trunk_port *tp;
1665 	int error;
1666 
1667 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
1668 		lacp_port_destroy(tp);
1669 
1670 	/* unlocking is safe here */
1671 	error = lacp_detach(tr);
1672 
1673 	return (error);
1674 }
1675 
1676 int
1677 trunk_lacp_start(struct trunk_softc *tr, struct mbuf *m)
1678 {
1679 	struct trunk_port *tp;
1680 
1681 	tp = lacp_select_tx_port(tr, m);
1682 	if (tp == NULL) {
1683 		m_freem(m);
1684 		return (EBUSY);
1685 	}
1686 
1687 	return (if_enqueue(tp->tp_if, m));
1688 }
1689 
1690 int
1691 trunk_lacp_input(struct trunk_softc *tr, struct trunk_port *tp, struct mbuf *m)
1692 {
1693 	return (lacp_input(tp, m));
1694 }
1695