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