xref: /openbsd-src/sys/net/if_trunk.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: if_trunk.c,v 1.78 2011/10/28 12:49:43 krw 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/systm.h>
30 #include <sys/proc.h>
31 #include <sys/hash.h>
32 
33 #include <dev/rndvar.h>
34 
35 #include <net/if.h>
36 #include <net/if_arp.h>
37 #include <net/if_dl.h>
38 #include <net/if_llc.h>
39 #include <net/if_media.h>
40 #include <net/if_types.h>
41 #if NBPFILTER > 0
42 #include <net/bpf.h>
43 #endif
44 
45 #ifdef INET
46 #include <netinet/in.h>
47 #include <netinet/in_systm.h>
48 #include <netinet/if_ether.h>
49 #include <netinet/ip.h>
50 #endif
51 
52 #ifdef INET6
53 #include <netinet/ip6.h>
54 #endif
55 
56 #include <net/if_vlan_var.h>
57 #include <net/if_trunk.h>
58 #include <net/trunklacp.h>
59 
60 
61 SLIST_HEAD(__trhead, trunk_softc) trunk_list;	/* list of trunks */
62 
63 extern struct ifaddr **ifnet_addrs;
64 
65 void	 trunkattach(int);
66 int	 trunk_clone_create(struct if_clone *, int);
67 int	 trunk_clone_destroy(struct ifnet *);
68 void	 trunk_lladdr(struct arpcom *, u_int8_t *);
69 int	 trunk_capabilities(struct trunk_softc *);
70 void	 trunk_port_lladdr(struct trunk_port *, u_int8_t *);
71 int	 trunk_port_create(struct trunk_softc *, struct ifnet *);
72 int	 trunk_port_destroy(struct trunk_port *);
73 void	 trunk_port_watchdog(struct ifnet *);
74 void	 trunk_port_state(void *);
75 int	 trunk_port_ioctl(struct ifnet *, u_long, caddr_t);
76 struct trunk_port *trunk_port_get(struct trunk_softc *, struct ifnet *);
77 int	 trunk_port_checkstacking(struct trunk_softc *);
78 void	 trunk_port2req(struct trunk_port *, struct trunk_reqport *);
79 int	 trunk_ioctl(struct ifnet *, u_long, caddr_t);
80 int	 trunk_ether_addmulti(struct trunk_softc *, struct ifreq *);
81 int	 trunk_ether_delmulti(struct trunk_softc *, struct ifreq *);
82 void	 trunk_ether_purgemulti(struct trunk_softc *);
83 int	 trunk_ether_cmdmulti(struct trunk_port *, u_long);
84 int	 trunk_ioctl_allports(struct trunk_softc *, u_long, caddr_t);
85 void	 trunk_start(struct ifnet *);
86 void	 trunk_init(struct ifnet *);
87 void	 trunk_stop(struct ifnet *);
88 void	 trunk_watchdog(struct ifnet *);
89 int	 trunk_media_change(struct ifnet *);
90 void	 trunk_media_status(struct ifnet *, struct ifmediareq *);
91 struct trunk_port *trunk_link_active(struct trunk_softc *,
92 	    struct trunk_port *);
93 const void *trunk_gethdr(struct mbuf *, u_int, u_int, void *);
94 
95 struct if_clone trunk_cloner =
96     IF_CLONE_INITIALIZER("trunk", trunk_clone_create, trunk_clone_destroy);
97 
98 /* Simple round robin */
99 int	 trunk_rr_attach(struct trunk_softc *);
100 int	 trunk_rr_detach(struct trunk_softc *);
101 void	 trunk_rr_port_destroy(struct trunk_port *);
102 int	 trunk_rr_start(struct trunk_softc *, struct mbuf *);
103 int	 trunk_rr_input(struct trunk_softc *, struct trunk_port *,
104 	    struct ether_header *, struct mbuf *);
105 
106 /* Active failover */
107 int	 trunk_fail_attach(struct trunk_softc *);
108 int	 trunk_fail_detach(struct trunk_softc *);
109 int	 trunk_fail_start(struct trunk_softc *, struct mbuf *);
110 int	 trunk_fail_input(struct trunk_softc *, struct trunk_port *,
111 	    struct ether_header *, struct mbuf *);
112 
113 /* Loadbalancing */
114 int	 trunk_lb_attach(struct trunk_softc *);
115 int	 trunk_lb_detach(struct trunk_softc *);
116 int	 trunk_lb_port_create(struct trunk_port *);
117 void	 trunk_lb_port_destroy(struct trunk_port *);
118 int	 trunk_lb_start(struct trunk_softc *, struct mbuf *);
119 int	 trunk_lb_input(struct trunk_softc *, struct trunk_port *,
120 	    struct ether_header *, struct mbuf *);
121 int	 trunk_lb_porttable(struct trunk_softc *, struct trunk_port *);
122 
123 /* Broadcast mode */
124 int	 trunk_bcast_attach(struct trunk_softc *);
125 int	 trunk_bcast_detach(struct trunk_softc *);
126 int	 trunk_bcast_start(struct trunk_softc *, struct mbuf *);
127 int	 trunk_bcast_input(struct trunk_softc *, struct trunk_port *,
128 	    struct ether_header *, struct mbuf *);
129 
130 /* 802.3ad LACP */
131 int	 trunk_lacp_attach(struct trunk_softc *);
132 int	 trunk_lacp_detach(struct trunk_softc *);
133 int	 trunk_lacp_start(struct trunk_softc *, struct mbuf *);
134 int	 trunk_lacp_input(struct trunk_softc *, struct trunk_port *,
135 	    struct ether_header *, struct mbuf *);
136 
137 /* Trunk protocol table */
138 static const struct {
139 	enum trunk_proto	ti_proto;
140 	int			(*ti_attach)(struct trunk_softc *);
141 } trunk_protos[] = {
142 	{ TRUNK_PROTO_ROUNDROBIN,	trunk_rr_attach },
143 	{ TRUNK_PROTO_FAILOVER,		trunk_fail_attach },
144 	{ TRUNK_PROTO_LOADBALANCE,	trunk_lb_attach },
145 	{ TRUNK_PROTO_BROADCAST,	trunk_bcast_attach },
146 	{ TRUNK_PROTO_LACP,		trunk_lacp_attach },
147 	{ TRUNK_PROTO_NONE,		NULL }
148 };
149 
150 void
151 trunkattach(int count)
152 {
153 	SLIST_INIT(&trunk_list);
154 	if_clone_attach(&trunk_cloner);
155 }
156 
157 int
158 trunk_clone_create(struct if_clone *ifc, int unit)
159 {
160 	struct trunk_softc *tr;
161 	struct ifnet *ifp;
162 	int i, error = 0;
163 
164 	if ((tr = malloc(sizeof(struct trunk_softc),
165 	    M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
166 		return (ENOMEM);
167 
168 	tr->tr_unit = unit;
169 	tr->tr_proto = TRUNK_PROTO_NONE;
170 	for (i = 0; trunk_protos[i].ti_proto != TRUNK_PROTO_NONE; i++) {
171 		if (trunk_protos[i].ti_proto == TRUNK_PROTO_DEFAULT) {
172 			tr->tr_proto = trunk_protos[i].ti_proto;
173 			if ((error = trunk_protos[i].ti_attach(tr)) != 0) {
174 				free(tr, M_DEVBUF);
175 				return (error);
176 			}
177 			break;
178 		}
179 	}
180 	SLIST_INIT(&tr->tr_ports);
181 
182 	/* Initialise pseudo media types */
183 	ifmedia_init(&tr->tr_media, 0, trunk_media_change,
184 	    trunk_media_status);
185 	ifmedia_add(&tr->tr_media, IFM_ETHER | IFM_AUTO, 0, NULL);
186 	ifmedia_set(&tr->tr_media, IFM_ETHER | IFM_AUTO);
187 
188 	ifp = &tr->tr_ac.ac_if;
189 	ifp->if_softc = tr;
190 	ifp->if_start = trunk_start;
191 	ifp->if_watchdog = trunk_watchdog;
192 	ifp->if_ioctl = trunk_ioctl;
193 	ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST;
194 	ifp->if_capabilities = trunk_capabilities(tr);
195 
196 	IFQ_SET_MAXLEN(&ifp->if_snd, 1);
197 	IFQ_SET_READY(&ifp->if_snd);
198 
199 	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
200 	    ifc->ifc_name, unit);
201 
202 	/*
203 	 * Attach as an ordinary ethernet device, children will be attached
204 	 * as special device IFT_IEEE8023ADLAG.
205 	 */
206 	if_attach(ifp);
207 	ether_ifattach(ifp);
208 
209 	/* Insert into the global list of trunks */
210 	SLIST_INSERT_HEAD(&trunk_list, tr, tr_entries);
211 
212 	return (0);
213 }
214 
215 int
216 trunk_clone_destroy(struct ifnet *ifp)
217 {
218 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
219 	struct trunk_port *tp;
220 	int error, s;
221 
222 	/* Remove any multicast groups that we may have joined. */
223 	trunk_ether_purgemulti(tr);
224 
225 	s = splnet();
226 
227 	/* Shutdown and remove trunk ports, return on error */
228 	while ((tp = SLIST_FIRST(&tr->tr_ports)) != NULL) {
229 		if ((error = trunk_port_destroy(tp)) != 0) {
230 			splx(s);
231 			return (error);
232 		}
233 	}
234 
235 	ifmedia_delete_instance(&tr->tr_media, IFM_INST_ANY);
236 	ether_ifdetach(ifp);
237 	if_detach(ifp);
238 
239 	SLIST_REMOVE(&trunk_list, tr, trunk_softc, tr_entries);
240 	free(tr, M_DEVBUF);
241 
242 	splx(s);
243 
244 	return (0);
245 }
246 
247 void
248 trunk_lladdr(struct arpcom *ac, u_int8_t *lladdr)
249 {
250 	struct ifnet *ifp = &ac->ac_if;
251 	struct ifaddr *ifa;
252 	struct sockaddr_dl *sdl;
253 
254 	ifa = ifnet_addrs[ifp->if_index];
255 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
256 	sdl->sdl_type = IFT_ETHER;
257 	sdl->sdl_alen = ETHER_ADDR_LEN;
258 	bcopy(lladdr, LLADDR(sdl), ETHER_ADDR_LEN);
259 	bcopy(lladdr, ac->ac_enaddr, ETHER_ADDR_LEN);
260 }
261 
262 int
263 trunk_capabilities(struct trunk_softc *tr)
264 {
265 	struct trunk_port *tp;
266 	int cap = ~0, priv;
267 
268 	/* Preserve private capabilities */
269 	priv = tr->tr_capabilities & IFCAP_TRUNK_MASK;
270 
271 	/* Get capabilities from the trunk ports */
272 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
273 		cap &= tp->tp_capabilities;
274 
275 	if (tr->tr_ifflags & IFF_DEBUG) {
276 		printf("%s: capabilities 0x%08x\n",
277 		    tr->tr_ifname, cap == ~0 ? priv : (cap | priv));
278 	}
279 
280 	return (cap == ~0 ? priv : (cap | priv));
281 }
282 
283 void
284 trunk_port_lladdr(struct trunk_port *tp, u_int8_t *lladdr)
285 {
286 	struct ifnet *ifp = tp->tp_if;
287 
288 	/* Set the link layer address */
289 	trunk_lladdr((struct arpcom *)ifp, lladdr);
290 
291 	/* Reset the port to update the lladdr */
292 	ifnewlladdr(ifp);
293 }
294 
295 int
296 trunk_port_create(struct trunk_softc *tr, struct ifnet *ifp)
297 {
298 	struct trunk_softc *tr_ptr;
299 	struct trunk_port *tp;
300 	int error = 0;
301 
302 	/* Limit the maximal number of trunk ports */
303 	if (tr->tr_count >= TRUNK_MAX_PORTS)
304 		return (ENOSPC);
305 
306 	/* New trunk port has to be in an idle state */
307 	if (ifp->if_flags & IFF_OACTIVE)
308 		return (EBUSY);
309 
310 	/* Check if port has already been associated to a trunk */
311 	if (trunk_port_get(NULL, ifp) != NULL)
312 		return (EBUSY);
313 
314 	/* XXX Disallow non-ethernet interfaces (this should be any of 802) */
315 	if (ifp->if_type != IFT_ETHER)
316 		return (EPROTONOSUPPORT);
317 
318 	if ((error = ifpromisc(ifp, 1)) != 0)
319 		return (error);
320 
321 	if ((tp = malloc(sizeof(struct trunk_port),
322 	    M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
323 		return (ENOMEM);
324 
325 	/* Check if port is a stacked trunk */
326 	SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) {
327 		if (ifp == &tr_ptr->tr_ac.ac_if) {
328 			tp->tp_flags |= TRUNK_PORT_STACK;
329 			if (trunk_port_checkstacking(tr_ptr) >=
330 			    TRUNK_MAX_STACKING) {
331 				free(tp, M_DEVBUF);
332 				return (E2BIG);
333 			}
334 		}
335 	}
336 
337 	/* Change the interface type */
338 	tp->tp_iftype = ifp->if_type;
339 	ifp->if_type = IFT_IEEE8023ADLAG;
340 	ifp->if_tp = (caddr_t)tp;
341 	tp->tp_watchdog = ifp->if_watchdog;
342 	ifp->if_watchdog = trunk_port_watchdog;
343 	tp->tp_ioctl = ifp->if_ioctl;
344 	ifp->if_ioctl = trunk_port_ioctl;
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 	/* Update link layer address for this port */
359 	trunk_port_lladdr(tp,
360 	    ((struct arpcom *)(tr->tr_primary->tp_if))->ac_enaddr);
361 
362 	/* Insert into the list of ports */
363 	SLIST_INSERT_HEAD(&tr->tr_ports, tp, tp_entries);
364 	tr->tr_count++;
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 	if (ifp->if_linkstatehooks != NULL)
374 		tp->lh_cookie = hook_establish(ifp->if_linkstatehooks, 1,
375 		    trunk_port_state, tp);
376 
377 	if (tr->tr_port_create != NULL)
378 		error = (*tr->tr_port_create)(tp);
379 
380 	return (error);
381 }
382 
383 int
384 trunk_port_checkstacking(struct trunk_softc *tr)
385 {
386 	struct trunk_softc *tr_ptr;
387 	struct trunk_port *tp;
388 	int m = 0;
389 
390 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
391 		if (tp->tp_flags & TRUNK_PORT_STACK) {
392 			tr_ptr = (struct trunk_softc *)tp->tp_if->if_softc;
393 			m = MAX(m, trunk_port_checkstacking(tr_ptr));
394 		}
395 	}
396 
397 	return (m + 1);
398 }
399 
400 int
401 trunk_port_destroy(struct trunk_port *tp)
402 {
403 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
404 	struct trunk_port *tp_ptr;
405 	struct ifnet *ifp = tp->tp_if;
406 
407 	if (tr->tr_port_destroy != NULL)
408 		(*tr->tr_port_destroy)(tp);
409 
410 	/* Remove multicast addresses from this port */
411 	trunk_ether_cmdmulti(tp, SIOCDELMULTI);
412 
413 	/* Port has to be down */
414 	if (ifp->if_flags & IFF_UP)
415 		if_down(ifp);
416 
417 	ifpromisc(ifp, 0);
418 
419 	/* Restore interface */
420 	ifp->if_type = tp->tp_iftype;
421 	ifp->if_watchdog = tp->tp_watchdog;
422 	ifp->if_ioctl = tp->tp_ioctl;
423 	ifp->if_tp = NULL;
424 
425 	if (ifp->if_linkstatehooks != NULL)
426 		hook_disestablish(ifp->if_linkstatehooks, tp->lh_cookie);
427 
428 	/* Finally, remove the port from the trunk */
429 	SLIST_REMOVE(&tr->tr_ports, tp, trunk_port, tp_entries);
430 	tr->tr_count--;
431 
432 	/* Update the primary interface */
433 	if (tp == tr->tr_primary) {
434 		u_int8_t lladdr[ETHER_ADDR_LEN];
435 
436 		if ((tp_ptr = SLIST_FIRST(&tr->tr_ports)) == NULL) {
437 			bzero(&lladdr, ETHER_ADDR_LEN);
438 		} else {
439 			bcopy(((struct arpcom *)tp_ptr->tp_if)->ac_enaddr,
440 			    lladdr, ETHER_ADDR_LEN);
441 			tp_ptr->tp_flags = TRUNK_PORT_MASTER;
442 		}
443 		trunk_lladdr(&tr->tr_ac, lladdr);
444 		tr->tr_primary = tp_ptr;
445 
446 		/* Update link layer address for each port */
447 		SLIST_FOREACH(tp_ptr, &tr->tr_ports, tp_entries)
448 			trunk_port_lladdr(tp_ptr, lladdr);
449 	}
450 
451 	/* Reset the port lladdr */
452 	trunk_port_lladdr(tp, tp->tp_lladdr);
453 
454 	free(tp, M_DEVBUF);
455 
456 	/* Update trunk capabilities */
457 	tr->tr_capabilities = trunk_capabilities(tr);
458 
459 	return (0);
460 }
461 
462 void
463 trunk_port_watchdog(struct ifnet *ifp)
464 {
465 	struct trunk_port *tp;
466 
467 	/* Should be checked by the caller */
468 	if (ifp->if_type != IFT_IEEE8023ADLAG)
469 		return;
470 	if ((tp = (struct trunk_port *)ifp->if_tp) == NULL ||
471 	    tp->tp_trunk == NULL)
472 		return;
473 
474 	if (tp->tp_watchdog != NULL)
475 		(*tp->tp_watchdog)(ifp);
476 }
477 
478 
479 int
480 trunk_port_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
481 {
482 	struct trunk_reqport *rp = (struct trunk_reqport *)data;
483 	struct trunk_softc *tr;
484 	struct trunk_port *tp = NULL;
485 	int s, error = 0;
486 
487 	s = splnet();
488 
489 	/* Should be checked by the caller */
490 	if (ifp->if_type != IFT_IEEE8023ADLAG ||
491 	    (tp = (struct trunk_port *)ifp->if_tp) == NULL ||
492 	    (tr = (struct trunk_softc *)tp->tp_trunk) == NULL) {
493 		error = EINVAL;
494 		goto fallback;
495 	}
496 
497 	switch (cmd) {
498 	case SIOCGTRUNKPORT:
499 		if (rp->rp_portname[0] == '\0' ||
500 		    ifunit(rp->rp_portname) != ifp) {
501 			error = EINVAL;
502 			break;
503 		}
504 
505 		/* Search in all trunks if the global flag is set */
506 		if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
507 		    NULL : tr, ifp)) == NULL) {
508 			error = ENOENT;
509 			break;
510 		}
511 
512 		trunk_port2req(tp, rp);
513 		break;
514 	default:
515 		error = ENOTTY;
516 		goto fallback;
517 	}
518 
519 	splx(s);
520 	return (error);
521 
522  fallback:
523 	splx(s);
524 
525 	if (tp != NULL)
526 		error = (*tp->tp_ioctl)(ifp, cmd, data);
527 
528 	return (error);
529 }
530 
531 void
532 trunk_port_ifdetach(struct ifnet *ifp)
533 {
534 	struct trunk_port *tp;
535 
536 	if ((tp = (struct trunk_port *)ifp->if_tp) == NULL)
537 		return;
538 
539 	trunk_port_destroy(tp);
540 }
541 
542 struct trunk_port *
543 trunk_port_get(struct trunk_softc *tr, struct ifnet *ifp)
544 {
545 	struct trunk_port *tp;
546 	struct trunk_softc *tr_ptr;
547 
548 	if (tr != NULL) {
549 		/* Search port in specified trunk */
550 		SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
551 			if (tp->tp_if == ifp)
552 				return (tp);
553 		}
554 	} else {
555 		/* Search all trunks for the selected port */
556 		SLIST_FOREACH(tr_ptr, &trunk_list, tr_entries) {
557 			SLIST_FOREACH(tp, &tr_ptr->tr_ports, tp_entries) {
558 				if (tp->tp_if == ifp)
559 					return (tp);
560 			}
561 		}
562 	}
563 
564 	return (NULL);
565 }
566 
567 void
568 trunk_port2req(struct trunk_port *tp, struct trunk_reqport *rp)
569 {
570 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
571 
572 	strlcpy(rp->rp_ifname, tr->tr_ifname, sizeof(rp->rp_ifname));
573 	strlcpy(rp->rp_portname, tp->tp_if->if_xname, sizeof(rp->rp_portname));
574 	rp->rp_prio = tp->tp_prio;
575 	if (tr->tr_portreq != NULL)
576 		(*tr->tr_portreq)(tp, (caddr_t)&rp->rp_psc);
577 
578 	/* Add protocol specific flags */
579 	switch (tr->tr_proto) {
580 	case TRUNK_PROTO_FAILOVER:
581 		rp->rp_flags = tp->tp_flags;
582 		if (tp == trunk_link_active(tr, tr->tr_primary))
583 			rp->rp_flags |= TRUNK_PORT_ACTIVE;
584 		break;
585 
586 	case TRUNK_PROTO_ROUNDROBIN:
587 	case TRUNK_PROTO_LOADBALANCE:
588 	case TRUNK_PROTO_BROADCAST:
589 		rp->rp_flags = tp->tp_flags;
590 		if (TRUNK_PORTACTIVE(tp))
591 			rp->rp_flags |= TRUNK_PORT_ACTIVE;
592 		break;
593 
594 	case TRUNK_PROTO_LACP:
595 		/* LACP has a different definition of active */
596 		rp->rp_flags = lacp_port_status(tp);
597 		break;
598 	default:
599 		break;
600 	}
601 }
602 
603 int
604 trunk_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
605 {
606 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
607 	struct trunk_reqall *ra = (struct trunk_reqall *)data;
608 	struct trunk_reqport *rp = (struct trunk_reqport *)data, rpbuf;
609 	struct ifreq *ifr = (struct ifreq *)data;
610 	struct ifaddr *ifa = (struct ifaddr *)data;
611 	struct trunk_port *tp;
612 	struct ifnet *tpif;
613 	int s, i, error = 0;
614 
615 	s = splnet();
616 
617 	bzero(&rpbuf, sizeof(rpbuf));
618 
619 	switch (cmd) {
620 	case SIOCGTRUNK:
621 		ra->ra_proto = tr->tr_proto;
622 		if (tr->tr_req != NULL)
623 			(*tr->tr_req)(tr, (caddr_t)&ra->ra_psc);
624 		ra->ra_ports = i = 0;
625 		tp = SLIST_FIRST(&tr->tr_ports);
626 		while (tp && ra->ra_size >=
627 		    i + sizeof(struct trunk_reqport)) {
628 			trunk_port2req(tp, &rpbuf);
629 			error = copyout(&rpbuf, (caddr_t)ra->ra_port + i,
630 			    sizeof(struct trunk_reqport));
631 			if (error)
632 				break;
633 			i += sizeof(struct trunk_reqport);
634 			ra->ra_ports++;
635 			tp = SLIST_NEXT(tp, tp_entries);
636 		}
637 		break;
638 	case SIOCSTRUNK:
639 		if ((error = suser(curproc, 0)) != 0) {
640 			error = EPERM;
641 			break;
642 		}
643 		if (ra->ra_proto >= TRUNK_PROTO_MAX) {
644 			error = EPROTONOSUPPORT;
645 			break;
646 		}
647 		if (tr->tr_proto != TRUNK_PROTO_NONE)
648 			error = tr->tr_detach(tr);
649 		if (error != 0)
650 			break;
651 		for (i = 0; i < (sizeof(trunk_protos) /
652 		    sizeof(trunk_protos[0])); i++) {
653 			if (trunk_protos[i].ti_proto == ra->ra_proto) {
654 				if (tr->tr_ifflags & IFF_DEBUG)
655 					printf("%s: using proto %u\n",
656 					    tr->tr_ifname,
657 					    trunk_protos[i].ti_proto);
658 				tr->tr_proto = trunk_protos[i].ti_proto;
659 				if (tr->tr_proto != TRUNK_PROTO_NONE)
660 					error = trunk_protos[i].ti_attach(tr);
661 				goto out;
662 			}
663 		}
664 		error = EPROTONOSUPPORT;
665 		break;
666 	case SIOCGTRUNKPORT:
667 		if (rp->rp_portname[0] == '\0' ||
668 		    (tpif = ifunit(rp->rp_portname)) == NULL) {
669 			error = EINVAL;
670 			break;
671 		}
672 
673 		/* Search in all trunks if the global flag is set */
674 		if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
675 		    NULL : tr, tpif)) == NULL) {
676 			error = ENOENT;
677 			break;
678 		}
679 
680 		trunk_port2req(tp, rp);
681 		break;
682 	case SIOCSTRUNKPORT:
683 		if ((error = suser(curproc, 0)) != 0) {
684 			error = EPERM;
685 			break;
686 		}
687 		if (rp->rp_portname[0] == '\0' ||
688 		    (tpif = ifunit(rp->rp_portname)) == NULL) {
689 			error = EINVAL;
690 			break;
691 		}
692 		error = trunk_port_create(tr, tpif);
693 		break;
694 	case SIOCSTRUNKDELPORT:
695 		if ((error = suser(curproc, 0)) != 0) {
696 			error = EPERM;
697 			break;
698 		}
699 		if (rp->rp_portname[0] == '\0' ||
700 		    (tpif = ifunit(rp->rp_portname)) == NULL) {
701 			error = EINVAL;
702 			break;
703 		}
704 
705 		/* Search in all trunks if the global flag is set */
706 		if ((tp = trunk_port_get(rp->rp_flags & TRUNK_PORT_GLOBAL ?
707 		    NULL : tr, tpif)) == NULL) {
708 			error = ENOENT;
709 			break;
710 		}
711 
712 		error = trunk_port_destroy(tp);
713 		break;
714 	case SIOCSIFADDR:
715 		ifp->if_flags |= IFF_UP;
716 #ifdef INET
717 		if (ifa->ifa_addr->sa_family == AF_INET)
718 			arp_ifinit(&tr->tr_ac, ifa);
719 #endif /* INET */
720 		error = ENETRESET;
721 		break;
722 	case SIOCSIFFLAGS:
723 		error = ENETRESET;
724 		break;
725 	case SIOCADDMULTI:
726 		error = trunk_ether_addmulti(tr, ifr);
727 		break;
728 	case SIOCDELMULTI:
729 		error = trunk_ether_delmulti(tr, ifr);
730 		break;
731 	case SIOCSIFMEDIA:
732 	case SIOCGIFMEDIA:
733 		error = ifmedia_ioctl(ifp, ifr, &tr->tr_media, cmd);
734 		break;
735 	case SIOCSIFLLADDR:
736 		/* Update the port lladdrs as well */
737 		SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
738 			trunk_port_lladdr(tp, ifr->ifr_addr.sa_data);
739 		error = ENETRESET;
740 		break;
741 	default:
742 		error = ether_ioctl(ifp, &tr->tr_ac, cmd, data);
743 	}
744 
745 	if (error == ENETRESET) {
746 		if (ifp->if_flags & IFF_UP) {
747 			if ((ifp->if_flags & IFF_RUNNING) == 0)
748 				trunk_init(ifp);
749 		} else {
750 			if (ifp->if_flags & IFF_RUNNING)
751 				trunk_stop(ifp);
752 		}
753 		error = 0;
754 	}
755 
756  out:
757 	splx(s);
758 	return (error);
759 }
760 
761 int
762 trunk_ether_addmulti(struct trunk_softc *tr, struct ifreq *ifr)
763 {
764 	struct trunk_mc *mc;
765 	u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
766 	int error;
767 
768 	/* Ignore ENETRESET error code */
769 	if ((error = ether_addmulti(ifr, &tr->tr_ac)) != ENETRESET)
770 		return (error);
771 
772 	if ((mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT)) == NULL) {
773 		error = ENOMEM;
774 		goto failed;
775 	}
776 
777 	ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
778 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, mc->mc_enm);
779 	bcopy(&ifr->ifr_addr, &mc->mc_addr, ifr->ifr_addr.sa_len);
780 	SLIST_INSERT_HEAD(&tr->tr_mc_head, mc, mc_entries);
781 
782 	if ((error = trunk_ioctl_allports(tr, SIOCADDMULTI,
783 	    (caddr_t)ifr)) != 0) {
784 		trunk_ether_delmulti(tr, ifr);
785 		return (error);
786 	}
787 
788 	return (error);
789 
790  failed:
791 	ether_delmulti(ifr, &tr->tr_ac);
792 
793 	return (error);
794 }
795 
796 int
797 trunk_ether_delmulti(struct trunk_softc *tr, struct ifreq *ifr)
798 {
799 	struct ether_multi *enm;
800 	struct trunk_mc *mc;
801 	u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
802 	int error;
803 
804 	if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
805 		return (error);
806 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &tr->tr_ac, enm);
807 	if (enm == NULL)
808 		return (EINVAL);
809 
810 	SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries)
811 		if (mc->mc_enm == enm)
812 			break;
813 
814 	/* We won't delete entries we didn't add */
815 	if (mc == NULL)
816 		return (EINVAL);
817 
818 	if ((error = ether_delmulti(ifr, &tr->tr_ac)) != ENETRESET)
819 		return (error);
820 
821 	if ((error = trunk_ioctl_allports(tr, SIOCDELMULTI,
822 	    (caddr_t)ifr)) != 0) {
823 		/* XXX At least one port failed to remove the address */
824 		if (tr->tr_ifflags & IFF_DEBUG) {
825 			printf("%s: failed to remove multicast address "
826 			    "on all ports\n", tr->tr_ifname);
827 		}
828 	}
829 
830 	SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries);
831 	free(mc, M_DEVBUF);
832 
833 	return (0);
834 }
835 
836 void
837 trunk_ether_purgemulti(struct trunk_softc *tr)
838 {
839 	struct trunk_mc *mc;
840 	struct trunk_ifreq ifs;
841 	struct ifreq *ifr = &ifs.ifreq.ifreq;
842 
843 	while ((mc = SLIST_FIRST(&tr->tr_mc_head)) != NULL) {
844 		bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len);
845 
846 		/* Try to remove multicast address on all ports */
847 		trunk_ioctl_allports(tr, SIOCDELMULTI, (caddr_t)ifr);
848 
849 		SLIST_REMOVE(&tr->tr_mc_head, mc, trunk_mc, mc_entries);
850 		free(mc, M_DEVBUF);
851 	}
852 }
853 
854 int
855 trunk_ether_cmdmulti(struct trunk_port *tp, u_long cmd)
856 {
857 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
858 	struct trunk_mc *mc;
859 	struct trunk_ifreq ifs;
860 	struct ifreq *ifr = &ifs.ifreq.ifreq;
861 	int ret, error = 0;
862 
863 	bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ);
864 	SLIST_FOREACH(mc, &tr->tr_mc_head, mc_entries) {
865 		bcopy(&mc->mc_addr, &ifr->ifr_addr, mc->mc_addr.ss_len);
866 
867 		if ((ret = tp->tp_ioctl(tp->tp_if, cmd, (caddr_t)ifr)) != 0) {
868 			if (tr->tr_ifflags & IFF_DEBUG) {
869 				printf("%s: ioctl %lu failed on %s: %d\n",
870 				    tr->tr_ifname, cmd, tp->tp_ifname, ret);
871 			}
872 			/* Store last known error and continue */
873 			error = ret;
874 		}
875 	}
876 
877 	return (error);
878 }
879 
880 int
881 trunk_ioctl_allports(struct trunk_softc *tr, u_long cmd, caddr_t data)
882 {
883 	struct ifreq *ifr = (struct ifreq *)data;
884 	struct trunk_port *tp;
885 	int ret, error = 0;
886 
887 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
888 		bcopy(tp->tp_ifname, ifr->ifr_name, IFNAMSIZ);
889 		if ((ret = tp->tp_ioctl(tp->tp_if, cmd, data)) != 0) {
890 			if (tr->tr_ifflags & IFF_DEBUG) {
891 				printf("%s: ioctl %lu failed on %s: %d\n",
892 				    tr->tr_ifname, cmd, tp->tp_ifname, ret);
893 			}
894 			/* Store last known error and continue */
895 			error = ret;
896 		}
897 	}
898 
899 	return (error);
900 }
901 
902 void
903 trunk_start(struct ifnet *ifp)
904 {
905 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
906 	struct mbuf *m;
907 	int error;
908 
909 	for (;;) {
910 		IFQ_DEQUEUE(&ifp->if_snd, m);
911 		if (m == NULL)
912 			break;
913 
914 #if NBPFILTER > 0
915 		if (ifp->if_bpf)
916 			bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
917 #endif
918 
919 		if (tr->tr_proto != TRUNK_PROTO_NONE && tr->tr_count) {
920 			error = (*tr->tr_start)(tr, m);
921 			if (error == 0)
922 				ifp->if_opackets++;
923 			else
924 				ifp->if_oerrors++;
925 		} else {
926 			m_freem(m);
927 			if (tr->tr_proto != TRUNK_PROTO_NONE)
928 				ifp->if_oerrors++;
929 		}
930 	}
931 }
932 
933 int
934 trunk_enqueue(struct ifnet *ifp, struct mbuf *m)
935 {
936 	int len, error = 0;
937 	u_short mflags;
938 
939 	splassert(IPL_NET);
940 
941 	/* Send mbuf */
942 	mflags = m->m_flags;
943 	len = m->m_pkthdr.len;
944 	IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
945 	if (error)
946 		return (error);
947 	if_start(ifp);
948 
949 	ifp->if_obytes += len;
950 	if (mflags & M_MCAST)
951 		ifp->if_omcasts++;
952 
953 	return (error);
954 }
955 
956 u_int32_t
957 trunk_hashmbuf(struct mbuf *m, u_int32_t key)
958 {
959 	u_int16_t etype, ether_vtag;
960 	u_int32_t p = 0;
961 	u_int16_t *vlan, vlanbuf[2];
962 	int off;
963 	struct ether_header *eh;
964 #ifdef INET
965 	struct ip *ip, ipbuf;
966 #endif
967 #ifdef INET6
968 	u_int32_t flow;
969 	struct ip6_hdr *ip6, ip6buf;
970 #endif
971 
972 	off = sizeof(*eh);
973 	if (m->m_len < off)
974 		return (p);
975 	eh = mtod(m, struct ether_header *);
976 	etype = ntohs(eh->ether_type);
977 	p = hash32_buf(&eh->ether_shost, ETHER_ADDR_LEN, key);
978 	p = hash32_buf(&eh->ether_dhost, ETHER_ADDR_LEN, p);
979 
980 	/* Special handling for encapsulating VLAN frames */
981 	if (m->m_flags & M_VLANTAG) {
982 		ether_vtag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
983 		p = hash32_buf(&ether_vtag, sizeof(ether_vtag), p);
984 	} else if (etype == ETHERTYPE_VLAN) {
985 		if ((vlan = (u_int16_t *)
986 		    trunk_gethdr(m, off, EVL_ENCAPLEN, &vlanbuf)) == NULL)
987 			return (p);
988 		ether_vtag = EVL_VLANOFTAG(*vlan);
989 		p = hash32_buf(&ether_vtag, sizeof(ether_vtag), p);
990 		etype = ntohs(vlan[1]);
991 		off += EVL_ENCAPLEN;
992 	}
993 
994 	switch (etype) {
995 #ifdef INET
996 	case ETHERTYPE_IP:
997 		if ((ip = (struct ip *)
998 		    trunk_gethdr(m, off, sizeof(*ip), &ipbuf)) == NULL)
999 			return (p);
1000 		p = hash32_buf(&ip->ip_src, sizeof(struct in_addr), p);
1001 		p = hash32_buf(&ip->ip_dst, sizeof(struct in_addr), p);
1002 		break;
1003 #endif
1004 #ifdef INET6
1005 	case ETHERTYPE_IPV6:
1006 		if ((ip6 = (struct ip6_hdr *)
1007 		    trunk_gethdr(m, off, sizeof(*ip6), &ip6buf)) == NULL)
1008 			return (p);
1009 		p = hash32_buf(&ip6->ip6_src, sizeof(struct in6_addr), p);
1010 		p = hash32_buf(&ip6->ip6_dst, sizeof(struct in6_addr), p);
1011 		flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
1012 		p = hash32_buf(&flow, sizeof(flow), p); /* IPv6 flow label */
1013 		break;
1014 #endif
1015 	}
1016 
1017 	return (p);
1018 }
1019 
1020 void
1021 trunk_init(struct ifnet *ifp)
1022 {
1023 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1024 	int s;
1025 
1026 	s = splnet();
1027 
1028 	ifp->if_flags |= IFF_RUNNING;
1029 	ifp->if_flags &= ~IFF_OACTIVE;
1030 
1031 	if (tr->tr_init != NULL)
1032 		(*tr->tr_init)(tr);
1033 
1034 	splx(s);
1035 }
1036 
1037 void
1038 trunk_stop(struct ifnet *ifp)
1039 {
1040 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1041 	int s;
1042 
1043 	s = splnet();
1044 
1045 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1046 
1047 	if (tr->tr_stop != NULL)
1048 		(*tr->tr_stop)(tr);
1049 
1050 	splx(s);
1051 }
1052 
1053 void
1054 trunk_watchdog(struct ifnet *ifp)
1055 {
1056 	struct trunk_softc *tr = (struct trunk_softc *)ifp->if_softc;
1057 
1058 	if (tr->tr_proto != TRUNK_PROTO_NONE &&
1059 	    (*tr->tr_watchdog)(tr) != 0) {
1060 		ifp->if_oerrors++;
1061 	}
1062 
1063 }
1064 
1065 int
1066 trunk_input(struct ifnet *ifp, struct ether_header *eh, struct mbuf *m)
1067 {
1068 	struct trunk_softc *tr;
1069 	struct trunk_port *tp;
1070 	struct ifnet *trifp = NULL;
1071 	int error = 0;
1072 
1073 	/* Should be checked by the caller */
1074 	if (ifp->if_type != IFT_IEEE8023ADLAG) {
1075 		error = EPROTONOSUPPORT;
1076 		goto bad;
1077 	}
1078 	if ((tp = (struct trunk_port *)ifp->if_tp) == NULL ||
1079 	    (tr = (struct trunk_softc *)tp->tp_trunk) == NULL) {
1080 		error = ENOENT;
1081 		goto bad;
1082 	}
1083 	trifp = &tr->tr_ac.ac_if;
1084 	if (tr->tr_proto == TRUNK_PROTO_NONE) {
1085 		error = ENOENT;
1086 		goto bad;
1087 	}
1088 
1089 #if NBPFILTER > 0
1090 	if (trifp->if_bpf && tr->tr_proto != TRUNK_PROTO_FAILOVER)
1091 		bpf_mtap_hdr(trifp->if_bpf, (char *)eh, ETHER_HDR_LEN, m,
1092 		    BPF_DIRECTION_IN);
1093 #endif
1094 
1095 	error = (*tr->tr_input)(tr, tp, eh, m);
1096 	if (error != 0)
1097 		return (error);
1098 
1099 	trifp->if_ipackets++;
1100 	return (0);
1101 
1102  bad:
1103 	if (error > 0 && trifp != NULL)
1104 		trifp->if_ierrors++;
1105 	m_freem(m);
1106 	return (error);
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 	/* Send mbuf */
1272 	if ((error = trunk_enqueue(tp->tp_if, m)) != 0)
1273 		return (error);
1274 
1275 	/* Get next active port */
1276 	tp_next = trunk_link_active(tr, SLIST_NEXT(tp, tp_entries));
1277 	tr->tr_psc = (caddr_t)tp_next;
1278 
1279 	return (0);
1280 }
1281 
1282 int
1283 trunk_rr_input(struct trunk_softc *tr, struct trunk_port *tp,
1284     struct ether_header *eh, struct mbuf *m)
1285 {
1286 	struct ifnet *ifp = &tr->tr_ac.ac_if;
1287 
1288 	/* Just pass in the packet to our trunk device */
1289 	m->m_pkthdr.rcvif = ifp;
1290 
1291 	return (0);
1292 }
1293 
1294 /*
1295  * Active failover
1296  */
1297 
1298 int
1299 trunk_fail_attach(struct trunk_softc *tr)
1300 {
1301 	tr->tr_detach = trunk_fail_detach;
1302 	tr->tr_start = trunk_fail_start;
1303 	tr->tr_input = trunk_fail_input;
1304 	tr->tr_init = NULL;
1305 	tr->tr_stop = NULL;
1306 	tr->tr_port_create = NULL;
1307 	tr->tr_port_destroy = NULL;
1308 	tr->tr_linkstate = NULL;
1309 	tr->tr_req = NULL;
1310 	tr->tr_portreq = NULL;
1311 
1312 	return (0);
1313 }
1314 
1315 int
1316 trunk_fail_detach(struct trunk_softc *tr)
1317 {
1318 	return (0);
1319 }
1320 
1321 int
1322 trunk_fail_start(struct trunk_softc *tr, struct mbuf *m)
1323 {
1324 	struct trunk_port *tp;
1325 
1326 	/* Use the master port if active or the next available port */
1327 	if ((tp = trunk_link_active(tr, tr->tr_primary)) == NULL) {
1328 		m_freem(m);
1329 		return (ENOENT);
1330 	}
1331 
1332 	/* Send mbuf */
1333 	return (trunk_enqueue(tp->tp_if, m));
1334 }
1335 
1336 int
1337 trunk_fail_input(struct trunk_softc *tr, struct trunk_port *tp,
1338     struct ether_header *eh, struct mbuf *m)
1339 {
1340 	struct ifnet *ifp = &tr->tr_ac.ac_if;
1341 	struct trunk_port *tmp_tp;
1342 	int accept = 0;
1343 
1344 	if (tp == tr->tr_primary) {
1345 		accept = 1;
1346 	} else if (tr->tr_primary->tp_link_state == LINK_STATE_DOWN) {
1347 		tmp_tp = trunk_link_active(tr, NULL);
1348 		/*
1349 		 * If tmp_tp is null, we've received a packet when all
1350 		 * our links are down. Weird, but process it anyways.
1351 		 */
1352 		if ((tmp_tp == NULL || tmp_tp == tp))
1353 			accept = 1;
1354 	}
1355 	if (!accept) {
1356 		m_freem(m);
1357 		return (-1);
1358 	}
1359 #if NBPFILTER > 0
1360 	if (ifp->if_bpf)
1361 		bpf_mtap_hdr(ifp->if_bpf, (char *)eh, ETHER_HDR_LEN, m,
1362 		    BPF_DIRECTION_IN);
1363 #endif
1364 
1365 	m->m_pkthdr.rcvif = ifp;
1366 	return (0);
1367 }
1368 
1369 /*
1370  * Loadbalancing
1371  */
1372 
1373 int
1374 trunk_lb_attach(struct trunk_softc *tr)
1375 {
1376 	struct trunk_lb *lb;
1377 
1378 	if ((lb = malloc(sizeof(*lb), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
1379 		return (ENOMEM);
1380 
1381 	tr->tr_detach = trunk_lb_detach;
1382 	tr->tr_start = trunk_lb_start;
1383 	tr->tr_input = trunk_lb_input;
1384 	tr->tr_port_create = trunk_lb_port_create;
1385 	tr->tr_port_destroy = trunk_lb_port_destroy;
1386 	tr->tr_linkstate = NULL;
1387 	tr->tr_capabilities = IFCAP_TRUNK_FULLDUPLEX;
1388 	tr->tr_req = NULL;
1389 	tr->tr_portreq = NULL;
1390 	tr->tr_init = NULL;
1391 	tr->tr_stop = NULL;
1392 
1393 	lb->lb_key = arc4random();
1394 	tr->tr_psc = (caddr_t)lb;
1395 
1396 	return (0);
1397 }
1398 
1399 int
1400 trunk_lb_detach(struct trunk_softc *tr)
1401 {
1402 	struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
1403 	if (lb != NULL)
1404 		free(lb, M_DEVBUF);
1405 	return (0);
1406 }
1407 
1408 int
1409 trunk_lb_porttable(struct trunk_softc *tr, struct trunk_port *tp)
1410 {
1411 	struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
1412 	struct trunk_port *tp_next;
1413 	int i = 0;
1414 
1415 	bzero(&lb->lb_ports, sizeof(lb->lb_ports));
1416 	SLIST_FOREACH(tp_next, &tr->tr_ports, tp_entries) {
1417 		if (tp_next == tp)
1418 			continue;
1419 		if (i >= TRUNK_MAX_PORTS)
1420 			return (EINVAL);
1421 		if (tr->tr_ifflags & IFF_DEBUG)
1422 			printf("%s: port %s at index %d\n",
1423 			    tr->tr_ifname, tp_next->tp_ifname, i);
1424 		lb->lb_ports[i++] = tp_next;
1425 	}
1426 
1427 	return (0);
1428 }
1429 
1430 int
1431 trunk_lb_port_create(struct trunk_port *tp)
1432 {
1433 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
1434 	return (trunk_lb_porttable(tr, NULL));
1435 }
1436 
1437 void
1438 trunk_lb_port_destroy(struct trunk_port *tp)
1439 {
1440 	struct trunk_softc *tr = (struct trunk_softc *)tp->tp_trunk;
1441 	trunk_lb_porttable(tr, tp);
1442 }
1443 
1444 int
1445 trunk_lb_start(struct trunk_softc *tr, struct mbuf *m)
1446 {
1447 	struct trunk_lb *lb = (struct trunk_lb *)tr->tr_psc;
1448 	struct trunk_port *tp = NULL;
1449 	u_int32_t p = 0;
1450 
1451 	p = trunk_hashmbuf(m, lb->lb_key);
1452 	p %= tr->tr_count;
1453 	tp = lb->lb_ports[p];
1454 
1455 	/*
1456 	 * Check the port's link state. This will return the next active
1457 	 * port if the link is down or the port is NULL.
1458 	 */
1459 	if ((tp = trunk_link_active(tr, tp)) == NULL) {
1460 		m_freem(m);
1461 		return (ENOENT);
1462 	}
1463 
1464 	/* Send mbuf */
1465 	return (trunk_enqueue(tp->tp_if, m));
1466 }
1467 
1468 int
1469 trunk_lb_input(struct trunk_softc *tr, struct trunk_port *tp,
1470     struct ether_header *eh, struct mbuf *m)
1471 {
1472 	struct ifnet *ifp = &tr->tr_ac.ac_if;
1473 
1474 	/* Just pass in the packet to our trunk device */
1475 	m->m_pkthdr.rcvif = ifp;
1476 
1477 	return (0);
1478 }
1479 
1480 /*
1481  * Broadcast mode
1482  */
1483 
1484 int
1485 trunk_bcast_attach(struct trunk_softc *tr)
1486 {
1487 	tr->tr_detach = trunk_bcast_detach;
1488 	tr->tr_start = trunk_bcast_start;
1489 	tr->tr_input = trunk_bcast_input;
1490 	tr->tr_init = NULL;
1491 	tr->tr_stop = NULL;
1492 	tr->tr_port_create = NULL;
1493 	tr->tr_port_destroy = NULL;
1494 	tr->tr_linkstate = NULL;
1495 	tr->tr_req = NULL;
1496 	tr->tr_portreq = NULL;
1497 
1498 	return (0);
1499 }
1500 
1501 int
1502 trunk_bcast_detach(struct trunk_softc *tr)
1503 {
1504 	return (0);
1505 }
1506 
1507 int
1508 trunk_bcast_start(struct trunk_softc *tr, struct mbuf *m)
1509 {
1510 	int			 active_ports = 0;
1511 	int			 errors = 0;
1512 	int			 ret;
1513 	struct trunk_port	*tp;
1514 	struct mbuf		*n;
1515 
1516 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries) {
1517 		if (TRUNK_PORTACTIVE(tp)) {
1518 			if (active_ports) {
1519 				n = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
1520 				if (n == NULL) {
1521 					m_freem(m);
1522 					return (ENOBUFS);
1523 				}
1524 			} else
1525 				n = m;
1526 			active_ports++;
1527 			if ((ret = trunk_enqueue(tp->tp_if, n)))
1528 				errors++;
1529 		}
1530 	}
1531 	if (active_ports == 0) {
1532 		m_freem(m);
1533 		return (ENOENT);
1534 	}
1535 	if (errors == active_ports)
1536 		return (ret);
1537 	return (0);
1538 }
1539 
1540 int
1541 trunk_bcast_input(struct trunk_softc *tr, struct trunk_port *tp,
1542     struct ether_header *eh, struct mbuf *m)
1543 {
1544 	struct ifnet *ifp = &tr->tr_ac.ac_if;
1545 
1546 	m->m_pkthdr.rcvif = ifp;
1547 	return (0);
1548 }
1549 
1550 /*
1551  * 802.3ad LACP
1552  */
1553 
1554 int
1555 trunk_lacp_attach(struct trunk_softc *tr)
1556 {
1557 	struct trunk_port *tp;
1558 	int error;
1559 
1560 	tr->tr_detach = trunk_lacp_detach;
1561 	tr->tr_port_create = lacp_port_create;
1562 	tr->tr_port_destroy = lacp_port_destroy;
1563 	tr->tr_linkstate = lacp_linkstate;
1564 	tr->tr_start = trunk_lacp_start;
1565 	tr->tr_input = trunk_lacp_input;
1566 	tr->tr_init = lacp_init;
1567 	tr->tr_stop = lacp_stop;
1568 	tr->tr_req = lacp_req;
1569 	tr->tr_portreq = lacp_portreq;
1570 
1571 	error = lacp_attach(tr);
1572 	if (error)
1573 		return (error);
1574 
1575 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
1576 		lacp_port_create(tp);
1577 
1578 	return (error);
1579 }
1580 
1581 int
1582 trunk_lacp_detach(struct trunk_softc *tr)
1583 {
1584 	struct trunk_port *tp;
1585 	int error;
1586 
1587 	SLIST_FOREACH(tp, &tr->tr_ports, tp_entries)
1588 		lacp_port_destroy(tp);
1589 
1590 	/* unlocking is safe here */
1591 	error = lacp_detach(tr);
1592 
1593 	return (error);
1594 }
1595 
1596 int
1597 trunk_lacp_start(struct trunk_softc *tr, struct mbuf *m)
1598 {
1599 	struct trunk_port *tp;
1600 
1601 	tp = lacp_select_tx_port(tr, m);
1602 	if (tp == NULL) {
1603 		m_freem(m);
1604 		return (EBUSY);
1605 	}
1606 
1607 	/* Send mbuf */
1608 	return (trunk_enqueue(tp->tp_if, m));
1609 }
1610 
1611 int
1612 trunk_lacp_input(struct trunk_softc *tr, struct trunk_port *tp,
1613     struct ether_header *eh, struct mbuf *m)
1614 {
1615 	struct ifnet *ifp = &tr->tr_ac.ac_if;
1616 
1617 	m = lacp_input(tp, eh, m);
1618 	if (m == NULL)
1619 		return (-1);
1620 
1621 	m->m_pkthdr.rcvif = ifp;
1622 	return (0);
1623 }
1624