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