xref: /openbsd-src/sys/net/if_trunk.c (revision 5054e3e78af0749a9bb00ba9a024b3ee2d90290f)
1 /*	$OpenBSD: if_trunk.c,v 1.70 2009/11/18 02:09:59 deraadt 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 "bpfilter.h"
20 #include "trunk.h"
21 
22 #include <sys/param.h>
23 #include <sys/kernel.h>
24 #include <sys/malloc.h>
25 #include <sys/mbuf.h>
26 #include <sys/queue.h>
27 #include <sys/socket.h>
28 #include <sys/sockio.h>
29 #include <sys/sysctl.h>
30 #include <sys/systm.h>
31 #include <sys/proc.h>
32 #include <sys/hash.h>
33 
34 #include <dev/rndvar.h>
35 
36 #include <net/if.h>
37 #include <net/if_arp.h>
38 #include <net/if_dl.h>
39 #include <net/if_llc.h>
40 #include <net/if_media.h>
41 #include <net/if_types.h>
42 #if NBPFILTER > 0
43 #include <net/bpf.h>
44 #endif
45 
46 #ifdef INET
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/if_ether.h>
50 #include <netinet/ip.h>
51 #endif
52 
53 #ifdef INET6
54 #include <netinet/ip6.h>
55 #endif
56 
57 #include <net/if_vlan_var.h>
58 #include <net/if_trunk.h>
59 #include <net/trunklacp.h>
60 
61 
62 SLIST_HEAD(__trhead, trunk_softc) trunk_list;	/* list of trunks */
63 
64 extern struct ifaddr **ifnet_addrs;
65 
66 void	 trunkattach(int);
67 int	 trunk_clone_create(struct if_clone *, int);
68 int	 trunk_clone_destroy(struct ifnet *);
69 void	 trunk_lladdr(struct arpcom *, u_int8_t *);
70 int	 trunk_capabilities(struct trunk_softc *);
71 void	 trunk_port_lladdr(struct trunk_port *, u_int8_t *);
72 int	 trunk_port_create(struct trunk_softc *, struct ifnet *);
73 int	 trunk_port_destroy(struct trunk_port *);
74 void	 trunk_port_watchdog(struct ifnet *);
75 void	 trunk_port_state(void *);
76 int	 trunk_port_ioctl(struct ifnet *, u_long, caddr_t);
77 struct trunk_port *trunk_port_get(struct trunk_softc *, struct ifnet *);
78 int	 trunk_port_checkstacking(struct trunk_softc *);
79 void	 trunk_port2req(struct trunk_port *, struct trunk_reqport *);
80 int	 trunk_ioctl(struct ifnet *, u_long, caddr_t);
81 int	 trunk_ether_addmulti(struct trunk_softc *, struct ifreq *);
82 int	 trunk_ether_delmulti(struct trunk_softc *, struct ifreq *);
83 void	 trunk_ether_purgemulti(struct trunk_softc *);
84 int	 trunk_ether_cmdmulti(struct trunk_port *, u_long);
85 int	 trunk_ioctl_allports(struct trunk_softc *, u_long, caddr_t);
86 void	 trunk_start(struct ifnet *);
87 void	 trunk_init(struct ifnet *);
88 void	 trunk_stop(struct ifnet *);
89 void	 trunk_watchdog(struct ifnet *);
90 int	 trunk_media_change(struct ifnet *);
91 void	 trunk_media_status(struct ifnet *, struct ifmediareq *);
92 struct trunk_port *trunk_link_active(struct trunk_softc *,
93 	    struct trunk_port *);
94 const void *trunk_gethdr(struct mbuf *, u_int, u_int, void *);
95 
96 struct if_clone trunk_cloner =
97     IF_CLONE_INITIALIZER("trunk", trunk_clone_create, trunk_clone_destroy);
98 
99 /* Simple round robin */
100 int	 trunk_rr_attach(struct trunk_softc *);
101 int	 trunk_rr_detach(struct trunk_softc *);
102 void	 trunk_rr_port_destroy(struct trunk_port *);
103 int	 trunk_rr_start(struct trunk_softc *, struct mbuf *);
104 int	 trunk_rr_input(struct trunk_softc *, struct trunk_port *,
105 	    struct ether_header *, struct mbuf *);
106 
107 /* Active failover */
108 int	 trunk_fail_attach(struct trunk_softc *);
109 int	 trunk_fail_detach(struct trunk_softc *);
110 int	 trunk_fail_start(struct trunk_softc *, struct mbuf *);
111 int	 trunk_fail_input(struct trunk_softc *, struct trunk_port *,
112 	    struct ether_header *, struct mbuf *);
113 
114 /* Loadbalancing */
115 int	 trunk_lb_attach(struct trunk_softc *);
116 int	 trunk_lb_detach(struct trunk_softc *);
117 int	 trunk_lb_port_create(struct trunk_port *);
118 void	 trunk_lb_port_destroy(struct trunk_port *);
119 int	 trunk_lb_start(struct trunk_softc *, struct mbuf *);
120 int	 trunk_lb_input(struct trunk_softc *, struct trunk_port *,
121 	    struct ether_header *, struct mbuf *);
122 int	 trunk_lb_porttable(struct trunk_softc *, struct trunk_port *);
123 
124 /* Broadcast mode */
125 int	 trunk_bcast_attach(struct trunk_softc *);
126 int	 trunk_bcast_detach(struct trunk_softc *);
127 int	 trunk_bcast_start(struct trunk_softc *, struct mbuf *);
128 int	 trunk_bcast_input(struct trunk_softc *, struct trunk_port *,
129 	    struct ether_header *, struct mbuf *);
130 
131 /* 802.3ad LACP */
132 int	 trunk_lacp_attach(struct trunk_softc *);
133 int	 trunk_lacp_detach(struct trunk_softc *);
134 int	 trunk_lacp_start(struct trunk_softc *, struct mbuf *);
135 int	 trunk_lacp_input(struct trunk_softc *, struct trunk_port *,
136 	    struct ether_header *, struct mbuf *);
137 
138 /* Trunk protocol table */
139 static const struct {
140 	enum trunk_proto	ti_proto;
141 	int			(*ti_attach)(struct trunk_softc *);
142 } trunk_protos[] = {
143 	{ TRUNK_PROTO_ROUNDROBIN,	trunk_rr_attach },
144 	{ TRUNK_PROTO_FAILOVER,		trunk_fail_attach },
145 	{ TRUNK_PROTO_LOADBALANCE,	trunk_lb_attach },
146 	{ TRUNK_PROTO_BROADCAST,	trunk_bcast_attach },
147 	{ TRUNK_PROTO_LACP,		trunk_lacp_attach },
148 	{ TRUNK_PROTO_NONE,		NULL }
149 };
150 
151 void
152 trunkattach(int count)
153 {
154 	SLIST_INIT(&trunk_list);
155 	if_clone_attach(&trunk_cloner);
156 }
157 
158 int
159 trunk_clone_create(struct if_clone *ifc, int unit)
160 {
161 	struct trunk_softc *tr;
162 	struct ifnet *ifp;
163 	int i, error = 0;
164 
165 	if ((tr = malloc(sizeof(struct trunk_softc),
166 	    M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
167 		return (ENOMEM);
168 
169 	tr->tr_unit = unit;
170 	tr->tr_proto = TRUNK_PROTO_NONE;
171 	for (i = 0; trunk_protos[i].ti_proto != TRUNK_PROTO_NONE; i++) {
172 		if (trunk_protos[i].ti_proto == TRUNK_PROTO_DEFAULT) {
173 			tr->tr_proto = trunk_protos[i].ti_proto;
174 			if ((error = trunk_protos[i].ti_attach(tr)) != 0) {
175 				free(tr, M_DEVBUF);
176 				return (error);
177 			}
178 			break;
179 		}
180 	}
181 	SLIST_INIT(&tr->tr_ports);
182 
183 	/* Initialise pseudo media types */
184 	ifmedia_init(&tr->tr_media, 0, trunk_media_change,
185 	    trunk_media_status);
186 	ifmedia_add(&tr->tr_media, IFM_ETHER | IFM_AUTO, 0, NULL);
187 	ifmedia_set(&tr->tr_media, IFM_ETHER | IFM_AUTO);
188 
189 	ifp = &tr->tr_ac.ac_if;
190 	ifp->if_softc = tr;
191 	ifp->if_start = trunk_start;
192 	ifp->if_watchdog = trunk_watchdog;
193 	ifp->if_ioctl = trunk_ioctl;
194 	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
195 	ifp->if_capabilities = trunk_capabilities(tr);
196 
197 	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
198 	IFQ_SET_READY(&ifp->if_snd);
199 
200 	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
201 	    ifc->ifc_name, unit);
202 
203 	/*
204 	 * Attach as an ordinary ethernet device, childs will be attached
205 	 * as special device IFT_IEEE8023ADLAG.
206 	 */
207 	if_attach(ifp);
208 	ether_ifattach(ifp);
209 
210 	/* Insert into the global list of trunks */
211 	SLIST_INSERT_HEAD(&trunk_list, tr, tr_entries);
212 
213 	return (0);
214 }
215 
216 int
217 trunk_clone_destroy(struct ifnet *ifp)
218 {
219 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
220 	struct trunk_port *tp;
221 	int error, s;
222 
223 	/* Remove any multicast groups that we may have joined. */
224 	trunk_ether_purgemulti(tr);
225 
226 	s = splnet();
227 
228 	/* Shutdown and remove trunk ports, return on error */
229 	while ((tp = SLIST_FIRST(&tr->tr_ports)) != NULL) {
230 		if ((error = trunk_port_destroy(tp)) != 0) {
231 			splx(s);
232 			return (error);
233 		}
234 	}
235 
236 	ifmedia_delete_instance(&tr->tr_media, IFM_INST_ANY);
237 	ether_ifdetach(ifp);
238 	if_detach(ifp);
239 
240 	SLIST_REMOVE(&trunk_list, tr, trunk_softc, tr_entries);
241 	free(tr, M_DEVBUF);
242 
243 	splx(s);
244 
245 	return (0);
246 }
247 
248 void
249 trunk_lladdr(struct arpcom *ac, u_int8_t *lladdr)
250 {
251 	struct ifnet *ifp = &ac->ac_if;
252 	struct ifaddr *ifa;
253 	struct sockaddr_dl *sdl;
254 
255 	ifa = ifnet_addrs[ifp->if_index];
256 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
257 	sdl->sdl_type = IFT_ETHER;
258 	sdl->sdl_alen = ETHER_ADDR_LEN;
259 	bcopy(lladdr, LLADDR(sdl), ETHER_ADDR_LEN);
260 	bcopy(lladdr, ac->ac_enaddr, ETHER_ADDR_LEN);
261 }
262 
263 int
264 trunk_capabilities(struct trunk_softc *tr)
265 {
266 	struct trunk_port *tp;
267 	int cap = ~0, priv;
268 
269 	/* Preserve private capabilities */
270 	priv = tr->tr_capabilities & IFCAP_TRUNK_MASK;
271 
272 	/* Get capabilities from the trunk ports */
273 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
274 		cap &= tp->tp_capabilities;
275 
276 	if (tr->tr_ifflags & IFF_DEBUG) {
277 		printf("%s: capabilities 0x%08x\n",
278 		    tr->tr_ifname, cap == ~0 ? priv : (cap | priv));
279 	}
280 
281 	return (cap == ~0 ? priv : (cap | priv));
282 }
283 
284 void
285 trunk_port_lladdr(struct trunk_port *tp, u_int8_t *lladdr)
286 {
287 	struct ifnet *ifp = tp->tp_if;
288 	struct ifaddr *ifa;
289 	struct ifreq ifr;
290 
291 	/* Set the link layer address */
292 	trunk_lladdr((struct arpcom *)ifp, lladdr);
293 
294 	/* Reset the port to update the lladdr */
295 	if (ifp->if_flags & IFF_UP) {
296 		int s = splnet();
297 		ifp->if_flags &= ~IFF_UP;
298 		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
299 		ifp->if_flags |= IFF_UP;
300 		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
301 		splx(s);
302 		TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
303 			if (ifa->ifa_addr != NULL &&
304 			    ifa->ifa_addr->sa_family == AF_INET)
305 				arp_ifinit((struct arpcom *)ifp, ifa);
306 		}
307 	}
308 }
309 
310 int
311 trunk_port_create(struct trunk_softc *tr, struct ifnet *ifp)
312 {
313 	struct trunk_softc *tr_ptr;
314 	struct trunk_port *tp;
315 	int error = 0;
316 
317 	/* Limit the maximal number of trunk ports */
318 	if (tr->tr_count >= TRUNK_MAX_PORTS)
319 		return (ENOSPC);
320 
321 	/* New trunk port has to be in an idle state */
322 	if (ifp->if_flags & IFF_OACTIVE)
323 		return (EBUSY);
324 
325 	/* Check if port has already been associated to a trunk */
326 	if (trunk_port_get(NULL, ifp) != NULL)
327 		return (EBUSY);
328 
329 	/* XXX Disallow non-ethernet interfaces (this should be any of 802) */
330 	if (ifp->if_type != IFT_ETHER)
331 		return (EPROTONOSUPPORT);
332 
333 	if ((error = ifpromisc(ifp, 1)) != 0)
334 		return (error);
335 
336 	if ((tp = malloc(sizeof(struct trunk_port),
337 	    M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
338 		return (ENOMEM);
339 
340 	/* Check if port is a stacked trunk */
341 	SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) {
342 		if (ifp == &tr_ptr->tr_ac.ac_if) {
343 			tp->tp_flags |= TRUNK_PORT_STACK;
344 			if (trunk_port_checkstacking(tr_ptr) >=
345 			    TRUNK_MAX_STACKING) {
346 				free(tp, M_DEVBUF);
347 				return (E2BIG);
348 			}
349 		}
350 	}
351 
352 	/* Change the interface type */
353 	tp->tp_iftype = ifp->if_type;
354 	ifp->if_type = IFT_IEEE8023ADLAG;
355 	ifp->if_tp = (caddr_t)tp;
356 	tp->tp_watchdog = ifp->if_watchdog;
357 	ifp->if_watchdog = trunk_port_watchdog;
358 	tp->tp_ioctl = ifp->if_ioctl;
359 	ifp->if_ioctl = trunk_port_ioctl;
360 
361 	tp->tp_if = ifp;
362 	tp->tp_trunk = tr;
363 
364 	/* Save port link layer address */
365 	bcopy(((struct arpcom *)ifp)->ac_enaddr, tp->tp_lladdr, ETHER_ADDR_LEN);
366 
367 	if (SLIST_EMPTY(&tr->tr_ports)) {
368 		tr->tr_primary = tp;
369 		tp->tp_flags |= TRUNK_PORT_MASTER;
370 		trunk_lladdr(&tr->tr_ac, tp->tp_lladdr);
371 	}
372 
373 	/* Update link layer address for this port */
374 	trunk_port_lladdr(tp, tr->tr_primary->tp_lladdr);
375 
376 	/* Insert into the list of ports */
377 	SLIST_INSERT_HEAD(&tr->tr_ports, tp, tp_entries);
378 	tr->tr_count++;
379 
380 	/* Update trunk capabilities */
381 	tr->tr_capabilities = trunk_capabilities(tr);
382 
383 	/* Add multicast addresses to this port */
384 	trunk_ether_cmdmulti(tp, SIOCADDMULTI);
385 
386 	/* Register callback for physical link state changes */
387 	if (ifp->if_linkstatehooks != NULL)
388 		tp->lh_cookie = hook_establish(ifp->if_linkstatehooks, 1,
389 		    trunk_port_state, tp);
390 
391 	if (tr->tr_port_create != NULL)
392 		error = (*tr->tr_port_create)(tp);
393 
394 	return (error);
395 }
396 
397 int
398 trunk_port_checkstacking(struct trunk_softc *tr)
399 {
400 	struct trunk_softc *tr_ptr;
401 	struct trunk_port *tp;
402 	int m = 0;
403 
404 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
405 		if (tp->tp_flags & TRUNK_PORT_STACK) {
406 			tr_ptr = (struct trunk_softc *)tp->tp_if->if_softc;
407 			m = MAX(m, trunk_port_checkstacking(tr_ptr));
408 		}
409 	}
410 
411 	return (m + 1);
412 }
413 
414 int
415 trunk_port_destroy(struct trunk_port *tp)
416 {
417 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
418 	struct trunk_port *tp_ptr;
419 	struct ifnet *ifp = tp->tp_if;
420 
421 	if (tr->tr_port_destroy != NULL)
422 		(*tr->tr_port_destroy)(tp);
423 
424 	/* Remove multicast addresses from this port */
425 	trunk_ether_cmdmulti(tp, SIOCDELMULTI);
426 
427 	/* Port has to be down */
428 	if (ifp->if_flags & IFF_UP)
429 		if_down(ifp);
430 
431 	ifpromisc(ifp, 0);
432 
433 	/* Restore interface */
434 	ifp->if_type = tp->tp_iftype;
435 	ifp->if_watchdog = tp->tp_watchdog;
436 	ifp->if_ioctl = tp->tp_ioctl;
437 	ifp->if_tp = NULL;
438 
439 	if (ifp->if_linkstatehooks != NULL)
440 		hook_disestablish(ifp->if_linkstatehooks, tp->lh_cookie);
441 
442 	/* Finally, remove the port from the trunk */
443 	SLIST_REMOVE(&tr->tr_ports, tp, trunk_port, tp_entries);
444 	tr->tr_count--;
445 
446 	/* Update the primary interface */
447 	if (tp == tr->tr_primary) {
448 		u_int8_t lladdr[ETHER_ADDR_LEN];
449 
450 		if ((tp_ptr = SLIST_FIRST(&tr->tr_ports)) == NULL) {
451 			bzero(&lladdr, ETHER_ADDR_LEN);
452 		} else {
453 			bcopy(((struct arpcom *)tp_ptr->tp_if)->ac_enaddr,
454 			    lladdr, ETHER_ADDR_LEN);
455 			tp_ptr->tp_flags = TRUNK_PORT_MASTER;
456 		}
457 		trunk_lladdr(&tr->tr_ac, lladdr);
458 		tr->tr_primary = tp_ptr;
459 
460 		/* Update link layer address for each port */
461 		SLIST_FOREACH(tp_ptr, &tr->tr_ports, tp_entries)
462 			trunk_port_lladdr(tp_ptr, lladdr);
463 	}
464 
465 	/* Reset the port lladdr */
466 	trunk_port_lladdr(tp, tp->tp_lladdr);
467 
468 	free(tp, M_DEVBUF);
469 
470 	/* Update trunk capabilities */
471 	tr->tr_capabilities = trunk_capabilities(tr);
472 
473 	return (0);
474 }
475 
476 void
477 trunk_port_watchdog(struct ifnet *ifp)
478 {
479 	struct trunk_port *tp;
480 
481 	/* Should be checked by the caller */
482 	if (ifp->if_type != IFT_IEEE8023ADLAG)
483 		return;
484 	if ((tp = (struct trunk_port *)ifp->if_tp) == NULL ||
485 	    tp->tp_trunk == NULL)
486 		return;
487 
488 	if (tp->tp_watchdog != NULL)
489 		(*tp->tp_watchdog)(ifp);
490 }
491 
492 
493 int
494 trunk_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
495 {
496 	struct trunk_reqport *rp = (struct trunk_reqport *)data;
497 	struct trunk_softc *tr;
498 	struct trunk_port *tp = NULL;
499 	int s, error = 0;
500 
501 	s = splnet();
502 
503 	/* Should be checked by the caller */
504 	if (ifp->if_type != IFT_IEEE8023ADLAG ||
505 	    (tp = (struct trunk_port *)ifp->if_tp) == NULL ||
506 	    (tr = (struct trunk_softc *)tp->tp_trunk) == NULL) {
507 		error = EINVAL;
508 		goto fallback;
509 	}
510 
511 	switch (cmd) {
512 	case SIOCGTRUNKPORT:
513 		if (rp->rp_portname[0] == '\0' ||
514 		    ifunit(rp->rp_portname) != ifp) {
515 			error = EINVAL;
516 			break;
517 		}
518 
519 		/* Search in all trunks if the global flag is set */
520 		if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
521 		    NULL : tr, ifp)) == NULL) {
522 			error = ENOENT;
523 			break;
524 		}
525 
526 		trunk_port2req(tp, rp);
527 		break;
528 	default:
529 		error = ENOTTY;
530 		goto fallback;
531 	}
532 
533 	splx(s);
534 	return (error);
535 
536  fallback:
537 	splx(s);
538 
539 	if (tp != NULL)
540 		error = (*tp->tp_ioctl)(ifp, cmd, data);
541 
542 	return (error);
543 }
544 
545 void
546 trunk_port_ifdetach(struct ifnet *ifp)
547 {
548 	struct trunk_port *tp;
549 
550 	if ((tp = (struct trunk_port *)ifp->if_tp) == NULL)
551 		return;
552 
553 	trunk_port_destroy(tp);
554 }
555 
556 struct trunk_port *
557 trunk_port_get(struct trunk_softc *tr, struct ifnet *ifp)
558 {
559 	struct trunk_port *tp;
560 	struct trunk_softc *tr_ptr;
561 
562 	if (tr != NULL) {
563 		/* Search port in specified trunk */
564 		SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
565 			if (tp->tp_if == ifp)
566 				return (tp);
567 		}
568 	} else {
569 		/* Search all trunks for the selected port */
570 		SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) {
571 			SLIST_FOREACH(tp, &tr_ptr->tr_ports, tp_entries) {
572 				if (tp->tp_if == ifp)
573 					return (tp);
574 			}
575 		}
576 	}
577 
578 	return (NULL);
579 }
580 
581 void
582 trunk_port2req(struct trunk_port *tp, struct trunk_reqport *rp)
583 {
584 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
585 
586 	strlcpy(rp->rp_ifname, tr->tr_ifname, sizeof(rp->rp_ifname));
587 	strlcpy(rp->rp_portname, tp->tp_if->if_xname, sizeof(rp->rp_portname));
588 	rp->rp_prio = tp->tp_prio;
589 	if (tr->tr_portreq != NULL)
590 		(*tr->tr_portreq)(tp, (caddr_t)&rp->rp_psc);
591 
592 	/* Add protocol specific flags */
593 	switch (tr->tr_proto) {
594 	case TRUNK_PROTO_FAILOVER:
595 		rp->rp_flags = tp->tp_flags;
596 		if (tp == trunk_link_active(tr, tr->tr_primary))
597 			rp->rp_flags |= TRUNK_PORT_ACTIVE;
598 		break;
599 
600 	case TRUNK_PROTO_ROUNDROBIN:
601 	case TRUNK_PROTO_LOADBALANCE:
602 	case TRUNK_PROTO_BROADCAST:
603 		rp->rp_flags = tp->tp_flags;
604 		if (TRUNK_PORTACTIVE(tp))
605 			rp->rp_flags |= TRUNK_PORT_ACTIVE;
606 		break;
607 
608 	case TRUNK_PROTO_LACP:
609 		/* LACP has a different definition of active */
610 		rp->rp_flags = lacp_port_status(tp);
611 		break;
612 	default:
613 		break;
614 	}
615 }
616 
617 int
618 trunk_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
619 {
620 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
621 	struct trunk_reqall *ra = (struct trunk_reqall *)data;
622 	struct trunk_reqport *rp = (struct trunk_reqport *)data, rpbuf;
623 	struct ifreq *ifr = (struct ifreq *)data;
624 	struct ifaddr *ifa = (struct ifaddr *)data;
625 	struct trunk_port *tp;
626 	struct ifnet *tpif;
627 	int s, i, error = 0;
628 
629 	s = splnet();
630 
631 	bzero(&rpbuf, sizeof(rpbuf));
632 
633 	switch (cmd) {
634 	case SIOCGTRUNK:
635 		ra->ra_proto = tr->tr_proto;
636 		if (tr->tr_req != NULL)
637 			(*tr->tr_req)(tr, (caddr_t)&ra->ra_psc);
638 		ra->ra_ports = i = 0;
639 		tp = SLIST_FIRST(&tr->tr_ports);
640 		while (tp && ra->ra_size >=
641 		    i + sizeof(struct trunk_reqport)) {
642 			trunk_port2req(tp, &rpbuf);
643 			error = copyout(&rpbuf, (caddr_t)ra->ra_port + i,
644 			    sizeof(struct trunk_reqport));
645 			if (error)
646 				break;
647 			i += sizeof(struct trunk_reqport);
648 			ra->ra_ports++;
649 			tp = SLIST_NEXT(tp, tp_entries);
650 		}
651 		break;
652 	case SIOCSTRUNK:
653 		if ((error = suser(curproc, 0)) != 0) {
654 			error = EPERM;
655 			break;
656 		}
657 		if (ra->ra_proto >= TRUNK_PROTO_MAX) {
658 			error = EPROTONOSUPPORT;
659 			break;
660 		}
661 		if (tr->tr_proto != TRUNK_PROTO_NONE)
662 			error = tr->tr_detach(tr);
663 		if (error != 0)
664 			break;
665 		for (i = 0; i < (sizeof(trunk_protos) /
666 		    sizeof(trunk_protos[0])); 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 				goto out;
676 			}
677 		}
678 		error = EPROTONOSUPPORT;
679 		break;
680 	case SIOCGTRUNKPORT:
681 		if (rp->rp_portname[0] == '\0' ||
682 		    (tpif = ifunit(rp->rp_portname)) == NULL) {
683 			error = EINVAL;
684 			break;
685 		}
686 
687 		/* Search in all trunks if the global flag is set */
688 		if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
689 		    NULL : tr, tpif)) == NULL) {
690 			error = ENOENT;
691 			break;
692 		}
693 
694 		trunk_port2req(tp, rp);
695 		break;
696 	case SIOCSTRUNKPORT:
697 		if ((error = suser(curproc, 0)) != 0) {
698 			error = EPERM;
699 			break;
700 		}
701 		if (rp->rp_portname[0] == '\0' ||
702 		    (tpif = ifunit(rp->rp_portname)) == NULL) {
703 			error = EINVAL;
704 			break;
705 		}
706 		error = trunk_port_create(tr, tpif);
707 		break;
708 	case SIOCSTRUNKDELPORT:
709 		if ((error = suser(curproc, 0)) != 0) {
710 			error = EPERM;
711 			break;
712 		}
713 		if (rp->rp_portname[0] == '\0' ||
714 		    (tpif = ifunit(rp->rp_portname)) == NULL) {
715 			error = EINVAL;
716 			break;
717 		}
718 
719 		/* Search in all trunks if the global flag is set */
720 		if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
721 		    NULL : tr, tpif)) == NULL) {
722 			error = ENOENT;
723 			break;
724 		}
725 
726 		error = trunk_port_destroy(tp);
727 		break;
728 	case SIOCSIFADDR:
729 		ifp->if_flags |= IFF_UP;
730 #ifdef INET
731 		if (ifa->ifa_addr->sa_family == AF_INET)
732 			arp_ifinit(&tr->tr_ac, ifa);
733 #endif /* INET */
734 		error = ENETRESET;
735 		break;
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 	if ((error = trunk_ioctl_allports(tr, SIOCDELMULTI,
836 	    (caddr_t)ifr)) != 0) {
837 		/* XXX At least one port failed to remove the address */
838 		if (tr->tr_ifflags & IFF_DEBUG) {
839 			printf("%s: failed to remove multicast address "
840 			    "on all ports\n", tr->tr_ifname);
841 		}
842 	}
843 
844 	SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries);
845 	free(mc, M_DEVBUF);
846 
847 	return (0);
848 }
849 
850 void
851 trunk_ether_purgemulti(struct trunk_softc *tr)
852 {
853 	struct trunk_mc *mc;
854 	struct trunk_ifreq ifs;
855 	struct ifreq *ifr = &ifs.ifreq.ifreq;
856 
857 	while ((mc = SLIST_FIRST(&tr->tr_mc_head)) != NULL) {
858 		bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len);
859 
860 		/* Try to remove multicast address on all ports */
861 		trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr);
862 
863 		SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries);
864 		free(mc, M_DEVBUF);
865 	}
866 }
867 
868 int
869 trunk_ether_cmdmulti(struct trunk_port *tp, u_long cmd)
870 {
871 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
872 	struct trunk_mc *mc;
873 	struct trunk_ifreq ifs;
874 	struct ifreq *ifr = &ifs.ifreq.ifreq;
875 	int ret, error = 0;
876 
877 	bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ);
878 	SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) {
879 		bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len);
880 
881 		if ((ret = tp->tp_ioctl(tp->tp_if, cmd, (caddr_t)ifr)) != 0) {
882 			if (tr->tr_ifflags & IFF_DEBUG) {
883 				printf("%s: ioctl %lu failed on %s: %d\n",
884 				    tr->tr_ifname, cmd, tp->tp_ifname, ret);
885 			}
886 			/* Store last known error and continue */
887 			error = ret;
888 		}
889 	}
890 
891 	return (error);
892 }
893 
894 int
895 trunk_ioctl_allports(struct trunk_softc *tr, u_long cmd, caddr_t data)
896 {
897 	struct ifreq *ifr = (struct ifreq *)data;
898 	struct trunk_port *tp;
899 	int ret, error = 0;
900 
901 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
902 		bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ);
903 		if ((ret = tp->tp_ioctl(tp->tp_if, cmd, data)) != 0) {
904 			if (tr->tr_ifflags & IFF_DEBUG) {
905 				printf("%s: ioctl %lu failed on %s: %d\n",
906 				    tr->tr_ifname, cmd, tp->tp_ifname, ret);
907 			}
908 			/* Store last known error and continue */
909 			error = ret;
910 		}
911 	}
912 
913 	return (error);
914 }
915 
916 void
917 trunk_start(struct ifnet *ifp)
918 {
919 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
920 	struct mbuf *m;
921 	int error;
922 
923 	for (;;) {
924 		IFQ_DEQUEUE(&ifp->if_snd, m);
925 		if (m == NULL)
926 			break;
927 
928 #if NBPFILTER > 0
929 		if (ifp->if_bpf)
930 			bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
931 #endif
932 
933 		if (tr->tr_proto != TRUNK_PROTO_NONE && tr->tr_count) {
934 			error = (*tr->tr_start)(tr, m);
935 			if (error == 0)
936 				ifp->if_opackets++;
937 			else
938 				ifp->if_oerrors++;
939 		} else {
940 			m_freem(m);
941 			if (tr->tr_proto != TRUNK_PROTO_NONE)
942 				ifp->if_oerrors++;
943 		}
944 	}
945 }
946 
947 int
948 trunk_enqueue(struct ifnet *ifp, struct mbuf *m)
949 {
950 	int len, error = 0;
951 	u_short mflags;
952 
953 	splassert(IPL_NET);
954 
955 	/* Send mbuf */
956 	mflags = m->m_flags;
957 	len = m->m_pkthdr.len;
958 	IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
959 	if (error)
960 		return (error);
961 	if_start(ifp);
962 
963 	ifp->if_obytes += len;
964 	if (mflags & M_MCAST)
965 		ifp->if_omcasts++;
966 
967 	return (error);
968 }
969 
970 u_int32_t
971 trunk_hashmbuf(struct mbuf *m, u_int32_t key)
972 {
973 	u_int16_t etype, ether_vtag;
974 	u_int32_t p = 0;
975 	u_int16_t *vlan, vlanbuf[2];
976 	int off;
977 	struct ether_header *eh;
978 #ifdef INET
979 	struct ip *ip, ipbuf;
980 #endif
981 #ifdef INET6
982 	u_int32_t flow;
983 	struct ip6_hdr *ip6, ip6buf;
984 #endif
985 
986 	off = sizeof(*eh);
987 	if (m->m_len < off)
988 		return (p);
989 	eh = mtod(m, struct ether_header *);
990 	etype = ntohs(eh->ether_type);
991 	p = hash32_buf(&eh->ether_shost, ETHER_ADDR_LEN, key);
992 	p = hash32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p);
993 
994 	/* Special handling for encapsulating VLAN frames */
995 	if (m->m_flags & M_VLANTAG) {
996 		ether_vtag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
997 		p = hash32_buf(&ether_vtag, sizeof(ether_vtag), p);
998 	} else if (etype == ETHERTYPE_VLAN) {
999 		if ((vlan = (u_int16_t *)
1000 		    trunk_gethdr(m, off, EVL_ENCAPLEN, &vlanbuf)) == NULL)
1001 			return (p);
1002 		ether_vtag = EVL_VLANOFTAG(*vlan);
1003 		p = hash32_buf(&ether_vtag, sizeof(ether_vtag), p);
1004 		etype = ntohs(vlan[1]);
1005 		off += EVL_ENCAPLEN;
1006 	}
1007 
1008 	switch (etype) {
1009 #ifdef INET
1010 	case ETHERTYPE_IP:
1011 		if ((ip = (struct ip *)
1012 		    trunk_gethdr(m, off, sizeof(*ip), &ipbuf)) == NULL)
1013 			return (p);
1014 		p = hash32_buf(&ip->ip_src, sizeof(struct in_addr), p);
1015 		p = hash32_buf(&ip->ip_dst, sizeof(struct in_addr), p);
1016 		break;
1017 #endif
1018 #ifdef INET6
1019 	case ETHERTYPE_IPV6:
1020 		if ((ip6 = (struct ip6_hdr *)
1021 		    trunk_gethdr(m, off, sizeof(*ip6), &ip6buf)) == NULL)
1022 			return (p);
1023 		p = hash32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p);
1024 		p = hash32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p);
1025 		flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
1026 		p = hash32_buf(&flow, sizeof(flow), p); /* IPv6 flow label */
1027 		break;
1028 #endif
1029 	}
1030 
1031 	return (p);
1032 }
1033 
1034 void
1035 trunk_init(struct ifnet *ifp)
1036 {
1037 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1038 	int s;
1039 
1040 	s = splnet();
1041 
1042 	ifp->if_flags |= IFF_RUNNING;
1043 	ifp->if_flags &= ~IFF_OACTIVE;
1044 
1045 	if (tr->tr_init != NULL)
1046 		(*tr->tr_init)(tr);
1047 
1048 	splx(s);
1049 }
1050 
1051 void
1052 trunk_stop(struct ifnet *ifp)
1053 {
1054 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1055 	int s;
1056 
1057 	s = splnet();
1058 
1059 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1060 
1061 	if (tr->tr_stop != NULL)
1062 		(*tr->tr_stop)(tr);
1063 
1064 	splx(s);
1065 }
1066 
1067 void
1068 trunk_watchdog(struct ifnet *ifp)
1069 {
1070 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1071 
1072 	if (tr->tr_proto != TRUNK_PROTO_NONE &&
1073 	    (*tr->tr_watchdog)(tr) != 0) {
1074 		ifp->if_oerrors++;
1075 	}
1076 
1077 }
1078 
1079 int
1080 trunk_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
1081 {
1082 	struct trunk_softc *tr;
1083 	struct trunk_port *tp;
1084 	struct ifnet *trifp = NULL;
1085 	int error = 0;
1086 
1087 	/* Should be checked by the caller */
1088 	if (ifp->if_type != IFT_IEEE8023ADLAG) {
1089 		error = EPROTONOSUPPORT;
1090 		goto bad;
1091 	}
1092 	if ((tp = (struct trunk_port *)ifp->if_tp) == NULL ||
1093 	    (tr = (struct trunk_softc *)tp->tp_trunk) == NULL) {
1094 		error = ENOENT;
1095 		goto bad;
1096 	}
1097 	trifp = &tr->tr_ac.ac_if;
1098 	if (tr->tr_proto == TRUNK_PROTO_NONE) {
1099 		error = ENOENT;
1100 		goto bad;
1101 	}
1102 
1103 #if NBPFILTER > 0
1104 	if (trifp->if_bpf && tr->tr_proto != TRUNK_PROTO_FAILOVER)
1105 		bpf_mtap_hdr(trifp->if_bpf, (char *)eh, ETHER_HDR_LEN, m,
1106 		    BPF_DIRECTION_IN);
1107 #endif
1108 
1109 	error = (*tr->tr_input)(tr, tp, eh, m);
1110 	if (error != 0)
1111 		return (error);
1112 
1113 	trifp->if_ipackets++;
1114 	return (0);
1115 
1116  bad:
1117 	if (error > 0 && trifp != NULL)
1118 		trifp->if_ierrors++;
1119 	m_freem(m);
1120 	return (error);
1121 }
1122 
1123 int
1124 trunk_media_change(struct ifnet *ifp)
1125 {
1126 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1127 
1128 	if (tr->tr_ifflags & IFF_DEBUG)
1129 		printf("%s\n", __func__);
1130 
1131 	/* Ignore */
1132 	return (0);
1133 }
1134 
1135 void
1136 trunk_media_status(struct ifnet *ifp, struct ifmediareq *imr)
1137 {
1138 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1139 	struct trunk_port *tp;
1140 
1141 	imr->ifm_status = IFM_AVALID;
1142 	imr->ifm_active = IFM_ETHER | IFM_AUTO;
1143 
1144 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
1145 		if (TRUNK_PORTACTIVE(tp))
1146 			imr->ifm_status |= IFM_ACTIVE;
1147 	}
1148 }
1149 
1150 void
1151 trunk_port_state(void *arg)
1152 {
1153 	struct trunk_port *tp = (struct trunk_port *)arg;
1154 	struct trunk_softc *tr = NULL;
1155 
1156 	if (tp != NULL)
1157 		tr = (struct trunk_softc *)tp->tp_trunk;
1158 	if (tr == NULL)
1159 		return;
1160 	if (tr->tr_linkstate != NULL)
1161 		(*tr->tr_linkstate)(tp);
1162 	trunk_link_active(tr, tp);
1163 }
1164 
1165 struct trunk_port *
1166 trunk_link_active(struct trunk_softc *tr, struct trunk_port *tp)
1167 {
1168 	struct trunk_port *tp_next, *rval = NULL;
1169 	int new_link = LINK_STATE_DOWN;
1170 
1171 	/*
1172 	 * Search a port which reports an active link state.
1173 	 */
1174 
1175 	if (tp == NULL)
1176 		goto search;
1177 	if (TRUNK_PORTACTIVE(tp)) {
1178 		rval = tp;
1179 		goto found;
1180 	}
1181 	if ((tp_next = SLIST_NEXT(tp, tp_entries)) != NULL &&
1182 	    TRUNK_PORTACTIVE(tp_next)) {
1183 		rval = tp_next;
1184 		goto found;
1185 	}
1186 
1187  search:
1188 	SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) {
1189 		if (TRUNK_PORTACTIVE(tp_next)) {
1190 			rval = tp_next;
1191 			goto found;
1192 		}
1193 	}
1194 
1195  found:
1196 	if (rval != NULL) {
1197 		/*
1198 		 * The IEEE 802.1D standard assumes that a trunk with
1199 		 * multiple ports is always full duplex. This is valid
1200 		 * for load sharing trunks and if at least two links
1201 		 * are active. Unfortunately, checking the latter would
1202 		 * be too expensive at this point.
1203 		 */
1204 		if ((tr->tr_capabilities & IFCAP_TRUNK_FULLDUPLEX) &&
1205 		    (tr->tr_count > 1))
1206 			new_link = LINK_STATE_FULL_DUPLEX;
1207 		else
1208 			new_link = rval->tp_link_state;
1209 	}
1210 
1211 	if (tr->tr_ac.ac_if.if_link_state != new_link) {
1212 		tr->tr_ac.ac_if.if_link_state = new_link;
1213 		if_link_state_change(&tr->tr_ac.ac_if);
1214 	}
1215 
1216 	return (rval);
1217 }
1218 
1219 const void *
1220 trunk_gethdr(struct mbuf *m, u_int off, u_int len, void *buf)
1221 {
1222 	if (m->m_pkthdr.len < (off + len))
1223 		return (NULL);
1224 	else if (m->m_len < (off + len)) {
1225 		m_copydata(m, off, len, buf);
1226 		return (buf);
1227 	}
1228 	return (mtod(m, const void *) + off);
1229 }
1230 
1231 /*
1232  * Simple round robin trunking
1233  */
1234 
1235 int
1236 trunk_rr_attach(struct trunk_softc *tr)
1237 {
1238 	struct trunk_port *tp;
1239 
1240 	tr->tr_detach = trunk_rr_detach;
1241 	tr->tr_start = trunk_rr_start;
1242 	tr->tr_input = trunk_rr_input;
1243 	tr->tr_init = NULL;
1244 	tr->tr_stop = NULL;
1245 	tr->tr_port_create = NULL;
1246 	tr->tr_port_destroy = trunk_rr_port_destroy;
1247 	tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX;
1248 	tr->tr_req = NULL;
1249 	tr->tr_portreq = NULL;
1250 
1251 	tp = SLIST_FIRST(&tr->tr_ports);
1252 	tr->tr_psc = (caddr_t)tp;
1253 
1254 	return (0);
1255 }
1256 
1257 int
1258 trunk_rr_detach(struct trunk_softc *tr)
1259 {
1260 	tr->tr_psc = NULL;
1261 	return (0);
1262 }
1263 
1264 void
1265 trunk_rr_port_destroy(struct trunk_port *tp)
1266 {
1267 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
1268 
1269 	if (tp == (struct trunk_port *)tr->tr_psc)
1270 		tr->tr_psc = NULL;
1271 }
1272 
1273 int
1274 trunk_rr_start(struct trunk_softc *tr, struct mbuf *m)
1275 {
1276 	struct trunk_port *tp = (struct trunk_port *)tr->tr_psc, *tp_next;
1277 	int error = 0;
1278 
1279 	if (tp == NULL && (tp = trunk_link_active(tr, NULL)) == NULL) {
1280 		m_freem(m);
1281 		return (ENOENT);
1282 	}
1283 
1284 	/* Send mbuf */
1285 	if ((error = trunk_enqueue(tp->tp_if, m)) != 0)
1286 		return (error);
1287 
1288 	/* Get next active port */
1289 	tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries));
1290 	tr->tr_psc = (caddr_t)tp_next;
1291 
1292 	return (0);
1293 }
1294 
1295 int
1296 trunk_rr_input(struct trunk_softc *tr, struct trunk_port *tp,
1297     struct ether_header *eh, struct mbuf *m)
1298 {
1299 	struct ifnet *ifp = &tr->tr_ac.ac_if;
1300 
1301 	/* Just pass in the packet to our trunk device */
1302 	m->m_pkthdr.rcvif = ifp;
1303 
1304 	return (0);
1305 }
1306 
1307 /*
1308  * Active failover
1309  */
1310 
1311 int
1312 trunk_fail_attach(struct trunk_softc *tr)
1313 {
1314 	tr->tr_detach = trunk_fail_detach;
1315 	tr->tr_start = trunk_fail_start;
1316 	tr->tr_input = trunk_fail_input;
1317 	tr->tr_init = NULL;
1318 	tr->tr_stop = NULL;
1319 	tr->tr_port_create = NULL;
1320 	tr->tr_port_destroy = NULL;
1321 	tr->tr_linkstate = NULL;
1322 	tr->tr_req = NULL;
1323 	tr->tr_portreq = NULL;
1324 
1325 	return (0);
1326 }
1327 
1328 int
1329 trunk_fail_detach(struct trunk_softc *tr)
1330 {
1331 	return (0);
1332 }
1333 
1334 int
1335 trunk_fail_start(struct trunk_softc *tr, struct mbuf *m)
1336 {
1337 	struct trunk_port *tp;
1338 
1339 	/* Use the master port if active or the next available port */
1340 	if ((tp = trunk_link_active(tr, tr->tr_primary)) == NULL) {
1341 		m_freem(m);
1342 		return (ENOENT);
1343 	}
1344 
1345 	/* Send mbuf */
1346 	return (trunk_enqueue(tp->tp_if, m));
1347 }
1348 
1349 int
1350 trunk_fail_input(struct trunk_softc *tr, struct trunk_port *tp,
1351     struct ether_header *eh, struct mbuf *m)
1352 {
1353 	struct ifnet *ifp = &tr->tr_ac.ac_if;
1354 	struct trunk_port *tmp_tp;
1355 	int accept = 0;
1356 
1357 	if (tp == tr->tr_primary) {
1358 		accept = 1;
1359 	} else if (tr->tr_primary->tp_link_state == LINK_STATE_DOWN) {
1360 		tmp_tp = trunk_link_active(tr, NULL);
1361 		/*
1362 		 * If tmp_tp is null, we've received a packet when all
1363 		 * our links are down. Weird, but process it anyways.
1364 		 */
1365 		if ((tmp_tp == NULL || tmp_tp == tp))
1366 			accept = 1;
1367 	}
1368 	if (!accept) {
1369 		m_freem(m);
1370 		return (-1);
1371 	}
1372 #if NBPFILTER > 0
1373 	if (ifp->if_bpf)
1374 		bpf_mtap_hdr(ifp->if_bpf, (char *)eh, ETHER_HDR_LEN, m,
1375 		    BPF_DIRECTION_IN);
1376 #endif
1377 
1378 	m->m_pkthdr.rcvif = ifp;
1379 	return (0);
1380 }
1381 
1382 /*
1383  * Loadbalancing
1384  */
1385 
1386 int
1387 trunk_lb_attach(struct trunk_softc *tr)
1388 {
1389 	struct trunk_lb *lb;
1390 
1391 	if ((lb = malloc(sizeof(*lb), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
1392 		return (ENOMEM);
1393 
1394 	tr->tr_detach = trunk_lb_detach;
1395 	tr->tr_start = trunk_lb_start;
1396 	tr->tr_input = trunk_lb_input;
1397 	tr->tr_port_create = trunk_lb_port_create;
1398 	tr->tr_port_destroy = trunk_lb_port_destroy;
1399 	tr->tr_linkstate = NULL;
1400 	tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX;
1401 	tr->tr_req = NULL;
1402 	tr->tr_portreq = NULL;
1403 
1404 	lb->lb_key = arc4random();
1405 	tr->tr_psc = (caddr_t)lb;
1406 
1407 	return (0);
1408 }
1409 
1410 int
1411 trunk_lb_detach(struct trunk_softc *tr)
1412 {
1413 	struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
1414 	if (lb != NULL)
1415 		free(lb, M_DEVBUF);
1416 	return (0);
1417 }
1418 
1419 int
1420 trunk_lb_porttable(struct trunk_softc *tr, struct trunk_port *tp)
1421 {
1422 	struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
1423 	struct trunk_port *tp_next;
1424 	int i = 0;
1425 
1426 	bzero(&lb->lb_ports, sizeof(lb->lb_ports));
1427 	SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) {
1428 		if (tp_next == tp)
1429 			continue;
1430 		if (i >= TRUNK_MAX_PORTS)
1431 			return (EINVAL);
1432 		if (tr->tr_ifflags & IFF_DEBUG)
1433 			printf("%s: port %s at index %d\n",
1434 			    tr->tr_ifname, tp_next->tp_ifname, i);
1435 		lb->lb_ports[i++] = tp_next;
1436 	}
1437 
1438 	return (0);
1439 }
1440 
1441 int
1442 trunk_lb_port_create(struct trunk_port *tp)
1443 {
1444 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
1445 	return (trunk_lb_porttable(tr, NULL));
1446 }
1447 
1448 void
1449 trunk_lb_port_destroy(struct trunk_port *tp)
1450 {
1451 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
1452 	trunk_lb_porttable(tr, tp);
1453 }
1454 
1455 int
1456 trunk_lb_start(struct trunk_softc *tr, struct mbuf *m)
1457 {
1458 	struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
1459 	struct trunk_port *tp = NULL;
1460 	u_int32_t p = 0;
1461 
1462 	p = trunk_hashmbuf(m, lb->lb_key);
1463 	p %= tr->tr_count;
1464 	tp = lb->lb_ports[p];
1465 
1466 	/*
1467 	 * Check the port's link state. This will return the next active
1468 	 * port if the link is down or the port is NULL.
1469 	 */
1470 	if ((tp = trunk_link_active(tr, tp)) == NULL) {
1471 		m_freem(m);
1472 		return (ENOENT);
1473 	}
1474 
1475 	/* Send mbuf */
1476 	return (trunk_enqueue(tp->tp_if, m));
1477 }
1478 
1479 int
1480 trunk_lb_input(struct trunk_softc *tr, struct trunk_port *tp,
1481     struct ether_header *eh, struct mbuf *m)
1482 {
1483 	struct ifnet *ifp = &tr->tr_ac.ac_if;
1484 
1485 	/* Just pass in the packet to our trunk device */
1486 	m->m_pkthdr.rcvif = ifp;
1487 
1488 	return (0);
1489 }
1490 
1491 /*
1492  * Broadcast mode
1493  */
1494 
1495 int
1496 trunk_bcast_attach(struct trunk_softc *tr)
1497 {
1498 	tr->tr_detach = trunk_bcast_detach;
1499 	tr->tr_start = trunk_bcast_start;
1500 	tr->tr_input = trunk_bcast_input;
1501 	tr->tr_init = NULL;
1502 	tr->tr_stop = NULL;
1503 	tr->tr_port_create = NULL;
1504 	tr->tr_port_destroy = NULL;
1505 	tr->tr_linkstate = NULL;
1506 	tr->tr_req = NULL;
1507 	tr->tr_portreq = NULL;
1508 
1509 	return (0);
1510 }
1511 
1512 int
1513 trunk_bcast_detach(struct trunk_softc *tr)
1514 {
1515 	return (0);
1516 }
1517 
1518 int
1519 trunk_bcast_start(struct trunk_softc *tr, struct mbuf *m)
1520 {
1521 	int			 active_ports = 0;
1522 	int			 errors = 0;
1523 	int			 ret;
1524 	struct trunk_port	*tp;
1525 	struct mbuf		*n;
1526 
1527 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
1528 		if (TRUNK_PORTACTIVE(tp)) {
1529 			if (active_ports) {
1530 				n = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
1531 				if (n == NULL) {
1532 					m_free(m);
1533 					return (ENOBUFS);
1534 				}
1535 			} else
1536 				n = m;
1537 			active_ports++;
1538 			if ((ret = trunk_enqueue(tp->tp_if, n)))
1539 				errors++;
1540 		}
1541 	}
1542 	if (active_ports == 0) {
1543 		m_free(m);
1544 		return (ENOENT);
1545 	}
1546 	if (errors == active_ports)
1547 		return (ret);
1548 	return (0);
1549 }
1550 
1551 int
1552 trunk_bcast_input(struct trunk_softc *tr, struct trunk_port *tp,
1553     struct ether_header *eh, struct mbuf *m)
1554 {
1555 	struct ifnet *ifp = &tr->tr_ac.ac_if;
1556 
1557 	m->m_pkthdr.rcvif = ifp;
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 	/* Send mbuf */
1619 	return (trunk_enqueue(tp->tp_if, m));
1620 }
1621 
1622 int
1623 trunk_lacp_input(struct trunk_softc *tr, struct trunk_port *tp,
1624     struct ether_header *eh, struct mbuf *m)
1625 {
1626 	struct ifnet *ifp = &tr->tr_ac.ac_if;
1627 
1628 	m = lacp_input(tp, eh, m);
1629 	if (m == NULL)
1630 		return (-1);
1631 
1632 	m->m_pkthdr.rcvif = ifp;
1633 	return (0);
1634 }
1635