2 * Copyright (c) 2004-2018 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 * - bond/failover interface
32 * - implements IEEE 802.3ad Link Aggregation
36 * Modification History:
38 * April 29, 2004 Dieter Siegmund (dieter@apple.com)
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.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>
53 #include <net/ethernet.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>
65 #include <net/devtimer.h>
66 #include <net/if_vlan_var.h>
67 #include <net/kpi_protocol.h>
69 #include <kern/locks.h>
70 #include <kern/zalloc.h>
71 #include <libkern/OSAtomic.h>
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>
79 #include <net/if_media.h>
80 #include <net/multicast_list.h>
82 static struct ether_addr slow_proto_multicast
= {
83 IEEE8023AD_SLOW_PROTO_MULTICAST
86 typedef struct ifbond_s ifbond
, * ifbond_ref
;
87 typedef struct bondport_s bondport
, * bondport_ref
;
89 #define BOND_MAXUNIT 128
90 #define BOND_ZONE_MAX_ELEM MIN(IFNETS_MAX, BOND_MAXUNIT)
91 #define BONDNAME "bond"
93 #define M_BOND M_DEVBUF
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)
99 #define timestamp_printf printf
104 static __inline__ lck_grp_t
*
105 my_lck_grp_alloc_init(const char * grp_name
)
108 lck_grp_attr_t
* grp_attrs
;
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
);
116 static __inline__ lck_mtx_t
*
117 my_lck_mtx_alloc_init(lck_grp_t
* lck_grp
)
119 lck_attr_t
* lck_attrs
;
122 lck_attrs
= lck_attr_alloc_init();
123 lck_mtx
= lck_mtx_alloc_init(lck_grp
, lck_attrs
);
124 lck_attr_free(lck_attrs
);
128 static lck_mtx_t
* bond_lck_mtx
;
130 static __inline__
void
133 lck_grp_t
* bond_lck_grp
;
135 bond_lck_grp
= my_lck_grp_alloc_init("if_bond");
136 bond_lck_mtx
= my_lck_mtx_alloc_init(bond_lck_grp
);
139 static __inline__
void
140 bond_assert_lock_held(void)
142 LCK_MTX_ASSERT(bond_lck_mtx
, LCK_MTX_ASSERT_OWNED
);
146 static __inline__
void
147 bond_assert_lock_not_held(void)
149 LCK_MTX_ASSERT(bond_lck_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
153 static __inline__
void
156 lck_mtx_lock(bond_lck_mtx
);
160 static __inline__
void
163 lck_mtx_unlock(bond_lck_mtx
);
168 ** bond structures, types
172 lacp_system li_system
;
173 lacp_system_priority li_system_priority
;
176 typedef struct LAG_info_s LAG_info
, * LAG_info_ref
;
179 TAILQ_HEAD(port_list
, bondport_s
);
181 TAILQ_HEAD(ifbond_list
, ifbond_s
);
183 TAILQ_HEAD(lag_list
, LAG_s
);
185 typedef struct ifbond_s ifbond
, * ifbond_ref
;
186 typedef struct bondport_s bondport
, * bondport_ref
;
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
;
196 typedef struct LAG_s LAG
, * LAG_ref
;
198 typedef struct partner_state_s
{
199 LAG_info ps_lag_info
;
201 lacp_port_priority ps_port_priority
;
202 lacp_actor_partner_state ps_state
;
203 } partner_state
, * partner_state_ref
;
206 TAILQ_ENTRY(ifbond_s
) ifb_bond_list
;
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
;
214 struct port_list ifb_port_list
;
215 short ifb_port_count
;
216 struct lag_list ifb_lag_list
;
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 */
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,
242 typedef u_char ReceiveState
;
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
249 typedef u_char SelectedState
;
251 static __inline__
const char *
252 SelectedStateString(SelectedState s
)
254 static const char * names
[] = { "UNSELECTED", "SELECTED", "STANDBY" };
256 if (s
<= SelectedState_STANDBY
) {
259 return ("<unknown>");
264 MuxState_DETACHED
= 1,
265 MuxState_WAITING
= 2,
266 MuxState_ATTACHED
= 3,
267 MuxState_COLLECTING_DISTRIBUTING
= 4,
270 typedef u_char MuxState
;
273 TAILQ_ENTRY(bondport_s
) po_port_list
;
275 struct multicast_list po_multicast
;
276 struct ifnet
* po_ifp
;
277 struct ether_addr po_saved_addr
;
279 char po_name
[IFNAMSIZ
];
280 struct ifdevmtu po_devmtu
;
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
;
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
;
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 */
307 static int bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
,
310 static __inline__
int
311 ifbond_flags_if_detaching(ifbond_ref ifb
)
313 return ((ifb
->ifb_flags
& IFBF_IF_DETACHING
) != 0);
316 static __inline__
void
317 ifbond_flags_set_if_detaching(ifbond_ref ifb
)
319 ifb
->ifb_flags
|= IFBF_IF_DETACHING
;
323 static __inline__
int
324 ifbond_flags_lladdr(ifbond_ref ifb
)
326 return ((ifb
->ifb_flags
& IFBF_LLADDR
) != 0);
329 static __inline__
int
330 ifbond_flags_change_in_progress(ifbond_ref ifb
)
332 return ((ifb
->ifb_flags
& IFBF_CHANGE_IN_PROGRESS
) != 0);
335 static __inline__
void
336 ifbond_flags_set_change_in_progress(ifbond_ref ifb
)
338 ifb
->ifb_flags
|= IFBF_CHANGE_IN_PROGRESS
;
342 static __inline__
void
343 ifbond_flags_clear_change_in_progress(ifbond_ref ifb
)
345 ifb
->ifb_flags
&= ~IFBF_CHANGE_IN_PROGRESS
;
350 * bondport_ref->po_flags bits
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
361 static __inline__
void
362 bondport_flags_set_ntt(bondport_ref p
)
364 p
->po_flags
|= BONDPORT_FLAGS_NTT
;
368 static __inline__
void
369 bondport_flags_clear_ntt(bondport_ref p
)
371 p
->po_flags
&= ~BONDPORT_FLAGS_NTT
;
375 static __inline__
int
376 bondport_flags_ntt(bondport_ref p
)
378 return ((p
->po_flags
& BONDPORT_FLAGS_NTT
) != 0);
381 static __inline__
void
382 bondport_flags_set_ready(bondport_ref p
)
384 p
->po_flags
|= BONDPORT_FLAGS_READY
;
388 static __inline__
void
389 bondport_flags_clear_ready(bondport_ref p
)
391 p
->po_flags
&= ~BONDPORT_FLAGS_READY
;
395 static __inline__
int
396 bondport_flags_ready(bondport_ref p
)
398 return ((p
->po_flags
& BONDPORT_FLAGS_READY
) != 0);
401 static __inline__
void
402 bondport_flags_set_selected_changed(bondport_ref p
)
404 p
->po_flags
|= BONDPORT_FLAGS_SELECTED_CHANGED
;
408 static __inline__
void
409 bondport_flags_clear_selected_changed(bondport_ref p
)
411 p
->po_flags
&= ~BONDPORT_FLAGS_SELECTED_CHANGED
;
415 static __inline__
int
416 bondport_flags_selected_changed(bondport_ref p
)
418 return ((p
->po_flags
& BONDPORT_FLAGS_SELECTED_CHANGED
) != 0);
421 static __inline__
void
422 bondport_flags_set_mux_attached(bondport_ref p
)
424 p
->po_flags
|= BONDPORT_FLAGS_MUX_ATTACHED
;
428 static __inline__
void
429 bondport_flags_clear_mux_attached(bondport_ref p
)
431 p
->po_flags
&= ~BONDPORT_FLAGS_MUX_ATTACHED
;
435 static __inline__
int
436 bondport_flags_mux_attached(bondport_ref p
)
438 return ((p
->po_flags
& BONDPORT_FLAGS_MUX_ATTACHED
) != 0);
441 static __inline__
void
442 bondport_flags_set_distributing(bondport_ref p
)
444 p
->po_flags
|= BONDPORT_FLAGS_DISTRIBUTING
;
448 static __inline__
void
449 bondport_flags_clear_distributing(bondport_ref p
)
451 p
->po_flags
&= ~BONDPORT_FLAGS_DISTRIBUTING
;
455 static __inline__
int
456 bondport_flags_distributing(bondport_ref p
)
458 return ((p
->po_flags
& BONDPORT_FLAGS_DISTRIBUTING
) != 0);
461 typedef struct bond_globals_s
{
462 struct ifbond_list ifbond_list
;
464 lacp_system_priority system_priority
;
466 } * bond_globals_ref
;
468 static bond_globals_ref g_bond
;
471 ** packet_buffer routines
472 ** - thin wrapper for mbuf
475 typedef struct mbuf
* packet_buffer_ref
;
477 static packet_buffer_ref
478 packet_buffer_allocate(int length
)
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",
491 m
= m_getcl(M_WAITOK
, MT_DATA
, M_PKTHDR
);
493 m
= m_gethdr(M_WAITOK
, MT_DATA
);
499 m
->m_pkthdr
.len
= size
;
504 packet_buffer_byteptr(packet_buffer_ref buf
)
506 return (buf
->m_data
+ sizeof(struct ether_header
));
514 LAEventSelectedChange
,
523 bondport_receive_machine(bondport_ref p
, LAEvent event
,
526 ** Periodic Transmission machine
529 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
535 #define TRANSMIT_MACHINE_TX_IMMEDIATE ((void *)1)
538 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
545 bondport_mux_machine(bondport_ref p
, LAEvent event
,
552 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
);
555 ifbond_deactivate_LAG(ifbond_ref bond
, LAG_ref lag
);
558 ifbond_all_ports_ready(ifbond_ref bond
);
561 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
);
564 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
);
567 ifbond_selection(ifbond_ref bond
);
575 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
);
578 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
);
581 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
582 int active
, int short_timeout
, int * error
);
584 bondport_start(bondport_ref p
);
587 bondport_free(bondport_ref p
);
590 bondport_aggregatable(bondport_ref p
);
593 bondport_remove_from_LAG(bondport_ref p
);
596 bondport_set_selected(bondport_ref p
, SelectedState s
);
599 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
);
602 bondport_link_status_changed(bondport_ref p
);
605 bondport_enable_distributing(bondport_ref p
);
608 bondport_disable_distributing(bondport_ref p
);
610 static __inline__
int
611 bondport_collecting(bondport_ref p
)
613 if (p
->po_bond
->ifb_mode
== IF_BOND_MODE_LACP
) {
614 return (lacp_actor_partner_state_collecting(p
->po_actor_state
));
620 ** bond interface/dlil specific routines
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
,
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
);
638 static struct if_clone bond_cloner
= IF_CLONE_INITIALIZER(BONDNAME
,
647 siocsifmtu(struct ifnet
* ifp
, int mtu
)
651 bzero(&ifr
, sizeof(ifr
));
653 return (ifnet_ioctl(ifp
, 0, SIOCSIFMTU
, &ifr
));
657 siocgifdevmtu(struct ifnet
* ifp
, struct ifdevmtu
* ifdm_p
)
662 bzero(&ifr
, sizeof(ifr
));
663 error
= ifnet_ioctl(ifp
, 0, SIOCGIFDEVMTU
, &ifr
);
665 *ifdm_p
= ifr
.ifr_devmtu
;
670 static __inline__
void
671 ether_addr_copy(void * dest
, const void * source
)
673 bcopy(source
, dest
, ETHER_ADDR_LEN
);
677 static __inline__
void
678 ifbond_retain(ifbond_ref ifb
)
680 OSIncrementAtomic(&ifb
->ifb_retain_count
);
683 static __inline__
void
684 ifbond_release(ifbond_ref ifb
)
686 UInt32 old_retain_count
;
688 old_retain_count
= OSDecrementAtomic(&ifb
->ifb_retain_count
);
689 switch (old_retain_count
) {
691 panic("ifbond_release: retain count is 0\n");
694 if (g_bond
->verbose
) {
695 printf("ifbond_release(%s)\n", ifb
->ifb_name
);
697 if (ifb
->ifb_ifma_slow_proto
!= NULL
) {
698 if (g_bond
->verbose
) {
699 printf("ifbond_release(%s) removing multicast\n",
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
);
706 if (ifb
->ifb_distributing_array
!= NULL
) {
707 FREE(ifb
->ifb_distributing_array
, M_BOND
);
709 if_clone_softc_deallocate(&bond_cloner
, ifb
);
718 * Function: ifbond_wait
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.
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.
734 * Before calling, you must be holding the bond_lock and have taken
735 * a reference on the ifbond_ref.
738 ifbond_wait(ifbond_ref ifb
, const char * msg
)
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
);
748 (void)msleep(ifb
, bond_lck_mtx
, PZERO
, msg
, 0);
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
);
759 * Function: ifbond_signal
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
765 * Before calling, you must be holding the bond_lock and have taken
766 * a reference on the ifbond_ref.
769 ifbond_signal(ifbond_ref ifb
, const char * msg
)
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
);
784 link_speed(int active
)
786 switch (IFM_SUBTYPE(active
)) {
807 /* assume that new defined types are going to be at least 10GigE */
818 static __inline__
int
819 media_active(const struct media_info
* mi
)
821 if ((mi
->mi_status
& IFM_AVALID
) == 0) {
824 return ((mi
->mi_status
& IFM_ACTIVE
) != 0);
827 static __inline__
int
828 media_full_duplex(const struct media_info
* mi
)
830 return ((mi
->mi_active
& IFM_FDX
) != 0);
833 static __inline__
int
834 media_speed(const struct media_info
* mi
)
836 return (link_speed(mi
->mi_active
));
839 static struct media_info
840 interface_media_info(struct ifnet
* ifp
)
842 struct ifmediareq ifmr
;
843 struct media_info mi
;
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
;
857 if_siflladdr(struct ifnet
* ifp
, const struct ether_addr
* ea_p
)
862 * XXX setting the sa_len to ETHER_ADDR_LEN is wrong, but the driver
863 * currently expects it that way
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
));
874 static bond_globals_ref
875 bond_globals_create(lacp_system_priority sys_pri
,
880 b
= _MALLOC(sizeof(*b
), M_BOND
, M_WAITOK
| M_ZERO
);
884 TAILQ_INIT(&b
->ifbond_list
);
886 b
->system_priority
= sys_pri
;
891 bond_globals_init(void)
897 bond_assert_lock_not_held();
899 if (g_bond
!= NULL
) {
904 * use en0's ethernet address as the system identifier, and if it's not
905 * there, use en1 .. en3
908 for (i
= 0; i
< 4; i
++) {
909 char ifname
[IFNAMSIZ
+1];
910 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
911 ifp
= ifunit(ifname
);
918 b
= bond_globals_create(0x8000, (lacp_system_ref
)IF_LLADDR(ifp
));
921 if (g_bond
!= NULL
) {
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
)
942 struct ether_vlan_header
* vlh_p
;
945 vl_m
= m_get(M_DONTWAIT
, MT_DATA
);
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
;
963 static __inline__
void
964 bond_bpf_output(struct ifnet
* ifp
, struct mbuf
* m
,
965 bpf_packet_func func
)
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
;
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
)
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
);
991 /* restore the header */
992 m
->m_data
-= ETHER_HDR_LEN
;
993 m
->m_len
+= ETHER_HDR_LEN
;
995 m
->m_data
+= ETHER_HDR_LEN
;
996 m
->m_len
-= ETHER_HDR_LEN
;
1003 * Function: bond_setmulti
1005 * Enable multicast reception on "our" interface by enabling multicasts on
1006 * each of the member ports.
1009 bond_setmulti(struct ifnet
* ifp
)
1017 ifb
= ifnet_softc(ifp
);
1018 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1019 || TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
1024 ifbond_wait(ifb
, "bond_setmulti");
1026 if (ifbond_flags_if_detaching(ifb
)) {
1027 /* someone destroyed the bond while we were waiting */
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
;
1037 error
= multicast_list_program(&p
->po_multicast
,
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
);
1049 ifbond_signal(ifb
, "bond_setmulti");
1051 ifbond_release(ifb
);
1056 bond_clone_attach(void)
1060 if ((error
= if_clone_attach(&bond_cloner
)) != 0)
1067 ifbond_add_slow_proto_multicast(ifbond_ref ifb
)
1070 struct ifmultiaddr
* ifma
= NULL
;
1071 struct sockaddr_dl sdl
;
1073 bond_assert_lock_not_held();
1075 bzero(&sdl
, sizeof(sdl
));
1076 sdl
.sdl_len
= sizeof(sdl
);
1077 sdl
.sdl_family
= AF_LINK
;
1078 sdl
.sdl_type
= IFT_ETHER
;
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
);
1084 ifb
->ifb_ifma_slow_proto
= ifma
;
1090 bond_clone_create(struct if_clone
* ifc
, u_int32_t unit
, __unused
void *params
)
1095 struct ifnet_init_eparams bond_init
;
1097 error
= bond_globals_init();
1102 ifb
= if_clone_softc_allocate(&bond_cloner
);
1108 TAILQ_INIT(&ifb
->ifb_port_list
);
1109 TAILQ_INIT(&ifb
->ifb_lag_list
);
1110 ifb
->ifb_key
= unit
+ 1;
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
);
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
);
1144 ifbond_release(ifb
);
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);
1155 error
= ifnet_attach(ifp
, NULL
);
1158 ifbond_release(ifb
);
1161 error
= ifbond_add_slow_proto_multicast(ifb
);
1163 printf("bond_clone_create(%s): "
1164 "failed to add slow_proto multicast, %d\n",
1165 ifb
->ifb_name
, error
);
1168 /* attach as ethernet */
1169 bpfattach(ifp
, DLT_EN10MB
, sizeof(struct ether_header
));
1172 TAILQ_INSERT_HEAD(&g_bond
->ifbond_list
, ifb
, ifb_bond_list
);
1179 bond_remove_all_interfaces(ifbond_ref ifb
)
1183 bond_assert_lock_held();
1186 * do this in reverse order to avoid re-programming the mac address
1187 * as each head interface is removed
1189 while ((p
= TAILQ_LAST(&ifb
->ifb_port_list
, port_list
)) != NULL
) {
1190 bond_remove_interface(ifb
, p
->po_ifp
);
1196 bond_remove(ifbond_ref ifb
)
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
);
1206 bond_if_detach(struct ifnet
* ifp
)
1210 error
= ifnet_detach(ifp
);
1212 printf("bond_if_detach %s%d: ifnet_detach failed, %d\n",
1213 ifnet_name(ifp
), ifnet_unit(ifp
), error
);
1220 bond_clone_destroy(struct ifnet
* ifp
)
1225 ifb
= ifnet_softc(ifp
);
1226 if (ifb
== NULL
|| ifnet_type(ifp
) != IFT_IEEE8023ADLAG
) {
1230 if (ifbond_flags_if_detaching(ifb
)) {
1236 bond_if_detach(ifp
);
1241 bond_set_bpf_tap(struct ifnet
* ifp
, bpf_tap_mode mode
, bpf_packet_func func
)
1246 ifb
= ifnet_softc(ifp
);
1247 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
1252 case BPF_TAP_DISABLE
:
1253 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= NULL
;
1257 ifb
->ifb_bpf_input
= func
;
1260 case BPF_TAP_OUTPUT
:
1261 ifb
->ifb_bpf_output
= func
;
1264 case BPF_TAP_INPUT_OUTPUT
:
1265 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= func
;
1275 ether_header_hash(struct ether_header
* eh_p
)
1279 /* get 32-bits from destination ether and ether type */
1280 h
= (*((uint16_t *)&eh_p
->ether_dhost
[4]) << 16)
1282 h
^= *((uint32_t *)&eh_p
->ether_dhost
[0]);
1286 static struct mbuf
*
1287 S_mbuf_skip_to_offset(struct mbuf
* m
, int32_t * offset
)
1292 while (*offset
>= len
) {
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
)
1307 return (((uint32_t)c0
<< 24) | ((uint32_t)c1
<< 16)
1308 | ((uint32_t)c2
<< 8) | (uint32_t)c3
);
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
)
1314 return (((uint32_t)c3
<< 24) | ((uint32_t)c2
<< 16)
1315 | ((uint32_t)c1
<< 8) | (uint32_t)c0
);
1317 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1320 S_mbuf_copy_uint32(struct mbuf
* m
, int32_t offset
, uint32_t * val
)
1322 struct mbuf
* current
;
1323 u_char
* current_data
;
1328 current
= S_mbuf_skip_to_offset(m
, &offset
);
1329 if (current
== NULL
) {
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
);
1338 next
= current
->m_next
;
1339 if (next
== NULL
|| (next
->m_len
+ space_current
) < (int)sizeof(uint32_t)) {
1342 next_data
= mtod(next
, u_char
*);
1343 switch (space_current
) {
1345 *val
= make_uint32(current_data
[0], next_data
[0],
1346 next_data
[1], next_data
[2]);
1349 *val
= make_uint32(current_data
[0], current_data
[1],
1350 next_data
[0], next_data
[1]);
1353 *val
= make_uint32(current_data
[0], current_data
[1],
1354 current_data
[2], next_data
[0]);
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))
1364 ip_header_hash(struct mbuf
* m
)
1367 struct in_addr ip_dst
;
1368 struct in_addr ip_src
;
1371 struct mbuf
* orig_m
= m
;
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) {
1379 data
= mtod(m
, u_char
*) + offset
;
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
);
1390 if (S_mbuf_copy_uint32(m
, offset
+ IP_SRC_OFFSET
,
1391 (uint32_t *)&ip_src
.s_addr
)) {
1394 if (S_mbuf_copy_uint32(m
, offset
+ IP_DST_OFFSET
,
1395 (uint32_t *)&ip_dst
.s_addr
)) {
1399 return (ntohl(ip_dst
.s_addr
) ^ ntohl(ip_src
.s_addr
) ^ ((uint32_t)ip_p
));
1402 return (ether_header_hash(mtod(orig_m
, struct ether_header
*)));
1405 #define IP6_ADDRS_LEN (sizeof(struct in6_addr) * 2)
1407 ipv6_header_hash(struct mbuf
* m
)
1412 struct mbuf
* orig_m
= m
;
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
);
1420 goto bad_ipv6_packet
;
1422 data
= mtod(m
, u_char
*) + offset
;
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));
1433 for (i
= 0; i
< (int)(IP6_ADDRS_LEN
/ sizeof(uint32_t)); i
++) {
1435 if (S_mbuf_copy_uint32(m
, offset
+ i
* sizeof(uint32_t),
1436 (uint32_t *)&tmp
)) {
1437 goto bad_ipv6_packet
;
1442 return (ntohl(val
));
1445 return (ether_header_hash(mtod(orig_m
, struct ether_header
*)));
1449 bond_output(struct ifnet
* ifp
, struct mbuf
* m
)
1451 bpf_packet_func bpf_func
;
1454 struct ifnet
* port_ifp
= NULL
;
1456 struct flowadv adv
= { FADV_SUCCESS
};
1461 if ((m
->m_flags
& M_PKTHDR
) == 0) {
1465 if (m
->m_pkthdr
.pkt_flowid
!= 0) {
1466 h
= m
->m_pkthdr
.pkt_flowid
;
1469 struct ether_header
* eh_p
;
1471 eh_p
= mtod(m
, struct ether_header
*);
1472 switch (ntohs(eh_p
->ether_type
)) {
1474 h
= ip_header_hash(m
);
1476 case ETHERTYPE_IPV6
:
1477 h
= ipv6_header_hash(m
);
1480 h
= ether_header_hash(eh_p
);
1485 ifb
= ifnet_softc(ifp
);
1486 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1487 || ifb
->ifb_distributing_count
== 0) {
1490 h
%= ifb
->ifb_distributing_count
;
1491 port_ifp
= ifb
->ifb_distributing_array
[h
]->po_ifp
;
1492 bpf_func
= ifb
->ifb_bpf_output
;
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
,
1500 (void)ifnet_stat_increment_out(ifp
, 1, m
->m_pkthdr
.len
, 0);
1502 bond_bpf_output(ifp
, m
, bpf_func
);
1504 err
= dlil_output(port_ifp
, PF_BOND
, m
, NULL
, NULL
, 1, &adv
);
1507 if (adv
.code
== FADV_FLOW_CONTROLLED
) {
1509 } else if (adv
.code
== FADV_SUSPENDED
) {
1523 ifbond_lookup_port(ifbond_ref ifb
, struct ifnet
* port_ifp
)
1526 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
1527 if (p
->po_ifp
== port_ifp
) {
1535 bond_lookup_port(struct ifnet
* port_ifp
)
1540 TAILQ_FOREACH(ifb
, &g_bond
->ifbond_list
, ifb_bond_list
) {
1541 port
= ifbond_lookup_port(ifb
, port_ifp
);
1550 bond_receive_lacpdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1552 struct ifnet
* bond_ifp
= NULL
;
1558 if ((ifnet_eflags(port_ifp
) & IFEF_BOND
) == 0) {
1561 p
= bond_lookup_port(port_ifp
);
1565 if (p
->po_enabled
== 0) {
1569 if (ifb
->ifb_mode
!= IF_BOND_MODE_LACP
) {
1572 bondport_receive_lacpdu(p
, (lacpdu_ref
)m
->m_data
);
1573 if (ifbond_selection(ifb
)) {
1574 event_code
= (ifb
->ifb_active_lag
== NULL
)
1577 /* XXX need to take a reference on bond_ifp */
1578 bond_ifp
= ifb
->ifb_ifp
;
1579 ifb
->ifb_last_link_event
= event_code
;
1582 event_code
= (ifb
->ifb_active_lag
== NULL
)
1585 if (event_code
!= ifb
->ifb_last_link_event
) {
1586 if (g_bond
->verbose
) {
1587 timestamp_printf("%s: (receive) generating LINK event\n",
1590 bond_ifp
= ifb
->ifb_ifp
;
1591 ifb
->ifb_last_link_event
= event_code
;
1597 if (bond_ifp
!= NULL
) {
1598 interface_link_event(bond_ifp
, event_code
);
1605 bond_receive_la_marker_pdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1607 la_marker_pdu_ref marker_p
;
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
) {
1615 if ((ifnet_eflags(port_ifp
) & IFEF_BOND
) == 0) {
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
) {
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
);
1637 bond_input(ifnet_t port_ifp
, __unused protocol_family_t protocol
, mbuf_t m
,
1638 char * frame_header
)
1640 bpf_packet_func bpf_func
;
1641 const struct ether_header
* eh_p
;
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
*);
1653 if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP
) {
1654 if (m
->m_pkthdr
.len
< (int)offsetof(lacpdu
, la_reserved
)) {
1659 if (m
->m_len
< (int)offsetof(lacpdu
, la_reserved
)) {
1660 m
= m_pullup(m
, offsetof(lacpdu
, la_reserved
));
1665 bond_receive_lacpdu(m
, port_ifp
);
1668 else if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LA_MARKER_PROTOCOL
) {
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
) {
1681 if (m
->m_len
< min_size
) {
1682 m
= m_pullup(m
, min_size
);
1687 /* send to marker responder */
1688 bond_receive_la_marker_pdu(m
, port_ifp
);
1691 else if (subtype
== 0
1692 || subtype
> IEEE8023AD_SLOW_PROTO_SUBTYPE_RESERVED_END
) {
1693 /* invalid subtype, discard the frame */
1699 if ((ifnet_eflags(port_ifp
) & IFEF_BOND
) == 0) {
1702 p
= bond_lookup_port(port_ifp
);
1703 if (p
== NULL
|| bondport_collecting(p
) == 0) {
1707 /* make the packet appear as if it arrived on the bonded interface */
1710 bpf_func
= ifb
->ifb_bpf_input
;
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);
1719 (void)ifnet_stat_increment_in(ifp
, 1,
1720 (m
->m_pkthdr
.len
+ ETHER_HDR_LEN
), 0);
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
);
1734 static __inline__
const char *
1735 bondport_get_name(bondport_ref p
)
1737 return (p
->po_name
);
1740 static __inline__
int
1741 bondport_get_index(bondport_ref p
)
1743 return (ifnet_index(p
->po_ifp
));
1747 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
)
1749 struct ether_header
* eh_p
;
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
);
1759 printf("bondport_slow_proto_transmit(%s) failed %d\n",
1760 bondport_get_name(p
), error
);
1766 bondport_timer_process_func(devtimer_ref timer
,
1767 devtimer_process_func_event event
)
1772 case devtimer_process_func_event_lock
:
1774 devtimer_retain(timer
);
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 */
1780 struct ifnet
* bond_ifp
= NULL
;
1782 p
= (bondport_ref
)devtimer_arg0(timer
);
1783 if (ifbond_selection(p
->po_bond
)) {
1784 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
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
;
1792 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
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
);
1800 bond_ifp
= p
->po_bond
->ifb_ifp
;
1801 p
->po_bond
->ifb_last_link_event
= event_code
;
1804 devtimer_release(timer
);
1806 if (bond_ifp
!= NULL
) {
1807 interface_link_event(bond_ifp
, event_code
);
1811 /* timer is going away */
1812 devtimer_release(timer
);
1822 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
1823 int active
, int short_timeout
, int * ret_error
)
1826 bondport_ref p
= NULL
;
1827 lacp_actor_partner_state s
;
1830 p
= _MALLOC(sizeof(*p
), M_BOND
, M_WAITOK
| M_ZERO
);
1832 *ret_error
= ENOMEM
;
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
;
1843 error
= siocgifdevmtu(port_ifp
, &p
->po_devmtu
);
1845 printf("if_bond: SIOCGIFDEVMTU %s failed, %d\n",
1846 bondport_get_name(p
), error
);
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
;
1858 p
->po_periodic_timer
= devtimer_create(bondport_timer_process_func
, p
);
1859 if (p
->po_periodic_timer
== NULL
) {
1860 *ret_error
= ENOMEM
;
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
;
1868 p
->po_transmit_timer
= devtimer_create(bondport_timer_process_func
, p
);
1869 if (p
->po_transmit_timer
== NULL
) {
1870 *ret_error
= ENOMEM
;
1873 p
->po_receive_state
= ReceiveState_none
;
1874 p
->po_mux_state
= MuxState_none
;
1875 p
->po_priority
= priority
;
1877 s
= lacp_actor_partner_state_set_aggregatable(s
);
1878 if (short_timeout
) {
1879 s
= lacp_actor_partner_state_set_short_timeout(s
);
1882 s
= lacp_actor_partner_state_set_active_lacp(s
);
1884 p
->po_actor_state
= s
;
1893 bondport_start(bondport_ref p
)
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
);
1903 * Function: bondport_invalidate_timers
1905 * Invalidate all of the timers for the bondport.
1908 bondport_invalidate_timers(bondport_ref p
)
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
);
1917 * Function: bondport_cancel_timers
1919 * Cancel all of the timers for the bondport.
1922 bondport_cancel_timers(bondport_ref p
)
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
);
1931 bondport_free(bondport_ref p
)
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
);
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
1947 static __inline__
int
1948 bond_device_mtu(struct ifnet
* ifp
, ifbond_ref ifb
)
1950 return (((int)ifnet_mtu(ifp
) > ifb
->ifb_altmtu
)
1951 ? (int)ifnet_mtu(ifp
) : ifb
->ifb_altmtu
);
1955 bond_add_interface(struct ifnet
* ifp
, struct ifnet
* port_ifp
)
1962 bondport_ref
* new_array
= NULL
;
1963 bondport_ref
* old_array
= NULL
;
1967 if (IFNET_IS_INTCOPROC(port_ifp
)) {
1971 /* pre-allocate space for new port */
1972 p
= bondport_create(port_ifp
, 0x8000, 1, 0, &error
);
1977 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
1978 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
1981 return ((ifb
== NULL
? EOPNOTSUPP
: EBUSY
));
1984 /* make sure this interface can handle our current MTU */
1985 devmtu
= bond_device_mtu(ifp
, ifb
);
1987 && (devmtu
> p
->po_devmtu
.ifdm_max
|| devmtu
< p
->po_devmtu
.ifdm_min
)) {
1989 printf("if_bond: interface %s doesn't support mtu %d",
1990 bondport_get_name(p
), devmtu
);
1995 /* make sure ifb doesn't get de-allocated while we wait */
1998 /* wait for other add or remove to complete */
1999 ifbond_wait(ifb
, "bond_add_interface");
2001 if (ifbond_flags_if_detaching(ifb
)) {
2002 /* someone destroyed the bond while we were waiting */
2006 if (bond_lookup_port(port_ifp
) != NULL
) {
2007 /* port is already part of a bond */
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
);
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
);
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
) {
2031 ifnet_offload_t ifp_offload
;
2032 ifnet_offload_t port_ifp_offload
;
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
;
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
);
2046 * if the bond has VLAN's, we can't simply change the hwassist
2047 * field behind its back: this needs work
2049 ifnet_set_offload(ifp
, offload
);
2054 /* remember the port's ethernet address so it can be restored */
2055 ether_addr_copy(&p
->po_saved_addr
, IF_LLADDR(port_ifp
));
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
++;
2061 /* set the default MTU */
2062 if (ifnet_mtu(ifp
) == 0) {
2063 ifnet_set_mtu(ifp
, ETHERMTU
);
2068 /* first port added to bond determines bond's ethernet address */
2070 ifnet_set_lladdr_and_type(ifp
, IF_LLADDR(port_ifp
), ETHER_ADDR_LEN
,
2074 progress
|= BOND_ADD_PROGRESS_IN_LIST
;
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
) {
2084 /* attach our BOND "protocol" to the interface */
2085 error
= bond_attach_protocol(port_ifp
);
2089 progress
|= BOND_ADD_PROGRESS_PROTO_ATTACHED
;
2091 /* set the interface MTU */
2092 devmtu
= bond_device_mtu(ifp
, ifb
);
2093 error
= siocsifmtu(port_ifp
, devmtu
);
2095 printf("bond_add_interface(%s, %s):"
2096 " SIOCSIFMTU %d failed %d\n",
2097 ifb
->ifb_name
, bondport_get_name(p
), devmtu
, error
);
2100 progress
|= BOND_ADD_PROGRESS_MTU_SET
;
2102 /* program the port with our multicast addresses */
2103 error
= multicast_list_program(&p
->po_multicast
, ifp
, port_ifp
);
2105 printf("bond_add_interface(%s, %s):"
2106 " multicast_list_program failed %d\n",
2107 ifb
->ifb_name
, bondport_get_name(p
), error
);
2111 /* mark the interface up */
2112 ifnet_set_flags(port_ifp
, IFF_UP
, IFF_UP
);
2114 error
= ifnet_ioctl(port_ifp
, 0, SIOCSIFFLAGS
, NULL
);
2116 printf("bond_add_interface(%s, %s): SIOCSIFFLAGS failed %d\n",
2117 ifb
->ifb_name
, bondport_get_name(p
), error
);
2121 /* re-program the port's ethernet address */
2122 error
= if_siflladdr(port_ifp
,
2123 (const struct ether_addr
*)IF_LLADDR(ifp
));
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
);
2130 progress
|= BOND_ADD_PROGRESS_LLADDR_SET
;
2134 /* no failures past this point */
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
);
2142 old_array
= ifb
->ifb_distributing_array
;
2143 ifb
->ifb_distributing_array
= new_array
;
2145 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
2148 /* check if we need to generate a link status event */
2149 if (ifbond_selection(ifb
)) {
2150 event_code
= (ifb
->ifb_active_lag
== NULL
)
2153 ifb
->ifb_last_link_event
= event_code
;
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
;
2162 bondport_enable_distributing(p
);
2165 bondport_disable_distributing(p
);
2168 /* clear the busy state, and wakeup anyone waiting */
2169 ifbond_signal(ifb
, "bond_add_interface");
2171 if (event_code
!= 0) {
2172 interface_link_event(ifp
, event_code
);
2174 if (old_array
!= NULL
) {
2175 FREE(old_array
, M_BOND
);
2180 bond_assert_lock_not_held();
2182 /* if this was the first port to be added, clear our address */
2184 ifnet_set_lladdr_and_type(ifp
, NULL
, 0, IFT_IEEE8023ADLAG
);
2187 if (new_array
!= NULL
) {
2188 FREE(new_array
, M_BOND
);
2190 if ((progress
& BOND_ADD_PROGRESS_LLADDR_SET
) != 0) {
2193 error1
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2195 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2196 ifb
->ifb_name
, bondport_get_name(p
), error1
);
2199 if ((progress
& BOND_ADD_PROGRESS_PROTO_ATTACHED
) != 0) {
2200 (void)bond_detach_protocol(port_ifp
);
2202 if ((progress
& BOND_ADD_PROGRESS_MTU_SET
) != 0) {
2205 error1
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
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
);
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
--;
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);
2225 ifbond_signal(ifb
, "bond_add_interface");
2227 ifbond_release(ifb
);
2233 bond_remove_interface(ifbond_ref ifb
, struct ifnet
* port_ifp
)
2238 bondport_ref head_port
;
2241 int new_link_address
= FALSE
;
2243 lacp_actor_partner_state s
;
2244 int was_distributing
;
2246 bond_assert_lock_held();
2249 ifbond_wait(ifb
, "bond_remove_interface");
2251 p
= ifbond_lookup_port(ifb
, port_ifp
);
2254 /* it got removed by another thread */
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
);
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
);
2277 TAILQ_REMOVE(&ifb
->ifb_port_list
, p
, po_port_list
);
2278 ifb
->ifb_port_count
--;
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
) {
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
;
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
)
2301 ifb
->ifb_last_link_event
= event_code
;
2303 bondport_transmit_machine(p
, LAEventStart
,
2304 TRANSMIT_MACHINE_TX_IMMEDIATE
);
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
;
2316 ifnet_set_lladdr_and_type(ifp
, NULL
, 0, IFT_IEEE8023ADLAG
);
2318 else if (new_link_address
) {
2319 struct ifnet
* scan_ifp
;
2320 bondport_ref scan_port
;
2322 /* ifbond_wait() allows port list traversal without holding the lock */
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
,
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
;
2333 error
= if_siflladdr(scan_ifp
,
2334 (const struct ether_addr
*) IF_LLADDR(ifp
));
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
);
2344 /* restore the port's ethernet address */
2345 error
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2347 printf("bond_remove_interface(%s, %s): if_siflladdr failed %d\n",
2348 ifb
->ifb_name
, bondport_get_name(p
), error
);
2351 /* restore the port's MTU */
2352 error
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
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
);
2359 /* remove the bond "protocol" */
2360 bond_detach_protocol(port_ifp
);
2362 /* generate link event */
2363 if (event_code
!= 0) {
2364 interface_link_event(ifp
, event_code
);
2369 ifnet_set_eflags(port_ifp
, 0, IFEF_BOND
);
2370 /* release this bondport's reference to the ifbond */
2371 ifbond_release(ifb
);
2374 ifbond_signal(ifb
, "bond_remove_interface");
2375 ifbond_release(ifb
);
2380 bond_set_lacp_mode(ifbond_ref ifb
)
2384 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2385 bondport_disable_distributing(p
);
2392 bond_set_static_mode(ifbond_ref ifb
)
2395 lacp_actor_partner_state s
;
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
);
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
);
2414 p
->po_actor_state
= 0;
2415 bzero(&p
->po_partner_state
, sizeof(p
->po_partner_state
));
2417 if (media_active(&p
->po_media_info
)) {
2418 bondport_enable_distributing(p
);
2421 bondport_disable_distributing(p
);
2428 bond_set_mode(struct ifnet
* ifp
, int mode
)
2435 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2436 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2438 return ((ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
);
2440 if (ifb
->ifb_mode
== mode
) {
2446 ifbond_wait(ifb
, "bond_set_mode");
2448 /* verify (again) that the mode is actually different */
2449 if (ifb
->ifb_mode
== mode
) {
2454 ifb
->ifb_mode
= mode
;
2455 if (mode
== IF_BOND_MODE_LACP
) {
2456 bond_set_lacp_mode(ifb
);
2458 /* check if we need to generate a link status event */
2459 if (ifbond_selection(ifb
)) {
2460 event_code
= (ifb
->ifb_active_lag
== NULL
)
2465 bond_set_static_mode(ifb
);
2466 event_code
= (ifb
->ifb_distributing_count
== 0)
2470 ifb
->ifb_last_link_event
= event_code
;
2473 ifbond_signal(ifb
, "bond_set_mode");
2475 ifbond_release(ifb
);
2477 if (event_code
!= 0) {
2478 interface_link_event(ifp
, event_code
);
2484 bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
, user_addr_t datap
)
2489 struct if_bond_status_req
* ibsr
;
2490 struct if_bond_status ibs
;
2493 ibsr
= &(ibr_p
->ibr_ibru
.ibru_status
);
2494 if (ibsr
->ibsr_version
!= IF_BOND_STATUS_REQ_VERSION
) {
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 */
2507 if (ibsr
->ibsr_count
< 0) {
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
;
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
;
2535 /* fake the selected information */
2536 ibs
.ibs_selected_state
= bondport_flags_distributing(port
)
2537 ? SelectedState_SELECTED
: SelectedState_UNSELECTED
;
2539 error
= copyout(&ibs
, dst
, sizeof(ibs
));
2549 error
= copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2552 (void)copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2558 bond_set_promisc(__unused
struct ifnet
*ifp
)
2565 bond_get_mtu_values(ifbond_ref ifb
, int * ret_min
, int * ret_max
)
2571 if (TAILQ_FIRST(&ifb
->ifb_port_list
) != NULL
) {
2572 mtu_min
= IF_MINMTU
;
2574 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2575 struct ifdevmtu
* devmtu_p
= &p
->po_devmtu
;
2577 if (devmtu_p
->ifdm_min
> mtu_min
) {
2578 mtu_min
= devmtu_p
->ifdm_min
;
2580 if (mtu_max
== 0 || devmtu_p
->ifdm_max
< mtu_max
) {
2581 mtu_max
= devmtu_p
->ifdm_max
;
2590 bond_set_mtu_on_ports(ifbond_ref ifb
, int mtu
)
2595 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2596 error
= siocsifmtu(p
->po_ifp
, mtu
);
2598 printf("if_bond(%s): SIOCSIFMTU %s failed, %d\n",
2599 ifb
->ifb_name
, bondport_get_name(p
), error
);
2607 bond_set_mtu(struct ifnet
* ifp
, int mtu
, int isdevmtu
)
2617 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2618 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2619 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2623 ifbond_wait(ifb
, "bond_set_mtu");
2626 if (ifnet_softc(ifp
) == NULL
|| ifbond_flags_if_detaching(ifb
)) {
2630 bond_get_mtu_values(ifb
, &mtu_min
, &mtu_max
);
2631 if (mtu
> mtu_max
) {
2635 if (mtu
< mtu_min
&& (isdevmtu
== 0 || mtu
!= 0)) {
2636 /* allow SIOCSIFALTMTU to set the mtu to 0 */
2641 new_max
= (mtu
> (int)ifnet_mtu(ifp
)) ? mtu
: (int)ifnet_mtu(ifp
);
2644 new_max
= (mtu
> ifb
->ifb_altmtu
) ? mtu
: ifb
->ifb_altmtu
;
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 */
2651 error
= bond_set_mtu_on_ports(ifb
, new_max
);
2653 /* try our best to back out of it */
2654 (void)bond_set_mtu_on_ports(ifb
, old_max
);
2660 ifb
->ifb_altmtu
= mtu
;
2663 ifnet_set_mtu(ifp
, mtu
);
2668 ifbond_signal(ifb
, "bond_set_mtu");
2669 ifbond_release(ifb
);
2677 bond_ioctl(struct ifnet
*ifp
, u_long cmd
, void * data
)
2680 struct if_bond_req ibr
;
2681 struct ifaddr
* ifa
;
2684 struct ifmediareq
*ifmr
;
2685 struct ifnet
* port_ifp
= NULL
;
2686 user_addr_t user_addr
;
2688 if (ifnet_type(ifp
) != IFT_IEEE8023ADLAG
) {
2689 return (EOPNOTSUPP
);
2691 ifr
= (struct ifreq
*)data
;
2692 ifa
= (struct ifaddr
*)data
;
2696 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
2699 case SIOCGIFMEDIA32
:
2700 case SIOCGIFMEDIA64
:
2702 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2703 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2705 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2707 ifmr
= (struct ifmediareq
*)data
;
2708 ifmr
->ifm_current
= IFM_ETHER
;
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
;
2719 else if (ifb
->ifb_distributing_count
> 0) {
2721 = ifb
->ifb_distributing_array
[0]->po_media_info
.mi_active
;
2722 ifmr
->ifm_status
|= IFM_ACTIVE
;
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
,
2736 /* XXX send the SIFMEDIA to all children? Or force autoselect? */
2742 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2743 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2745 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
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
);
2756 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2757 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2759 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2762 ifr
->ifr_mtu
= ifb
->ifb_altmtu
;
2767 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 1);
2771 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 0);
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
));
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
) {
2789 if (ifnet_type(port_ifp
) != IFT_ETHER
) {
2790 error
= EPROTONOSUPPORT
;
2794 case IF_BOND_OP_SET_VERBOSE
:
2795 case IF_BOND_OP_SET_MODE
:
2804 switch (ibr
.ibr_op
) {
2805 case IF_BOND_OP_ADD_INTERFACE
:
2806 error
= bond_add_interface(ifp
, port_ifp
);
2808 case IF_BOND_OP_REMOVE_INTERFACE
:
2810 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2811 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2813 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2815 error
= bond_remove_interface(ifb
, port_ifp
);
2818 case IF_BOND_OP_SET_VERBOSE
:
2820 if (g_bond
== NULL
) {
2825 g_bond
->verbose
= ibr
.ibr_ibru
.ibru_int_val
;
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
:
2840 error
= bond_set_mode(ifp
, ibr
.ibr_ibru
.ibru_int_val
);
2843 break; /* SIOCSIFBOND */
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
));
2852 switch (ibr
.ibr_op
) {
2853 case IF_BOND_OP_GET_STATUS
:
2863 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2864 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2866 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2868 switch (ibr
.ibr_op
) {
2869 case IF_BOND_OP_GET_STATUS
:
2870 error
= bond_get_status(ifb
, &ibr
, user_addr
);
2874 break; /* SIOCGIFBOND */
2881 /* enable/disable promiscuous mode */
2883 error
= bond_set_promisc(ifp
);
2889 error
= bond_setmulti(ifp
);
2898 bond_if_free(struct ifnet
* ifp
)
2906 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2911 ifbond_release(ifb
);
2918 bond_handle_event(struct ifnet
* port_ifp
, int event_code
)
2920 struct ifnet
* bond_ifp
= NULL
;
2922 int old_distributing_count
;
2924 struct media_info media_info
= { 0, 0};
2926 switch (event_code
) {
2927 case KEV_DL_IF_DETACHED
:
2929 case KEV_DL_LINK_OFF
:
2930 case KEV_DL_LINK_ON
:
2931 media_info
= interface_media_info(port_ifp
);
2937 p
= bond_lookup_port(port_ifp
);
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
);
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
);
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
)
2962 /* XXX need to take a reference on bond_ifp */
2963 bond_ifp
= ifb
->ifb_ifp
;
2964 ifb
->ifb_last_link_event
= event_code
;
2967 event_code
= (ifb
->ifb_active_lag
== NULL
)
2970 if (event_code
!= ifb
->ifb_last_link_event
) {
2971 if (g_bond
->verbose
) {
2972 timestamp_printf("%s: (event) generating LINK event\n",
2975 bond_ifp
= ifb
->ifb_ifp
;
2976 ifb
->ifb_last_link_event
= event_code
;
2982 * if the distributing array membership changed from 0 <-> !0
2983 * generate a link event
2985 if (old_distributing_count
== 0
2986 && ifb
->ifb_distributing_count
!= 0) {
2987 event_code
= KEV_DL_LINK_ON
;
2989 else if (old_distributing_count
!= 0
2990 && ifb
->ifb_distributing_count
== 0) {
2991 event_code
= KEV_DL_LINK_OFF
;
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
;
3000 if (bond_ifp
!= NULL
) {
3001 interface_link_event(bond_ifp
, event_code
);
3007 bond_event(struct ifnet
* port_ifp
, __unused protocol_family_t protocol
,
3008 const struct kev_msg
* event
)
3012 if (event
->vendor_code
!= KEV_VENDOR_APPLE
3013 || event
->kev_class
!= KEV_NETWORK_CLASS
3014 || event
->kev_subclass
!= KEV_DL_SUBCLASS
) {
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
);
3031 bond_detached(ifnet_t port_ifp
, __unused protocol_family_t protocol
)
3033 bond_handle_event(port_ifp
, KEV_DL_IF_DETACHED
);
3038 interface_link_event(struct ifnet
* ifp
, u_int32_t event_code
)
3041 struct kern_event_msg header
;
3043 char if_name
[IFNAMSIZ
];
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
);
3060 * Function: bond_attach_protocol
3062 * Attach a DLIL protocol to the interface.
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
3070 bond_attach_protocol(struct ifnet
*ifp
)
3073 struct ifnet_attach_proto_param reg
;
3075 bzero(®
, sizeof(reg
));
3076 reg
.input
= bond_input
;
3077 reg
.event
= bond_event
;
3078 reg
.detached
= bond_detached
;
3080 error
= ifnet_attach_protocol(ifp
, PF_BOND
, ®
);
3082 printf("bond over %s%d: ifnet_attach_protocol failed, %d\n",
3083 ifnet_name(ifp
), ifnet_unit(ifp
), error
);
3089 * Function: bond_detach_protocol
3091 * Detach our DLIL protocol from an interface
3094 bond_detach_protocol(struct ifnet
*ifp
)
3098 error
= ifnet_detach_protocol(ifp
, PF_BOND
);
3100 printf("bond over %s%d: ifnet_detach_protocol failed, %d\n",
3101 ifnet_name(ifp
), ifnet_unit(ifp
), error
);
3107 * DLIL interface family functions
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
);
3116 __private_extern__
int
3117 bond_family_init(void)
3121 error
= proto_register_plumber(PF_INET
, APPLE_IF_FAM_BOND
,
3125 printf("bond: proto_register_plumber failed for AF_INET error=%d\n",
3130 error
= proto_register_plumber(PF_INET6
, APPLE_IF_FAM_BOND
,
3132 ether_detach_inet6
);
3134 printf("bond: proto_register_plumber failed for AF_INET6 error=%d\n",
3139 error
= bond_clone_attach();
3141 printf("bond: proto_register_plumber failed bond_clone_attach error=%d\n",
3156 ** LACP ifbond_list routines
3159 ifbond_list_find_moved_port(bondport_ref rx_port
,
3160 const lacp_actor_partner_tlv_ref atlv
)
3164 partner_state_ref ps
;
3167 TAILQ_FOREACH(bond
, &g_bond
->ifbond_list
, ifb_bond_list
) {
3168 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3171 /* no point in comparing against ourselves */
3174 if (p
->po_receive_state
!= ReceiveState_PORT_DISABLED
) {
3175 /* it's not clear that we should be checking this */
3178 ps
= &p
->po_partner_state
;
3179 if (lacp_actor_partner_state_defaulted(ps
->ps_state
)) {
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
));
3201 ** LACP ifbond, LAG routines
3205 ifbond_selection(ifbond_ref bond
)
3207 int all_ports_ready
= 0;
3208 int active_media
= 0;
3210 int lag_changed
= 0;
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
;
3220 bond
->ifb_active_lag
= lag
;
3222 ifbond_activate_LAG(bond
, lag
, active_media
);
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
));
3233 ifbond_deactivate_LAG(bond
, lag
);
3234 ifbond_activate_LAG(bond
, lag
, active_media
);
3239 port_speed
= link_speed(active_media
);
3240 all_ports_ready
= ifbond_all_ports_ready(bond
);
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
);
3256 else if (p
->po_selected
== SelectedState_UNSELECTED
) {
3257 bondport_set_selected(p
, SelectedState_STANDBY
);
3261 bondport_set_selected(p
, SelectedState_SELECTED
);
3264 if (bondport_flags_selected_changed(p
)) {
3265 bondport_flags_clear_selected_changed(p
);
3266 bondport_mux_machine(p
, LAEventSelectedChange
, NULL
);
3269 && bondport_flags_ready(p
)
3270 && p
->po_mux_state
== MuxState_WAITING
) {
3271 bondport_mux_machine(p
, LAEventReady
, NULL
);
3273 bondport_transmit_machine(p
, LAEventStart
, NULL
);
3275 return (lag_changed
);
3279 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
)
3281 int best_active
= 0;
3282 LAG_ref best_lag
= NULL
;
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
;
3294 best_speed
= link_speed(best_active
);
3296 TAILQ_FOREACH(lag
, &bond
->ifb_lag_list
, lag_list
) {
3301 if (lag
== bond
->ifb_active_lag
) {
3302 /* we've already computed it */
3305 count
= LAG_get_aggregatable_port_count(lag
, &active
);
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
;
3314 speed
= link_speed(active
);
3315 if ((count
* speed
) > (best_count
* best_speed
)) {
3318 best_active
= active
;
3322 if (best_count
== 0) {
3325 *active_media
= best_active
;
3330 ifbond_deactivate_LAG(__unused ifbond_ref bond
, LAG_ref lag
)
3334 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3335 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3341 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
)
3346 if (bond
->ifb_max_active
> 0) {
3347 need
= bond
->ifb_max_active
;
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
);
3354 else if (media_speed(&p
->po_media_info
) != link_speed(active_media
)) {
3355 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3357 else if (p
->po_mux_state
== MuxState_DETACHED
) {
3358 if (bond
->ifb_max_active
> 0) {
3360 bondport_set_selected(p
, SelectedState_SELECTED
);
3364 bondport_set_selected(p
, SelectedState_STANDBY
);
3368 bondport_set_selected(p
, SelectedState_SELECTED
);
3372 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3380 ifbond_set_max_active(ifbond_ref bond
, int max_active
)
3382 LAG_ref lag
= bond
->ifb_active_lag
;
3384 bond
->ifb_max_active
= max_active
;
3385 if (bond
->ifb_max_active
<= 0 || lag
== NULL
) {
3388 if (lag
->lag_selected_port_count
> bond
->ifb_max_active
) {
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
);
3397 if (remove_count
== 0) {
3408 ifbond_all_ports_ready(ifbond_ref bond
)
3413 if (bond
->ifb_active_lag
== NULL
) {
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) {
3423 /* note that there was at least one ready port */
3430 ifbond_all_ports_attached(ifbond_ref bond
, bondport_ref this_port
)
3434 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3435 if (this_port
== p
) {
3438 if (bondport_flags_mux_attached(p
) == 0) {
3446 ifbond_get_LAG_matching_port(ifbond_ref bond
, bondport_ref p
)
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) {
3460 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
)
3470 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3471 if (bondport_aggregatable(p
)) {
3474 this_speed
= media_speed(&p
->po_media_info
);
3475 if (this_speed
== 0) {
3478 if (this_speed
> speed
) {
3479 active
= p
->po_media_info
.mi_active
;
3483 else if (this_speed
== speed
) {
3488 *active_media
= active
;
3494 ** LACP bondport routines
3497 bondport_link_status_changed(bondport_ref p
)
3499 ifbond_ref bond
= p
->po_bond
;
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
)
3510 timestamp_printf("[%s] Link DOWN\n", bondport_get_name(p
));
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
));
3525 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3528 bondport_receive_machine(p
, LAEventMediaChange
, NULL
);
3529 bondport_mux_machine(p
, LAEventMediaChange
, NULL
);
3530 bondport_periodic_transmit_machine(p
, LAEventMediaChange
, NULL
);
3533 if (media_active(&p
->po_media_info
)) {
3534 bondport_enable_distributing(p
);
3537 bondport_disable_distributing(p
);
3544 bondport_aggregatable(bondport_ref p
)
3546 partner_state_ref ps
= &p
->po_partner_state
;
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 */
3553 if (p
->po_lag
== NULL
) {
3556 switch (p
->po_receive_state
) {
3558 if (g_bond
->verbose
) {
3559 timestamp_printf("[%s] Port is not selectable\n",
3560 bondport_get_name(p
));
3563 case ReceiveState_CURRENT
:
3564 case ReceiveState_EXPIRED
:
3571 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
)
3573 LAG_info_ref lag_li
;
3574 partner_state_ref ps
;
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
))
3591 bondport_remove_from_LAG(bondport_ref p
)
3594 ifbond_ref bond
= p
->po_bond
;
3595 LAG_ref lag
= p
->po_lag
;
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
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
);
3610 lag
->lag_port_count
--;
3611 if (lag
->lag_port_count
> 0) {
3612 return (bond
->ifb_active_lag
== lag
);
3614 if (g_bond
->verbose
) {
3615 timestamp_printf("Key 0x%04x: LAG Released (%04x," EA_FORMAT
3618 lag
->lag_info
.li_system_priority
,
3619 EA_LIST(&lag
->lag_info
.li_system
),
3620 lag
->lag_info
.li_key
);
3622 TAILQ_REMOVE(&bond
->ifb_lag_list
, lag
, lag_list
);
3623 if (bond
->ifb_active_lag
== lag
) {
3624 bond
->ifb_active_lag
= NULL
;
3628 return (active_lag
);
3632 bondport_add_to_LAG(bondport_ref p
, LAG_ref lag
)
3634 TAILQ_INSERT_TAIL(&lag
->lag_port_list
, p
, po_lag_port_list
);
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
);
3648 bondport_assign_to_LAG(bondport_ref p
)
3650 ifbond_ref bond
= p
->po_bond
;
3653 if (lacp_actor_partner_state_defaulted(p
->po_actor_state
)) {
3654 bondport_remove_from_LAG(p
);
3659 if (bondport_matches_LAG(p
, lag
)) {
3663 bondport_remove_from_LAG(p
);
3665 lag
= ifbond_get_LAG_matching_port(bond
, p
);
3667 bondport_add_to_LAG(p
, lag
);
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
3680 lag
->lag_info
.li_system_priority
,
3681 EA_LIST(&lag
->lag_info
.li_system
),
3682 lag
->lag_info
.li_key
);
3684 bondport_add_to_LAG(p
, lag
);
3689 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
)
3691 bondport_ref 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
);
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
);
3706 bondport_set_selected(bondport_ref p
, SelectedState s
)
3708 if (s
!= p
->po_selected
) {
3709 ifbond_ref bond
= p
->po_bond
;
3710 LAG_ref lag
= p
->po_lag
;
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
--;
3717 else if (s
== SelectedState_SELECTED
) {
3718 lag
->lag_selected_port_count
++;
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
));
3737 bondport_UpdateDefaultSelected(bondport_ref p
)
3739 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3744 bondport_RecordDefault(bondport_ref p
)
3746 bzero(&p
->po_partner_state
, sizeof(p
->po_partner_state
));
3748 = lacp_actor_partner_state_set_defaulted(p
->po_actor_state
);
3749 bondport_assign_to_LAG(p
);
3754 bondport_UpdateSelected(bondport_ref p
, lacpdu_ref lacpdu_p
)
3756 lacp_actor_partner_tlv_ref actor
;
3757 partner_state_ref ps
;
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
));
3783 bondport_RecordPDU(bondport_ref p
, lacpdu_ref lacpdu_p
)
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
;
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
);
3804 = lacp_actor_partner_state_set_not_defaulted(p
->po_actor_state
);
3806 /* compare the PDU's Partner information to our own information */
3807 partner
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_partner_tlv
;
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
));
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
)
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
));
3836 else if (lacp_actor_partner_state_aggregatable(actor
->lap_state
) == 0
3837 && lacp_actor_partner_state_in_sync(actor
->lap_state
)
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
));
3845 bondport_assign_to_LAG(p
);
3849 static __inline__ lacp_actor_partner_state
3850 updateNTTBits(lacp_actor_partner_state s
)
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
));
3859 bondport_UpdateNTT(bondport_ref p
, lacpdu_ref lacpdu_p
)
3861 ifbond_ref bond
= p
->po_bond
;
3862 lacp_actor_partner_tlv_ref partner
;
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
));
3884 bondport_AttachMuxToAggregator(bondport_ref p
)
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
));
3891 bondport_flags_set_mux_attached(p
);
3897 bondport_DetachMuxFromAggregator(bondport_ref p
)
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
));
3904 bondport_flags_clear_mux_attached(p
);
3910 bondport_enable_distributing(bondport_ref p
)
3912 if (bondport_flags_distributing(p
) == 0) {
3913 ifbond_ref bond
= p
->po_bond
;
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
));
3920 bondport_flags_set_distributing(p
);
3926 bondport_disable_distributing(bondport_ref p
)
3928 if (bondport_flags_distributing(p
)) {
3929 bondport_ref
* array
;
3935 array
= bond
->ifb_distributing_array
;
3936 count
= bond
->ifb_distributing_count
;
3937 for (i
= 0; i
< count
; i
++) {
3938 if (array
[i
] == p
) {
3941 for (j
= i
; j
< (count
- 1); j
++) {
3942 array
[j
] = array
[j
+ 1];
3947 bond
->ifb_distributing_count
--;
3948 if (g_bond
->verbose
) {
3949 timestamp_printf("[%s] Distribution Disabled\n",
3950 bondport_get_name(p
));
3952 bondport_flags_clear_distributing(p
);
3958 ** Receive machine functions
3961 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
3964 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
3967 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
3970 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
3973 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
3976 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
3980 bondport_receive_machine_event(bondport_ref p
, LAEvent event
,
3983 switch (p
->po_receive_state
) {
3984 case ReceiveState_none
:
3985 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
3987 case ReceiveState_INITIALIZE
:
3988 bondport_receive_machine_initialize(p
, event
, event_data
);
3990 case ReceiveState_PORT_DISABLED
:
3991 bondport_receive_machine_port_disabled(p
, event
, event_data
);
3993 case ReceiveState_EXPIRED
:
3994 bondport_receive_machine_expired(p
, event
, event_data
);
3996 case ReceiveState_LACP_DISABLED
:
3997 bondport_receive_machine_lacp_disabled(p
, event
, event_data
);
3999 case ReceiveState_DEFAULTED
:
4000 bondport_receive_machine_defaulted(p
, event
, event_data
);
4002 case ReceiveState_CURRENT
:
4003 bondport_receive_machine_current(p
, event
, event_data
);
4012 bondport_receive_machine(bondport_ref p
, LAEvent event
,
4017 if (p
->po_receive_state
!= ReceiveState_LACP_DISABLED
) {
4018 bondport_receive_machine_current(p
, event
, event_data
);
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
);
4033 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
4037 bondport_receive_machine_event(p
, event
, event_data
);
4044 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
4045 __unused
void * event_data
)
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
));
4054 p
->po_receive_state
= ReceiveState_INITIALIZE
;
4055 bondport_set_selected(p
, SelectedState_UNSELECTED
);
4056 bondport_RecordDefault(p
);
4058 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4059 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
4068 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
4069 __unused
void * event_data
)
4071 partner_state_ref ps
;
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
));
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
);
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
);
4090 bondport_receive_machine_lacp_disabled(p
, LAEventStart
, NULL
);
4093 else if (p
->po_selected
== SelectedState_SELECTED
) {
4096 if (g_bond
->verbose
) {
4097 timestamp_printf("[%s] Receive PORT_DISABLED: "
4098 "link timer started\n",
4099 bondport_get_name(p
));
4103 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4104 (devtimer_timeout_func
)
4105 bondport_receive_machine_port_disabled
,
4106 (void *)LAEventTimeout
, NULL
);
4108 else if (p
->po_selected
== SelectedState_STANDBY
) {
4109 bondport_set_selected(p
, SelectedState_UNSELECTED
);
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
));
4119 bondport_set_selected(p
, SelectedState_UNSELECTED
);
4122 case LAEventPortMoved
:
4123 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
4132 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
4133 __unused
void * event_data
)
4135 lacp_actor_partner_state s
;
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
));
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
;
4151 = lacp_actor_partner_state_set_expired(p
->po_actor_state
);
4152 /* start current_while timer */
4153 tv
.tv_sec
= LACP_SHORT_TIMEOUT_TIME
;
4155 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4156 (devtimer_timeout_func
)
4157 bondport_receive_machine_expired
,
4158 (void *)LAEventTimeout
, NULL
);
4161 case LAEventTimeout
:
4162 bondport_receive_machine_defaulted(p
, LAEventStart
, NULL
);
4171 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
4172 __unused
void * event_data
)
4174 partner_state_ref ps
;
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
));
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
);
4188 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4197 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
4198 __unused
void * event_data
)
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
));
4207 p
->po_receive_state
= ReceiveState_DEFAULTED
;
4208 bondport_UpdateDefaultSelected(p
);
4209 bondport_RecordDefault(p
);
4211 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4220 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
4223 partner_state_ref ps
;
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
));
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
);
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
;
4246 tv
.tv_sec
= LACP_LONG_TIMEOUT_TIME
;
4249 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4250 (devtimer_timeout_func
)
4251 bondport_receive_machine_current
,
4252 (void *)LAEventTimeout
, NULL
);
4254 case LAEventTimeout
:
4255 bondport_receive_machine_expired(p
, LAEventStart
, NULL
);
4264 ** Periodic Transmission machine
4268 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
4269 __unused
void * event_data
)
4272 partner_state_ref ps
;
4277 if (g_bond
->verbose
) {
4278 timestamp_printf("[%s] periodic_transmit Start\n",
4279 bondport_get_name(p
));
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) {
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
)
4295 devtimer_cancel(p
->po_periodic_timer
);
4296 p
->po_periodic_interval
= 0;
4299 if (lacp_actor_partner_state_short_timeout(ps
->ps_state
)) {
4300 interval
= LACP_FAST_PERIODIC_TIME
;
4303 interval
= LACP_SLOW_PERIODIC_TIME
;
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
));
4313 bondport_flags_set_ntt(p
);
4315 p
->po_periodic_interval
= interval
;
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
);
4329 case LAEventTimeout
:
4330 bondport_flags_set_ntt(p
);
4331 tv
.tv_sec
= p
->po_periodic_interval
;
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
);
4351 bondport_can_transmit(bondport_ref p
, int32_t current_secs
,
4352 __darwin_time_t
* next_secs
)
4354 if (p
->po_last_transmit_secs
!= current_secs
) {
4355 p
->po_last_transmit_secs
= current_secs
;
4356 p
->po_n_transmit
= 0;
4358 if (p
->po_n_transmit
< LACP_PACKET_RATE
) {
4362 if (next_secs
!= NULL
) {
4363 *next_secs
= current_secs
+ 1;
4369 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
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
;
4381 case LAEventTimeout
:
4383 if (p
->po_periodic_interval
== 0 || bondport_flags_ntt(p
) == 0) {
4386 if (event_data
== TRANSMIT_MACHINE_TX_IMMEDIATE
) {
4387 /* we're going away, transmit the packet no matter what */
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
));
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
);
4410 if (g_bond
->verbose
> 0) {
4411 if (event
== LAEventTimeout
) {
4412 timestamp_printf("[%s] Transmit Timer Complete\n",
4413 bondport_get_name(p
));
4416 pkt
= packet_buffer_allocate(sizeof(*out_lacpdu_p
));
4418 printf("[%s] Transmit: failed to allocate packet buffer\n",
4419 bondport_get_name(p
));
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
;
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
;
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
;
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
;
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
);
4472 ** Mux machine functions
4476 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4479 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4482 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4486 bondport_mux_machine_collecting_distributing(bondport_ref p
, LAEvent event
,
4490 bondport_mux_machine(bondport_ref p
, LAEvent event
, void * event_data
)
4492 switch (p
->po_mux_state
) {
4494 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4496 case MuxState_DETACHED
:
4497 bondport_mux_machine_detached(p
, event
, event_data
);
4499 case MuxState_WAITING
:
4500 bondport_mux_machine_waiting(p
, event
, event_data
);
4502 case MuxState_ATTACHED
:
4503 bondport_mux_machine_attached(p
, event
, event_data
);
4505 case MuxState_COLLECTING_DISTRIBUTING
:
4506 bondport_mux_machine_collecting_distributing(p
, event
, event_data
);
4515 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4516 __unused
void * event_data
)
4518 lacp_actor_partner_state s
;
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
));
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
);
4538 case LAEventSelectedChange
:
4540 case LAEventMediaChange
:
4541 if (p
->po_selected
== SelectedState_SELECTED
4542 || p
->po_selected
== SelectedState_STANDBY
) {
4543 bondport_mux_machine_waiting(p
, LAEventStart
, NULL
);
4553 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4554 __unused
void * event_data
)
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
));
4565 p
->po_mux_state
= MuxState_WAITING
;
4568 case LAEventSelectedChange
:
4569 if (p
->po_selected
== SelectedState_UNSELECTED
) {
4570 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
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
));
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
));
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
));
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
));
4602 bondport_flags_set_ready(p
);
4605 if (g_bond
->verbose
) {
4606 timestamp_printf("[%s] Mux WAITING: 2 seconds\n",
4607 bondport_get_name(p
));
4609 tv
.tv_sec
= LACP_AGGREGATE_WAIT_TIME
;
4611 devtimer_set_relative(p
->po_wait_while_timer
, tv
,
4612 (devtimer_timeout_func
)
4613 bondport_mux_machine_waiting
,
4614 (void *)LAEventTimeout
, NULL
);
4616 case LAEventTimeout
:
4617 if (g_bond
->verbose
) {
4618 timestamp_printf("[%s] Mux WAITING: Ready\n",
4619 bondport_get_name(p
));
4621 bondport_flags_set_ready(p
);
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
));
4630 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);
4639 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4640 __unused
void * event_data
)
4642 lacp_actor_partner_state s
;
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
));
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
);
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
,
4671 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4680 bondport_mux_machine_collecting_distributing(bondport_ref p
,
4682 __unused
void * event_data
)
4684 lacp_actor_partner_state s
;
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
));
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
);
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
);
4707 switch (p
->po_selected
) {
4708 case SelectedState_UNSELECTED
:
4709 case SelectedState_STANDBY
:
4710 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);