]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/if_bond.c
xnu-4903.241.1.tar.gz
[apple/xnu.git] / bsd / net / if_bond.c
1 /*
2 * Copyright (c) 2004-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * if_bond.c
31 * - bond/failover interface
32 * - implements IEEE 802.3ad Link Aggregation
33 */
34
35 /*
36 * Modification History:
37 *
38 * April 29, 2004 Dieter Siegmund (dieter@apple.com)
39 * - created
40 */
41
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
45 #include <sys/mbuf.h>
46 #include <sys/queue.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/sysctl.h>
50 #include <sys/systm.h>
51 #include <sys/kern_event.h>
52 #include <net/bpf.h>
53 #include <net/ethernet.h>
54 #include <net/if.h>
55 #include <net/kpi_interface.h>
56 #include <net/if_arp.h>
57 #include <net/if_dl.h>
58 #include <net/if_ether.h>
59 #include <net/if_types.h>
60 #include <net/if_bond_var.h>
61 #include <net/ieee8023ad.h>
62 #include <net/lacp.h>
63 #include <net/dlil.h>
64 #include <sys/time.h>
65 #include <net/devtimer.h>
66 #include <net/if_vlan_var.h>
67 #include <net/kpi_protocol.h>
68
69 #include <kern/locks.h>
70 #include <kern/zalloc.h>
71 #include <libkern/OSAtomic.h>
72
73 #include <netinet/in.h>
74 #include <netinet/if_ether.h>
75 #include <netinet/in_systm.h>
76 #include <netinet/ip.h>
77 #include <netinet/ip6.h>
78
79 #include <net/if_media.h>
80 #include <net/multicast_list.h>
81
82 static struct ether_addr slow_proto_multicast = {
83 IEEE8023AD_SLOW_PROTO_MULTICAST
84 };
85
86 typedef struct ifbond_s ifbond, * ifbond_ref;
87 typedef struct bondport_s bondport, * bondport_ref;
88
89 #define BOND_MAXUNIT 128
90 #define BOND_ZONE_MAX_ELEM MIN(IFNETS_MAX, BOND_MAXUNIT)
91 #define BONDNAME "bond"
92
93 #define M_BOND M_DEVBUF
94
95 #define EA_FORMAT "%x:%x:%x:%x:%x:%x"
96 #define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)])
97 #define EA_LIST(ea) EA_CH(ea,0),EA_CH(ea,1),EA_CH(ea,2),EA_CH(ea,3),EA_CH(ea,4),EA_CH(ea,5)
98
99 #define timestamp_printf printf
100
101 /**
102 ** bond locks
103 **/
104 static __inline__ lck_grp_t *
105 my_lck_grp_alloc_init(const char * grp_name)
106 {
107 lck_grp_t * grp;
108 lck_grp_attr_t * grp_attrs;
109
110 grp_attrs = lck_grp_attr_alloc_init();
111 grp = lck_grp_alloc_init(grp_name, grp_attrs);
112 lck_grp_attr_free(grp_attrs);
113 return (grp);
114 }
115
116 static __inline__ lck_mtx_t *
117 my_lck_mtx_alloc_init(lck_grp_t * lck_grp)
118 {
119 lck_attr_t * lck_attrs;
120 lck_mtx_t * lck_mtx;
121
122 lck_attrs = lck_attr_alloc_init();
123 lck_mtx = lck_mtx_alloc_init(lck_grp, lck_attrs);
124 lck_attr_free(lck_attrs);
125 return (lck_mtx);
126 }
127
128 static lck_mtx_t * bond_lck_mtx;
129
130 static __inline__ void
131 bond_lock_init(void)
132 {
133 lck_grp_t * bond_lck_grp;
134
135 bond_lck_grp = my_lck_grp_alloc_init("if_bond");
136 bond_lck_mtx = my_lck_mtx_alloc_init(bond_lck_grp);
137 }
138
139 static __inline__ void
140 bond_assert_lock_held(void)
141 {
142 LCK_MTX_ASSERT(bond_lck_mtx, LCK_MTX_ASSERT_OWNED);
143 return;
144 }
145
146 static __inline__ void
147 bond_assert_lock_not_held(void)
148 {
149 LCK_MTX_ASSERT(bond_lck_mtx, LCK_MTX_ASSERT_NOTOWNED);
150 return;
151 }
152
153 static __inline__ void
154 bond_lock(void)
155 {
156 lck_mtx_lock(bond_lck_mtx);
157 return;
158 }
159
160 static __inline__ void
161 bond_unlock(void)
162 {
163 lck_mtx_unlock(bond_lck_mtx);
164 return;
165 }
166
167 /**
168 ** bond structures, types
169 **/
170
171 struct LAG_info_s {
172 lacp_system li_system;
173 lacp_system_priority li_system_priority;
174 lacp_key li_key;
175 };
176 typedef struct LAG_info_s LAG_info, * LAG_info_ref;
177
178 struct bondport_s;
179 TAILQ_HEAD(port_list, bondport_s);
180 struct ifbond_s;
181 TAILQ_HEAD(ifbond_list, ifbond_s);
182 struct LAG_s;
183 TAILQ_HEAD(lag_list, LAG_s);
184
185 typedef struct ifbond_s ifbond, * ifbond_ref;
186 typedef struct bondport_s bondport, * bondport_ref;
187
188 struct LAG_s {
189 TAILQ_ENTRY(LAG_s) lag_list;
190 struct port_list lag_port_list;
191 short lag_port_count;
192 short lag_selected_port_count;
193 int lag_active_media;
194 LAG_info lag_info;
195 };
196 typedef struct LAG_s LAG, * LAG_ref;
197
198 typedef struct partner_state_s {
199 LAG_info ps_lag_info;
200 lacp_port ps_port;
201 lacp_port_priority ps_port_priority;
202 lacp_actor_partner_state ps_state;
203 } partner_state, * partner_state_ref;
204
205 struct ifbond_s {
206 TAILQ_ENTRY(ifbond_s) ifb_bond_list;
207 int ifb_flags;
208 SInt32 ifb_retain_count;
209 char ifb_name[IFNAMSIZ];
210 struct ifnet * ifb_ifp;
211 bpf_packet_func ifb_bpf_input;
212 bpf_packet_func ifb_bpf_output;
213 int ifb_altmtu;
214 struct port_list ifb_port_list;
215 short ifb_port_count;
216 struct lag_list ifb_lag_list;
217 lacp_key ifb_key;
218 short ifb_max_active; /* 0 == unlimited */
219 LAG_ref ifb_active_lag;
220 struct ifmultiaddr * ifb_ifma_slow_proto;
221 bondport_ref * ifb_distributing_array;
222 int ifb_distributing_count;
223 int ifb_last_link_event;
224 int ifb_mode; /* LACP, STATIC */
225 };
226
227 struct media_info {
228 int mi_active;
229 int mi_status;
230 };
231
232 enum {
233 ReceiveState_none = 0,
234 ReceiveState_INITIALIZE = 1,
235 ReceiveState_PORT_DISABLED = 2,
236 ReceiveState_EXPIRED = 3,
237 ReceiveState_LACP_DISABLED = 4,
238 ReceiveState_DEFAULTED = 5,
239 ReceiveState_CURRENT = 6,
240 };
241
242 typedef u_char ReceiveState;
243
244 enum {
245 SelectedState_UNSELECTED = IF_BOND_STATUS_SELECTED_STATE_UNSELECTED,
246 SelectedState_SELECTED = IF_BOND_STATUS_SELECTED_STATE_SELECTED,
247 SelectedState_STANDBY = IF_BOND_STATUS_SELECTED_STATE_STANDBY
248 };
249 typedef u_char SelectedState;
250
251 static __inline__ const char *
252 SelectedStateString(SelectedState s)
253 {
254 static const char * names[] = { "UNSELECTED", "SELECTED", "STANDBY" };
255
256 if (s <= SelectedState_STANDBY) {
257 return (names[s]);
258 }
259 return ("<unknown>");
260 }
261
262 enum {
263 MuxState_none = 0,
264 MuxState_DETACHED = 1,
265 MuxState_WAITING = 2,
266 MuxState_ATTACHED = 3,
267 MuxState_COLLECTING_DISTRIBUTING = 4,
268 };
269
270 typedef u_char MuxState;
271
272 struct bondport_s {
273 TAILQ_ENTRY(bondport_s) po_port_list;
274 ifbond_ref po_bond;
275 struct multicast_list po_multicast;
276 struct ifnet * po_ifp;
277 struct ether_addr po_saved_addr;
278 int po_enabled;
279 char po_name[IFNAMSIZ];
280 struct ifdevmtu po_devmtu;
281
282 /* LACP */
283 TAILQ_ENTRY(bondport_s) po_lag_port_list;
284 devtimer_ref po_current_while_timer;
285 devtimer_ref po_periodic_timer;
286 devtimer_ref po_wait_while_timer;
287 devtimer_ref po_transmit_timer;
288 partner_state po_partner_state;
289 lacp_port_priority po_priority;
290 lacp_actor_partner_state po_actor_state;
291 u_char po_flags;
292 u_char po_periodic_interval;
293 u_char po_n_transmit;
294 ReceiveState po_receive_state;
295 MuxState po_mux_state;
296 SelectedState po_selected;
297 int32_t po_last_transmit_secs;
298 struct media_info po_media_info;
299 LAG_ref po_lag;
300 };
301
302 #define IFBF_PROMISC 0x1 /* promiscuous mode */
303 #define IFBF_IF_DETACHING 0x2 /* interface is detaching */
304 #define IFBF_LLADDR 0x4 /* specific link address requested */
305 #define IFBF_CHANGE_IN_PROGRESS 0x8 /* interface add/remove in progress */
306
307 static int bond_get_status(ifbond_ref ifb, struct if_bond_req * ibr_p,
308 user_addr_t datap);
309
310 static __inline__ int
311 ifbond_flags_if_detaching(ifbond_ref ifb)
312 {
313 return ((ifb->ifb_flags & IFBF_IF_DETACHING) != 0);
314 }
315
316 static __inline__ void
317 ifbond_flags_set_if_detaching(ifbond_ref ifb)
318 {
319 ifb->ifb_flags |= IFBF_IF_DETACHING;
320 return;
321 }
322
323 static __inline__ int
324 ifbond_flags_lladdr(ifbond_ref ifb)
325 {
326 return ((ifb->ifb_flags & IFBF_LLADDR) != 0);
327 }
328
329 static __inline__ int
330 ifbond_flags_change_in_progress(ifbond_ref ifb)
331 {
332 return ((ifb->ifb_flags & IFBF_CHANGE_IN_PROGRESS) != 0);
333 }
334
335 static __inline__ void
336 ifbond_flags_set_change_in_progress(ifbond_ref ifb)
337 {
338 ifb->ifb_flags |= IFBF_CHANGE_IN_PROGRESS;
339 return;
340 }
341
342 static __inline__ void
343 ifbond_flags_clear_change_in_progress(ifbond_ref ifb)
344 {
345 ifb->ifb_flags &= ~IFBF_CHANGE_IN_PROGRESS;
346 return;
347 }
348
349 /*
350 * bondport_ref->po_flags bits
351 */
352 #define BONDPORT_FLAGS_NTT 0x01
353 #define BONDPORT_FLAGS_READY 0x02
354 #define BONDPORT_FLAGS_SELECTED_CHANGED 0x04
355 #define BONDPORT_FLAGS_MUX_ATTACHED 0x08
356 #define BONDPORT_FLAGS_DISTRIBUTING 0x10
357 #define BONDPORT_FLAGS_UNUSED2 0x20
358 #define BONDPORT_FLAGS_UNUSED3 0x40
359 #define BONDPORT_FLAGS_UNUSED4 0x80
360
361 static __inline__ void
362 bondport_flags_set_ntt(bondport_ref p)
363 {
364 p->po_flags |= BONDPORT_FLAGS_NTT;
365 return;
366 }
367
368 static __inline__ void
369 bondport_flags_clear_ntt(bondport_ref p)
370 {
371 p->po_flags &= ~BONDPORT_FLAGS_NTT;
372 return;
373 }
374
375 static __inline__ int
376 bondport_flags_ntt(bondport_ref p)
377 {
378 return ((p->po_flags & BONDPORT_FLAGS_NTT) != 0);
379 }
380
381 static __inline__ void
382 bondport_flags_set_ready(bondport_ref p)
383 {
384 p->po_flags |= BONDPORT_FLAGS_READY;
385 return;
386 }
387
388 static __inline__ void
389 bondport_flags_clear_ready(bondport_ref p)
390 {
391 p->po_flags &= ~BONDPORT_FLAGS_READY;
392 return;
393 }
394
395 static __inline__ int
396 bondport_flags_ready(bondport_ref p)
397 {
398 return ((p->po_flags & BONDPORT_FLAGS_READY) != 0);
399 }
400
401 static __inline__ void
402 bondport_flags_set_selected_changed(bondport_ref p)
403 {
404 p->po_flags |= BONDPORT_FLAGS_SELECTED_CHANGED;
405 return;
406 }
407
408 static __inline__ void
409 bondport_flags_clear_selected_changed(bondport_ref p)
410 {
411 p->po_flags &= ~BONDPORT_FLAGS_SELECTED_CHANGED;
412 return;
413 }
414
415 static __inline__ int
416 bondport_flags_selected_changed(bondport_ref p)
417 {
418 return ((p->po_flags & BONDPORT_FLAGS_SELECTED_CHANGED) != 0);
419 }
420
421 static __inline__ void
422 bondport_flags_set_mux_attached(bondport_ref p)
423 {
424 p->po_flags |= BONDPORT_FLAGS_MUX_ATTACHED;
425 return;
426 }
427
428 static __inline__ void
429 bondport_flags_clear_mux_attached(bondport_ref p)
430 {
431 p->po_flags &= ~BONDPORT_FLAGS_MUX_ATTACHED;
432 return;
433 }
434
435 static __inline__ int
436 bondport_flags_mux_attached(bondport_ref p)
437 {
438 return ((p->po_flags & BONDPORT_FLAGS_MUX_ATTACHED) != 0);
439 }
440
441 static __inline__ void
442 bondport_flags_set_distributing(bondport_ref p)
443 {
444 p->po_flags |= BONDPORT_FLAGS_DISTRIBUTING;
445 return;
446 }
447
448 static __inline__ void
449 bondport_flags_clear_distributing(bondport_ref p)
450 {
451 p->po_flags &= ~BONDPORT_FLAGS_DISTRIBUTING;
452 return;
453 }
454
455 static __inline__ int
456 bondport_flags_distributing(bondport_ref p)
457 {
458 return ((p->po_flags & BONDPORT_FLAGS_DISTRIBUTING) != 0);
459 }
460
461 typedef struct bond_globals_s {
462 struct ifbond_list ifbond_list;
463 lacp_system system;
464 lacp_system_priority system_priority;
465 int verbose;
466 } * bond_globals_ref;
467
468 static bond_globals_ref g_bond;
469
470 /**
471 ** packet_buffer routines
472 ** - thin wrapper for mbuf
473 **/
474
475 typedef struct mbuf * packet_buffer_ref;
476
477 static packet_buffer_ref
478 packet_buffer_allocate(int length)
479 {
480 packet_buffer_ref m;
481 int size;
482
483 /* leave room for ethernet header */
484 size = length + sizeof(struct ether_header);
485 if (size > (int)MHLEN) {
486 if (size > (int)MCLBYTES) {
487 printf("bond: packet_buffer_allocate size %d > max %u\n",
488 size, MCLBYTES);
489 return (NULL);
490 }
491 m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR);
492 } else {
493 m = m_gethdr(M_WAITOK, MT_DATA);
494 }
495 if (m == NULL) {
496 return (NULL);
497 }
498 m->m_len = size;
499 m->m_pkthdr.len = size;
500 return (m);
501 }
502
503 static void *
504 packet_buffer_byteptr(packet_buffer_ref buf)
505 {
506 return (buf->m_data + sizeof(struct ether_header));
507 }
508
509 typedef enum {
510 LAEventStart,
511 LAEventTimeout,
512 LAEventPacket,
513 LAEventMediaChange,
514 LAEventSelectedChange,
515 LAEventPortMoved,
516 LAEventReady
517 } LAEvent;
518
519 /**
520 ** Receive machine
521 **/
522 static void
523 bondport_receive_machine(bondport_ref p, LAEvent event,
524 void * event_data);
525 /**
526 ** Periodic Transmission machine
527 **/
528 static void
529 bondport_periodic_transmit_machine(bondport_ref p, LAEvent event,
530 void * event_data);
531
532 /**
533 ** Transmit machine
534 **/
535 #define TRANSMIT_MACHINE_TX_IMMEDIATE ((void *)1)
536
537 static void
538 bondport_transmit_machine(bondport_ref p, LAEvent event,
539 void * event_data);
540
541 /**
542 ** Mux machine
543 **/
544 static void
545 bondport_mux_machine(bondport_ref p, LAEvent event,
546 void * event_data);
547
548 /**
549 ** bond, LAG
550 **/
551 static void
552 ifbond_activate_LAG(ifbond_ref bond, LAG_ref lag, int active_media);
553
554 static void
555 ifbond_deactivate_LAG(ifbond_ref bond, LAG_ref lag);
556
557 static int
558 ifbond_all_ports_ready(ifbond_ref bond);
559
560 static LAG_ref
561 ifbond_find_best_LAG(ifbond_ref bond, int * active_media);
562
563 static int
564 LAG_get_aggregatable_port_count(LAG_ref lag, int * active_media);
565
566 static int
567 ifbond_selection(ifbond_ref bond);
568
569
570 /**
571 ** bondport
572 **/
573
574 static void
575 bondport_receive_lacpdu(bondport_ref p, lacpdu_ref in_lacpdu_p);
576
577 static void
578 bondport_slow_proto_transmit(bondport_ref p, packet_buffer_ref buf);
579
580 static bondport_ref
581 bondport_create(struct ifnet * port_ifp, lacp_port_priority priority,
582 int active, int short_timeout, int * error);
583 static void
584 bondport_start(bondport_ref p);
585
586 static void
587 bondport_free(bondport_ref p);
588
589 static int
590 bondport_aggregatable(bondport_ref p);
591
592 static int
593 bondport_remove_from_LAG(bondport_ref p);
594
595 static void
596 bondport_set_selected(bondport_ref p, SelectedState s);
597
598 static int
599 bondport_matches_LAG(bondport_ref p, LAG_ref lag);
600
601 static void
602 bondport_link_status_changed(bondport_ref p);
603
604 static void
605 bondport_enable_distributing(bondport_ref p);
606
607 static void
608 bondport_disable_distributing(bondport_ref p);
609
610 static __inline__ int
611 bondport_collecting(bondport_ref p)
612 {
613 if (p->po_bond->ifb_mode == IF_BOND_MODE_LACP) {
614 return (lacp_actor_partner_state_collecting(p->po_actor_state));
615 }
616 return (TRUE);
617 }
618
619 /**
620 ** bond interface/dlil specific routines
621 **/
622 static int bond_clone_create(struct if_clone *, u_int32_t, void *);
623 static int bond_clone_destroy(struct ifnet *);
624 static int bond_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t m,
625 char *frame_header);
626 static int bond_output(struct ifnet *ifp, struct mbuf *m);
627 static int bond_ioctl(struct ifnet *ifp, u_long cmd, void * addr);
628 static int bond_set_bpf_tap(struct ifnet * ifp, bpf_tap_mode mode,
629 bpf_packet_func func);
630 static int bond_attach_protocol(struct ifnet *ifp);
631 static int bond_detach_protocol(struct ifnet *ifp);
632 static int bond_setmulti(struct ifnet *ifp);
633 static int bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp);
634 static int bond_remove_interface(ifbond_ref ifb, struct ifnet * port_ifp);
635 static void bond_if_free(struct ifnet * ifp);
636 static void interface_link_event(struct ifnet * ifp, u_int32_t event_code);
637
638 static struct if_clone bond_cloner = IF_CLONE_INITIALIZER(BONDNAME,
639 bond_clone_create,
640 bond_clone_destroy,
641 0,
642 BOND_MAXUNIT,
643 BOND_ZONE_MAX_ELEM,
644 sizeof(ifbond));
645
646 static int
647 siocsifmtu(struct ifnet * ifp, int mtu)
648 {
649 struct ifreq ifr;
650
651 bzero(&ifr, sizeof(ifr));
652 ifr.ifr_mtu = mtu;
653 return (ifnet_ioctl(ifp, 0, SIOCSIFMTU, &ifr));
654 }
655
656 static int
657 siocgifdevmtu(struct ifnet * ifp, struct ifdevmtu * ifdm_p)
658 {
659 struct ifreq ifr;
660 int error;
661
662 bzero(&ifr, sizeof(ifr));
663 error = ifnet_ioctl(ifp, 0, SIOCGIFDEVMTU, &ifr);
664 if (error == 0) {
665 *ifdm_p = ifr.ifr_devmtu;
666 }
667 return (error);
668 }
669
670 static __inline__ void
671 ether_addr_copy(void * dest, const void * source)
672 {
673 bcopy(source, dest, ETHER_ADDR_LEN);
674 return;
675 }
676
677 static __inline__ void
678 ifbond_retain(ifbond_ref ifb)
679 {
680 OSIncrementAtomic(&ifb->ifb_retain_count);
681 }
682
683 static __inline__ void
684 ifbond_release(ifbond_ref ifb)
685 {
686 UInt32 old_retain_count;
687
688 old_retain_count = OSDecrementAtomic(&ifb->ifb_retain_count);
689 switch (old_retain_count) {
690 case 0:
691 panic("ifbond_release: retain count is 0\n");
692 break;
693 case 1:
694 if (g_bond->verbose) {
695 printf("ifbond_release(%s)\n", ifb->ifb_name);
696 }
697 if (ifb->ifb_ifma_slow_proto != NULL) {
698 if (g_bond->verbose) {
699 printf("ifbond_release(%s) removing multicast\n",
700 ifb->ifb_name);
701 }
702 (void) if_delmulti_anon(ifb->ifb_ifma_slow_proto->ifma_ifp,
703 ifb->ifb_ifma_slow_proto->ifma_addr);
704 IFMA_REMREF(ifb->ifb_ifma_slow_proto);
705 }
706 if (ifb->ifb_distributing_array != NULL) {
707 FREE(ifb->ifb_distributing_array, M_BOND);
708 }
709 if_clone_softc_deallocate(&bond_cloner, ifb);
710 break;
711 default:
712 break;
713 }
714 return;
715 }
716
717 /*
718 * Function: ifbond_wait
719 * Purpose:
720 * Allows a single thread to gain exclusive access to the ifbond
721 * data structure. Some operations take a long time to complete,
722 * and some have side-effects that we can't predict. Holding the
723 * bond_lock() across such operations is not possible.
724 *
725 * For example:
726 * 1) The SIOCSIFLLADDR ioctl takes a long time (several seconds) to
727 * complete. Simply holding the bond_lock() would freeze all other
728 * data structure accesses during that time.
729 * 2) When we attach our protocol to the interface, a dlil event is
730 * generated and invokes our bond_event() function. bond_event()
731 * needs to take the bond_lock(), but we're already holding it, so
732 * we're deadlocked against ourselves.
733 * Notes:
734 * Before calling, you must be holding the bond_lock and have taken
735 * a reference on the ifbond_ref.
736 */
737 static void
738 ifbond_wait(ifbond_ref ifb, const char * msg)
739 {
740 int waited = 0;
741
742 /* other add/remove in progress */
743 while (ifbond_flags_change_in_progress(ifb)) {
744 if (g_bond->verbose) {
745 printf("%s: %s msleep\n", ifb->ifb_name, msg);
746 }
747 waited = 1;
748 (void)msleep(ifb, bond_lck_mtx, PZERO, msg, 0);
749 }
750 /* prevent other bond list remove/add from taking place */
751 ifbond_flags_set_change_in_progress(ifb);
752 if (g_bond->verbose && waited) {
753 printf("%s: %s woke up\n", ifb->ifb_name, msg);
754 }
755 return;
756 }
757
758 /*
759 * Function: ifbond_signal
760 * Purpose:
761 * Allows the thread that previously invoked ifbond_wait() to
762 * give up exclusive access to the ifbond data structure, and wake up
763 * any other threads waiting to access
764 * Notes:
765 * Before calling, you must be holding the bond_lock and have taken
766 * a reference on the ifbond_ref.
767 */
768 static void
769 ifbond_signal(ifbond_ref ifb, const char * msg)
770 {
771 ifbond_flags_clear_change_in_progress(ifb);
772 wakeup((caddr_t)ifb);
773 if (g_bond->verbose) {
774 printf("%s: %s wakeup\n", ifb->ifb_name, msg);
775 }
776 return;
777 }
778
779 /**
780 ** Media information
781 **/
782
783 static int
784 link_speed(int active)
785 {
786 switch (IFM_SUBTYPE(active)) {
787 case IFM_10_T:
788 case IFM_10_2:
789 case IFM_10_5:
790 case IFM_10_STP:
791 case IFM_10_FL:
792 return (10);
793 case IFM_100_TX:
794 case IFM_100_FX:
795 case IFM_100_T4:
796 case IFM_100_VG:
797 case IFM_100_T2:
798 return (100);
799 case IFM_1000_SX:
800 case IFM_1000_LX:
801 case IFM_1000_CX:
802 case IFM_1000_TX:
803 return (1000);
804 case IFM_HPNA_1:
805 return (0);
806 default:
807 /* assume that new defined types are going to be at least 10GigE */
808 case IFM_10G_SR:
809 case IFM_10G_LR:
810 return (10000);
811 case IFM_2500_T:
812 return (2500);
813 case IFM_5000_T:
814 return (5000);
815 }
816 }
817
818 static __inline__ int
819 media_active(const struct media_info * mi)
820 {
821 if ((mi->mi_status & IFM_AVALID) == 0) {
822 return (1);
823 }
824 return ((mi->mi_status & IFM_ACTIVE) != 0);
825 }
826
827 static __inline__ int
828 media_full_duplex(const struct media_info * mi)
829 {
830 return ((mi->mi_active & IFM_FDX) != 0);
831 }
832
833 static __inline__ int
834 media_speed(const struct media_info * mi)
835 {
836 return (link_speed(mi->mi_active));
837 }
838
839 static struct media_info
840 interface_media_info(struct ifnet * ifp)
841 {
842 struct ifmediareq ifmr;
843 struct media_info mi;
844
845 bzero(&mi, sizeof(mi));
846 bzero(&ifmr, sizeof(ifmr));
847 if (ifnet_ioctl(ifp, 0, SIOCGIFMEDIA, &ifmr) == 0) {
848 if (ifmr.ifm_count != 0) {
849 mi.mi_status = ifmr.ifm_status;
850 mi.mi_active = ifmr.ifm_active;
851 }
852 }
853 return (mi);
854 }
855
856 static int
857 if_siflladdr(struct ifnet * ifp, const struct ether_addr * ea_p)
858 {
859 struct ifreq ifr;
860
861 /*
862 * XXX setting the sa_len to ETHER_ADDR_LEN is wrong, but the driver
863 * currently expects it that way
864 */
865 ifr.ifr_addr.sa_family = AF_UNSPEC;
866 ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
867 ether_addr_copy(ifr.ifr_addr.sa_data, ea_p);
868 return (ifnet_ioctl(ifp, 0, SIOCSIFLLADDR, &ifr));
869 }
870
871 /**
872 ** bond_globals
873 **/
874 static bond_globals_ref
875 bond_globals_create(lacp_system_priority sys_pri,
876 lacp_system_ref sys)
877 {
878 bond_globals_ref b;
879
880 b = _MALLOC(sizeof(*b), M_BOND, M_WAITOK | M_ZERO);
881 if (b == NULL) {
882 return (NULL);
883 }
884 TAILQ_INIT(&b->ifbond_list);
885 b->system = *sys;
886 b->system_priority = sys_pri;
887 return (b);
888 }
889
890 static int
891 bond_globals_init(void)
892 {
893 bond_globals_ref b;
894 int i;
895 struct ifnet * ifp;
896
897 bond_assert_lock_not_held();
898
899 if (g_bond != NULL) {
900 return (0);
901 }
902
903 /*
904 * use en0's ethernet address as the system identifier, and if it's not
905 * there, use en1 .. en3
906 */
907 ifp = NULL;
908 for (i = 0; i < 4; i++) {
909 char ifname[IFNAMSIZ+1];
910 snprintf(ifname, sizeof(ifname), "en%d", i);
911 ifp = ifunit(ifname);
912 if (ifp != NULL) {
913 break;
914 }
915 }
916 b = NULL;
917 if (ifp != NULL) {
918 b = bond_globals_create(0x8000, (lacp_system_ref)IF_LLADDR(ifp));
919 }
920 bond_lock();
921 if (g_bond != NULL) {
922 bond_unlock();
923 _FREE(b, M_BOND);
924 return (0);
925 }
926 g_bond = b;
927 bond_unlock();
928 if (ifp == NULL) {
929 return (ENXIO);
930 }
931 if (b == NULL) {
932 return (ENOMEM);
933 }
934 return (0);
935 }
936
937 static void
938 bond_bpf_vlan(struct ifnet * ifp, struct mbuf * m,
939 const struct ether_header * eh_p,
940 u_int16_t vlan_tag, bpf_packet_func func)
941 {
942 struct ether_vlan_header * vlh_p;
943 struct mbuf * vl_m;
944
945 vl_m = m_get(M_DONTWAIT, MT_DATA);
946 if (vl_m == NULL) {
947 return;
948 }
949 /* populate a new mbuf containing the vlan ethernet header */
950 vl_m->m_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
951 vlh_p = mtod(vl_m, struct ether_vlan_header *);
952 bcopy(eh_p, vlh_p, offsetof(struct ether_header, ether_type));
953 vlh_p->evl_encap_proto = htons(ETHERTYPE_VLAN);
954 vlh_p->evl_tag = htons(vlan_tag);
955 vlh_p->evl_proto = eh_p->ether_type;
956 vl_m->m_next = m;
957 (*func)(ifp, vl_m);
958 vl_m->m_next = NULL;
959 m_free(vl_m);
960 return;
961 }
962
963 static __inline__ void
964 bond_bpf_output(struct ifnet * ifp, struct mbuf * m,
965 bpf_packet_func func)
966 {
967 if (func != NULL) {
968 if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
969 const struct ether_header * eh_p;
970 eh_p = mtod(m, const struct ether_header *);
971 m->m_data += ETHER_HDR_LEN;
972 m->m_len -= ETHER_HDR_LEN;
973 bond_bpf_vlan(ifp, m, eh_p, m->m_pkthdr.vlan_tag, func);
974 m->m_data -= ETHER_HDR_LEN;
975 m->m_len += ETHER_HDR_LEN;
976 } else {
977 (*func)(ifp, m);
978 }
979 }
980 return;
981 }
982
983 static __inline__ void
984 bond_bpf_input(ifnet_t ifp, mbuf_t m, const struct ether_header * eh_p,
985 bpf_packet_func func)
986 {
987 if (func != NULL) {
988 if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
989 bond_bpf_vlan(ifp, m, eh_p, m->m_pkthdr.vlan_tag, func);
990 } else {
991 /* restore the header */
992 m->m_data -= ETHER_HDR_LEN;
993 m->m_len += ETHER_HDR_LEN;
994 (*func)(ifp, m);
995 m->m_data += ETHER_HDR_LEN;
996 m->m_len -= ETHER_HDR_LEN;
997 }
998 }
999 return;
1000 }
1001
1002 /*
1003 * Function: bond_setmulti
1004 * Purpose:
1005 * Enable multicast reception on "our" interface by enabling multicasts on
1006 * each of the member ports.
1007 */
1008 static int
1009 bond_setmulti(struct ifnet * ifp)
1010 {
1011 ifbond_ref ifb;
1012 int error;
1013 int result = 0;
1014 bondport_ref p;
1015
1016 bond_lock();
1017 ifb = ifnet_softc(ifp);
1018 if (ifb == NULL || ifbond_flags_if_detaching(ifb)
1019 || TAILQ_EMPTY(&ifb->ifb_port_list)) {
1020 bond_unlock();
1021 return (0);
1022 }
1023 ifbond_retain(ifb);
1024 ifbond_wait(ifb, "bond_setmulti");
1025
1026 if (ifbond_flags_if_detaching(ifb)) {
1027 /* someone destroyed the bond while we were waiting */
1028 result = EBUSY;
1029 goto signal_done;
1030 }
1031 bond_unlock();
1032
1033 /* ifbond_wait() let's us safely walk the list without holding the lock */
1034 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
1035 struct ifnet * port_ifp = p->po_ifp;
1036
1037 error = multicast_list_program(&p->po_multicast,
1038 ifp, port_ifp);
1039 if (error != 0) {
1040 printf("bond_setmulti(%s): "
1041 "multicast_list_program(%s%d) failed, %d\n",
1042 ifb->ifb_name, ifnet_name(port_ifp),
1043 ifnet_unit(port_ifp), error);
1044 result = error;
1045 }
1046 }
1047 bond_lock();
1048 signal_done:
1049 ifbond_signal(ifb, "bond_setmulti");
1050 bond_unlock();
1051 ifbond_release(ifb);
1052 return (result);
1053 }
1054
1055 static int
1056 bond_clone_attach(void)
1057 {
1058 int error;
1059
1060 if ((error = if_clone_attach(&bond_cloner)) != 0)
1061 return error;
1062 bond_lock_init();
1063 return 0;
1064 }
1065
1066 static int
1067 ifbond_add_slow_proto_multicast(ifbond_ref ifb)
1068 {
1069 int error;
1070 struct ifmultiaddr * ifma = NULL;
1071 struct sockaddr_dl sdl;
1072
1073 bond_assert_lock_not_held();
1074
1075 bzero(&sdl, sizeof(sdl));
1076 sdl.sdl_len = sizeof(sdl);
1077 sdl.sdl_family = AF_LINK;
1078 sdl.sdl_type = IFT_ETHER;
1079 sdl.sdl_nlen = 0;
1080 sdl.sdl_alen = sizeof(slow_proto_multicast);
1081 bcopy(&slow_proto_multicast, sdl.sdl_data, sizeof(slow_proto_multicast));
1082 error = if_addmulti_anon(ifb->ifb_ifp, (struct sockaddr *)&sdl, &ifma);
1083 if (error == 0) {
1084 ifb->ifb_ifma_slow_proto = ifma;
1085 }
1086 return (error);
1087 }
1088
1089 static int
1090 bond_clone_create(struct if_clone * ifc, u_int32_t unit, __unused void *params)
1091 {
1092 int error;
1093 ifbond_ref ifb;
1094 ifnet_t ifp;
1095 struct ifnet_init_eparams bond_init;
1096
1097 error = bond_globals_init();
1098 if (error != 0) {
1099 return (error);
1100 }
1101
1102 ifb = if_clone_softc_allocate(&bond_cloner);
1103 if (ifb == NULL) {
1104 return (ENOMEM);
1105 }
1106
1107 ifbond_retain(ifb);
1108 TAILQ_INIT(&ifb->ifb_port_list);
1109 TAILQ_INIT(&ifb->ifb_lag_list);
1110 ifb->ifb_key = unit + 1;
1111
1112 /* use the interface name as the unique id for ifp recycle */
1113 if ((u_int32_t)snprintf(ifb->ifb_name, sizeof(ifb->ifb_name), "%s%d",
1114 ifc->ifc_name, unit) >= sizeof(ifb->ifb_name)) {
1115 ifbond_release(ifb);
1116 return (EINVAL);
1117 }
1118
1119 bzero(&bond_init, sizeof(bond_init));
1120 bond_init.ver = IFNET_INIT_CURRENT_VERSION;
1121 bond_init.len = sizeof (bond_init);
1122 bond_init.flags = IFNET_INIT_LEGACY;
1123 bond_init.uniqueid = ifb->ifb_name;
1124 bond_init.uniqueid_len = strlen(ifb->ifb_name);
1125 bond_init.name = ifc->ifc_name;
1126 bond_init.unit = unit;
1127 bond_init.family = IFNET_FAMILY_BOND;
1128 bond_init.type = IFT_IEEE8023ADLAG;
1129 bond_init.output = bond_output;
1130 bond_init.demux = ether_demux;
1131 bond_init.add_proto = ether_add_proto;
1132 bond_init.del_proto = ether_del_proto;
1133 bond_init.check_multi = ether_check_multi;
1134 bond_init.framer_extended = ether_frameout_extended;
1135 bond_init.ioctl = bond_ioctl;
1136 bond_init.set_bpf_tap = bond_set_bpf_tap;
1137 bond_init.detach = bond_if_free;
1138 bond_init.broadcast_addr = etherbroadcastaddr;
1139 bond_init.broadcast_len = ETHER_ADDR_LEN;
1140 bond_init.softc = ifb;
1141 error = ifnet_allocate_extended(&bond_init, &ifp);
1142
1143 if (error) {
1144 ifbond_release(ifb);
1145 return (error);
1146 }
1147
1148 ifb->ifb_ifp = ifp;
1149 ifnet_set_offload(ifp, 0);
1150 ifnet_set_addrlen(ifp, ETHER_ADDR_LEN); /* XXX ethernet specific */
1151 ifnet_set_flags(ifp, IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX, 0xffff);
1152 ifnet_set_baudrate(ifp, 0);
1153 ifnet_set_mtu(ifp, 0);
1154
1155 error = ifnet_attach(ifp, NULL);
1156 if (error != 0) {
1157 ifnet_release(ifp);
1158 ifbond_release(ifb);
1159 return (error);
1160 }
1161 error = ifbond_add_slow_proto_multicast(ifb);
1162 if (error != 0) {
1163 printf("bond_clone_create(%s): "
1164 "failed to add slow_proto multicast, %d\n",
1165 ifb->ifb_name, error);
1166 }
1167
1168 /* attach as ethernet */
1169 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
1170
1171 bond_lock();
1172 TAILQ_INSERT_HEAD(&g_bond->ifbond_list, ifb, ifb_bond_list);
1173 bond_unlock();
1174
1175 return (0);
1176 }
1177
1178 static void
1179 bond_remove_all_interfaces(ifbond_ref ifb)
1180 {
1181 bondport_ref p;
1182
1183 bond_assert_lock_held();
1184
1185 /*
1186 * do this in reverse order to avoid re-programming the mac address
1187 * as each head interface is removed
1188 */
1189 while ((p = TAILQ_LAST(&ifb->ifb_port_list, port_list)) != NULL) {
1190 bond_remove_interface(ifb, p->po_ifp);
1191 }
1192 return;
1193 }
1194
1195 static void
1196 bond_remove(ifbond_ref ifb)
1197 {
1198 bond_assert_lock_held();
1199 ifbond_flags_set_if_detaching(ifb);
1200 TAILQ_REMOVE(&g_bond->ifbond_list, ifb, ifb_bond_list);
1201 bond_remove_all_interfaces(ifb);
1202 return;
1203 }
1204
1205 static void
1206 bond_if_detach(struct ifnet * ifp)
1207 {
1208 int error;
1209
1210 error = ifnet_detach(ifp);
1211 if (error) {
1212 printf("bond_if_detach %s%d: ifnet_detach failed, %d\n",
1213 ifnet_name(ifp), ifnet_unit(ifp), error);
1214 }
1215
1216 return;
1217 }
1218
1219 static int
1220 bond_clone_destroy(struct ifnet * ifp)
1221 {
1222 ifbond_ref ifb;
1223
1224 bond_lock();
1225 ifb = ifnet_softc(ifp);
1226 if (ifb == NULL || ifnet_type(ifp) != IFT_IEEE8023ADLAG) {
1227 bond_unlock();
1228 return 0;
1229 }
1230 if (ifbond_flags_if_detaching(ifb)) {
1231 bond_unlock();
1232 return 0;
1233 }
1234 bond_remove(ifb);
1235 bond_unlock();
1236 bond_if_detach(ifp);
1237 return 0;
1238 }
1239
1240 static int
1241 bond_set_bpf_tap(struct ifnet * ifp, bpf_tap_mode mode, bpf_packet_func func)
1242 {
1243 ifbond_ref ifb;
1244
1245 bond_lock();
1246 ifb = ifnet_softc(ifp);
1247 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
1248 bond_unlock();
1249 return (ENODEV);
1250 }
1251 switch (mode) {
1252 case BPF_TAP_DISABLE:
1253 ifb->ifb_bpf_input = ifb->ifb_bpf_output = NULL;
1254 break;
1255
1256 case BPF_TAP_INPUT:
1257 ifb->ifb_bpf_input = func;
1258 break;
1259
1260 case BPF_TAP_OUTPUT:
1261 ifb->ifb_bpf_output = func;
1262 break;
1263
1264 case BPF_TAP_INPUT_OUTPUT:
1265 ifb->ifb_bpf_input = ifb->ifb_bpf_output = func;
1266 break;
1267 default:
1268 break;
1269 }
1270 bond_unlock();
1271 return 0;
1272 }
1273
1274 static uint32_t
1275 ether_header_hash(struct ether_header * eh_p)
1276 {
1277 uint32_t h;
1278
1279 /* get 32-bits from destination ether and ether type */
1280 h = (*((uint16_t *)&eh_p->ether_dhost[4]) << 16)
1281 | eh_p->ether_type;
1282 h ^= *((uint32_t *)&eh_p->ether_dhost[0]);
1283 return (h);
1284 }
1285
1286 static struct mbuf *
1287 S_mbuf_skip_to_offset(struct mbuf * m, int32_t * offset)
1288 {
1289 int len;
1290
1291 len = m->m_len;
1292 while (*offset >= len) {
1293 *offset -= len;
1294 m = m->m_next;
1295 if (m == NULL) {
1296 break;
1297 }
1298 len = m->m_len;
1299 }
1300 return (m);
1301 }
1302
1303 #if BYTE_ORDER == BIG_ENDIAN
1304 static __inline__ uint32_t
1305 make_uint32(u_char c0, u_char c1, u_char c2, u_char c3)
1306 {
1307 return (((uint32_t)c0 << 24) | ((uint32_t)c1 << 16)
1308 | ((uint32_t)c2 << 8) | (uint32_t)c3);
1309 }
1310 #else /* BYTE_ORDER == LITTLE_ENDIAN */
1311 static __inline__ uint32_t
1312 make_uint32(u_char c0, u_char c1, u_char c2, u_char c3)
1313 {
1314 return (((uint32_t)c3 << 24) | ((uint32_t)c2 << 16)
1315 | ((uint32_t)c1 << 8) | (uint32_t)c0);
1316 }
1317 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1318
1319 static int
1320 S_mbuf_copy_uint32(struct mbuf * m, int32_t offset, uint32_t * val)
1321 {
1322 struct mbuf * current;
1323 u_char * current_data;
1324 struct mbuf * next;
1325 u_char * next_data;
1326 int space_current;
1327
1328 current = S_mbuf_skip_to_offset(m, &offset);
1329 if (current == NULL) {
1330 return (1);
1331 }
1332 current_data = mtod(current, u_char *) + offset;
1333 space_current = current->m_len - offset;
1334 if (space_current >= (int)sizeof(uint32_t)) {
1335 *val = *((uint32_t *)current_data);
1336 return (0);
1337 }
1338 next = current->m_next;
1339 if (next == NULL || (next->m_len + space_current) < (int)sizeof(uint32_t)) {
1340 return (1);
1341 }
1342 next_data = mtod(next, u_char *);
1343 switch (space_current) {
1344 case 1:
1345 *val = make_uint32(current_data[0], next_data[0],
1346 next_data[1], next_data[2]);
1347 break;
1348 case 2:
1349 *val = make_uint32(current_data[0], current_data[1],
1350 next_data[0], next_data[1]);
1351 break;
1352 default:
1353 *val = make_uint32(current_data[0], current_data[1],
1354 current_data[2], next_data[0]);
1355 break;
1356 }
1357 return (0);
1358 }
1359
1360 #define IP_SRC_OFFSET (offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p))
1361 #define IP_DST_OFFSET (offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p))
1362
1363 static uint32_t
1364 ip_header_hash(struct mbuf * m)
1365 {
1366 u_char * data;
1367 struct in_addr ip_dst;
1368 struct in_addr ip_src;
1369 u_char ip_p;
1370 int32_t offset;
1371 struct mbuf * orig_m = m;
1372
1373 /* find the IP protocol field relative to the start of the packet */
1374 offset = offsetof(struct ip, ip_p) + sizeof(struct ether_header);
1375 m = S_mbuf_skip_to_offset(m, &offset);
1376 if (m == NULL || m->m_len < 1) {
1377 goto bad_ip_packet;
1378 }
1379 data = mtod(m, u_char *) + offset;
1380 ip_p = *data;
1381
1382 /* find the IP src relative to the IP protocol */
1383 if ((m->m_len - offset)
1384 >= (int)(IP_SRC_OFFSET + sizeof(struct in_addr) * 2)) {
1385 /* this should be the normal case */
1386 ip_src = *(struct in_addr *)(data + IP_SRC_OFFSET);
1387 ip_dst = *(struct in_addr *)(data + IP_DST_OFFSET);
1388 }
1389 else {
1390 if (S_mbuf_copy_uint32(m, offset + IP_SRC_OFFSET,
1391 (uint32_t *)&ip_src.s_addr)) {
1392 goto bad_ip_packet;
1393 }
1394 if (S_mbuf_copy_uint32(m, offset + IP_DST_OFFSET,
1395 (uint32_t *)&ip_dst.s_addr)) {
1396 goto bad_ip_packet;
1397 }
1398 }
1399 return (ntohl(ip_dst.s_addr) ^ ntohl(ip_src.s_addr) ^ ((uint32_t)ip_p));
1400
1401 bad_ip_packet:
1402 return (ether_header_hash(mtod(orig_m, struct ether_header *)));
1403 }
1404
1405 #define IP6_ADDRS_LEN (sizeof(struct in6_addr) * 2)
1406 static uint32_t
1407 ipv6_header_hash(struct mbuf * m)
1408 {
1409 u_char * data;
1410 int i;
1411 int32_t offset;
1412 struct mbuf * orig_m = m;
1413 uint32_t * scan;
1414 uint32_t val;
1415
1416 /* find the IP protocol field relative to the start of the packet */
1417 offset = offsetof(struct ip6_hdr, ip6_src) + sizeof(struct ether_header);
1418 m = S_mbuf_skip_to_offset(m, &offset);
1419 if (m == NULL) {
1420 goto bad_ipv6_packet;
1421 }
1422 data = mtod(m, u_char *) + offset;
1423 val = 0;
1424 if ((m->m_len - offset) >= (int)IP6_ADDRS_LEN) {
1425 /* this should be the normal case */
1426 for (i = 0, scan = (uint32_t *)data;
1427 i < (int)(IP6_ADDRS_LEN / sizeof(uint32_t));
1428 i++, scan++) {
1429 val ^= *scan;
1430 }
1431 }
1432 else {
1433 for (i = 0; i < (int)(IP6_ADDRS_LEN / sizeof(uint32_t)); i++) {
1434 uint32_t tmp;
1435 if (S_mbuf_copy_uint32(m, offset + i * sizeof(uint32_t),
1436 (uint32_t *)&tmp)) {
1437 goto bad_ipv6_packet;
1438 }
1439 val ^= tmp;
1440 }
1441 }
1442 return (ntohl(val));
1443
1444 bad_ipv6_packet:
1445 return (ether_header_hash(mtod(orig_m, struct ether_header *)));
1446 }
1447
1448 static int
1449 bond_output(struct ifnet * ifp, struct mbuf * m)
1450 {
1451 bpf_packet_func bpf_func;
1452 uint32_t h;
1453 ifbond_ref ifb;
1454 struct ifnet * port_ifp = NULL;
1455 int err;
1456 struct flowadv adv = { FADV_SUCCESS };
1457
1458 if (m == 0) {
1459 return (0);
1460 }
1461 if ((m->m_flags & M_PKTHDR) == 0) {
1462 m_freem(m);
1463 return (0);
1464 }
1465 if (m->m_pkthdr.pkt_flowid != 0) {
1466 h = m->m_pkthdr.pkt_flowid;
1467 }
1468 else {
1469 struct ether_header * eh_p;
1470
1471 eh_p = mtod(m, struct ether_header *);
1472 switch (ntohs(eh_p->ether_type)) {
1473 case ETHERTYPE_IP:
1474 h = ip_header_hash(m);
1475 break;
1476 case ETHERTYPE_IPV6:
1477 h = ipv6_header_hash(m);
1478 break;
1479 default:
1480 h = ether_header_hash(eh_p);
1481 break;
1482 }
1483 }
1484 bond_lock();
1485 ifb = ifnet_softc(ifp);
1486 if (ifb == NULL || ifbond_flags_if_detaching(ifb)
1487 || ifb->ifb_distributing_count == 0) {
1488 goto done;
1489 }
1490 h %= ifb->ifb_distributing_count;
1491 port_ifp = ifb->ifb_distributing_array[h]->po_ifp;
1492 bpf_func = ifb->ifb_bpf_output;
1493 bond_unlock();
1494
1495 if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
1496 (void)ifnet_stat_increment_out(ifp, 1,
1497 m->m_pkthdr.len + ETHER_VLAN_ENCAP_LEN,
1498 0);
1499 } else {
1500 (void)ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0);
1501 }
1502 bond_bpf_output(ifp, m, bpf_func);
1503
1504 err = dlil_output(port_ifp, PF_BOND, m, NULL, NULL, 1, &adv);
1505
1506 if (err == 0) {
1507 if (adv.code == FADV_FLOW_CONTROLLED) {
1508 err = EQFULL;
1509 } else if (adv.code == FADV_SUSPENDED) {
1510 err = EQSUSPENDED;
1511 }
1512 }
1513
1514 return (err);
1515
1516 done:
1517 bond_unlock();
1518 m_freem(m);
1519 return (0);
1520 }
1521
1522 static bondport_ref
1523 ifbond_lookup_port(ifbond_ref ifb, struct ifnet * port_ifp)
1524 {
1525 bondport_ref p;
1526 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
1527 if (p->po_ifp == port_ifp) {
1528 return (p);
1529 }
1530 }
1531 return (NULL);
1532 }
1533
1534 static bondport_ref
1535 bond_lookup_port(struct ifnet * port_ifp)
1536 {
1537 ifbond_ref ifb;
1538 bondport_ref port;
1539
1540 TAILQ_FOREACH(ifb, &g_bond->ifbond_list, ifb_bond_list) {
1541 port = ifbond_lookup_port(ifb, port_ifp);
1542 if (port != NULL) {
1543 return (port);
1544 }
1545 }
1546 return (NULL);
1547 }
1548
1549 static void
1550 bond_receive_lacpdu(struct mbuf * m, struct ifnet * port_ifp)
1551 {
1552 struct ifnet * bond_ifp = NULL;
1553 ifbond_ref ifb;
1554 int event_code = 0;
1555 bondport_ref p;
1556
1557 bond_lock();
1558 if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) {
1559 goto done;
1560 }
1561 p = bond_lookup_port(port_ifp);
1562 if (p == NULL) {
1563 goto done;
1564 }
1565 if (p->po_enabled == 0) {
1566 goto done;
1567 }
1568 ifb = p->po_bond;
1569 if (ifb->ifb_mode != IF_BOND_MODE_LACP) {
1570 goto done;
1571 }
1572 bondport_receive_lacpdu(p, (lacpdu_ref)m->m_data);
1573 if (ifbond_selection(ifb)) {
1574 event_code = (ifb->ifb_active_lag == NULL)
1575 ? KEV_DL_LINK_OFF
1576 : KEV_DL_LINK_ON;
1577 /* XXX need to take a reference on bond_ifp */
1578 bond_ifp = ifb->ifb_ifp;
1579 ifb->ifb_last_link_event = event_code;
1580 }
1581 else {
1582 event_code = (ifb->ifb_active_lag == NULL)
1583 ? KEV_DL_LINK_OFF
1584 : KEV_DL_LINK_ON;
1585 if (event_code != ifb->ifb_last_link_event) {
1586 if (g_bond->verbose) {
1587 timestamp_printf("%s: (receive) generating LINK event\n",
1588 ifb->ifb_name);
1589 }
1590 bond_ifp = ifb->ifb_ifp;
1591 ifb->ifb_last_link_event = event_code;
1592 }
1593 }
1594
1595 done:
1596 bond_unlock();
1597 if (bond_ifp != NULL) {
1598 interface_link_event(bond_ifp, event_code);
1599 }
1600 m_freem(m);
1601 return;
1602 }
1603
1604 static void
1605 bond_receive_la_marker_pdu(struct mbuf * m, struct ifnet * port_ifp)
1606 {
1607 la_marker_pdu_ref marker_p;
1608 bondport_ref p;
1609
1610 marker_p = (la_marker_pdu_ref)(m->m_data + ETHER_HDR_LEN);
1611 if (marker_p->lm_marker_tlv_type != LA_MARKER_TLV_TYPE_MARKER) {
1612 goto failed;
1613 }
1614 bond_lock();
1615 if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) {
1616 bond_unlock();
1617 goto failed;
1618 }
1619 p = bond_lookup_port(port_ifp);
1620 if (p == NULL || p->po_enabled == 0
1621 || p->po_bond->ifb_mode != IF_BOND_MODE_LACP) {
1622 bond_unlock();
1623 goto failed;
1624 }
1625 /* echo back the same packet as a marker response */
1626 marker_p->lm_marker_tlv_type = LA_MARKER_TLV_TYPE_MARKER_RESPONSE;
1627 bondport_slow_proto_transmit(p, (packet_buffer_ref)m);
1628 bond_unlock();
1629 return;
1630
1631 failed:
1632 m_freem(m);
1633 return;
1634 }
1635
1636 static int
1637 bond_input(ifnet_t port_ifp, __unused protocol_family_t protocol, mbuf_t m,
1638 char * frame_header)
1639 {
1640 bpf_packet_func bpf_func;
1641 const struct ether_header * eh_p;
1642 ifbond_ref ifb;
1643 struct ifnet * ifp;
1644 bondport_ref p;
1645
1646 eh_p = (const struct ether_header *)frame_header;
1647 if ((m->m_flags & M_MCAST) != 0
1648 && bcmp(eh_p->ether_dhost, &slow_proto_multicast,
1649 sizeof(eh_p->ether_dhost)) == 0
1650 && ntohs(eh_p->ether_type) == IEEE8023AD_SLOW_PROTO_ETHERTYPE) {
1651 u_char subtype = *mtod(m, u_char *);
1652
1653 if (subtype == IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP) {
1654 if (m->m_pkthdr.len < (int)offsetof(lacpdu, la_reserved)) {
1655 m_freem(m);
1656 return (0);
1657 }
1658 /* send to lacp */
1659 if (m->m_len < (int)offsetof(lacpdu, la_reserved)) {
1660 m = m_pullup(m, offsetof(lacpdu, la_reserved));
1661 if (m == NULL) {
1662 return (0);
1663 }
1664 }
1665 bond_receive_lacpdu(m, port_ifp);
1666 return (0);
1667 }
1668 else if (subtype == IEEE8023AD_SLOW_PROTO_SUBTYPE_LA_MARKER_PROTOCOL) {
1669 int min_size;
1670
1671 /* restore the ethernet header pointer in the mbuf */
1672 m->m_pkthdr.len += ETHER_HDR_LEN;
1673 m->m_data -= ETHER_HDR_LEN;
1674 m->m_len += ETHER_HDR_LEN;
1675 min_size = ETHER_HDR_LEN + offsetof(la_marker_pdu, lm_reserved);
1676 if (m->m_pkthdr.len < min_size) {
1677 m_freem(m);
1678 return (0);
1679 }
1680 /* send to lacp */
1681 if (m->m_len < min_size) {
1682 m = m_pullup(m, min_size);
1683 if (m == NULL) {
1684 return (0);
1685 }
1686 }
1687 /* send to marker responder */
1688 bond_receive_la_marker_pdu(m, port_ifp);
1689 return (0);
1690 }
1691 else if (subtype == 0
1692 || subtype > IEEE8023AD_SLOW_PROTO_SUBTYPE_RESERVED_END) {
1693 /* invalid subtype, discard the frame */
1694 m_freem(m);
1695 return (0);
1696 }
1697 }
1698 bond_lock();
1699 if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) {
1700 goto done;
1701 }
1702 p = bond_lookup_port(port_ifp);
1703 if (p == NULL || bondport_collecting(p) == 0) {
1704 goto done;
1705 }
1706
1707 /* make the packet appear as if it arrived on the bonded interface */
1708 ifb = p->po_bond;
1709 ifp = ifb->ifb_ifp;
1710 bpf_func = ifb->ifb_bpf_input;
1711 bond_unlock();
1712
1713 if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
1714 (void)ifnet_stat_increment_in(ifp, 1,
1715 (m->m_pkthdr.len + ETHER_HDR_LEN
1716 + ETHER_VLAN_ENCAP_LEN), 0);
1717 }
1718 else {
1719 (void)ifnet_stat_increment_in(ifp, 1,
1720 (m->m_pkthdr.len + ETHER_HDR_LEN), 0);
1721 }
1722 m->m_pkthdr.rcvif = ifp;
1723 bond_bpf_input(ifp, m, eh_p, bpf_func);
1724 m->m_pkthdr.pkt_hdr = frame_header;
1725 dlil_input_packet_list(ifp, m);
1726 return 0;
1727
1728 done:
1729 bond_unlock();
1730 m_freem(m);
1731 return (0);
1732 }
1733
1734 static __inline__ const char *
1735 bondport_get_name(bondport_ref p)
1736 {
1737 return (p->po_name);
1738 }
1739
1740 static __inline__ int
1741 bondport_get_index(bondport_ref p)
1742 {
1743 return (ifnet_index(p->po_ifp));
1744 }
1745
1746 static void
1747 bondport_slow_proto_transmit(bondport_ref p, packet_buffer_ref buf)
1748 {
1749 struct ether_header * eh_p;
1750 int error;
1751
1752 /* packet_buffer_allocate leaves room for ethernet header */
1753 eh_p = mtod(buf, struct ether_header *);
1754 bcopy(&slow_proto_multicast, &eh_p->ether_dhost, sizeof(eh_p->ether_dhost));
1755 bcopy(&p->po_saved_addr, eh_p->ether_shost, sizeof(eh_p->ether_shost));
1756 eh_p->ether_type = htons(IEEE8023AD_SLOW_PROTO_ETHERTYPE);
1757 error = ifnet_output_raw(p->po_ifp, PF_BOND, buf);
1758 if (error != 0) {
1759 printf("bondport_slow_proto_transmit(%s) failed %d\n",
1760 bondport_get_name(p), error);
1761 }
1762 return;
1763 }
1764
1765 static void
1766 bondport_timer_process_func(devtimer_ref timer,
1767 devtimer_process_func_event event)
1768 {
1769 bondport_ref p;
1770
1771 switch (event) {
1772 case devtimer_process_func_event_lock:
1773 bond_lock();
1774 devtimer_retain(timer);
1775 break;
1776 case devtimer_process_func_event_unlock:
1777 if (devtimer_valid(timer)) {
1778 /* as long as the devtimer is valid, we can look at arg0 */
1779 int event_code = 0;
1780 struct ifnet * bond_ifp = NULL;
1781
1782 p = (bondport_ref)devtimer_arg0(timer);
1783 if (ifbond_selection(p->po_bond)) {
1784 event_code = (p->po_bond->ifb_active_lag == NULL)
1785 ? KEV_DL_LINK_OFF
1786 : KEV_DL_LINK_ON;
1787 /* XXX need to take a reference on bond_ifp */
1788 bond_ifp = p->po_bond->ifb_ifp;
1789 p->po_bond->ifb_last_link_event = event_code;
1790 }
1791 else {
1792 event_code = (p->po_bond->ifb_active_lag == NULL)
1793 ? KEV_DL_LINK_OFF
1794 : KEV_DL_LINK_ON;
1795 if (event_code != p->po_bond->ifb_last_link_event) {
1796 if (g_bond->verbose) {
1797 timestamp_printf("%s: (timer) generating LINK event\n",
1798 p->po_bond->ifb_name);
1799 }
1800 bond_ifp = p->po_bond->ifb_ifp;
1801 p->po_bond->ifb_last_link_event = event_code;
1802 }
1803 }
1804 devtimer_release(timer);
1805 bond_unlock();
1806 if (bond_ifp != NULL) {
1807 interface_link_event(bond_ifp, event_code);
1808 }
1809 }
1810 else {
1811 /* timer is going away */
1812 devtimer_release(timer);
1813 bond_unlock();
1814 }
1815 break;
1816 default:
1817 break;
1818 }
1819 }
1820
1821 static bondport_ref
1822 bondport_create(struct ifnet * port_ifp, lacp_port_priority priority,
1823 int active, int short_timeout, int * ret_error)
1824 {
1825 int error = 0;
1826 bondport_ref p = NULL;
1827 lacp_actor_partner_state s;
1828
1829 *ret_error = 0;
1830 p = _MALLOC(sizeof(*p), M_BOND, M_WAITOK | M_ZERO);
1831 if (p == NULL) {
1832 *ret_error = ENOMEM;
1833 return (NULL);
1834 }
1835 multicast_list_init(&p->po_multicast);
1836 if ((u_int32_t)snprintf(p->po_name, sizeof(p->po_name), "%s%d",
1837 ifnet_name(port_ifp), ifnet_unit(port_ifp))
1838 >= sizeof(p->po_name)) {
1839 printf("if_bond: name too large\n");
1840 *ret_error = EINVAL;
1841 goto failed;
1842 }
1843 error = siocgifdevmtu(port_ifp, &p->po_devmtu);
1844 if (error != 0) {
1845 printf("if_bond: SIOCGIFDEVMTU %s failed, %d\n",
1846 bondport_get_name(p), error);
1847 goto failed;
1848 }
1849 /* remember the current interface MTU so it can be restored */
1850 p->po_devmtu.ifdm_current = ifnet_mtu(port_ifp);
1851 p->po_ifp = port_ifp;
1852 p->po_media_info = interface_media_info(port_ifp);
1853 p->po_current_while_timer = devtimer_create(bondport_timer_process_func, p);
1854 if (p->po_current_while_timer == NULL) {
1855 *ret_error = ENOMEM;
1856 goto failed;
1857 }
1858 p->po_periodic_timer = devtimer_create(bondport_timer_process_func, p);
1859 if (p->po_periodic_timer == NULL) {
1860 *ret_error = ENOMEM;
1861 goto failed;
1862 }
1863 p->po_wait_while_timer = devtimer_create(bondport_timer_process_func, p);
1864 if (p->po_wait_while_timer == NULL) {
1865 *ret_error = ENOMEM;
1866 goto failed;
1867 }
1868 p->po_transmit_timer = devtimer_create(bondport_timer_process_func, p);
1869 if (p->po_transmit_timer == NULL) {
1870 *ret_error = ENOMEM;
1871 goto failed;
1872 }
1873 p->po_receive_state = ReceiveState_none;
1874 p->po_mux_state = MuxState_none;
1875 p->po_priority = priority;
1876 s = 0;
1877 s = lacp_actor_partner_state_set_aggregatable(s);
1878 if (short_timeout) {
1879 s = lacp_actor_partner_state_set_short_timeout(s);
1880 }
1881 if (active) {
1882 s = lacp_actor_partner_state_set_active_lacp(s);
1883 }
1884 p->po_actor_state = s;
1885 return (p);
1886
1887 failed:
1888 bondport_free(p);
1889 return (NULL);
1890 }
1891
1892 static void
1893 bondport_start(bondport_ref p)
1894 {
1895 bondport_receive_machine(p, LAEventStart, NULL);
1896 bondport_mux_machine(p, LAEventStart, NULL);
1897 bondport_periodic_transmit_machine(p, LAEventStart, NULL);
1898 bondport_transmit_machine(p, LAEventStart, NULL);
1899 return;
1900 }
1901
1902 /*
1903 * Function: bondport_invalidate_timers
1904 * Purpose:
1905 * Invalidate all of the timers for the bondport.
1906 */
1907 static void
1908 bondport_invalidate_timers(bondport_ref p)
1909 {
1910 devtimer_invalidate(p->po_current_while_timer);
1911 devtimer_invalidate(p->po_periodic_timer);
1912 devtimer_invalidate(p->po_wait_while_timer);
1913 devtimer_invalidate(p->po_transmit_timer);
1914 }
1915
1916 /*
1917 * Function: bondport_cancel_timers
1918 * Purpose:
1919 * Cancel all of the timers for the bondport.
1920 */
1921 static void
1922 bondport_cancel_timers(bondport_ref p)
1923 {
1924 devtimer_cancel(p->po_current_while_timer);
1925 devtimer_cancel(p->po_periodic_timer);
1926 devtimer_cancel(p->po_wait_while_timer);
1927 devtimer_cancel(p->po_transmit_timer);
1928 }
1929
1930 static void
1931 bondport_free(bondport_ref p)
1932 {
1933 multicast_list_remove(&p->po_multicast);
1934 devtimer_release(p->po_current_while_timer);
1935 devtimer_release(p->po_periodic_timer);
1936 devtimer_release(p->po_wait_while_timer);
1937 devtimer_release(p->po_transmit_timer);
1938 FREE(p, M_BOND);
1939 return;
1940 }
1941
1942 #define BOND_ADD_PROGRESS_IN_LIST 0x1
1943 #define BOND_ADD_PROGRESS_PROTO_ATTACHED 0x2
1944 #define BOND_ADD_PROGRESS_LLADDR_SET 0x4
1945 #define BOND_ADD_PROGRESS_MTU_SET 0x8
1946
1947 static __inline__ int
1948 bond_device_mtu(struct ifnet * ifp, ifbond_ref ifb)
1949 {
1950 return (((int)ifnet_mtu(ifp) > ifb->ifb_altmtu)
1951 ? (int)ifnet_mtu(ifp) : ifb->ifb_altmtu);
1952 }
1953
1954 static int
1955 bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp)
1956 {
1957 int devmtu;
1958 int error = 0;
1959 int event_code = 0;
1960 int first = FALSE;
1961 ifbond_ref ifb;
1962 bondport_ref * new_array = NULL;
1963 bondport_ref * old_array = NULL;
1964 bondport_ref p;
1965 int progress = 0;
1966
1967 if (IFNET_IS_INTCOPROC(port_ifp)) {
1968 return (EINVAL);
1969 }
1970
1971 /* pre-allocate space for new port */
1972 p = bondport_create(port_ifp, 0x8000, 1, 0, &error);
1973 if (p == NULL) {
1974 return (error);
1975 }
1976 bond_lock();
1977 ifb = (ifbond_ref)ifnet_softc(ifp);
1978 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
1979 bond_unlock();
1980 bondport_free(p);
1981 return ((ifb == NULL ? EOPNOTSUPP : EBUSY));
1982 }
1983
1984 /* make sure this interface can handle our current MTU */
1985 devmtu = bond_device_mtu(ifp, ifb);
1986 if (devmtu != 0
1987 && (devmtu > p->po_devmtu.ifdm_max || devmtu < p->po_devmtu.ifdm_min)) {
1988 bond_unlock();
1989 printf("if_bond: interface %s doesn't support mtu %d",
1990 bondport_get_name(p), devmtu);
1991 bondport_free(p);
1992 return (EINVAL);
1993 }
1994
1995 /* make sure ifb doesn't get de-allocated while we wait */
1996 ifbond_retain(ifb);
1997
1998 /* wait for other add or remove to complete */
1999 ifbond_wait(ifb, "bond_add_interface");
2000
2001 if (ifbond_flags_if_detaching(ifb)) {
2002 /* someone destroyed the bond while we were waiting */
2003 error = EBUSY;
2004 goto signal_done;
2005 }
2006 if (bond_lookup_port(port_ifp) != NULL) {
2007 /* port is already part of a bond */
2008 error = EBUSY;
2009 goto signal_done;
2010 }
2011 ifnet_lock_exclusive(port_ifp);
2012 if ((ifnet_eflags(port_ifp) & (IFEF_VLAN | IFEF_BOND)) != 0) {
2013 /* interface already has VLAN's, or is part of bond */
2014 ifnet_lock_done(port_ifp);
2015 error = EBUSY;
2016 goto signal_done;
2017 }
2018
2019 /* mark the interface busy */
2020 /* can't use ifnet_set_eflags because that takes the lock */
2021 port_ifp->if_eflags |= IFEF_BOND;
2022 ifnet_lock_done(port_ifp);
2023
2024 if (TAILQ_EMPTY(&ifb->ifb_port_list)) {
2025 ifnet_set_offload(ifp, ifnet_offload(port_ifp));
2026 ifnet_set_flags(ifp, IFF_RUNNING, IFF_RUNNING);
2027 if (ifbond_flags_lladdr(ifb) == FALSE) {
2028 first = TRUE;
2029 }
2030 } else {
2031 ifnet_offload_t ifp_offload;
2032 ifnet_offload_t port_ifp_offload;
2033
2034 ifp_offload = ifnet_offload(ifp);
2035 port_ifp_offload = ifnet_offload(port_ifp);
2036 if (ifp_offload != port_ifp_offload) {
2037 ifnet_offload_t offload;
2038
2039 offload = ifp_offload & port_ifp_offload;
2040 printf("bond_add_interface(%s, %s) "
2041 "hwassist values don't match 0x%x != 0x%x, using 0x%x instead\n",
2042 ifb->ifb_name, bondport_get_name(p),
2043 ifp_offload, port_ifp_offload, offload);
2044 /*
2045 * XXX
2046 * if the bond has VLAN's, we can't simply change the hwassist
2047 * field behind its back: this needs work
2048 */
2049 ifnet_set_offload(ifp, offload);
2050 }
2051 }
2052 p->po_bond = ifb;
2053
2054 /* remember the port's ethernet address so it can be restored */
2055 ether_addr_copy(&p->po_saved_addr, IF_LLADDR(port_ifp));
2056
2057 /* add it to the list of ports */
2058 TAILQ_INSERT_TAIL(&ifb->ifb_port_list, p, po_port_list);
2059 ifb->ifb_port_count++;
2060
2061 /* set the default MTU */
2062 if (ifnet_mtu(ifp) == 0) {
2063 ifnet_set_mtu(ifp, ETHERMTU);
2064 }
2065 bond_unlock();
2066
2067
2068 /* first port added to bond determines bond's ethernet address */
2069 if (first) {
2070 ifnet_set_lladdr_and_type(ifp, IF_LLADDR(port_ifp), ETHER_ADDR_LEN,
2071 IFT_ETHER);
2072 }
2073
2074 progress |= BOND_ADD_PROGRESS_IN_LIST;
2075
2076 /* allocate a larger distributing array */
2077 new_array = (bondport_ref *)
2078 _MALLOC(sizeof(*new_array) * ifb->ifb_port_count, M_BOND, M_WAITOK);
2079 if (new_array == NULL) {
2080 error = ENOMEM;
2081 goto failed;
2082 }
2083
2084 /* attach our BOND "protocol" to the interface */
2085 error = bond_attach_protocol(port_ifp);
2086 if (error) {
2087 goto failed;
2088 }
2089 progress |= BOND_ADD_PROGRESS_PROTO_ATTACHED;
2090
2091 /* set the interface MTU */
2092 devmtu = bond_device_mtu(ifp, ifb);
2093 error = siocsifmtu(port_ifp, devmtu);
2094 if (error != 0) {
2095 printf("bond_add_interface(%s, %s):"
2096 " SIOCSIFMTU %d failed %d\n",
2097 ifb->ifb_name, bondport_get_name(p), devmtu, error);
2098 goto failed;
2099 }
2100 progress |= BOND_ADD_PROGRESS_MTU_SET;
2101
2102 /* program the port with our multicast addresses */
2103 error = multicast_list_program(&p->po_multicast, ifp, port_ifp);
2104 if (error) {
2105 printf("bond_add_interface(%s, %s):"
2106 " multicast_list_program failed %d\n",
2107 ifb->ifb_name, bondport_get_name(p), error);
2108 goto failed;
2109 }
2110
2111 /* mark the interface up */
2112 ifnet_set_flags(port_ifp, IFF_UP, IFF_UP);
2113
2114 error = ifnet_ioctl(port_ifp, 0, SIOCSIFFLAGS, NULL);
2115 if (error != 0) {
2116 printf("bond_add_interface(%s, %s): SIOCSIFFLAGS failed %d\n",
2117 ifb->ifb_name, bondport_get_name(p), error);
2118 goto failed;
2119 }
2120
2121 /* re-program the port's ethernet address */
2122 error = if_siflladdr(port_ifp,
2123 (const struct ether_addr *)IF_LLADDR(ifp));
2124 if (error != 0) {
2125 /* port doesn't support setting the link address */
2126 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2127 ifb->ifb_name, bondport_get_name(p), error);
2128 goto failed;
2129 }
2130 progress |= BOND_ADD_PROGRESS_LLADDR_SET;
2131
2132 bond_lock();
2133
2134 /* no failures past this point */
2135 p->po_enabled = 1;
2136
2137 /* copy the contents of the existing distributing array */
2138 if (ifb->ifb_distributing_count) {
2139 bcopy(ifb->ifb_distributing_array, new_array,
2140 sizeof(*new_array) * ifb->ifb_distributing_count);
2141 }
2142 old_array = ifb->ifb_distributing_array;
2143 ifb->ifb_distributing_array = new_array;
2144
2145 if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2146 bondport_start(p);
2147
2148 /* check if we need to generate a link status event */
2149 if (ifbond_selection(ifb)) {
2150 event_code = (ifb->ifb_active_lag == NULL)
2151 ? KEV_DL_LINK_OFF
2152 : KEV_DL_LINK_ON;
2153 ifb->ifb_last_link_event = event_code;
2154 }
2155 }
2156 else {
2157 /* are we adding the first distributing interface? */
2158 if (media_active(&p->po_media_info)) {
2159 if (ifb->ifb_distributing_count == 0) {
2160 ifb->ifb_last_link_event = event_code = KEV_DL_LINK_ON;
2161 }
2162 bondport_enable_distributing(p);
2163 }
2164 else {
2165 bondport_disable_distributing(p);
2166 }
2167 }
2168 /* clear the busy state, and wakeup anyone waiting */
2169 ifbond_signal(ifb, "bond_add_interface");
2170 bond_unlock();
2171 if (event_code != 0) {
2172 interface_link_event(ifp, event_code);
2173 }
2174 if (old_array != NULL) {
2175 FREE(old_array, M_BOND);
2176 }
2177 return 0;
2178
2179 failed:
2180 bond_assert_lock_not_held();
2181
2182 /* if this was the first port to be added, clear our address */
2183 if (first) {
2184 ifnet_set_lladdr_and_type(ifp, NULL, 0, IFT_IEEE8023ADLAG);
2185 }
2186
2187 if (new_array != NULL) {
2188 FREE(new_array, M_BOND);
2189 }
2190 if ((progress & BOND_ADD_PROGRESS_LLADDR_SET) != 0) {
2191 int error1;
2192
2193 error1 = if_siflladdr(port_ifp, &p->po_saved_addr);
2194 if (error1 != 0) {
2195 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2196 ifb->ifb_name, bondport_get_name(p), error1);
2197 }
2198 }
2199 if ((progress & BOND_ADD_PROGRESS_PROTO_ATTACHED) != 0) {
2200 (void)bond_detach_protocol(port_ifp);
2201 }
2202 if ((progress & BOND_ADD_PROGRESS_MTU_SET) != 0) {
2203 int error1;
2204
2205 error1 = siocsifmtu(port_ifp, p->po_devmtu.ifdm_current);
2206 if (error1 != 0) {
2207 printf("bond_add_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2208 ifb->ifb_name, bondport_get_name(p),
2209 p->po_devmtu.ifdm_current, error1);
2210 }
2211 }
2212 bond_lock();
2213 if ((progress & BOND_ADD_PROGRESS_IN_LIST) != 0) {
2214 TAILQ_REMOVE(&ifb->ifb_port_list, p, po_port_list);
2215 ifb->ifb_port_count--;
2216 }
2217 ifnet_set_eflags(ifp, 0, IFEF_BOND);
2218 if (TAILQ_EMPTY(&ifb->ifb_port_list)) {
2219 ifb->ifb_altmtu = 0;
2220 ifnet_set_mtu(ifp, 0);
2221 ifnet_set_offload(ifp, 0);
2222 }
2223
2224 signal_done:
2225 ifbond_signal(ifb, "bond_add_interface");
2226 bond_unlock();
2227 ifbond_release(ifb);
2228 bondport_free(p);
2229 return (error);
2230 }
2231
2232 static int
2233 bond_remove_interface(ifbond_ref ifb, struct ifnet * port_ifp)
2234 {
2235 int active_lag = 0;
2236 int error = 0;
2237 int event_code = 0;
2238 bondport_ref head_port;
2239 struct ifnet * ifp;
2240 int last = FALSE;
2241 int new_link_address = FALSE;
2242 bondport_ref p;
2243 lacp_actor_partner_state s;
2244 int was_distributing;
2245
2246 bond_assert_lock_held();
2247
2248 ifbond_retain(ifb);
2249 ifbond_wait(ifb, "bond_remove_interface");
2250
2251 p = ifbond_lookup_port(ifb, port_ifp);
2252 if (p == NULL) {
2253 error = ENXIO;
2254 /* it got removed by another thread */
2255 goto signal_done;
2256 }
2257
2258 /* de-select it and remove it from the lists */
2259 was_distributing = bondport_flags_distributing(p);
2260 bondport_disable_distributing(p);
2261 if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2262 bondport_set_selected(p, SelectedState_UNSELECTED);
2263 active_lag = bondport_remove_from_LAG(p);
2264 /* invalidate timers here while holding the bond_lock */
2265 bondport_invalidate_timers(p);
2266
2267 /* announce that we're Individual now */
2268 s = p->po_actor_state;
2269 s = lacp_actor_partner_state_set_individual(s);
2270 s = lacp_actor_partner_state_set_not_collecting(s);
2271 s = lacp_actor_partner_state_set_not_distributing(s);
2272 s = lacp_actor_partner_state_set_out_of_sync(s);
2273 p->po_actor_state = s;
2274 bondport_flags_set_ntt(p);
2275 }
2276
2277 TAILQ_REMOVE(&ifb->ifb_port_list, p, po_port_list);
2278 ifb->ifb_port_count--;
2279
2280 ifp = ifb->ifb_ifp;
2281 head_port = TAILQ_FIRST(&ifb->ifb_port_list);
2282 if (head_port == NULL) {
2283 ifnet_set_flags(ifp, 0, IFF_RUNNING);
2284 if (ifbond_flags_lladdr(ifb) == FALSE) {
2285 last = TRUE;
2286 }
2287 ifnet_set_offload(ifp, 0);
2288 ifnet_set_mtu(ifp, 0);
2289 ifb->ifb_altmtu = 0;
2290 } else if (ifbond_flags_lladdr(ifb) == FALSE
2291 && bcmp(&p->po_saved_addr, IF_LLADDR(ifp),
2292 ETHER_ADDR_LEN) == 0) {
2293 new_link_address = TRUE;
2294 }
2295 /* check if we need to generate a link status event */
2296 if (ifb->ifb_mode == IF_BOND_MODE_LACP ) {
2297 if (ifbond_selection(ifb) || active_lag) {
2298 event_code = (ifb->ifb_active_lag == NULL)
2299 ? KEV_DL_LINK_OFF
2300 : KEV_DL_LINK_ON;
2301 ifb->ifb_last_link_event = event_code;
2302 }
2303 bondport_transmit_machine(p, LAEventStart,
2304 TRANSMIT_MACHINE_TX_IMMEDIATE);
2305 }
2306 else {
2307 /* are we removing the last distributing interface? */
2308 if (was_distributing && ifb->ifb_distributing_count == 0) {
2309 ifb->ifb_last_link_event = event_code = KEV_DL_LINK_OFF;
2310 }
2311 }
2312
2313 bond_unlock();
2314
2315 if (last) {
2316 ifnet_set_lladdr_and_type(ifp, NULL, 0, IFT_IEEE8023ADLAG);
2317 }
2318 else if (new_link_address) {
2319 struct ifnet * scan_ifp;
2320 bondport_ref scan_port;
2321
2322 /* ifbond_wait() allows port list traversal without holding the lock */
2323
2324 /* this port gave the bond its ethernet address, switch to new one */
2325 ifnet_set_lladdr_and_type(ifp,
2326 &head_port->po_saved_addr, ETHER_ADDR_LEN,
2327 IFT_ETHER);
2328
2329 /* re-program each port with the new link address */
2330 TAILQ_FOREACH(scan_port, &ifb->ifb_port_list, po_port_list) {
2331 scan_ifp = scan_port->po_ifp;
2332
2333 error = if_siflladdr(scan_ifp,
2334 (const struct ether_addr *) IF_LLADDR(ifp));
2335 if (error != 0) {
2336 printf("bond_remove_interface(%s, %s): "
2337 "if_siflladdr (%s) failed %d\n",
2338 ifb->ifb_name, bondport_get_name(p),
2339 bondport_get_name(scan_port), error);
2340 }
2341 }
2342 }
2343
2344 /* restore the port's ethernet address */
2345 error = if_siflladdr(port_ifp, &p->po_saved_addr);
2346 if (error != 0) {
2347 printf("bond_remove_interface(%s, %s): if_siflladdr failed %d\n",
2348 ifb->ifb_name, bondport_get_name(p), error);
2349 }
2350
2351 /* restore the port's MTU */
2352 error = siocsifmtu(port_ifp, p->po_devmtu.ifdm_current);
2353 if (error != 0) {
2354 printf("bond_remove_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2355 ifb->ifb_name, bondport_get_name(p),
2356 p->po_devmtu.ifdm_current, error);
2357 }
2358
2359 /* remove the bond "protocol" */
2360 bond_detach_protocol(port_ifp);
2361
2362 /* generate link event */
2363 if (event_code != 0) {
2364 interface_link_event(ifp, event_code);
2365 }
2366
2367 bond_lock();
2368 bondport_free(p);
2369 ifnet_set_eflags(port_ifp, 0, IFEF_BOND);
2370 /* release this bondport's reference to the ifbond */
2371 ifbond_release(ifb);
2372
2373 signal_done:
2374 ifbond_signal(ifb, "bond_remove_interface");
2375 ifbond_release(ifb);
2376 return (error);
2377 }
2378
2379 static void
2380 bond_set_lacp_mode(ifbond_ref ifb)
2381 {
2382 bondport_ref p;
2383
2384 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2385 bondport_disable_distributing(p);
2386 bondport_start(p);
2387 }
2388 return;
2389 }
2390
2391 static void
2392 bond_set_static_mode(ifbond_ref ifb)
2393 {
2394 bondport_ref p;
2395 lacp_actor_partner_state s;
2396
2397 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2398 bondport_disable_distributing(p);
2399 bondport_set_selected(p, SelectedState_UNSELECTED);
2400 (void)bondport_remove_from_LAG(p);
2401 bondport_cancel_timers(p);
2402
2403 /* announce that we're Individual now */
2404 s = p->po_actor_state;
2405 s = lacp_actor_partner_state_set_individual(s);
2406 s = lacp_actor_partner_state_set_not_collecting(s);
2407 s = lacp_actor_partner_state_set_not_distributing(s);
2408 s = lacp_actor_partner_state_set_out_of_sync(s);
2409 p->po_actor_state = s;
2410 bondport_flags_set_ntt(p);
2411 bondport_transmit_machine(p, LAEventStart,
2412 TRANSMIT_MACHINE_TX_IMMEDIATE);
2413 /* clear state */
2414 p->po_actor_state = 0;
2415 bzero(&p->po_partner_state, sizeof(p->po_partner_state));
2416
2417 if (media_active(&p->po_media_info)) {
2418 bondport_enable_distributing(p);
2419 }
2420 else {
2421 bondport_disable_distributing(p);
2422 }
2423 }
2424 return;
2425 }
2426
2427 static int
2428 bond_set_mode(struct ifnet * ifp, int mode)
2429 {
2430 int error = 0;
2431 int event_code = 0;
2432 ifbond_ref ifb;
2433
2434 bond_lock();
2435 ifb = (ifbond_ref)ifnet_softc(ifp);
2436 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2437 bond_unlock();
2438 return ((ifb == NULL) ? EOPNOTSUPP : EBUSY);
2439 }
2440 if (ifb->ifb_mode == mode) {
2441 bond_unlock();
2442 return (0);
2443 }
2444
2445 ifbond_retain(ifb);
2446 ifbond_wait(ifb, "bond_set_mode");
2447
2448 /* verify (again) that the mode is actually different */
2449 if (ifb->ifb_mode == mode) {
2450 /* nothing to do */
2451 goto signal_done;
2452 }
2453
2454 ifb->ifb_mode = mode;
2455 if (mode == IF_BOND_MODE_LACP) {
2456 bond_set_lacp_mode(ifb);
2457
2458 /* check if we need to generate a link status event */
2459 if (ifbond_selection(ifb)) {
2460 event_code = (ifb->ifb_active_lag == NULL)
2461 ? KEV_DL_LINK_OFF
2462 : KEV_DL_LINK_ON;
2463 }
2464 } else {
2465 bond_set_static_mode(ifb);
2466 event_code = (ifb->ifb_distributing_count == 0)
2467 ? KEV_DL_LINK_OFF
2468 : KEV_DL_LINK_ON;
2469 }
2470 ifb->ifb_last_link_event = event_code;
2471
2472 signal_done:
2473 ifbond_signal(ifb, "bond_set_mode");
2474 bond_unlock();
2475 ifbond_release(ifb);
2476
2477 if (event_code != 0) {
2478 interface_link_event(ifp, event_code);
2479 }
2480 return (error);
2481 }
2482
2483 static int
2484 bond_get_status(ifbond_ref ifb, struct if_bond_req * ibr_p, user_addr_t datap)
2485 {
2486 int count;
2487 user_addr_t dst;
2488 int error = 0;
2489 struct if_bond_status_req * ibsr;
2490 struct if_bond_status ibs;
2491 bondport_ref port;
2492
2493 ibsr = &(ibr_p->ibr_ibru.ibru_status);
2494 if (ibsr->ibsr_version != IF_BOND_STATUS_REQ_VERSION) {
2495 return (EINVAL);
2496 }
2497 ibsr->ibsr_key = ifb->ifb_key;
2498 ibsr->ibsr_mode = ifb->ifb_mode;
2499 ibsr->ibsr_total = ifb->ifb_port_count;
2500 dst = proc_is64bit(current_proc())
2501 ? ibsr->ibsr_ibsru.ibsru_buffer64
2502 : CAST_USER_ADDR_T(ibsr->ibsr_ibsru.ibsru_buffer);
2503 if (dst == USER_ADDR_NULL) {
2504 /* just want to know how many there are */
2505 goto done;
2506 }
2507 if (ibsr->ibsr_count < 0) {
2508 return (EINVAL);
2509 }
2510 count = (ifb->ifb_port_count < ibsr->ibsr_count)
2511 ? ifb->ifb_port_count : ibsr->ibsr_count;
2512 TAILQ_FOREACH(port, &ifb->ifb_port_list, po_port_list) {
2513 struct if_bond_partner_state * ibps_p;
2514 partner_state_ref ps;
2515
2516 if (count == 0) {
2517 break;
2518 }
2519 bzero(&ibs, sizeof(ibs));
2520 strlcpy(ibs.ibs_if_name, port->po_name, sizeof(ibs.ibs_if_name));
2521 ibs.ibs_port_priority = port->po_priority;
2522 if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2523 ibs.ibs_state = port->po_actor_state;
2524 ibs.ibs_selected_state = port->po_selected;
2525 ps = &port->po_partner_state;
2526 ibps_p = &ibs.ibs_partner_state;
2527 ibps_p->ibps_system = ps->ps_lag_info.li_system;
2528 ibps_p->ibps_system_priority = ps->ps_lag_info.li_system_priority;
2529 ibps_p->ibps_key = ps->ps_lag_info.li_key;
2530 ibps_p->ibps_port = ps->ps_port;
2531 ibps_p->ibps_port_priority = ps->ps_port_priority;
2532 ibps_p->ibps_state = ps->ps_state;
2533 }
2534 else {
2535 /* fake the selected information */
2536 ibs.ibs_selected_state = bondport_flags_distributing(port)
2537 ? SelectedState_SELECTED : SelectedState_UNSELECTED;
2538 }
2539 error = copyout(&ibs, dst, sizeof(ibs));
2540 if (error != 0) {
2541 break;
2542 }
2543 dst += sizeof(ibs);
2544 count--;
2545 }
2546
2547 done:
2548 if (error == 0) {
2549 error = copyout(ibr_p, datap, sizeof(*ibr_p));
2550 }
2551 else {
2552 (void)copyout(ibr_p, datap, sizeof(*ibr_p));
2553 }
2554 return (error);
2555 }
2556
2557 static int
2558 bond_set_promisc(__unused struct ifnet *ifp)
2559 {
2560 int error = 0;
2561 return (error);
2562 }
2563
2564 static void
2565 bond_get_mtu_values(ifbond_ref ifb, int * ret_min, int * ret_max)
2566 {
2567 int mtu_min = 0;
2568 int mtu_max = 0;
2569 bondport_ref p;
2570
2571 if (TAILQ_FIRST(&ifb->ifb_port_list) != NULL) {
2572 mtu_min = IF_MINMTU;
2573 }
2574 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2575 struct ifdevmtu * devmtu_p = &p->po_devmtu;
2576
2577 if (devmtu_p->ifdm_min > mtu_min) {
2578 mtu_min = devmtu_p->ifdm_min;
2579 }
2580 if (mtu_max == 0 || devmtu_p->ifdm_max < mtu_max) {
2581 mtu_max = devmtu_p->ifdm_max;
2582 }
2583 }
2584 *ret_min = mtu_min;
2585 *ret_max = mtu_max;
2586 return;
2587 }
2588
2589 static int
2590 bond_set_mtu_on_ports(ifbond_ref ifb, int mtu)
2591 {
2592 int error = 0;
2593 bondport_ref p;
2594
2595 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2596 error = siocsifmtu(p->po_ifp, mtu);
2597 if (error != 0) {
2598 printf("if_bond(%s): SIOCSIFMTU %s failed, %d\n",
2599 ifb->ifb_name, bondport_get_name(p), error);
2600 break;
2601 }
2602 }
2603 return (error);
2604 }
2605
2606 static int
2607 bond_set_mtu(struct ifnet * ifp, int mtu, int isdevmtu)
2608 {
2609 int error = 0;
2610 ifbond_ref ifb;
2611 int mtu_min;
2612 int mtu_max;
2613 int new_max;
2614 int old_max;
2615
2616 bond_lock();
2617 ifb = (ifbond_ref)ifnet_softc(ifp);
2618 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2619 error = (ifb == NULL) ? EOPNOTSUPP : EBUSY;
2620 goto done;
2621 }
2622 ifbond_retain(ifb);
2623 ifbond_wait(ifb, "bond_set_mtu");
2624
2625 /* check again */
2626 if (ifnet_softc(ifp) == NULL || ifbond_flags_if_detaching(ifb)) {
2627 error = EBUSY;
2628 goto signal_done;
2629 }
2630 bond_get_mtu_values(ifb, &mtu_min, &mtu_max);
2631 if (mtu > mtu_max) {
2632 error = EINVAL;
2633 goto signal_done;
2634 }
2635 if (mtu < mtu_min && (isdevmtu == 0 || mtu != 0)) {
2636 /* allow SIOCSIFALTMTU to set the mtu to 0 */
2637 error = EINVAL;
2638 goto signal_done;
2639 }
2640 if (isdevmtu) {
2641 new_max = (mtu > (int)ifnet_mtu(ifp)) ? mtu : (int)ifnet_mtu(ifp);
2642 }
2643 else {
2644 new_max = (mtu > ifb->ifb_altmtu) ? mtu : ifb->ifb_altmtu;
2645 }
2646 old_max = ((int)ifnet_mtu(ifp) > ifb->ifb_altmtu)
2647 ? (int)ifnet_mtu(ifp) : ifb->ifb_altmtu;
2648 if (new_max != old_max) {
2649 /* we can safely walk the list of port without the lock held */
2650 bond_unlock();
2651 error = bond_set_mtu_on_ports(ifb, new_max);
2652 if (error != 0) {
2653 /* try our best to back out of it */
2654 (void)bond_set_mtu_on_ports(ifb, old_max);
2655 }
2656 bond_lock();
2657 }
2658 if (error == 0) {
2659 if (isdevmtu) {
2660 ifb->ifb_altmtu = mtu;
2661 }
2662 else {
2663 ifnet_set_mtu(ifp, mtu);
2664 }
2665 }
2666
2667 signal_done:
2668 ifbond_signal(ifb, "bond_set_mtu");
2669 ifbond_release(ifb);
2670
2671 done:
2672 bond_unlock();
2673 return (error);
2674 }
2675
2676 static int
2677 bond_ioctl(struct ifnet *ifp, u_long cmd, void * data)
2678 {
2679 int error = 0;
2680 struct if_bond_req ibr;
2681 struct ifaddr * ifa;
2682 ifbond_ref ifb;
2683 struct ifreq * ifr;
2684 struct ifmediareq *ifmr;
2685 struct ifnet * port_ifp = NULL;
2686 user_addr_t user_addr;
2687
2688 if (ifnet_type(ifp) != IFT_IEEE8023ADLAG) {
2689 return (EOPNOTSUPP);
2690 }
2691 ifr = (struct ifreq *)data;
2692 ifa = (struct ifaddr *)data;
2693
2694 switch (cmd) {
2695 case SIOCSIFADDR:
2696 ifnet_set_flags(ifp, IFF_UP, IFF_UP);
2697 break;
2698
2699 case SIOCGIFMEDIA32:
2700 case SIOCGIFMEDIA64:
2701 bond_lock();
2702 ifb = (ifbond_ref)ifnet_softc(ifp);
2703 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2704 bond_unlock();
2705 return (ifb == NULL ? EOPNOTSUPP : EBUSY);
2706 }
2707 ifmr = (struct ifmediareq *)data;
2708 ifmr->ifm_current = IFM_ETHER;
2709 ifmr->ifm_mask = 0;
2710 ifmr->ifm_status = IFM_AVALID;
2711 ifmr->ifm_active = IFM_ETHER;
2712 ifmr->ifm_count = 1;
2713 if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2714 if (ifb->ifb_active_lag != NULL) {
2715 ifmr->ifm_active = ifb->ifb_active_lag->lag_active_media;
2716 ifmr->ifm_status |= IFM_ACTIVE;
2717 }
2718 }
2719 else if (ifb->ifb_distributing_count > 0) {
2720 ifmr->ifm_active
2721 = ifb->ifb_distributing_array[0]->po_media_info.mi_active;
2722 ifmr->ifm_status |= IFM_ACTIVE;
2723 }
2724 bond_unlock();
2725 user_addr = (cmd == SIOCGIFMEDIA64) ?
2726 ((struct ifmediareq64 *)ifmr)->ifmu_ulist :
2727 CAST_USER_ADDR_T(((struct ifmediareq32 *)ifmr)->ifmu_ulist);
2728 if (user_addr != USER_ADDR_NULL) {
2729 error = copyout(&ifmr->ifm_current,
2730 user_addr,
2731 sizeof(int));
2732 }
2733 break;
2734
2735 case SIOCSIFMEDIA:
2736 /* XXX send the SIFMEDIA to all children? Or force autoselect? */
2737 error = EINVAL;
2738 break;
2739
2740 case SIOCGIFDEVMTU:
2741 bond_lock();
2742 ifb = (ifbond_ref)ifnet_softc(ifp);
2743 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2744 bond_unlock();
2745 error = (ifb == NULL) ? EOPNOTSUPP : EBUSY;
2746 break;
2747 }
2748 ifr->ifr_devmtu.ifdm_current = bond_device_mtu(ifp, ifb);
2749 bond_get_mtu_values(ifb, &ifr->ifr_devmtu.ifdm_min,
2750 &ifr->ifr_devmtu.ifdm_max);
2751 bond_unlock();
2752 break;
2753
2754 case SIOCGIFALTMTU:
2755 bond_lock();
2756 ifb = (ifbond_ref)ifnet_softc(ifp);
2757 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2758 bond_unlock();
2759 error = (ifb == NULL) ? EOPNOTSUPP : EBUSY;
2760 break;
2761 }
2762 ifr->ifr_mtu = ifb->ifb_altmtu;
2763 bond_unlock();
2764 break;
2765
2766 case SIOCSIFALTMTU:
2767 error = bond_set_mtu(ifp, ifr->ifr_mtu, 1);
2768 break;
2769
2770 case SIOCSIFMTU:
2771 error = bond_set_mtu(ifp, ifr->ifr_mtu, 0);
2772 break;
2773
2774 case SIOCSIFBOND:
2775 user_addr = proc_is64bit(current_proc())
2776 ? ifr->ifr_data64 : CAST_USER_ADDR_T(ifr->ifr_data);
2777 error = copyin(user_addr, &ibr, sizeof(ibr));
2778 if (error) {
2779 break;
2780 }
2781 switch (ibr.ibr_op) {
2782 case IF_BOND_OP_ADD_INTERFACE:
2783 case IF_BOND_OP_REMOVE_INTERFACE:
2784 port_ifp = ifunit(ibr.ibr_ibru.ibru_if_name);
2785 if (port_ifp == NULL) {
2786 error = ENXIO;
2787 break;
2788 }
2789 if (ifnet_type(port_ifp) != IFT_ETHER) {
2790 error = EPROTONOSUPPORT;
2791 break;
2792 }
2793 break;
2794 case IF_BOND_OP_SET_VERBOSE:
2795 case IF_BOND_OP_SET_MODE:
2796 break;
2797 default:
2798 error = EOPNOTSUPP;
2799 break;
2800 }
2801 if (error != 0) {
2802 break;
2803 }
2804 switch (ibr.ibr_op) {
2805 case IF_BOND_OP_ADD_INTERFACE:
2806 error = bond_add_interface(ifp, port_ifp);
2807 break;
2808 case IF_BOND_OP_REMOVE_INTERFACE:
2809 bond_lock();
2810 ifb = (ifbond_ref)ifnet_softc(ifp);
2811 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2812 bond_unlock();
2813 return (ifb == NULL ? EOPNOTSUPP : EBUSY);
2814 }
2815 error = bond_remove_interface(ifb, port_ifp);
2816 bond_unlock();
2817 break;
2818 case IF_BOND_OP_SET_VERBOSE:
2819 bond_lock();
2820 if (g_bond == NULL) {
2821 bond_unlock();
2822 error = ENXIO;
2823 break;
2824 }
2825 g_bond->verbose = ibr.ibr_ibru.ibru_int_val;
2826 bond_unlock();
2827 break;
2828 case IF_BOND_OP_SET_MODE:
2829 switch (ibr.ibr_ibru.ibru_int_val) {
2830 case IF_BOND_MODE_LACP:
2831 case IF_BOND_MODE_STATIC:
2832 break;
2833 default:
2834 error = EINVAL;
2835 break;
2836 }
2837 if (error != 0) {
2838 break;
2839 }
2840 error = bond_set_mode(ifp, ibr.ibr_ibru.ibru_int_val);
2841 break;
2842 }
2843 break; /* SIOCSIFBOND */
2844
2845 case SIOCGIFBOND:
2846 user_addr = proc_is64bit(current_proc())
2847 ? ifr->ifr_data64 : CAST_USER_ADDR_T(ifr->ifr_data);
2848 error = copyin(user_addr, &ibr, sizeof(ibr));
2849 if (error) {
2850 break;
2851 }
2852 switch (ibr.ibr_op) {
2853 case IF_BOND_OP_GET_STATUS:
2854 break;
2855 default:
2856 error = EOPNOTSUPP;
2857 break;
2858 }
2859 if (error != 0) {
2860 break;
2861 }
2862 bond_lock();
2863 ifb = (ifbond_ref)ifnet_softc(ifp);
2864 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2865 bond_unlock();
2866 return (ifb == NULL ? EOPNOTSUPP : EBUSY);
2867 }
2868 switch (ibr.ibr_op) {
2869 case IF_BOND_OP_GET_STATUS:
2870 error = bond_get_status(ifb, &ibr, user_addr);
2871 break;
2872 }
2873 bond_unlock();
2874 break; /* SIOCGIFBOND */
2875
2876 case SIOCSIFLLADDR:
2877 error = EOPNOTSUPP;
2878 break;
2879
2880 case SIOCSIFFLAGS:
2881 /* enable/disable promiscuous mode */
2882 bond_lock();
2883 error = bond_set_promisc(ifp);
2884 bond_unlock();
2885 break;
2886
2887 case SIOCADDMULTI:
2888 case SIOCDELMULTI:
2889 error = bond_setmulti(ifp);
2890 break;
2891 default:
2892 error = EOPNOTSUPP;
2893 }
2894 return error;
2895 }
2896
2897 static void
2898 bond_if_free(struct ifnet * ifp)
2899 {
2900 ifbond_ref ifb;
2901
2902 if (ifp == NULL) {
2903 return;
2904 }
2905 bond_lock();
2906 ifb = (ifbond_ref)ifnet_softc(ifp);
2907 if (ifb == NULL) {
2908 bond_unlock();
2909 return;
2910 }
2911 ifbond_release(ifb);
2912 bond_unlock();
2913 ifnet_release(ifp);
2914 return;
2915 }
2916
2917 static void
2918 bond_handle_event(struct ifnet * port_ifp, int event_code)
2919 {
2920 struct ifnet * bond_ifp = NULL;
2921 ifbond_ref ifb;
2922 int old_distributing_count;
2923 bondport_ref p;
2924 struct media_info media_info = { 0, 0};
2925
2926 switch (event_code) {
2927 case KEV_DL_IF_DETACHED:
2928 break;
2929 case KEV_DL_LINK_OFF:
2930 case KEV_DL_LINK_ON:
2931 media_info = interface_media_info(port_ifp);
2932 break;
2933 default:
2934 return;
2935 }
2936 bond_lock();
2937 p = bond_lookup_port(port_ifp);
2938 if (p == NULL) {
2939 bond_unlock();
2940 return;
2941 }
2942 ifb = p->po_bond;
2943 old_distributing_count = ifb->ifb_distributing_count;
2944 switch (event_code) {
2945 case KEV_DL_IF_DETACHED:
2946 bond_remove_interface(ifb, p->po_ifp);
2947 break;
2948 case KEV_DL_LINK_OFF:
2949 case KEV_DL_LINK_ON:
2950 p->po_media_info = media_info;
2951 if (p->po_enabled) {
2952 bondport_link_status_changed(p);
2953 }
2954 break;
2955 }
2956 /* generate a link-event */
2957 if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2958 if (ifbond_selection(ifb)) {
2959 event_code = (ifb->ifb_active_lag == NULL)
2960 ? KEV_DL_LINK_OFF
2961 : KEV_DL_LINK_ON;
2962 /* XXX need to take a reference on bond_ifp */
2963 bond_ifp = ifb->ifb_ifp;
2964 ifb->ifb_last_link_event = event_code;
2965 }
2966 else {
2967 event_code = (ifb->ifb_active_lag == NULL)
2968 ? KEV_DL_LINK_OFF
2969 : KEV_DL_LINK_ON;
2970 if (event_code != ifb->ifb_last_link_event) {
2971 if (g_bond->verbose) {
2972 timestamp_printf("%s: (event) generating LINK event\n",
2973 ifb->ifb_name);
2974 }
2975 bond_ifp = ifb->ifb_ifp;
2976 ifb->ifb_last_link_event = event_code;
2977 }
2978 }
2979 }
2980 else {
2981 /*
2982 * if the distributing array membership changed from 0 <-> !0
2983 * generate a link event
2984 */
2985 if (old_distributing_count == 0
2986 && ifb->ifb_distributing_count != 0) {
2987 event_code = KEV_DL_LINK_ON;
2988 }
2989 else if (old_distributing_count != 0
2990 && ifb->ifb_distributing_count == 0) {
2991 event_code = KEV_DL_LINK_OFF;
2992 }
2993 if (event_code != 0 && event_code != ifb->ifb_last_link_event) {
2994 bond_ifp = ifb->ifb_ifp;
2995 ifb->ifb_last_link_event = event_code;
2996 }
2997 }
2998
2999 bond_unlock();
3000 if (bond_ifp != NULL) {
3001 interface_link_event(bond_ifp, event_code);
3002 }
3003 return;
3004 }
3005
3006 static void
3007 bond_event(struct ifnet * port_ifp, __unused protocol_family_t protocol,
3008 const struct kev_msg * event)
3009 {
3010 int event_code;
3011
3012 if (event->vendor_code != KEV_VENDOR_APPLE
3013 || event->kev_class != KEV_NETWORK_CLASS
3014 || event->kev_subclass != KEV_DL_SUBCLASS) {
3015 return;
3016 }
3017 event_code = event->event_code;
3018 switch (event_code) {
3019 case KEV_DL_LINK_OFF:
3020 case KEV_DL_LINK_ON:
3021 /* we only care about link status changes */
3022 bond_handle_event(port_ifp, event_code);
3023 break;
3024 default:
3025 break;
3026 }
3027 return;
3028 }
3029
3030 static errno_t
3031 bond_detached(ifnet_t port_ifp, __unused protocol_family_t protocol)
3032 {
3033 bond_handle_event(port_ifp, KEV_DL_IF_DETACHED);
3034 return (0);
3035 }
3036
3037 static void
3038 interface_link_event(struct ifnet * ifp, u_int32_t event_code)
3039 {
3040 struct {
3041 struct kern_event_msg header;
3042 u_int32_t unit;
3043 char if_name[IFNAMSIZ];
3044 } event;
3045
3046 bzero(&event, sizeof(event));
3047 event.header.total_size = sizeof(event);
3048 event.header.vendor_code = KEV_VENDOR_APPLE;
3049 event.header.kev_class = KEV_NETWORK_CLASS;
3050 event.header.kev_subclass = KEV_DL_SUBCLASS;
3051 event.header.event_code = event_code;
3052 event.header.event_data[0] = ifnet_family(ifp);
3053 event.unit = (u_int32_t) ifnet_unit(ifp);
3054 strlcpy(event.if_name, ifnet_name(ifp), IFNAMSIZ);
3055 ifnet_event(ifp, &event.header);
3056 return;
3057 }
3058
3059 /*
3060 * Function: bond_attach_protocol
3061 * Purpose:
3062 * Attach a DLIL protocol to the interface.
3063 *
3064 * The ethernet demux special cases to always return PF_BOND if the
3065 * interface is bonded. That means we receive all traffic from that
3066 * interface without passing any of the traffic to any other attached
3067 * protocol.
3068 */
3069 static int
3070 bond_attach_protocol(struct ifnet *ifp)
3071 {
3072 int error;
3073 struct ifnet_attach_proto_param reg;
3074
3075 bzero(&reg, sizeof(reg));
3076 reg.input = bond_input;
3077 reg.event = bond_event;
3078 reg.detached = bond_detached;
3079
3080 error = ifnet_attach_protocol(ifp, PF_BOND, &reg);
3081 if (error) {
3082 printf("bond over %s%d: ifnet_attach_protocol failed, %d\n",
3083 ifnet_name(ifp), ifnet_unit(ifp), error);
3084 }
3085 return (error);
3086 }
3087
3088 /*
3089 * Function: bond_detach_protocol
3090 * Purpose:
3091 * Detach our DLIL protocol from an interface
3092 */
3093 static int
3094 bond_detach_protocol(struct ifnet *ifp)
3095 {
3096 int error;
3097
3098 error = ifnet_detach_protocol(ifp, PF_BOND);
3099 if (error) {
3100 printf("bond over %s%d: ifnet_detach_protocol failed, %d\n",
3101 ifnet_name(ifp), ifnet_unit(ifp), error);
3102 }
3103 return (error);
3104 }
3105
3106 /*
3107 * DLIL interface family functions
3108 */
3109 extern int ether_attach_inet(ifnet_t ifp, protocol_family_t protocol_family);
3110 extern void ether_detach_inet(ifnet_t ifp, protocol_family_t protocol_family);
3111 extern int ether_attach_inet6(ifnet_t ifp, protocol_family_t protocol_family);
3112 extern void ether_detach_inet6(ifnet_t ifp, protocol_family_t protocol_family);
3113 extern int ether_attach_at(ifnet_t ifp, protocol_family_t protocol_family);
3114 extern void ether_detach_at(ifnet_t ifp, protocol_family_t protocol_family);
3115
3116 __private_extern__ int
3117 bond_family_init(void)
3118 {
3119 int error=0;
3120
3121 error = proto_register_plumber(PF_INET, APPLE_IF_FAM_BOND,
3122 ether_attach_inet,
3123 ether_detach_inet);
3124 if (error != 0) {
3125 printf("bond: proto_register_plumber failed for AF_INET error=%d\n",
3126 error);
3127 goto done;
3128 }
3129 #if INET6
3130 error = proto_register_plumber(PF_INET6, APPLE_IF_FAM_BOND,
3131 ether_attach_inet6,
3132 ether_detach_inet6);
3133 if (error != 0) {
3134 printf("bond: proto_register_plumber failed for AF_INET6 error=%d\n",
3135 error);
3136 goto done;
3137 }
3138 #endif
3139 error = bond_clone_attach();
3140 if (error != 0) {
3141 printf("bond: proto_register_plumber failed bond_clone_attach error=%d\n",
3142 error);
3143 goto done;
3144 }
3145
3146 done:
3147 return (error);
3148 }
3149 /**
3150 **
3151 ** LACP routines:
3152 **
3153 **/
3154
3155 /**
3156 ** LACP ifbond_list routines
3157 **/
3158 static bondport_ref
3159 ifbond_list_find_moved_port(bondport_ref rx_port,
3160 const lacp_actor_partner_tlv_ref atlv)
3161 {
3162 ifbond_ref bond;
3163 bondport_ref p;
3164 partner_state_ref ps;
3165 LAG_info_ref ps_li;
3166
3167 TAILQ_FOREACH(bond, &g_bond->ifbond_list, ifb_bond_list) {
3168 TAILQ_FOREACH(p, &bond->ifb_port_list, po_port_list) {
3169
3170 if (rx_port == p) {
3171 /* no point in comparing against ourselves */
3172 continue;
3173 }
3174 if (p->po_receive_state != ReceiveState_PORT_DISABLED) {
3175 /* it's not clear that we should be checking this */
3176 continue;
3177 }
3178 ps = &p->po_partner_state;
3179 if (lacp_actor_partner_state_defaulted(ps->ps_state)) {
3180 continue;
3181 }
3182 ps_li = &ps->ps_lag_info;
3183 if (ps->ps_port == lacp_actor_partner_tlv_get_port(atlv)
3184 && bcmp(&ps_li->li_system, atlv->lap_system,
3185 sizeof(ps_li->li_system)) == 0) {
3186 if (g_bond->verbose) {
3187 timestamp_printf("System " EA_FORMAT
3188 " Port 0x%x moved from %s to %s\n",
3189 EA_LIST(&ps_li->li_system), ps->ps_port,
3190 bondport_get_name(p),
3191 bondport_get_name(rx_port));
3192 }
3193 return (p);
3194 }
3195 }
3196 }
3197 return (NULL);
3198 }
3199
3200 /**
3201 ** LACP ifbond, LAG routines
3202 **/
3203
3204 static int
3205 ifbond_selection(ifbond_ref bond)
3206 {
3207 int all_ports_ready = 0;
3208 int active_media = 0;
3209 LAG_ref lag = NULL;
3210 int lag_changed = 0;
3211 bondport_ref p;
3212 int port_speed = 0;
3213
3214 lag = ifbond_find_best_LAG(bond, &active_media);
3215 if (lag != bond->ifb_active_lag) {
3216 if (bond->ifb_active_lag != NULL) {
3217 ifbond_deactivate_LAG(bond, bond->ifb_active_lag);
3218 bond->ifb_active_lag = NULL;
3219 }
3220 bond->ifb_active_lag = lag;
3221 if (lag != NULL) {
3222 ifbond_activate_LAG(bond, lag, active_media);
3223 }
3224 lag_changed = 1;
3225 }
3226 else if (lag != NULL) {
3227 if (lag->lag_active_media != active_media) {
3228 if (g_bond->verbose) {
3229 timestamp_printf("LAG PORT SPEED CHANGED from %d to %d\n",
3230 link_speed(lag->lag_active_media),
3231 link_speed(active_media));
3232 }
3233 ifbond_deactivate_LAG(bond, lag);
3234 ifbond_activate_LAG(bond, lag, active_media);
3235 lag_changed = 1;
3236 }
3237 }
3238 if (lag != NULL) {
3239 port_speed = link_speed(active_media);
3240 all_ports_ready = ifbond_all_ports_ready(bond);
3241 }
3242 TAILQ_FOREACH(p, &bond->ifb_port_list, po_port_list) {
3243 if (lag != NULL && p->po_lag == lag
3244 && media_speed(&p->po_media_info) == port_speed
3245 && (p->po_mux_state == MuxState_DETACHED
3246 || p->po_selected == SelectedState_SELECTED
3247 || p->po_selected == SelectedState_STANDBY)
3248 && bondport_aggregatable(p)) {
3249 if (bond->ifb_max_active > 0) {
3250 if (lag->lag_selected_port_count < bond->ifb_max_active) {
3251 if (p->po_selected == SelectedState_STANDBY
3252 || p->po_selected == SelectedState_UNSELECTED) {
3253 bondport_set_selected(p, SelectedState_SELECTED);
3254 }
3255 }
3256 else if (p->po_selected == SelectedState_UNSELECTED) {
3257 bondport_set_selected(p, SelectedState_STANDBY);
3258 }
3259 }
3260 else {
3261 bondport_set_selected(p, SelectedState_SELECTED);
3262 }
3263 }
3264 if (bondport_flags_selected_changed(p)) {
3265 bondport_flags_clear_selected_changed(p);
3266 bondport_mux_machine(p, LAEventSelectedChange, NULL);
3267 }
3268 if (all_ports_ready
3269 && bondport_flags_ready(p)
3270 && p->po_mux_state == MuxState_WAITING) {
3271 bondport_mux_machine(p, LAEventReady, NULL);
3272 }
3273 bondport_transmit_machine(p, LAEventStart, NULL);
3274 }
3275 return (lag_changed);
3276 }
3277
3278 static LAG_ref
3279 ifbond_find_best_LAG(ifbond_ref bond, int * active_media)
3280 {
3281 int best_active = 0;
3282 LAG_ref best_lag = NULL;
3283 int best_count = 0;
3284 int best_speed = 0;
3285 LAG_ref lag;
3286
3287 if (bond->ifb_active_lag != NULL) {
3288 best_lag = bond->ifb_active_lag;
3289 best_count = LAG_get_aggregatable_port_count(best_lag, &best_active);
3290 if (bond->ifb_max_active > 0
3291 && best_count > bond->ifb_max_active) {
3292 best_count = bond->ifb_max_active;
3293 }
3294 best_speed = link_speed(best_active);
3295 }
3296 TAILQ_FOREACH(lag, &bond->ifb_lag_list, lag_list) {
3297 int active;
3298 int count;
3299 int speed;
3300
3301 if (lag == bond->ifb_active_lag) {
3302 /* we've already computed it */
3303 continue;
3304 }
3305 count = LAG_get_aggregatable_port_count(lag, &active);
3306 if (count == 0) {
3307 continue;
3308 }
3309 if (bond->ifb_max_active > 0
3310 && count > bond->ifb_max_active) {
3311 /* if there's a limit, don't count extra links */
3312 count = bond->ifb_max_active;
3313 }
3314 speed = link_speed(active);
3315 if ((count * speed) > (best_count * best_speed)) {
3316 best_count = count;
3317 best_speed = speed;
3318 best_active = active;
3319 best_lag = lag;
3320 }
3321 }
3322 if (best_count == 0) {
3323 return (NULL);
3324 }
3325 *active_media = best_active;
3326 return (best_lag);
3327 }
3328
3329 static void
3330 ifbond_deactivate_LAG(__unused ifbond_ref bond, LAG_ref lag)
3331 {
3332 bondport_ref p;
3333
3334 TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3335 bondport_set_selected(p, SelectedState_UNSELECTED);
3336 }
3337 return;
3338 }
3339
3340 static void
3341 ifbond_activate_LAG(ifbond_ref bond, LAG_ref lag, int active_media)
3342 {
3343 int need = 0;
3344 bondport_ref p;
3345
3346 if (bond->ifb_max_active > 0) {
3347 need = bond->ifb_max_active;
3348 }
3349 lag->lag_active_media = active_media;
3350 TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3351 if (bondport_aggregatable(p) == 0) {
3352 bondport_set_selected(p, SelectedState_UNSELECTED);
3353 }
3354 else if (media_speed(&p->po_media_info) != link_speed(active_media)) {
3355 bondport_set_selected(p, SelectedState_UNSELECTED);
3356 }
3357 else if (p->po_mux_state == MuxState_DETACHED) {
3358 if (bond->ifb_max_active > 0) {
3359 if (need > 0) {
3360 bondport_set_selected(p, SelectedState_SELECTED);
3361 need--;
3362 }
3363 else {
3364 bondport_set_selected(p, SelectedState_STANDBY);
3365 }
3366 }
3367 else {
3368 bondport_set_selected(p, SelectedState_SELECTED);
3369 }
3370 }
3371 else {
3372 bondport_set_selected(p, SelectedState_UNSELECTED);
3373 }
3374 }
3375 return;
3376 }
3377
3378 #if 0
3379 static void
3380 ifbond_set_max_active(ifbond_ref bond, int max_active)
3381 {
3382 LAG_ref lag = bond->ifb_active_lag;
3383
3384 bond->ifb_max_active = max_active;
3385 if (bond->ifb_max_active <= 0 || lag == NULL) {
3386 return;
3387 }
3388 if (lag->lag_selected_port_count > bond->ifb_max_active) {
3389 bondport_ref p;
3390 int remove_count;
3391
3392 remove_count = lag->lag_selected_port_count - bond->ifb_max_active;
3393 TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3394 if (p->po_selected == SelectedState_SELECTED) {
3395 bondport_set_selected(p, SelectedState_UNSELECTED);
3396 remove_count--;
3397 if (remove_count == 0) {
3398 break;
3399 }
3400 }
3401 }
3402 }
3403 return;
3404 }
3405 #endif
3406
3407 static int
3408 ifbond_all_ports_ready(ifbond_ref bond)
3409 {
3410 int ready = 0;
3411 bondport_ref p;
3412
3413 if (bond->ifb_active_lag == NULL) {
3414 return (0);
3415 }
3416 TAILQ_FOREACH(p, &bond->ifb_active_lag->lag_port_list, po_lag_port_list) {
3417 if (p->po_mux_state == MuxState_WAITING
3418 && p->po_selected == SelectedState_SELECTED) {
3419 if (bondport_flags_ready(p) == 0) {
3420 return (0);
3421 }
3422 }
3423 /* note that there was at least one ready port */
3424 ready = 1;
3425 }
3426 return (ready);
3427 }
3428
3429 static int
3430 ifbond_all_ports_attached(ifbond_ref bond, bondport_ref this_port)
3431 {
3432 bondport_ref p;
3433
3434 TAILQ_FOREACH(p, &bond->ifb_port_list, po_port_list) {
3435 if (this_port == p) {
3436 continue;
3437 }
3438 if (bondport_flags_mux_attached(p) == 0) {
3439 return (0);
3440 }
3441 }
3442 return (1);
3443 }
3444
3445 static LAG_ref
3446 ifbond_get_LAG_matching_port(ifbond_ref bond, bondport_ref p)
3447 {
3448 LAG_ref lag;
3449
3450 TAILQ_FOREACH(lag, &bond->ifb_lag_list, lag_list) {
3451 if (bcmp(&lag->lag_info, &p->po_partner_state.ps_lag_info,
3452 sizeof(lag->lag_info)) == 0) {
3453 return (lag);
3454 }
3455 }
3456 return (NULL);
3457 }
3458
3459 static int
3460 LAG_get_aggregatable_port_count(LAG_ref lag, int * active_media)
3461 {
3462 int active;
3463 int count;
3464 bondport_ref p;
3465 int speed;
3466
3467 active = 0;
3468 count = 0;
3469 speed = 0;
3470 TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3471 if (bondport_aggregatable(p)) {
3472 int this_speed;
3473
3474 this_speed = media_speed(&p->po_media_info);
3475 if (this_speed == 0) {
3476 continue;
3477 }
3478 if (this_speed > speed) {
3479 active = p->po_media_info.mi_active;
3480 speed = this_speed;
3481 count = 1;
3482 }
3483 else if (this_speed == speed) {
3484 count++;
3485 }
3486 }
3487 }
3488 *active_media = active;
3489 return (count);
3490 }
3491
3492
3493 /**
3494 ** LACP bondport routines
3495 **/
3496 static void
3497 bondport_link_status_changed(bondport_ref p)
3498 {
3499 ifbond_ref bond = p->po_bond;
3500
3501 if (g_bond->verbose) {
3502 if (media_active(&p->po_media_info)) {
3503 timestamp_printf("[%s] Link UP %d Mbit/s %s duplex\n",
3504 bondport_get_name(p),
3505 media_speed(&p->po_media_info),
3506 media_full_duplex(&p->po_media_info)
3507 ? "full" : "half");
3508 }
3509 else {
3510 timestamp_printf("[%s] Link DOWN\n", bondport_get_name(p));
3511 }
3512 }
3513 if (bond->ifb_mode == IF_BOND_MODE_LACP) {
3514 if (media_active(&p->po_media_info)
3515 && bond->ifb_active_lag != NULL
3516 && p->po_lag == bond->ifb_active_lag
3517 && p->po_selected != SelectedState_UNSELECTED) {
3518 if (media_speed(&p->po_media_info) != p->po_lag->lag_active_media) {
3519 if (g_bond->verbose) {
3520 timestamp_printf("[%s] Port speed %d differs from LAG %d\n",
3521 bondport_get_name(p),
3522 media_speed(&p->po_media_info),
3523 link_speed(p->po_lag->lag_active_media));
3524 }
3525 bondport_set_selected(p, SelectedState_UNSELECTED);
3526 }
3527 }
3528 bondport_receive_machine(p, LAEventMediaChange, NULL);
3529 bondport_mux_machine(p, LAEventMediaChange, NULL);
3530 bondport_periodic_transmit_machine(p, LAEventMediaChange, NULL);
3531 }
3532 else {
3533 if (media_active(&p->po_media_info)) {
3534 bondport_enable_distributing(p);
3535 }
3536 else {
3537 bondport_disable_distributing(p);
3538 }
3539 }
3540 return;
3541 }
3542
3543 static int
3544 bondport_aggregatable(bondport_ref p)
3545 {
3546 partner_state_ref ps = &p->po_partner_state;
3547
3548 if (lacp_actor_partner_state_aggregatable(p->po_actor_state) == 0
3549 || lacp_actor_partner_state_aggregatable(ps->ps_state) == 0) {
3550 /* we and/or our partner are individual */
3551 return (0);
3552 }
3553 if (p->po_lag == NULL) {
3554 return (0);
3555 }
3556 switch (p->po_receive_state) {
3557 default:
3558 if (g_bond->verbose) {
3559 timestamp_printf("[%s] Port is not selectable\n",
3560 bondport_get_name(p));
3561 }
3562 return (0);
3563 case ReceiveState_CURRENT:
3564 case ReceiveState_EXPIRED:
3565 break;
3566 }
3567 return (1);
3568 }
3569
3570 static int
3571 bondport_matches_LAG(bondport_ref p, LAG_ref lag)
3572 {
3573 LAG_info_ref lag_li;
3574 partner_state_ref ps;
3575 LAG_info_ref ps_li;
3576
3577 ps = &p->po_partner_state;
3578 ps_li = &ps->ps_lag_info;
3579 lag_li = &lag->lag_info;
3580 if (ps_li->li_system_priority == lag_li->li_system_priority
3581 && ps_li->li_key == lag_li->li_key
3582 && (bcmp(&ps_li->li_system, &lag_li->li_system,
3583 sizeof(lag_li->li_system))
3584 == 0)) {
3585 return (1);
3586 }
3587 return (0);
3588 }
3589
3590 static int
3591 bondport_remove_from_LAG(bondport_ref p)
3592 {
3593 int active_lag = 0;
3594 ifbond_ref bond = p->po_bond;
3595 LAG_ref lag = p->po_lag;
3596
3597 if (lag == NULL) {
3598 return (0);
3599 }
3600 TAILQ_REMOVE(&lag->lag_port_list, p, po_lag_port_list);
3601 if (g_bond->verbose) {
3602 timestamp_printf("[%s] Removed from LAG (0x%04x," EA_FORMAT
3603 ",0x%04x)\n",
3604 bondport_get_name(p),
3605 lag->lag_info.li_system_priority,
3606 EA_LIST(&lag->lag_info.li_system),
3607 lag->lag_info.li_key);
3608 }
3609 p->po_lag = NULL;
3610 lag->lag_port_count--;
3611 if (lag->lag_port_count > 0) {
3612 return (bond->ifb_active_lag == lag);
3613 }
3614 if (g_bond->verbose) {
3615 timestamp_printf("Key 0x%04x: LAG Released (%04x," EA_FORMAT
3616 ",0x%04x)\n",
3617 bond->ifb_key,
3618 lag->lag_info.li_system_priority,
3619 EA_LIST(&lag->lag_info.li_system),
3620 lag->lag_info.li_key);
3621 }
3622 TAILQ_REMOVE(&bond->ifb_lag_list, lag, lag_list);
3623 if (bond->ifb_active_lag == lag) {
3624 bond->ifb_active_lag = NULL;
3625 active_lag = 1;
3626 }
3627 FREE(lag, M_BOND);
3628 return (active_lag);
3629 }
3630
3631 static void
3632 bondport_add_to_LAG(bondport_ref p, LAG_ref lag)
3633 {
3634 TAILQ_INSERT_TAIL(&lag->lag_port_list, p, po_lag_port_list);
3635 p->po_lag = lag;
3636 lag->lag_port_count++;
3637 if (g_bond->verbose) {
3638 timestamp_printf("[%s] Added to LAG (0x%04x," EA_FORMAT "0x%04x)\n",
3639 bondport_get_name(p),
3640 lag->lag_info.li_system_priority,
3641 EA_LIST(&lag->lag_info.li_system),
3642 lag->lag_info.li_key);
3643 }
3644 return;
3645 }
3646
3647 static void
3648 bondport_assign_to_LAG(bondport_ref p)
3649 {
3650 ifbond_ref bond = p->po_bond;
3651 LAG_ref lag;
3652
3653 if (lacp_actor_partner_state_defaulted(p->po_actor_state)) {
3654 bondport_remove_from_LAG(p);
3655 return;
3656 }
3657 lag = p->po_lag;
3658 if (lag != NULL) {
3659 if (bondport_matches_LAG(p, lag)) {
3660 /* still OK */
3661 return;
3662 }
3663 bondport_remove_from_LAG(p);
3664 }
3665 lag = ifbond_get_LAG_matching_port(bond, p);
3666 if (lag != NULL) {
3667 bondport_add_to_LAG(p, lag);
3668 return;
3669 }
3670 lag = (LAG_ref)_MALLOC(sizeof(*lag), M_BOND, M_WAITOK);
3671 TAILQ_INIT(&lag->lag_port_list);
3672 lag->lag_port_count = 0;
3673 lag->lag_selected_port_count = 0;
3674 lag->lag_info = p->po_partner_state.ps_lag_info;
3675 TAILQ_INSERT_TAIL(&bond->ifb_lag_list, lag, lag_list);
3676 if (g_bond->verbose) {
3677 timestamp_printf("Key 0x%04x: LAG Created (0x%04x," EA_FORMAT
3678 ",0x%04x)\n",
3679 bond->ifb_key,
3680 lag->lag_info.li_system_priority,
3681 EA_LIST(&lag->lag_info.li_system),
3682 lag->lag_info.li_key);
3683 }
3684 bondport_add_to_LAG(p, lag);
3685 return;
3686 }
3687
3688 static void
3689 bondport_receive_lacpdu(bondport_ref p, lacpdu_ref in_lacpdu_p)
3690 {
3691 bondport_ref moved_port;
3692
3693 moved_port
3694 = ifbond_list_find_moved_port(p, (const lacp_actor_partner_tlv_ref)
3695 &in_lacpdu_p->la_actor_tlv);
3696 if (moved_port != NULL) {
3697 bondport_receive_machine(moved_port, LAEventPortMoved, NULL);
3698 }
3699 bondport_receive_machine(p, LAEventPacket, in_lacpdu_p);
3700 bondport_mux_machine(p, LAEventPacket, in_lacpdu_p);
3701 bondport_periodic_transmit_machine(p, LAEventPacket, in_lacpdu_p);
3702 return;
3703 }
3704
3705 static void
3706 bondport_set_selected(bondport_ref p, SelectedState s)
3707 {
3708 if (s != p->po_selected) {
3709 ifbond_ref bond = p->po_bond;
3710 LAG_ref lag = p->po_lag;
3711
3712 bondport_flags_set_selected_changed(p);
3713 if (lag != NULL && bond->ifb_active_lag == lag) {
3714 if (p->po_selected == SelectedState_SELECTED) {
3715 lag->lag_selected_port_count--;
3716 }
3717 else if (s == SelectedState_SELECTED) {
3718 lag->lag_selected_port_count++;
3719 }
3720 if (g_bond->verbose) {
3721 timestamp_printf("[%s] SetSelected: %s (was %s)\n",
3722 bondport_get_name(p),
3723 SelectedStateString(s),
3724 SelectedStateString(p->po_selected));
3725 }
3726 }
3727 }
3728 p->po_selected = s;
3729 return;
3730 }
3731
3732 /**
3733 ** Receive machine
3734 **/
3735
3736 static void
3737 bondport_UpdateDefaultSelected(bondport_ref p)
3738 {
3739 bondport_set_selected(p, SelectedState_UNSELECTED);
3740 return;
3741 }
3742
3743 static void
3744 bondport_RecordDefault(bondport_ref p)
3745 {
3746 bzero(&p->po_partner_state, sizeof(p->po_partner_state));
3747 p->po_actor_state
3748 = lacp_actor_partner_state_set_defaulted(p->po_actor_state);
3749 bondport_assign_to_LAG(p);
3750 return;
3751 }
3752
3753 static void
3754 bondport_UpdateSelected(bondport_ref p, lacpdu_ref lacpdu_p)
3755 {
3756 lacp_actor_partner_tlv_ref actor;
3757 partner_state_ref ps;
3758 LAG_info_ref ps_li;
3759
3760 /* compare the PDU's Actor information to our Partner state */
3761 actor = (lacp_actor_partner_tlv_ref)lacpdu_p->la_actor_tlv;
3762 ps = &p->po_partner_state;
3763 ps_li = &ps->ps_lag_info;
3764 if (lacp_actor_partner_tlv_get_port(actor) != ps->ps_port
3765 || (lacp_actor_partner_tlv_get_port_priority(actor)
3766 != ps->ps_port_priority)
3767 || bcmp(actor->lap_system, &ps_li->li_system, sizeof(ps_li->li_system))
3768 || (lacp_actor_partner_tlv_get_system_priority(actor)
3769 != ps_li->li_system_priority)
3770 || (lacp_actor_partner_tlv_get_key(actor) != ps_li->li_key)
3771 || (lacp_actor_partner_state_aggregatable(actor->lap_state)
3772 != lacp_actor_partner_state_aggregatable(ps->ps_state))) {
3773 bondport_set_selected(p, SelectedState_UNSELECTED);
3774 if (g_bond->verbose) {
3775 timestamp_printf("[%s] updateSelected UNSELECTED\n",
3776 bondport_get_name(p));
3777 }
3778 }
3779 return;
3780 }
3781
3782 static void
3783 bondport_RecordPDU(bondport_ref p, lacpdu_ref lacpdu_p)
3784 {
3785 lacp_actor_partner_tlv_ref actor;
3786 ifbond_ref bond = p->po_bond;
3787 int lacp_maintain = 0;
3788 partner_state_ref ps;
3789 lacp_actor_partner_tlv_ref partner;
3790 LAG_info_ref ps_li;
3791
3792 /* copy the PDU's Actor information into our Partner state */
3793 actor = (lacp_actor_partner_tlv_ref)lacpdu_p->la_actor_tlv;
3794 ps = &p->po_partner_state;
3795 ps_li = &ps->ps_lag_info;
3796 ps->ps_port = lacp_actor_partner_tlv_get_port(actor);
3797 ps->ps_port_priority = lacp_actor_partner_tlv_get_port_priority(actor);
3798 ps_li->li_system = *((lacp_system_ref)actor->lap_system);
3799 ps_li->li_system_priority
3800 = lacp_actor_partner_tlv_get_system_priority(actor);
3801 ps_li->li_key = lacp_actor_partner_tlv_get_key(actor);
3802 ps->ps_state = lacp_actor_partner_state_set_out_of_sync(actor->lap_state);
3803 p->po_actor_state
3804 = lacp_actor_partner_state_set_not_defaulted(p->po_actor_state);
3805
3806 /* compare the PDU's Partner information to our own information */
3807 partner = (lacp_actor_partner_tlv_ref)lacpdu_p->la_partner_tlv;
3808
3809 if (lacp_actor_partner_state_active_lacp(ps->ps_state)
3810 || (lacp_actor_partner_state_active_lacp(p->po_actor_state)
3811 && lacp_actor_partner_state_active_lacp(partner->lap_state))) {
3812 if (g_bond->verbose) {
3813 timestamp_printf("[%s] recordPDU: LACP will maintain\n",
3814 bondport_get_name(p));
3815 }
3816 lacp_maintain = 1;
3817 }
3818 if ((lacp_actor_partner_tlv_get_port(partner)
3819 == bondport_get_index(p))
3820 && lacp_actor_partner_tlv_get_port_priority(partner) == p->po_priority
3821 && bcmp(partner->lap_system, &g_bond->system,
3822 sizeof(g_bond->system)) == 0
3823 && (lacp_actor_partner_tlv_get_system_priority(partner)
3824 == g_bond->system_priority)
3825 && lacp_actor_partner_tlv_get_key(partner) == bond->ifb_key
3826 && (lacp_actor_partner_state_aggregatable(partner->lap_state)
3827 == lacp_actor_partner_state_aggregatable(p->po_actor_state))
3828 && lacp_actor_partner_state_in_sync(actor->lap_state)
3829 && lacp_maintain) {
3830 ps->ps_state = lacp_actor_partner_state_set_in_sync(ps->ps_state);
3831 if (g_bond->verbose) {
3832 timestamp_printf("[%s] recordPDU: LACP partner in sync\n",
3833 bondport_get_name(p));
3834 }
3835 }
3836 else if (lacp_actor_partner_state_aggregatable(actor->lap_state) == 0
3837 && lacp_actor_partner_state_in_sync(actor->lap_state)
3838 && lacp_maintain) {
3839 ps->ps_state = lacp_actor_partner_state_set_in_sync(ps->ps_state);
3840 if (g_bond->verbose) {
3841 timestamp_printf("[%s] recordPDU: LACP partner in sync (ind)\n",
3842 bondport_get_name(p));
3843 }
3844 }
3845 bondport_assign_to_LAG(p);
3846 return;
3847 }
3848
3849 static __inline__ lacp_actor_partner_state
3850 updateNTTBits(lacp_actor_partner_state s)
3851 {
3852 return (s & (LACP_ACTOR_PARTNER_STATE_LACP_ACTIVITY
3853 | LACP_ACTOR_PARTNER_STATE_LACP_TIMEOUT
3854 | LACP_ACTOR_PARTNER_STATE_AGGREGATION
3855 | LACP_ACTOR_PARTNER_STATE_SYNCHRONIZATION));
3856 }
3857
3858 static void
3859 bondport_UpdateNTT(bondport_ref p, lacpdu_ref lacpdu_p)
3860 {
3861 ifbond_ref bond = p->po_bond;
3862 lacp_actor_partner_tlv_ref partner;
3863
3864 /* compare the PDU's Actor information to our Partner state */
3865 partner = (lacp_actor_partner_tlv_ref)lacpdu_p->la_partner_tlv;
3866 if ((lacp_actor_partner_tlv_get_port(partner) != bondport_get_index(p))
3867 || lacp_actor_partner_tlv_get_port_priority(partner) != p->po_priority
3868 || bcmp(partner->lap_system, &g_bond->system, sizeof(g_bond->system))
3869 || (lacp_actor_partner_tlv_get_system_priority(partner)
3870 != g_bond->system_priority)
3871 || lacp_actor_partner_tlv_get_key(partner) != bond->ifb_key
3872 || (updateNTTBits(partner->lap_state)
3873 != updateNTTBits(p->po_actor_state))) {
3874 bondport_flags_set_ntt(p);
3875 if (g_bond->verbose) {
3876 timestamp_printf("[%s] updateNTT: Need To Transmit\n",
3877 bondport_get_name(p));
3878 }
3879 }
3880 return;
3881 }
3882
3883 static void
3884 bondport_AttachMuxToAggregator(bondport_ref p)
3885 {
3886 if (bondport_flags_mux_attached(p) == 0) {
3887 if (g_bond->verbose) {
3888 timestamp_printf("[%s] Attached Mux To Aggregator\n",
3889 bondport_get_name(p));
3890 }
3891 bondport_flags_set_mux_attached(p);
3892 }
3893 return;
3894 }
3895
3896 static void
3897 bondport_DetachMuxFromAggregator(bondport_ref p)
3898 {
3899 if (bondport_flags_mux_attached(p)) {
3900 if (g_bond->verbose) {
3901 timestamp_printf("[%s] Detached Mux From Aggregator\n",
3902 bondport_get_name(p));
3903 }
3904 bondport_flags_clear_mux_attached(p);
3905 }
3906 return;
3907 }
3908
3909 static void
3910 bondport_enable_distributing(bondport_ref p)
3911 {
3912 if (bondport_flags_distributing(p) == 0) {
3913 ifbond_ref bond = p->po_bond;
3914
3915 bond->ifb_distributing_array[bond->ifb_distributing_count++] = p;
3916 if (g_bond->verbose) {
3917 timestamp_printf("[%s] Distribution Enabled\n",
3918 bondport_get_name(p));
3919 }
3920 bondport_flags_set_distributing(p);
3921 }
3922 return;
3923 }
3924
3925 static void
3926 bondport_disable_distributing(bondport_ref p)
3927 {
3928 if (bondport_flags_distributing(p)) {
3929 bondport_ref * array;
3930 ifbond_ref bond;
3931 int count;
3932 int i;
3933
3934 bond = p->po_bond;
3935 array = bond->ifb_distributing_array;
3936 count = bond->ifb_distributing_count;
3937 for (i = 0; i < count; i++) {
3938 if (array[i] == p) {
3939 int j;
3940
3941 for (j = i; j < (count - 1); j++) {
3942 array[j] = array[j + 1];
3943 }
3944 break;
3945 }
3946 }
3947 bond->ifb_distributing_count--;
3948 if (g_bond->verbose) {
3949 timestamp_printf("[%s] Distribution Disabled\n",
3950 bondport_get_name(p));
3951 }
3952 bondport_flags_clear_distributing(p);
3953 }
3954 return;
3955 }
3956
3957 /**
3958 ** Receive machine functions
3959 **/
3960 static void
3961 bondport_receive_machine_initialize(bondport_ref p, LAEvent event,
3962 void * event_data);
3963 static void
3964 bondport_receive_machine_port_disabled(bondport_ref p, LAEvent event,
3965 void * event_data);
3966 static void
3967 bondport_receive_machine_expired(bondport_ref p, LAEvent event,
3968 void * event_data);
3969 static void
3970 bondport_receive_machine_lacp_disabled(bondport_ref p, LAEvent event,
3971 void * event_data);
3972 static void
3973 bondport_receive_machine_defaulted(bondport_ref p, LAEvent event,
3974 void * event_data);
3975 static void
3976 bondport_receive_machine_current(bondport_ref p, LAEvent event,
3977 void * event_data);
3978
3979 static void
3980 bondport_receive_machine_event(bondport_ref p, LAEvent event,
3981 void * event_data)
3982 {
3983 switch (p->po_receive_state) {
3984 case ReceiveState_none:
3985 bondport_receive_machine_initialize(p, LAEventStart, NULL);
3986 break;
3987 case ReceiveState_INITIALIZE:
3988 bondport_receive_machine_initialize(p, event, event_data);
3989 break;
3990 case ReceiveState_PORT_DISABLED:
3991 bondport_receive_machine_port_disabled(p, event, event_data);
3992 break;
3993 case ReceiveState_EXPIRED:
3994 bondport_receive_machine_expired(p, event, event_data);
3995 break;
3996 case ReceiveState_LACP_DISABLED:
3997 bondport_receive_machine_lacp_disabled(p, event, event_data);
3998 break;
3999 case ReceiveState_DEFAULTED:
4000 bondport_receive_machine_defaulted(p, event, event_data);
4001 break;
4002 case ReceiveState_CURRENT:
4003 bondport_receive_machine_current(p, event, event_data);
4004 break;
4005 default:
4006 break;
4007 }
4008 return;
4009 }
4010
4011 static void
4012 bondport_receive_machine(bondport_ref p, LAEvent event,
4013 void * event_data)
4014 {
4015 switch (event) {
4016 case LAEventPacket:
4017 if (p->po_receive_state != ReceiveState_LACP_DISABLED) {
4018 bondport_receive_machine_current(p, event, event_data);
4019 }
4020 break;
4021 case LAEventMediaChange:
4022 if (media_active(&p->po_media_info)) {
4023 switch (p->po_receive_state) {
4024 case ReceiveState_PORT_DISABLED:
4025 case ReceiveState_LACP_DISABLED:
4026 bondport_receive_machine_port_disabled(p, LAEventMediaChange, NULL);
4027 break;
4028 default:
4029 break;
4030 }
4031 }
4032 else {
4033 bondport_receive_machine_port_disabled(p, LAEventStart, NULL);
4034 }
4035 break;
4036 default:
4037 bondport_receive_machine_event(p, event, event_data);
4038 break;
4039 }
4040 return;
4041 }
4042
4043 static void
4044 bondport_receive_machine_initialize(bondport_ref p, LAEvent event,
4045 __unused void * event_data)
4046 {
4047 switch (event) {
4048 case LAEventStart:
4049 devtimer_cancel(p->po_current_while_timer);
4050 if (g_bond->verbose) {
4051 timestamp_printf("[%s] Receive INITIALIZE\n",
4052 bondport_get_name(p));
4053 }
4054 p->po_receive_state = ReceiveState_INITIALIZE;
4055 bondport_set_selected(p, SelectedState_UNSELECTED);
4056 bondport_RecordDefault(p);
4057 p->po_actor_state
4058 = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4059 bondport_receive_machine_port_disabled(p, LAEventStart, NULL);
4060 break;
4061 default:
4062 break;
4063 }
4064 return;
4065 }
4066
4067 static void
4068 bondport_receive_machine_port_disabled(bondport_ref p, LAEvent event,
4069 __unused void * event_data)
4070 {
4071 partner_state_ref ps;
4072
4073 switch (event) {
4074 case LAEventStart:
4075 devtimer_cancel(p->po_current_while_timer);
4076 if (g_bond->verbose) {
4077 timestamp_printf("[%s] Receive PORT_DISABLED\n",
4078 bondport_get_name(p));
4079 }
4080 p->po_receive_state = ReceiveState_PORT_DISABLED;
4081 ps = &p->po_partner_state;
4082 ps->ps_state = lacp_actor_partner_state_set_out_of_sync(ps->ps_state);
4083 /* FALL THROUGH */
4084 case LAEventMediaChange:
4085 if (media_active(&p->po_media_info)) {
4086 if (media_full_duplex(&p->po_media_info)) {
4087 bondport_receive_machine_expired(p, LAEventStart, NULL);
4088 }
4089 else {
4090 bondport_receive_machine_lacp_disabled(p, LAEventStart, NULL);
4091 }
4092 }
4093 else if (p->po_selected == SelectedState_SELECTED) {
4094 struct timeval tv;
4095
4096 if (g_bond->verbose) {
4097 timestamp_printf("[%s] Receive PORT_DISABLED: "
4098 "link timer started\n",
4099 bondport_get_name(p));
4100 }
4101 tv.tv_sec = 1;
4102 tv.tv_usec = 0;
4103 devtimer_set_relative(p->po_current_while_timer, tv,
4104 (devtimer_timeout_func)
4105 bondport_receive_machine_port_disabled,
4106 (void *)LAEventTimeout, NULL);
4107 }
4108 else if (p->po_selected == SelectedState_STANDBY) {
4109 bondport_set_selected(p, SelectedState_UNSELECTED);
4110 }
4111 break;
4112 case LAEventTimeout:
4113 if (p->po_selected == SelectedState_SELECTED) {
4114 if (g_bond->verbose) {
4115 timestamp_printf("[%s] Receive PORT_DISABLED: "
4116 "link timer completed, marking UNSELECTED\n",
4117 bondport_get_name(p));
4118 }
4119 bondport_set_selected(p, SelectedState_UNSELECTED);
4120 }
4121 break;
4122 case LAEventPortMoved:
4123 bondport_receive_machine_initialize(p, LAEventStart, NULL);
4124 break;
4125 default:
4126 break;
4127 }
4128 return;
4129 }
4130
4131 static void
4132 bondport_receive_machine_expired(bondport_ref p, LAEvent event,
4133 __unused void * event_data)
4134 {
4135 lacp_actor_partner_state s;
4136 struct timeval tv;
4137
4138 switch (event) {
4139 case LAEventStart:
4140 devtimer_cancel(p->po_current_while_timer);
4141 if (g_bond->verbose) {
4142 timestamp_printf("[%s] Receive EXPIRED\n",
4143 bondport_get_name(p));
4144 }
4145 p->po_receive_state = ReceiveState_EXPIRED;
4146 s = p->po_partner_state.ps_state;
4147 s = lacp_actor_partner_state_set_out_of_sync(s);
4148 s = lacp_actor_partner_state_set_short_timeout(s);
4149 p->po_partner_state.ps_state = s;
4150 p->po_actor_state
4151 = lacp_actor_partner_state_set_expired(p->po_actor_state);
4152 /* start current_while timer */
4153 tv.tv_sec = LACP_SHORT_TIMEOUT_TIME;
4154 tv.tv_usec = 0;
4155 devtimer_set_relative(p->po_current_while_timer, tv,
4156 (devtimer_timeout_func)
4157 bondport_receive_machine_expired,
4158 (void *)LAEventTimeout, NULL);
4159
4160 break;
4161 case LAEventTimeout:
4162 bondport_receive_machine_defaulted(p, LAEventStart, NULL);
4163 break;
4164 default:
4165 break;
4166 }
4167 return;
4168 }
4169
4170 static void
4171 bondport_receive_machine_lacp_disabled(bondport_ref p, LAEvent event,
4172 __unused void * event_data)
4173 {
4174 partner_state_ref ps;
4175 switch (event) {
4176 case LAEventStart:
4177 devtimer_cancel(p->po_current_while_timer);
4178 if (g_bond->verbose) {
4179 timestamp_printf("[%s] Receive LACP_DISABLED\n",
4180 bondport_get_name(p));
4181 }
4182 p->po_receive_state = ReceiveState_LACP_DISABLED;
4183 bondport_set_selected(p, SelectedState_UNSELECTED);
4184 bondport_RecordDefault(p);
4185 ps = &p->po_partner_state;
4186 ps->ps_state = lacp_actor_partner_state_set_individual(ps->ps_state);
4187 p->po_actor_state
4188 = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4189 break;
4190 default:
4191 break;
4192 }
4193 return;
4194 }
4195
4196 static void
4197 bondport_receive_machine_defaulted(bondport_ref p, LAEvent event,
4198 __unused void * event_data)
4199 {
4200 switch (event) {
4201 case LAEventStart:
4202 devtimer_cancel(p->po_current_while_timer);
4203 if (g_bond->verbose) {
4204 timestamp_printf("[%s] Receive DEFAULTED\n",
4205 bondport_get_name(p));
4206 }
4207 p->po_receive_state = ReceiveState_DEFAULTED;
4208 bondport_UpdateDefaultSelected(p);
4209 bondport_RecordDefault(p);
4210 p->po_actor_state
4211 = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4212 break;
4213 default:
4214 break;
4215 }
4216 return;
4217 }
4218
4219 static void
4220 bondport_receive_machine_current(bondport_ref p, LAEvent event,
4221 void * event_data)
4222 {
4223 partner_state_ref ps;
4224 struct timeval tv;
4225
4226 switch (event) {
4227 case LAEventPacket:
4228 devtimer_cancel(p->po_current_while_timer);
4229 if (g_bond->verbose) {
4230 timestamp_printf("[%s] Receive CURRENT\n",
4231 bondport_get_name(p));
4232 }
4233 p->po_receive_state = ReceiveState_CURRENT;
4234 bondport_UpdateSelected(p, event_data);
4235 bondport_UpdateNTT(p, event_data);
4236 bondport_RecordPDU(p, event_data);
4237 p->po_actor_state
4238 = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4239 bondport_assign_to_LAG(p);
4240 /* start current_while timer */
4241 ps = &p->po_partner_state;
4242 if (lacp_actor_partner_state_short_timeout(ps->ps_state)) {
4243 tv.tv_sec = LACP_SHORT_TIMEOUT_TIME;
4244 }
4245 else {
4246 tv.tv_sec = LACP_LONG_TIMEOUT_TIME;
4247 }
4248 tv.tv_usec = 0;
4249 devtimer_set_relative(p->po_current_while_timer, tv,
4250 (devtimer_timeout_func)
4251 bondport_receive_machine_current,
4252 (void *)LAEventTimeout, NULL);
4253 break;
4254 case LAEventTimeout:
4255 bondport_receive_machine_expired(p, LAEventStart, NULL);
4256 break;
4257 default:
4258 break;
4259 }
4260 return;
4261 }
4262
4263 /**
4264 ** Periodic Transmission machine
4265 **/
4266
4267 static void
4268 bondport_periodic_transmit_machine(bondport_ref p, LAEvent event,
4269 __unused void * event_data)
4270 {
4271 int interval;
4272 partner_state_ref ps;
4273 struct timeval tv;
4274
4275 switch (event) {
4276 case LAEventStart:
4277 if (g_bond->verbose) {
4278 timestamp_printf("[%s] periodic_transmit Start\n",
4279 bondport_get_name(p));
4280 }
4281 /* FALL THROUGH */
4282 case LAEventMediaChange:
4283 devtimer_cancel(p->po_periodic_timer);
4284 p->po_periodic_interval = 0;
4285 if (media_active(&p->po_media_info) == 0
4286 || media_full_duplex(&p->po_media_info) == 0) {
4287 break;
4288 }
4289 case LAEventPacket:
4290 /* Neither Partner nor Actor are LACP Active, no periodic tx */
4291 ps = &p->po_partner_state;
4292 if (lacp_actor_partner_state_active_lacp(p->po_actor_state) == 0
4293 && (lacp_actor_partner_state_active_lacp(ps->ps_state)
4294 == 0)) {
4295 devtimer_cancel(p->po_periodic_timer);
4296 p->po_periodic_interval = 0;
4297 break;
4298 }
4299 if (lacp_actor_partner_state_short_timeout(ps->ps_state)) {
4300 interval = LACP_FAST_PERIODIC_TIME;
4301 }
4302 else {
4303 interval = LACP_SLOW_PERIODIC_TIME;
4304 }
4305 if (p->po_periodic_interval != interval) {
4306 if (interval == LACP_FAST_PERIODIC_TIME
4307 && p->po_periodic_interval == LACP_SLOW_PERIODIC_TIME) {
4308 if (g_bond->verbose) {
4309 timestamp_printf("[%s] periodic_transmit:"
4310 " Need To Transmit\n",
4311 bondport_get_name(p));
4312 }
4313 bondport_flags_set_ntt(p);
4314 }
4315 p->po_periodic_interval = interval;
4316 tv.tv_usec = 0;
4317 tv.tv_sec = interval;
4318 devtimer_set_relative(p->po_periodic_timer, tv,
4319 (devtimer_timeout_func)
4320 bondport_periodic_transmit_machine,
4321 (void *)LAEventTimeout, NULL);
4322 if (g_bond->verbose) {
4323 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4324 bondport_get_name(p),
4325 p->po_periodic_interval);
4326 }
4327 }
4328 break;
4329 case LAEventTimeout:
4330 bondport_flags_set_ntt(p);
4331 tv.tv_sec = p->po_periodic_interval;
4332 tv.tv_usec = 0;
4333 devtimer_set_relative(p->po_periodic_timer, tv, (devtimer_timeout_func)
4334 bondport_periodic_transmit_machine,
4335 (void *)LAEventTimeout, NULL);
4336 if (g_bond->verbose > 1) {
4337 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4338 bondport_get_name(p), p->po_periodic_interval);
4339 }
4340 break;
4341 default:
4342 break;
4343 }
4344 return;
4345 }
4346
4347 /**
4348 ** Transmit machine
4349 **/
4350 static int
4351 bondport_can_transmit(bondport_ref p, int32_t current_secs,
4352 __darwin_time_t * next_secs)
4353 {
4354 if (p->po_last_transmit_secs != current_secs) {
4355 p->po_last_transmit_secs = current_secs;
4356 p->po_n_transmit = 0;
4357 }
4358 if (p->po_n_transmit < LACP_PACKET_RATE) {
4359 p->po_n_transmit++;
4360 return (1);
4361 }
4362 if (next_secs != NULL) {
4363 *next_secs = current_secs + 1;
4364 }
4365 return (0);
4366 }
4367
4368 static void
4369 bondport_transmit_machine(bondport_ref p, LAEvent event,
4370 void * event_data)
4371 {
4372 lacp_actor_partner_tlv_ref aptlv;
4373 lacp_collector_tlv_ref ctlv;
4374 struct timeval next_tick_time = {0, 0};
4375 lacpdu_ref out_lacpdu_p;
4376 packet_buffer_ref pkt;
4377 partner_state_ref ps;
4378 LAG_info_ref ps_li;
4379
4380 switch (event) {
4381 case LAEventTimeout:
4382 case LAEventStart:
4383 if (p->po_periodic_interval == 0 || bondport_flags_ntt(p) == 0) {
4384 break;
4385 }
4386 if (event_data == TRANSMIT_MACHINE_TX_IMMEDIATE) {
4387 /* we're going away, transmit the packet no matter what */
4388 }
4389 else if (bondport_can_transmit(p, devtimer_current_secs(),
4390 &next_tick_time.tv_sec) == 0) {
4391 if (devtimer_enabled(p->po_transmit_timer)) {
4392 if (g_bond->verbose > 0) {
4393 timestamp_printf("[%s] Transmit Timer Already Set\n",
4394 bondport_get_name(p));
4395 }
4396 }
4397 else {
4398 devtimer_set_absolute(p->po_transmit_timer, next_tick_time,
4399 (devtimer_timeout_func)
4400 bondport_transmit_machine,
4401 (void *)LAEventTimeout, NULL);
4402 if (g_bond->verbose > 0) {
4403 timestamp_printf("[%s] Transmit Timer Deadline %d secs\n",
4404 bondport_get_name(p),
4405 (int)next_tick_time.tv_sec);
4406 }
4407 }
4408 break;
4409 }
4410 if (g_bond->verbose > 0) {
4411 if (event == LAEventTimeout) {
4412 timestamp_printf("[%s] Transmit Timer Complete\n",
4413 bondport_get_name(p));
4414 }
4415 }
4416 pkt = packet_buffer_allocate(sizeof(*out_lacpdu_p));
4417 if (pkt == NULL) {
4418 printf("[%s] Transmit: failed to allocate packet buffer\n",
4419 bondport_get_name(p));
4420 break;
4421 }
4422 out_lacpdu_p = (lacpdu_ref)packet_buffer_byteptr(pkt);
4423 bzero(out_lacpdu_p, sizeof(*out_lacpdu_p));
4424 out_lacpdu_p->la_subtype = IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP;
4425 out_lacpdu_p->la_version = LACPDU_VERSION_1;
4426
4427 /* Actor */
4428 aptlv = (lacp_actor_partner_tlv_ref)out_lacpdu_p->la_actor_tlv;
4429 aptlv->lap_tlv_type = LACPDU_TLV_TYPE_ACTOR;
4430 aptlv->lap_length = LACPDU_ACTOR_TLV_LENGTH;
4431 *((lacp_system_ref)aptlv->lap_system) = g_bond->system;
4432 lacp_actor_partner_tlv_set_system_priority(aptlv,
4433 g_bond->system_priority);
4434 lacp_actor_partner_tlv_set_port_priority(aptlv, p->po_priority);
4435 lacp_actor_partner_tlv_set_port(aptlv, bondport_get_index(p));
4436 lacp_actor_partner_tlv_set_key(aptlv, p->po_bond->ifb_key);
4437 aptlv->lap_state = p->po_actor_state;
4438
4439 /* Partner */
4440 aptlv = (lacp_actor_partner_tlv_ref)out_lacpdu_p->la_partner_tlv;
4441 aptlv->lap_tlv_type = LACPDU_TLV_TYPE_PARTNER;
4442 aptlv->lap_length = LACPDU_PARTNER_TLV_LENGTH;
4443 ps = &p->po_partner_state;
4444 ps_li = &ps->ps_lag_info;
4445 lacp_actor_partner_tlv_set_port(aptlv, ps->ps_port);
4446 lacp_actor_partner_tlv_set_port_priority(aptlv, ps->ps_port_priority);
4447 *((lacp_system_ref)aptlv->lap_system) = ps_li->li_system;
4448 lacp_actor_partner_tlv_set_system_priority(aptlv,
4449 ps_li->li_system_priority);
4450 lacp_actor_partner_tlv_set_key(aptlv, ps_li->li_key);
4451 aptlv->lap_state = ps->ps_state;
4452
4453 /* Collector */
4454 ctlv = (lacp_collector_tlv_ref)out_lacpdu_p->la_collector_tlv;
4455 ctlv->lac_tlv_type = LACPDU_TLV_TYPE_COLLECTOR;
4456 ctlv->lac_length = LACPDU_COLLECTOR_TLV_LENGTH;
4457
4458 bondport_slow_proto_transmit(p, pkt);
4459 bondport_flags_clear_ntt(p);
4460 if (g_bond->verbose > 0) {
4461 timestamp_printf("[%s] Transmit Packet %d\n",
4462 bondport_get_name(p), p->po_n_transmit);
4463 }
4464 break;
4465 default:
4466 break;
4467 }
4468 return;
4469 }
4470
4471 /**
4472 ** Mux machine functions
4473 **/
4474
4475 static void
4476 bondport_mux_machine_detached(bondport_ref p, LAEvent event,
4477 void * event_data);
4478 static void
4479 bondport_mux_machine_waiting(bondport_ref p, LAEvent event,
4480 void * event_data);
4481 static void
4482 bondport_mux_machine_attached(bondport_ref p, LAEvent event,
4483 void * event_data);
4484
4485 static void
4486 bondport_mux_machine_collecting_distributing(bondport_ref p, LAEvent event,
4487 void * event_data);
4488
4489 static void
4490 bondport_mux_machine(bondport_ref p, LAEvent event, void * event_data)
4491 {
4492 switch (p->po_mux_state) {
4493 case MuxState_none:
4494 bondport_mux_machine_detached(p, LAEventStart, NULL);
4495 break;
4496 case MuxState_DETACHED:
4497 bondport_mux_machine_detached(p, event, event_data);
4498 break;
4499 case MuxState_WAITING:
4500 bondport_mux_machine_waiting(p, event, event_data);
4501 break;
4502 case MuxState_ATTACHED:
4503 bondport_mux_machine_attached(p, event, event_data);
4504 break;
4505 case MuxState_COLLECTING_DISTRIBUTING:
4506 bondport_mux_machine_collecting_distributing(p, event, event_data);
4507 break;
4508 default:
4509 break;
4510 }
4511 return;
4512 }
4513
4514 static void
4515 bondport_mux_machine_detached(bondport_ref p, LAEvent event,
4516 __unused void * event_data)
4517 {
4518 lacp_actor_partner_state s;
4519
4520 switch (event) {
4521 case LAEventStart:
4522 devtimer_cancel(p->po_wait_while_timer);
4523 if (g_bond->verbose) {
4524 timestamp_printf("[%s] Mux DETACHED\n",
4525 bondport_get_name(p));
4526 }
4527 p->po_mux_state = MuxState_DETACHED;
4528 bondport_flags_clear_ready(p);
4529 bondport_DetachMuxFromAggregator(p);
4530 bondport_disable_distributing(p);
4531 s = p->po_actor_state;
4532 s = lacp_actor_partner_state_set_out_of_sync(s);
4533 s = lacp_actor_partner_state_set_not_collecting(s);
4534 s = lacp_actor_partner_state_set_not_distributing(s);
4535 p->po_actor_state = s;
4536 bondport_flags_set_ntt(p);
4537 break;
4538 case LAEventSelectedChange:
4539 case LAEventPacket:
4540 case LAEventMediaChange:
4541 if (p->po_selected == SelectedState_SELECTED
4542 || p->po_selected == SelectedState_STANDBY) {
4543 bondport_mux_machine_waiting(p, LAEventStart, NULL);
4544 }
4545 break;
4546 default:
4547 break;
4548 }
4549 return;
4550 }
4551
4552 static void
4553 bondport_mux_machine_waiting(bondport_ref p, LAEvent event,
4554 __unused void * event_data)
4555 {
4556 struct timeval tv;
4557
4558 switch (event) {
4559 case LAEventStart:
4560 devtimer_cancel(p->po_wait_while_timer);
4561 if (g_bond->verbose) {
4562 timestamp_printf("[%s] Mux WAITING\n",
4563 bondport_get_name(p));
4564 }
4565 p->po_mux_state = MuxState_WAITING;
4566 /* FALL THROUGH */
4567 default:
4568 case LAEventSelectedChange:
4569 if (p->po_selected == SelectedState_UNSELECTED) {
4570 bondport_mux_machine_detached(p, LAEventStart, NULL);
4571 break;
4572 }
4573 if (p->po_selected == SelectedState_STANDBY) {
4574 devtimer_cancel(p->po_wait_while_timer);
4575 /* wait until state changes to SELECTED */
4576 if (g_bond->verbose) {
4577 timestamp_printf("[%s] Mux WAITING: Standby\n",
4578 bondport_get_name(p));
4579 }
4580 break;
4581 }
4582 if (bondport_flags_ready(p)) {
4583 if (g_bond->verbose) {
4584 timestamp_printf("[%s] Mux WAITING: Port is already ready\n",
4585 bondport_get_name(p));
4586 }
4587 break;
4588 }
4589 if (devtimer_enabled(p->po_wait_while_timer)) {
4590 if (g_bond->verbose) {
4591 timestamp_printf("[%s] Mux WAITING: Timer already set\n",
4592 bondport_get_name(p));
4593 }
4594 break;
4595 }
4596 if (ifbond_all_ports_attached(p->po_bond, p)) {
4597 devtimer_cancel(p->po_wait_while_timer);
4598 if (g_bond->verbose) {
4599 timestamp_printf("[%s] Mux WAITING: No waiting\n",
4600 bondport_get_name(p));
4601 }
4602 bondport_flags_set_ready(p);
4603 goto no_waiting;
4604 }
4605 if (g_bond->verbose) {
4606 timestamp_printf("[%s] Mux WAITING: 2 seconds\n",
4607 bondport_get_name(p));
4608 }
4609 tv.tv_sec = LACP_AGGREGATE_WAIT_TIME;
4610 tv.tv_usec = 0;
4611 devtimer_set_relative(p->po_wait_while_timer, tv,
4612 (devtimer_timeout_func)
4613 bondport_mux_machine_waiting,
4614 (void *)LAEventTimeout, NULL);
4615 break;
4616 case LAEventTimeout:
4617 if (g_bond->verbose) {
4618 timestamp_printf("[%s] Mux WAITING: Ready\n",
4619 bondport_get_name(p));
4620 }
4621 bondport_flags_set_ready(p);
4622 break;
4623 case LAEventReady:
4624 no_waiting:
4625 if (bondport_flags_ready(p)){
4626 if (g_bond->verbose) {
4627 timestamp_printf("[%s] Mux WAITING: All Ports Ready\n",
4628 bondport_get_name(p));
4629 }
4630 bondport_mux_machine_attached(p, LAEventStart, NULL);
4631 break;
4632 }
4633 break;
4634 }
4635 return;
4636 }
4637
4638 static void
4639 bondport_mux_machine_attached(bondport_ref p, LAEvent event,
4640 __unused void * event_data)
4641 {
4642 lacp_actor_partner_state s;
4643
4644 switch (event) {
4645 case LAEventStart:
4646 devtimer_cancel(p->po_wait_while_timer);
4647 if (g_bond->verbose) {
4648 timestamp_printf("[%s] Mux ATTACHED\n",
4649 bondport_get_name(p));
4650 }
4651 p->po_mux_state = MuxState_ATTACHED;
4652 bondport_AttachMuxToAggregator(p);
4653 s = p->po_actor_state;
4654 s = lacp_actor_partner_state_set_in_sync(s);
4655 s = lacp_actor_partner_state_set_not_collecting(s);
4656 s = lacp_actor_partner_state_set_not_distributing(s);
4657 bondport_disable_distributing(p);
4658 p->po_actor_state = s;
4659 bondport_flags_set_ntt(p);
4660 /* FALL THROUGH */
4661 default:
4662 switch (p->po_selected) {
4663 case SelectedState_SELECTED:
4664 s = p->po_partner_state.ps_state;
4665 if (lacp_actor_partner_state_in_sync(s)) {
4666 bondport_mux_machine_collecting_distributing(p, LAEventStart,
4667 NULL);
4668 }
4669 break;
4670 default:
4671 bondport_mux_machine_detached(p, LAEventStart, NULL);
4672 break;
4673 }
4674 break;
4675 }
4676 return;
4677 }
4678
4679 static void
4680 bondport_mux_machine_collecting_distributing(bondport_ref p,
4681 LAEvent event,
4682 __unused void * event_data)
4683 {
4684 lacp_actor_partner_state s;
4685
4686 switch (event) {
4687 case LAEventStart:
4688 devtimer_cancel(p->po_wait_while_timer);
4689 if (g_bond->verbose) {
4690 timestamp_printf("[%s] Mux COLLECTING_DISTRIBUTING\n",
4691 bondport_get_name(p));
4692 }
4693 p->po_mux_state = MuxState_COLLECTING_DISTRIBUTING;
4694 bondport_enable_distributing(p);
4695 s = p->po_actor_state;
4696 s = lacp_actor_partner_state_set_collecting(s);
4697 s = lacp_actor_partner_state_set_distributing(s);
4698 p->po_actor_state = s;
4699 bondport_flags_set_ntt(p);
4700 /* FALL THROUGH */
4701 default:
4702 s = p->po_partner_state.ps_state;
4703 if (lacp_actor_partner_state_in_sync(s) == 0) {
4704 bondport_mux_machine_attached(p, LAEventStart, NULL);
4705 break;
4706 }
4707 switch (p->po_selected) {
4708 case SelectedState_UNSELECTED:
4709 case SelectedState_STANDBY:
4710 bondport_mux_machine_attached(p, LAEventStart, NULL);
4711 break;
4712 default:
4713 break;
4714 }
4715 break;
4716 }
4717 return;
4718 }