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