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