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