2 * Copyright (c) 2004-2020 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/kpi_interfacefilter.h>
57 #include <net/if_arp.h>
58 #include <net/if_dl.h>
59 #include <net/if_ether.h>
60 #include <net/if_types.h>
61 #include <net/if_bond_var.h>
62 #include <net/ieee8023ad.h>
66 #include <net/devtimer.h>
67 #include <net/if_vlan_var.h>
68 #include <net/kpi_protocol.h>
69 #include <sys/protosw.h>
70 #include <kern/locks.h>
71 #include <kern/zalloc.h>
72 #include <os/refcnt.h>
74 #include <netinet/in.h>
75 #include <netinet/if_ether.h>
76 #include <netinet/in_systm.h>
77 #include <netinet/ip.h>
78 #include <netinet/ip6.h>
80 #include <net/if_media.h>
81 #include <net/multicast_list.h>
83 SYSCTL_DECL(_net_link
);
84 SYSCTL_NODE(_net_link
, OID_AUTO
, bond
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0,
87 static int if_bond_debug
= 0;
88 SYSCTL_INT(_net_link_bond
, OID_AUTO
, debug
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
89 &if_bond_debug
, 0, "Bond interface debug logs");
91 static struct ether_addr slow_proto_multicast
= {
92 .octet
= IEEE8023AD_SLOW_PROTO_MULTICAST
95 typedef struct ifbond_s ifbond
, * ifbond_ref
;
96 typedef struct bondport_s bondport
, * bondport_ref
;
98 #define BOND_MAXUNIT 128
99 #define BOND_ZONE_MAX_ELEM MIN(IFNETS_MAX, BOND_MAXUNIT)
100 #define BONDNAME "bond"
102 #define M_BOND M_DEVBUF
104 #define EA_FORMAT "%x:%x:%x:%x:%x:%x"
105 #define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)])
106 #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)
108 #define timestamp_printf printf
113 static __inline__ lck_grp_t
*
114 my_lck_grp_alloc_init(const char * grp_name
)
117 lck_grp_attr_t
* grp_attrs
;
119 grp_attrs
= lck_grp_attr_alloc_init();
120 grp
= lck_grp_alloc_init(grp_name
, grp_attrs
);
121 lck_grp_attr_free(grp_attrs
);
125 static __inline__ lck_mtx_t
*
126 my_lck_mtx_alloc_init(lck_grp_t
* lck_grp
)
128 lck_attr_t
* lck_attrs
;
131 lck_attrs
= lck_attr_alloc_init();
132 lck_mtx
= lck_mtx_alloc_init(lck_grp
, lck_attrs
);
133 lck_attr_free(lck_attrs
);
137 static lck_mtx_t
* bond_lck_mtx
;
139 static __inline__
void
142 lck_grp_t
* bond_lck_grp
;
144 bond_lck_grp
= my_lck_grp_alloc_init("if_bond");
145 bond_lck_mtx
= my_lck_mtx_alloc_init(bond_lck_grp
);
148 static __inline__
void
149 bond_assert_lock_held(void)
151 LCK_MTX_ASSERT(bond_lck_mtx
, LCK_MTX_ASSERT_OWNED
);
155 static __inline__
void
156 bond_assert_lock_not_held(void)
158 LCK_MTX_ASSERT(bond_lck_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
162 static __inline__
void
165 lck_mtx_lock(bond_lck_mtx
);
169 static __inline__
void
172 lck_mtx_unlock(bond_lck_mtx
);
177 ** bond structures, types
181 lacp_system li_system
;
182 lacp_system_priority li_system_priority
;
185 typedef struct LAG_info_s LAG_info
, * LAG_info_ref
;
188 TAILQ_HEAD(port_list
, bondport_s
);
190 TAILQ_HEAD(ifbond_list
, ifbond_s
);
192 TAILQ_HEAD(lag_list
, LAG_s
);
194 typedef struct ifbond_s ifbond
, * ifbond_ref
;
195 typedef struct bondport_s bondport
, * bondport_ref
;
198 TAILQ_ENTRY(LAG_s
) lag_list
;
199 struct port_list lag_port_list
;
200 short lag_port_count
;
201 short lag_selected_port_count
;
202 int lag_active_media
;
205 typedef struct LAG_s LAG
, * LAG_ref
;
207 typedef struct partner_state_s
{
208 LAG_info ps_lag_info
;
210 lacp_port_priority ps_port_priority
;
211 lacp_actor_partner_state ps_state
;
212 } partner_state
, * partner_state_ref
;
215 TAILQ_ENTRY(ifbond_s
) ifb_bond_list
;
217 struct os_refcnt ifb_retain_count
;
218 char ifb_name
[IFNAMSIZ
];
219 struct ifnet
* ifb_ifp
;
220 bpf_packet_func ifb_bpf_input
;
221 bpf_packet_func ifb_bpf_output
;
223 struct port_list ifb_port_list
;
224 short ifb_port_count
;
225 struct lag_list ifb_lag_list
;
227 short ifb_max_active
;/* 0 == unlimited */
228 LAG_ref ifb_active_lag
;
229 struct ifmultiaddr
* ifb_ifma_slow_proto
;
230 bondport_ref
* ifb_distributing_array
;
231 int ifb_distributing_count
;
232 int ifb_last_link_event
;
233 int ifb_mode
;/* LACP, STATIC */
242 ReceiveState_none
= 0,
243 ReceiveState_INITIALIZE
= 1,
244 ReceiveState_PORT_DISABLED
= 2,
245 ReceiveState_EXPIRED
= 3,
246 ReceiveState_LACP_DISABLED
= 4,
247 ReceiveState_DEFAULTED
= 5,
248 ReceiveState_CURRENT
= 6,
251 typedef u_char ReceiveState
;
254 SelectedState_UNSELECTED
= IF_BOND_STATUS_SELECTED_STATE_UNSELECTED
,
255 SelectedState_SELECTED
= IF_BOND_STATUS_SELECTED_STATE_SELECTED
,
256 SelectedState_STANDBY
= IF_BOND_STATUS_SELECTED_STATE_STANDBY
258 typedef u_char SelectedState
;
260 static __inline__
const char *
261 SelectedStateString(SelectedState s
)
263 static const char * names
[] = { "UNSELECTED", "SELECTED", "STANDBY" };
265 if (s
<= SelectedState_STANDBY
) {
273 MuxState_DETACHED
= 1,
274 MuxState_WAITING
= 2,
275 MuxState_ATTACHED
= 3,
276 MuxState_COLLECTING_DISTRIBUTING
= 4,
279 typedef u_char MuxState
;
281 #define PORT_CONTROL_FLAGS_IN_LIST 0x01
282 #define PORT_CONTROL_FLAGS_PROTO_ATTACHED 0x02
283 #define PORT_CONTROL_FLAGS_FILTER_ATTACHED 0x04
284 #define PORT_CONTROL_FLAGS_LLADDR_SET 0x08
285 #define PORT_CONTROL_FLAGS_MTU_SET 0x10
286 #define PORT_CONTROL_FLAGS_PROMISCUOUS_SET 0x20
289 TAILQ_ENTRY(bondport_s
) po_port_list
;
291 struct multicast_list po_multicast
;
292 struct ifnet
* po_ifp
;
293 struct ether_addr po_saved_addr
;
295 char po_name
[IFNAMSIZ
];
296 struct ifdevmtu po_devmtu
;
297 uint32_t po_control_flags
;
298 interface_filter_t po_filter
;
301 TAILQ_ENTRY(bondport_s
) po_lag_port_list
;
302 devtimer_ref po_current_while_timer
;
303 devtimer_ref po_periodic_timer
;
304 devtimer_ref po_wait_while_timer
;
305 devtimer_ref po_transmit_timer
;
306 partner_state po_partner_state
;
307 lacp_port_priority po_priority
;
308 lacp_actor_partner_state po_actor_state
;
310 u_char po_periodic_interval
;
311 u_char po_n_transmit
;
312 ReceiveState po_receive_state
;
313 MuxState po_mux_state
;
314 SelectedState po_selected
;
315 int32_t po_last_transmit_secs
;
316 struct media_info po_media_info
;
317 uint64_t po_force_link_event_time
;
321 #define IFBF_PROMISC 0x1 /* promiscuous mode */
322 #define IFBF_IF_DETACHING 0x2 /* interface is detaching */
323 #define IFBF_LLADDR 0x4 /* specific link address requested */
324 #define IFBF_CHANGE_IN_PROGRESS 0x8 /* interface add/remove in progress */
326 static int bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
,
329 static __inline__
int
330 ifbond_flags_if_detaching(ifbond_ref ifb
)
332 return (ifb
->ifb_flags
& IFBF_IF_DETACHING
) != 0;
335 static __inline__
void
336 ifbond_flags_set_if_detaching(ifbond_ref ifb
)
338 ifb
->ifb_flags
|= IFBF_IF_DETACHING
;
342 static __inline__
int
343 ifbond_flags_lladdr(ifbond_ref ifb
)
345 return (ifb
->ifb_flags
& IFBF_LLADDR
) != 0;
348 static __inline__
int
349 ifbond_flags_change_in_progress(ifbond_ref ifb
)
351 return (ifb
->ifb_flags
& IFBF_CHANGE_IN_PROGRESS
) != 0;
354 static __inline__
void
355 ifbond_flags_set_change_in_progress(ifbond_ref ifb
)
357 ifb
->ifb_flags
|= IFBF_CHANGE_IN_PROGRESS
;
361 static __inline__
void
362 ifbond_flags_clear_change_in_progress(ifbond_ref ifb
)
364 ifb
->ifb_flags
&= ~IFBF_CHANGE_IN_PROGRESS
;
369 * bondport_ref->po_flags bits
371 #define BONDPORT_FLAGS_NTT 0x01
372 #define BONDPORT_FLAGS_READY 0x02
373 #define BONDPORT_FLAGS_SELECTED_CHANGED 0x04
374 #define BONDPORT_FLAGS_MUX_ATTACHED 0x08
375 #define BONDPORT_FLAGS_DISTRIBUTING 0x10
376 #define BONDPORT_FLAGS_UNUSED2 0x20
377 #define BONDPORT_FLAGS_UNUSED3 0x40
378 #define BONDPORT_FLAGS_UNUSED4 0x80
380 static __inline__
void
381 bondport_flags_set_ntt(bondport_ref p
)
383 p
->po_flags
|= BONDPORT_FLAGS_NTT
;
387 static __inline__
void
388 bondport_flags_clear_ntt(bondport_ref p
)
390 p
->po_flags
&= ~BONDPORT_FLAGS_NTT
;
394 static __inline__
int
395 bondport_flags_ntt(bondport_ref p
)
397 return (p
->po_flags
& BONDPORT_FLAGS_NTT
) != 0;
400 static __inline__
void
401 bondport_flags_set_ready(bondport_ref p
)
403 p
->po_flags
|= BONDPORT_FLAGS_READY
;
407 static __inline__
void
408 bondport_flags_clear_ready(bondport_ref p
)
410 p
->po_flags
&= ~BONDPORT_FLAGS_READY
;
414 static __inline__
int
415 bondport_flags_ready(bondport_ref p
)
417 return (p
->po_flags
& BONDPORT_FLAGS_READY
) != 0;
420 static __inline__
void
421 bondport_flags_set_selected_changed(bondport_ref p
)
423 p
->po_flags
|= BONDPORT_FLAGS_SELECTED_CHANGED
;
427 static __inline__
void
428 bondport_flags_clear_selected_changed(bondport_ref p
)
430 p
->po_flags
&= ~BONDPORT_FLAGS_SELECTED_CHANGED
;
434 static __inline__
int
435 bondport_flags_selected_changed(bondport_ref p
)
437 return (p
->po_flags
& BONDPORT_FLAGS_SELECTED_CHANGED
) != 0;
440 static __inline__
void
441 bondport_flags_set_mux_attached(bondport_ref p
)
443 p
->po_flags
|= BONDPORT_FLAGS_MUX_ATTACHED
;
447 static __inline__
void
448 bondport_flags_clear_mux_attached(bondport_ref p
)
450 p
->po_flags
&= ~BONDPORT_FLAGS_MUX_ATTACHED
;
454 static __inline__
int
455 bondport_flags_mux_attached(bondport_ref p
)
457 return (p
->po_flags
& BONDPORT_FLAGS_MUX_ATTACHED
) != 0;
460 static __inline__
void
461 bondport_flags_set_distributing(bondport_ref p
)
463 p
->po_flags
|= BONDPORT_FLAGS_DISTRIBUTING
;
467 static __inline__
void
468 bondport_flags_clear_distributing(bondport_ref p
)
470 p
->po_flags
&= ~BONDPORT_FLAGS_DISTRIBUTING
;
474 static __inline__
int
475 bondport_flags_distributing(bondport_ref p
)
477 return (p
->po_flags
& BONDPORT_FLAGS_DISTRIBUTING
) != 0;
480 typedef struct bond_globals_s
{
481 struct ifbond_list ifbond_list
;
483 lacp_system_priority system_priority
;
484 } * bond_globals_ref
;
486 static bond_globals_ref g_bond
;
489 ** packet_buffer routines
490 ** - thin wrapper for mbuf
493 typedef struct mbuf
* packet_buffer_ref
;
495 static packet_buffer_ref
496 packet_buffer_allocate(int length
)
501 /* leave room for ethernet header */
502 size
= length
+ sizeof(struct ether_header
);
503 if (size
> (int)MHLEN
) {
504 if (size
> (int)MCLBYTES
) {
505 printf("bond: packet_buffer_allocate size %d > max %u\n",
509 m
= m_getcl(M_WAITOK
, MT_DATA
, M_PKTHDR
);
511 m
= m_gethdr(M_WAITOK
, MT_DATA
);
517 m
->m_pkthdr
.len
= size
;
522 packet_buffer_byteptr(packet_buffer_ref buf
)
524 return buf
->m_data
+ sizeof(struct ether_header
);
532 LAEventSelectedChange
,
541 bondport_receive_machine(bondport_ref p
, LAEvent event
,
544 ** Periodic Transmission machine
547 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
553 #define TRANSMIT_MACHINE_TX_IMMEDIATE ((void *)1)
556 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
563 bondport_mux_machine(bondport_ref p
, LAEvent event
,
570 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
);
573 ifbond_deactivate_LAG(ifbond_ref bond
, LAG_ref lag
);
576 ifbond_all_ports_ready(ifbond_ref bond
);
579 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
);
582 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
);
585 ifbond_selection(ifbond_ref bond
);
588 bond_handle_event(struct ifnet
* port_ifp
, int event_code
);
595 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
);
598 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
);
601 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
602 int active
, int short_timeout
, int * error
);
604 bondport_start(bondport_ref p
);
607 bondport_free(bondport_ref p
);
610 bondport_aggregatable(bondport_ref p
);
613 bondport_remove_from_LAG(bondport_ref p
);
616 bondport_set_selected(bondport_ref p
, SelectedState s
);
619 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
);
622 bondport_link_status_changed(bondport_ref p
);
625 bondport_enable_distributing(bondport_ref p
);
628 bondport_disable_distributing(bondport_ref p
);
630 static __inline__
int
631 bondport_collecting(bondport_ref p
)
633 if (p
->po_bond
->ifb_mode
== IF_BOND_MODE_LACP
) {
634 return lacp_actor_partner_state_collecting(p
->po_actor_state
);
640 ** bond interface/dlil specific routines
642 static int bond_clone_create(struct if_clone
*, u_int32_t
, void *);
643 static int bond_clone_destroy(struct ifnet
*);
644 static int bond_output(struct ifnet
*ifp
, struct mbuf
*m
);
645 static int bond_ioctl(struct ifnet
*ifp
, u_long cmd
, void * addr
);
646 static int bond_set_bpf_tap(struct ifnet
* ifp
, bpf_tap_mode mode
,
647 bpf_packet_func func
);
648 static int bond_attach_protocol(struct ifnet
*ifp
);
649 static int bond_detach_protocol(struct ifnet
*ifp
);
650 static errno_t
bond_iff_input(void *cookie
, ifnet_t ifp
,
651 protocol_family_t protocol
, mbuf_t
*data
, char **frame_ptr
);
652 static int bond_attach_filter(struct ifnet
*ifp
, interface_filter_t
* filter_p
);
653 static int bond_setmulti(struct ifnet
*ifp
);
654 static int bond_add_interface(struct ifnet
* ifp
, struct ifnet
* port_ifp
);
655 static int bond_remove_interface(ifbond_ref ifb
, struct ifnet
* port_ifp
);
656 static void bond_if_free(struct ifnet
* ifp
);
657 static void interface_link_event(struct ifnet
* ifp
, u_int32_t event_code
);
659 static struct if_clone bond_cloner
= IF_CLONE_INITIALIZER(BONDNAME
,
668 siocsifmtu(struct ifnet
* ifp
, int mtu
)
672 bzero(&ifr
, sizeof(ifr
));
674 return ifnet_ioctl(ifp
, 0, SIOCSIFMTU
, &ifr
);
678 siocgifdevmtu(struct ifnet
* ifp
, struct ifdevmtu
* ifdm_p
)
683 bzero(&ifr
, sizeof(ifr
));
684 error
= ifnet_ioctl(ifp
, 0, SIOCGIFDEVMTU
, &ifr
);
686 *ifdm_p
= ifr
.ifr_devmtu
;
691 static __inline__
void
692 ether_addr_copy(void * dest
, const void * source
)
694 bcopy(source
, dest
, ETHER_ADDR_LEN
);
698 static __inline__
void
699 ifbond_retain(ifbond_ref ifb
)
701 os_ref_retain(&ifb
->ifb_retain_count
);
704 static __inline__
void
705 ifbond_release(ifbond_ref ifb
)
707 if (os_ref_release(&ifb
->ifb_retain_count
) != 0) {
712 printf("ifbond_release(%s)\n", ifb
->ifb_name
);
714 if (ifb
->ifb_ifma_slow_proto
!= NULL
) {
716 printf("ifbond_release(%s) removing multicast\n",
719 (void) if_delmulti_anon(ifb
->ifb_ifma_slow_proto
->ifma_ifp
,
720 ifb
->ifb_ifma_slow_proto
->ifma_addr
);
721 IFMA_REMREF(ifb
->ifb_ifma_slow_proto
);
723 if (ifb
->ifb_distributing_array
!= NULL
) {
724 FREE(ifb
->ifb_distributing_array
, M_BOND
);
726 if_clone_softc_deallocate(&bond_cloner
, ifb
);
730 * Function: ifbond_wait
732 * Allows a single thread to gain exclusive access to the ifbond
733 * data structure. Some operations take a long time to complete,
734 * and some have side-effects that we can't predict. Holding the
735 * bond_lock() across such operations is not possible.
738 * 1) The SIOCSIFLLADDR ioctl takes a long time (several seconds) to
739 * complete. Simply holding the bond_lock() would freeze all other
740 * data structure accesses during that time.
741 * 2) When we attach our protocol to the interface, a dlil event is
742 * generated and invokes our bond_event() function. bond_event()
743 * needs to take the bond_lock(), but we're already holding it, so
744 * we're deadlocked against ourselves.
746 * Before calling, you must be holding the bond_lock and have taken
747 * a reference on the ifbond_ref.
750 ifbond_wait(ifbond_ref ifb
, const char * msg
)
754 /* other add/remove in progress */
755 while (ifbond_flags_change_in_progress(ifb
)) {
757 printf("%s: %s msleep\n", ifb
->ifb_name
, msg
);
760 (void)msleep(ifb
, bond_lck_mtx
, PZERO
, msg
, 0);
762 /* prevent other bond list remove/add from taking place */
763 ifbond_flags_set_change_in_progress(ifb
);
764 if (if_bond_debug
&& waited
) {
765 printf("%s: %s woke up\n", ifb
->ifb_name
, msg
);
771 * Function: ifbond_signal
773 * Allows the thread that previously invoked ifbond_wait() to
774 * give up exclusive access to the ifbond data structure, and wake up
775 * any other threads waiting to access
777 * Before calling, you must be holding the bond_lock and have taken
778 * a reference on the ifbond_ref.
781 ifbond_signal(ifbond_ref ifb
, const char * msg
)
783 ifbond_flags_clear_change_in_progress(ifb
);
784 wakeup((caddr_t
)ifb
);
786 printf("%s: %s wakeup\n", ifb
->ifb_name
, msg
);
796 link_speed(int active
)
798 switch (IFM_SUBTYPE(active
)) {
819 case IFM_1000_CX_SGMII
:
825 /* assume that new defined types are going to be at least 10GigE */
864 static __inline__
int
865 media_active(const struct media_info
* mi
)
867 if ((mi
->mi_status
& IFM_AVALID
) == 0) {
870 return (mi
->mi_status
& IFM_ACTIVE
) != 0;
873 static __inline__
int
874 media_full_duplex(const struct media_info
* mi
)
876 return (mi
->mi_active
& IFM_FDX
) != 0;
879 static __inline__
int
880 media_type_unknown(const struct media_info
* mi
)
884 switch (IFM_SUBTYPE(mi
->mi_active
)) {
897 static __inline__
int
898 media_ok(const struct media_info
* mi
)
900 return media_full_duplex(mi
) || media_type_unknown(mi
);
903 static __inline__
int
904 media_speed(const struct media_info
* mi
)
906 return link_speed(mi
->mi_active
);
909 static struct media_info
910 interface_media_info(struct ifnet
* ifp
)
912 struct ifmediareq ifmr
;
913 struct media_info mi
;
915 bzero(&mi
, sizeof(mi
));
916 bzero(&ifmr
, sizeof(ifmr
));
917 if (ifnet_ioctl(ifp
, 0, SIOCGIFMEDIA
, &ifmr
) == 0) {
918 if (ifmr
.ifm_count
!= 0) {
919 mi
.mi_status
= ifmr
.ifm_status
;
920 mi
.mi_active
= ifmr
.ifm_active
;
927 if_siflladdr(struct ifnet
* ifp
, const struct ether_addr
* ea_p
)
932 * XXX setting the sa_len to ETHER_ADDR_LEN is wrong, but the driver
933 * currently expects it that way
935 ifr
.ifr_addr
.sa_family
= AF_UNSPEC
;
936 ifr
.ifr_addr
.sa_len
= ETHER_ADDR_LEN
;
937 ether_addr_copy(ifr
.ifr_addr
.sa_data
, ea_p
);
938 return ifnet_ioctl(ifp
, 0, SIOCSIFLLADDR
, &ifr
);
944 static bond_globals_ref
945 bond_globals_create(lacp_system_priority sys_pri
,
950 b
= _MALLOC(sizeof(*b
), M_BOND
, M_WAITOK
| M_ZERO
);
954 TAILQ_INIT(&b
->ifbond_list
);
956 b
->system_priority
= sys_pri
;
961 bond_globals_init(void)
967 bond_assert_lock_not_held();
969 if (g_bond
!= NULL
) {
974 * use en0's ethernet address as the system identifier, and if it's not
975 * there, use en1 .. en3
978 for (i
= 0; i
< 4; i
++) {
979 char ifname
[IFNAMSIZ
+ 1];
980 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
981 ifp
= ifunit(ifname
);
988 b
= bond_globals_create(0x8000, (lacp_system_ref
)IF_LLADDR(ifp
));
991 if (g_bond
!= NULL
) {
1008 bond_bpf_vlan(struct ifnet
* ifp
, struct mbuf
* m
,
1009 const struct ether_header
* eh_p
,
1010 u_int16_t vlan_tag
, bpf_packet_func func
)
1012 struct ether_vlan_header
* vlh_p
;
1015 vl_m
= m_get(M_DONTWAIT
, MT_DATA
);
1019 /* populate a new mbuf containing the vlan ethernet header */
1020 vl_m
->m_len
= ETHER_HDR_LEN
+ ETHER_VLAN_ENCAP_LEN
;
1021 vlh_p
= mtod(vl_m
, struct ether_vlan_header
*);
1022 bcopy(eh_p
, vlh_p
, offsetof(struct ether_header
, ether_type
));
1023 vlh_p
->evl_encap_proto
= htons(ETHERTYPE_VLAN
);
1024 vlh_p
->evl_tag
= htons(vlan_tag
);
1025 vlh_p
->evl_proto
= eh_p
->ether_type
;
1028 vl_m
->m_next
= NULL
;
1033 static __inline__
void
1034 bond_bpf_output(struct ifnet
* ifp
, struct mbuf
* m
,
1035 bpf_packet_func func
)
1038 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1039 const struct ether_header
* eh_p
;
1040 eh_p
= mtod(m
, const struct ether_header
*);
1041 m
->m_data
+= ETHER_HDR_LEN
;
1042 m
->m_len
-= ETHER_HDR_LEN
;
1043 bond_bpf_vlan(ifp
, m
, eh_p
, m
->m_pkthdr
.vlan_tag
, func
);
1044 m
->m_data
-= ETHER_HDR_LEN
;
1045 m
->m_len
+= ETHER_HDR_LEN
;
1053 static __inline__
void
1054 bond_bpf_input(ifnet_t ifp
, mbuf_t m
, const struct ether_header
* eh_p
,
1055 bpf_packet_func func
)
1058 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1059 bond_bpf_vlan(ifp
, m
, eh_p
, m
->m_pkthdr
.vlan_tag
, func
);
1061 /* restore the header */
1062 m
->m_data
-= ETHER_HDR_LEN
;
1063 m
->m_len
+= ETHER_HDR_LEN
;
1065 m
->m_data
+= ETHER_HDR_LEN
;
1066 m
->m_len
-= ETHER_HDR_LEN
;
1073 * Function: bond_setmulti
1075 * Enable multicast reception on "our" interface by enabling multicasts on
1076 * each of the member ports.
1079 bond_setmulti(struct ifnet
* ifp
)
1087 ifb
= ifnet_softc(ifp
);
1088 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1089 || TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
1094 ifbond_wait(ifb
, "bond_setmulti");
1096 if (ifbond_flags_if_detaching(ifb
)) {
1097 /* someone destroyed the bond while we were waiting */
1103 /* ifbond_wait() let's us safely walk the list without holding the lock */
1104 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
1105 struct ifnet
* port_ifp
= p
->po_ifp
;
1107 error
= multicast_list_program(&p
->po_multicast
,
1110 printf("bond_setmulti(%s): "
1111 "multicast_list_program(%s%d) failed, %d\n",
1112 ifb
->ifb_name
, ifnet_name(port_ifp
),
1113 ifnet_unit(port_ifp
), error
);
1119 ifbond_signal(ifb
, __func__
);
1121 ifbond_release(ifb
);
1126 bond_clone_attach(void)
1130 if ((error
= if_clone_attach(&bond_cloner
)) != 0) {
1138 ifbond_add_slow_proto_multicast(ifbond_ref ifb
)
1141 struct ifmultiaddr
* ifma
= NULL
;
1142 struct sockaddr_dl sdl
;
1144 bond_assert_lock_not_held();
1146 bzero(&sdl
, sizeof(sdl
));
1147 sdl
.sdl_len
= sizeof(sdl
);
1148 sdl
.sdl_family
= AF_LINK
;
1149 sdl
.sdl_type
= IFT_ETHER
;
1151 sdl
.sdl_alen
= sizeof(slow_proto_multicast
);
1152 bcopy(&slow_proto_multicast
, sdl
.sdl_data
, sizeof(slow_proto_multicast
));
1153 error
= if_addmulti_anon(ifb
->ifb_ifp
, (struct sockaddr
*)&sdl
, &ifma
);
1155 ifb
->ifb_ifma_slow_proto
= ifma
;
1161 bond_clone_create(struct if_clone
* ifc
, u_int32_t unit
, __unused
void *params
)
1166 struct ifnet_init_eparams bond_init
;
1168 error
= bond_globals_init();
1173 ifb
= if_clone_softc_allocate(&bond_cloner
);
1178 os_ref_init(&ifb
->ifb_retain_count
, NULL
);
1179 TAILQ_INIT(&ifb
->ifb_port_list
);
1180 TAILQ_INIT(&ifb
->ifb_lag_list
);
1181 ifb
->ifb_key
= unit
+ 1;
1183 /* use the interface name as the unique id for ifp recycle */
1184 if ((u_int32_t
)snprintf(ifb
->ifb_name
, sizeof(ifb
->ifb_name
), "%s%d",
1185 ifc
->ifc_name
, unit
) >= sizeof(ifb
->ifb_name
)) {
1186 ifbond_release(ifb
);
1190 bzero(&bond_init
, sizeof(bond_init
));
1191 bond_init
.ver
= IFNET_INIT_CURRENT_VERSION
;
1192 bond_init
.len
= sizeof(bond_init
);
1193 bond_init
.flags
= IFNET_INIT_LEGACY
;
1194 bond_init
.uniqueid
= ifb
->ifb_name
;
1195 bond_init
.uniqueid_len
= strlen(ifb
->ifb_name
);
1196 bond_init
.name
= ifc
->ifc_name
;
1197 bond_init
.unit
= unit
;
1198 bond_init
.family
= IFNET_FAMILY_BOND
;
1199 bond_init
.type
= IFT_IEEE8023ADLAG
;
1200 bond_init
.output
= bond_output
;
1201 bond_init
.demux
= ether_demux
;
1202 bond_init
.add_proto
= ether_add_proto
;
1203 bond_init
.del_proto
= ether_del_proto
;
1204 bond_init
.check_multi
= ether_check_multi
;
1205 bond_init
.framer_extended
= ether_frameout_extended
;
1206 bond_init
.ioctl
= bond_ioctl
;
1207 bond_init
.set_bpf_tap
= bond_set_bpf_tap
;
1208 bond_init
.detach
= bond_if_free
;
1209 bond_init
.broadcast_addr
= etherbroadcastaddr
;
1210 bond_init
.broadcast_len
= ETHER_ADDR_LEN
;
1211 bond_init
.softc
= ifb
;
1212 error
= ifnet_allocate_extended(&bond_init
, &ifp
);
1215 ifbond_release(ifb
);
1220 ifnet_set_offload(ifp
, 0);
1221 ifnet_set_addrlen(ifp
, ETHER_ADDR_LEN
); /* XXX ethernet specific */
1222 ifnet_set_flags(ifp
, IFF_BROADCAST
| IFF_MULTICAST
| IFF_SIMPLEX
, 0xffff);
1223 ifnet_set_mtu(ifp
, ETHERMTU
);
1225 error
= ifnet_attach(ifp
, NULL
);
1228 ifbond_release(ifb
);
1231 error
= ifbond_add_slow_proto_multicast(ifb
);
1233 printf("bond_clone_create(%s): "
1234 "failed to add slow_proto multicast, %d\n",
1235 ifb
->ifb_name
, error
);
1238 /* attach as ethernet */
1239 bpfattach(ifp
, DLT_EN10MB
, sizeof(struct ether_header
));
1242 TAILQ_INSERT_HEAD(&g_bond
->ifbond_list
, ifb
, ifb_bond_list
);
1249 bond_remove_all_interfaces(ifbond_ref ifb
)
1253 bond_assert_lock_held();
1256 * do this in reverse order to avoid re-programming the mac address
1257 * as each head interface is removed
1259 while ((p
= TAILQ_LAST(&ifb
->ifb_port_list
, port_list
)) != NULL
) {
1260 bond_remove_interface(ifb
, p
->po_ifp
);
1266 bond_remove(ifbond_ref ifb
)
1268 bond_assert_lock_held();
1269 ifbond_flags_set_if_detaching(ifb
);
1270 TAILQ_REMOVE(&g_bond
->ifbond_list
, ifb
, ifb_bond_list
);
1271 bond_remove_all_interfaces(ifb
);
1276 bond_if_detach(struct ifnet
* ifp
)
1280 error
= ifnet_detach(ifp
);
1282 printf("bond_if_detach %s%d: ifnet_detach failed, %d\n",
1283 ifnet_name(ifp
), ifnet_unit(ifp
), error
);
1290 bond_clone_destroy(struct ifnet
* ifp
)
1295 ifb
= ifnet_softc(ifp
);
1296 if (ifb
== NULL
|| ifnet_type(ifp
) != IFT_IEEE8023ADLAG
) {
1300 if (ifbond_flags_if_detaching(ifb
)) {
1306 bond_if_detach(ifp
);
1311 bond_set_bpf_tap(struct ifnet
* ifp
, bpf_tap_mode mode
, bpf_packet_func func
)
1316 ifb
= ifnet_softc(ifp
);
1317 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
1322 case BPF_TAP_DISABLE
:
1323 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= NULL
;
1327 ifb
->ifb_bpf_input
= func
;
1330 case BPF_TAP_OUTPUT
:
1331 ifb
->ifb_bpf_output
= func
;
1334 case BPF_TAP_INPUT_OUTPUT
:
1335 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= func
;
1345 ether_header_hash(struct ether_header
* eh_p
)
1349 /* get 32-bits from destination ether and ether type */
1350 h
= (*((uint16_t *)&eh_p
->ether_dhost
[4]) << 16)
1352 h
^= *((uint32_t *)&eh_p
->ether_dhost
[0]);
1356 static struct mbuf
*
1357 S_mbuf_skip_to_offset(struct mbuf
* m
, int32_t * offset
)
1362 while (*offset
>= len
) {
1373 #if BYTE_ORDER == BIG_ENDIAN
1374 static __inline__
uint32_t
1375 make_uint32(u_char c0
, u_char c1
, u_char c2
, u_char c3
)
1377 return ((uint32_t)c0
<< 24) | ((uint32_t)c1
<< 16)
1378 | ((uint32_t)c2
<< 8) | (uint32_t)c3
;
1380 #else /* BYTE_ORDER == LITTLE_ENDIAN */
1381 static __inline__
uint32_t
1382 make_uint32(u_char c0
, u_char c1
, u_char c2
, u_char c3
)
1384 return ((uint32_t)c3
<< 24) | ((uint32_t)c2
<< 16)
1385 | ((uint32_t)c1
<< 8) | (uint32_t)c0
;
1387 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1390 S_mbuf_copy_uint32(struct mbuf
* m
, int32_t offset
, uint32_t * val
)
1392 struct mbuf
* current
;
1393 u_char
* current_data
;
1398 current
= S_mbuf_skip_to_offset(m
, &offset
);
1399 if (current
== NULL
) {
1402 current_data
= mtod(current
, u_char
*) + offset
;
1403 space_current
= current
->m_len
- offset
;
1404 if (space_current
>= (int)sizeof(uint32_t)) {
1405 *val
= *((uint32_t *)current_data
);
1408 next
= current
->m_next
;
1409 if (next
== NULL
|| (next
->m_len
+ space_current
) < (int)sizeof(uint32_t)) {
1412 next_data
= mtod(next
, u_char
*);
1413 switch (space_current
) {
1415 *val
= make_uint32(current_data
[0], next_data
[0],
1416 next_data
[1], next_data
[2]);
1419 *val
= make_uint32(current_data
[0], current_data
[1],
1420 next_data
[0], next_data
[1]);
1423 *val
= make_uint32(current_data
[0], current_data
[1],
1424 current_data
[2], next_data
[0]);
1430 #define IP_SRC_OFFSET (offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p))
1431 #define IP_DST_OFFSET (offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p))
1434 ip_header_hash(struct mbuf
* m
)
1437 struct in_addr ip_dst
;
1438 struct in_addr ip_src
;
1441 struct mbuf
* orig_m
= m
;
1443 /* find the IP protocol field relative to the start of the packet */
1444 offset
= offsetof(struct ip
, ip_p
) + sizeof(struct ether_header
);
1445 m
= S_mbuf_skip_to_offset(m
, &offset
);
1446 if (m
== NULL
|| m
->m_len
< 1) {
1449 data
= mtod(m
, u_char
*) + offset
;
1452 /* find the IP src relative to the IP protocol */
1453 if ((m
->m_len
- offset
)
1454 >= (int)(IP_SRC_OFFSET
+ sizeof(struct in_addr
) * 2)) {
1455 /* this should be the normal case */
1456 ip_src
= *(struct in_addr
*)(data
+ IP_SRC_OFFSET
);
1457 ip_dst
= *(struct in_addr
*)(data
+ IP_DST_OFFSET
);
1459 if (S_mbuf_copy_uint32(m
, offset
+ IP_SRC_OFFSET
,
1460 (uint32_t *)&ip_src
.s_addr
)) {
1463 if (S_mbuf_copy_uint32(m
, offset
+ IP_DST_OFFSET
,
1464 (uint32_t *)&ip_dst
.s_addr
)) {
1468 return ntohl(ip_dst
.s_addr
) ^ ntohl(ip_src
.s_addr
) ^ ((uint32_t)ip_p
);
1471 return ether_header_hash(mtod(orig_m
, struct ether_header
*));
1474 #define IP6_ADDRS_LEN (sizeof(struct in6_addr) * 2)
1476 ipv6_header_hash(struct mbuf
* m
)
1481 struct mbuf
* orig_m
= m
;
1485 /* find the IP protocol field relative to the start of the packet */
1486 offset
= offsetof(struct ip6_hdr
, ip6_src
) + sizeof(struct ether_header
);
1487 m
= S_mbuf_skip_to_offset(m
, &offset
);
1489 goto bad_ipv6_packet
;
1491 data
= mtod(m
, u_char
*) + offset
;
1493 if ((m
->m_len
- offset
) >= (int)IP6_ADDRS_LEN
) {
1494 /* this should be the normal case */
1495 for (i
= 0, scan
= (uint32_t *)data
;
1496 i
< (int)(IP6_ADDRS_LEN
/ sizeof(uint32_t));
1501 for (i
= 0; i
< (int)(IP6_ADDRS_LEN
/ sizeof(uint32_t)); i
++) {
1503 if (S_mbuf_copy_uint32(m
, offset
+ i
* sizeof(uint32_t),
1504 (uint32_t *)&tmp
)) {
1505 goto bad_ipv6_packet
;
1513 return ether_header_hash(mtod(orig_m
, struct ether_header
*));
1517 bond_output(struct ifnet
* ifp
, struct mbuf
* m
)
1519 bpf_packet_func bpf_func
;
1522 struct ifnet
* port_ifp
= NULL
;
1524 struct flowadv adv
= { .code
= FADV_SUCCESS
};
1529 if ((m
->m_flags
& M_PKTHDR
) == 0) {
1533 if (m
->m_pkthdr
.pkt_flowid
!= 0) {
1534 h
= m
->m_pkthdr
.pkt_flowid
;
1536 struct ether_header
* eh_p
;
1538 eh_p
= mtod(m
, struct ether_header
*);
1539 switch (ntohs(eh_p
->ether_type
)) {
1541 h
= ip_header_hash(m
);
1543 case ETHERTYPE_IPV6
:
1544 h
= ipv6_header_hash(m
);
1547 h
= ether_header_hash(eh_p
);
1552 ifb
= ifnet_softc(ifp
);
1553 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1554 || ifb
->ifb_distributing_count
== 0) {
1557 h
%= ifb
->ifb_distributing_count
;
1558 port_ifp
= ifb
->ifb_distributing_array
[h
]->po_ifp
;
1559 bpf_func
= ifb
->ifb_bpf_output
;
1562 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1563 (void)ifnet_stat_increment_out(ifp
, 1,
1564 m
->m_pkthdr
.len
+ ETHER_VLAN_ENCAP_LEN
,
1567 (void)ifnet_stat_increment_out(ifp
, 1, m
->m_pkthdr
.len
, 0);
1569 bond_bpf_output(ifp
, m
, bpf_func
);
1571 err
= dlil_output(port_ifp
, PF_BOND
, m
, NULL
, NULL
, 1, &adv
);
1574 if (adv
.code
== FADV_FLOW_CONTROLLED
) {
1576 } else if (adv
.code
== FADV_SUSPENDED
) {
1590 ifbond_lookup_port(ifbond_ref ifb
, struct ifnet
* port_ifp
)
1593 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
1594 if (p
->po_ifp
== port_ifp
) {
1602 bond_lookup_port(struct ifnet
* port_ifp
)
1607 TAILQ_FOREACH(ifb
, &g_bond
->ifbond_list
, ifb_bond_list
) {
1608 port
= ifbond_lookup_port(ifb
, port_ifp
);
1617 bond_receive_lacpdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1619 struct ifnet
* bond_ifp
= NULL
;
1622 bool need_link_update
= false;
1626 if ((ifnet_eflags(port_ifp
) & IFEF_BOND
) == 0) {
1629 p
= bond_lookup_port(port_ifp
);
1633 if (p
->po_enabled
== 0) {
1637 if (ifb
->ifb_mode
!= IF_BOND_MODE_LACP
) {
1641 * Work-around for rdar://problem/51372042
1642 * Sometimes, the link comes up but the driver doesn't report the
1643 * negotiated medium at that time. When we receive an LACPDU packet,
1644 * and the medium is unknown, force a link status check. Don't force
1645 * the link status check more often than _FORCE_LINK_EVENT_INTERVAL
1648 #define _FORCE_LINK_EVENT_INTERVAL 1
1649 if (media_type_unknown(&p
->po_media_info
)) {
1650 uint64_t now
= net_uptime();
1652 if ((now
- p
->po_force_link_event_time
) >=
1653 _FORCE_LINK_EVENT_INTERVAL
) {
1654 need_link_update
= true;
1655 p
->po_force_link_event_time
= now
;
1658 bondport_receive_lacpdu(p
, (lacpdu_ref
)m
->m_data
);
1659 if (ifbond_selection(ifb
)) {
1660 event_code
= (ifb
->ifb_active_lag
== NULL
)
1663 /* XXX need to take a reference on bond_ifp */
1664 bond_ifp
= ifb
->ifb_ifp
;
1665 ifb
->ifb_last_link_event
= event_code
;
1667 event_code
= (ifb
->ifb_active_lag
== NULL
)
1670 if (event_code
!= ifb
->ifb_last_link_event
) {
1671 if (if_bond_debug
) {
1672 timestamp_printf("%s: (receive) generating LINK event\n",
1675 bond_ifp
= ifb
->ifb_ifp
;
1676 ifb
->ifb_last_link_event
= event_code
;
1682 if (bond_ifp
!= NULL
) {
1683 interface_link_event(bond_ifp
, event_code
);
1686 if (need_link_update
) {
1687 if (if_bond_debug
!= 0) {
1688 printf("bond: simulating link status changed event");
1690 bond_handle_event(port_ifp
, KEV_DL_LINK_ON
);
1696 bond_receive_la_marker_pdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1698 la_marker_pdu_ref marker_p
;
1701 marker_p
= (la_marker_pdu_ref
)(m
->m_data
+ ETHER_HDR_LEN
);
1702 if (marker_p
->lm_marker_tlv_type
!= LA_MARKER_TLV_TYPE_MARKER
) {
1706 if ((ifnet_eflags(port_ifp
) & IFEF_BOND
) == 0) {
1710 p
= bond_lookup_port(port_ifp
);
1711 if (p
== NULL
|| p
->po_enabled
== 0
1712 || p
->po_bond
->ifb_mode
!= IF_BOND_MODE_LACP
) {
1716 /* echo back the same packet as a marker response */
1717 marker_p
->lm_marker_tlv_type
= LA_MARKER_TLV_TYPE_MARKER_RESPONSE
;
1718 bondport_slow_proto_transmit(p
, (packet_buffer_ref
)m
);
1728 bond_input(ifnet_t port_ifp
, mbuf_t m
, char *frame_header
)
1730 bpf_packet_func bpf_func
;
1731 const struct ether_header
* eh_p
;
1736 eh_p
= (const struct ether_header
*)frame_header
;
1737 if ((m
->m_flags
& M_MCAST
) != 0
1738 && bcmp(eh_p
->ether_dhost
, &slow_proto_multicast
,
1739 sizeof(eh_p
->ether_dhost
)) == 0
1740 && ntohs(eh_p
->ether_type
) == IEEE8023AD_SLOW_PROTO_ETHERTYPE
) {
1741 u_char subtype
= *mtod(m
, u_char
*);
1743 if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP
) {
1744 if (m
->m_pkthdr
.len
< (int)offsetof(lacpdu
, la_reserved
)) {
1749 if (m
->m_len
< (int)offsetof(lacpdu
, la_reserved
)) {
1750 m
= m_pullup(m
, offsetof(lacpdu
, la_reserved
));
1755 bond_receive_lacpdu(m
, port_ifp
);
1757 } else if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LA_MARKER_PROTOCOL
) {
1760 /* restore the ethernet header pointer in the mbuf */
1761 m
->m_pkthdr
.len
+= ETHER_HDR_LEN
;
1762 m
->m_data
-= ETHER_HDR_LEN
;
1763 m
->m_len
+= ETHER_HDR_LEN
;
1764 min_size
= ETHER_HDR_LEN
+ offsetof(la_marker_pdu
, lm_reserved
);
1765 if (m
->m_pkthdr
.len
< min_size
) {
1770 if (m
->m_len
< min_size
) {
1771 m
= m_pullup(m
, min_size
);
1776 /* send to marker responder */
1777 bond_receive_la_marker_pdu(m
, port_ifp
);
1779 } else if (subtype
== 0
1780 || subtype
> IEEE8023AD_SLOW_PROTO_SUBTYPE_RESERVED_END
) {
1781 /* invalid subtype, discard the frame */
1787 if ((ifnet_eflags(port_ifp
) & IFEF_BOND
) == 0) {
1790 p
= bond_lookup_port(port_ifp
);
1791 if (p
== NULL
|| bondport_collecting(p
) == 0) {
1797 bpf_func
= ifb
->ifb_bpf_input
;
1801 * Need to clear the promiscous flags otherwise it will be
1802 * dropped by DLIL after processing filters
1804 if ((mbuf_flags(m
) & MBUF_PROMISC
)) {
1805 mbuf_setflags_mask(m
, 0, MBUF_PROMISC
);
1808 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1809 (void)ifnet_stat_increment_in(ifp
, 1,
1810 (m
->m_pkthdr
.len
+ ETHER_HDR_LEN
1811 + ETHER_VLAN_ENCAP_LEN
), 0);
1813 (void)ifnet_stat_increment_in(ifp
, 1,
1814 (m
->m_pkthdr
.len
+ ETHER_HDR_LEN
), 0);
1817 /* make the packet appear as if it arrived on the bonded interface */
1818 m
->m_pkthdr
.rcvif
= ifp
;
1819 bond_bpf_input(ifp
, m
, eh_p
, bpf_func
);
1820 m
->m_pkthdr
.pkt_hdr
= frame_header
;
1821 dlil_input_packet_list(ifp
, m
);
1831 bond_iff_input(void *cookie
, ifnet_t port_ifp
, protocol_family_t protocol
,
1832 mbuf_t
*data
, char **frame_header_ptr
)
1834 #pragma unused(cookie)
1835 #pragma unused(protocol)
1837 char * frame_header
= *frame_header_ptr
;
1839 bond_input(port_ifp
, m
, frame_header
);
1843 static __inline__
const char *
1844 bondport_get_name(bondport_ref p
)
1849 static __inline__
int
1850 bondport_get_index(bondport_ref p
)
1852 return ifnet_index(p
->po_ifp
);
1856 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
)
1858 struct ether_header
* eh_p
;
1861 /* packet_buffer_allocate leaves room for ethernet header */
1862 eh_p
= mtod(buf
, struct ether_header
*);
1863 bcopy(&slow_proto_multicast
, &eh_p
->ether_dhost
, sizeof(eh_p
->ether_dhost
));
1864 bcopy(&p
->po_saved_addr
, eh_p
->ether_shost
, sizeof(eh_p
->ether_shost
));
1865 eh_p
->ether_type
= htons(IEEE8023AD_SLOW_PROTO_ETHERTYPE
);
1866 error
= ifnet_output_raw(p
->po_ifp
, PF_BOND
, buf
);
1868 printf("bondport_slow_proto_transmit(%s) failed %d\n",
1869 bondport_get_name(p
), error
);
1875 bondport_timer_process_func(devtimer_ref timer
,
1876 devtimer_process_func_event event
)
1881 case devtimer_process_func_event_lock
:
1883 devtimer_retain(timer
);
1885 case devtimer_process_func_event_unlock
:
1886 if (devtimer_valid(timer
)) {
1887 /* as long as the devtimer is valid, we can look at arg0 */
1889 struct ifnet
* bond_ifp
= NULL
;
1891 p
= (bondport_ref
)devtimer_arg0(timer
);
1892 if (ifbond_selection(p
->po_bond
)) {
1893 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
1896 /* XXX need to take a reference on bond_ifp */
1897 bond_ifp
= p
->po_bond
->ifb_ifp
;
1898 p
->po_bond
->ifb_last_link_event
= event_code
;
1900 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
1903 if (event_code
!= p
->po_bond
->ifb_last_link_event
) {
1904 if (if_bond_debug
) {
1905 timestamp_printf("%s: (timer) generating LINK event\n",
1906 p
->po_bond
->ifb_name
);
1908 bond_ifp
= p
->po_bond
->ifb_ifp
;
1909 p
->po_bond
->ifb_last_link_event
= event_code
;
1912 devtimer_release(timer
);
1914 if (bond_ifp
!= NULL
) {
1915 interface_link_event(bond_ifp
, event_code
);
1918 /* timer is going away */
1919 devtimer_release(timer
);
1929 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
1930 int active
, int short_timeout
, int * ret_error
)
1933 bondport_ref p
= NULL
;
1934 lacp_actor_partner_state s
;
1937 p
= _MALLOC(sizeof(*p
), M_BOND
, M_WAITOK
| M_ZERO
);
1939 *ret_error
= ENOMEM
;
1942 multicast_list_init(&p
->po_multicast
);
1943 if ((u_int32_t
)snprintf(p
->po_name
, sizeof(p
->po_name
), "%s%d",
1944 ifnet_name(port_ifp
), ifnet_unit(port_ifp
))
1945 >= sizeof(p
->po_name
)) {
1946 printf("if_bond: name too large\n");
1947 *ret_error
= EINVAL
;
1950 error
= siocgifdevmtu(port_ifp
, &p
->po_devmtu
);
1952 printf("if_bond: SIOCGIFDEVMTU %s failed, %d\n",
1953 bondport_get_name(p
), error
);
1956 /* remember the current interface MTU so it can be restored */
1957 p
->po_devmtu
.ifdm_current
= ifnet_mtu(port_ifp
);
1958 p
->po_ifp
= port_ifp
;
1959 p
->po_media_info
= interface_media_info(port_ifp
);
1960 p
->po_current_while_timer
= devtimer_create(bondport_timer_process_func
, p
);
1961 if (p
->po_current_while_timer
== NULL
) {
1962 *ret_error
= ENOMEM
;
1965 p
->po_periodic_timer
= devtimer_create(bondport_timer_process_func
, p
);
1966 if (p
->po_periodic_timer
== NULL
) {
1967 *ret_error
= ENOMEM
;
1970 p
->po_wait_while_timer
= devtimer_create(bondport_timer_process_func
, p
);
1971 if (p
->po_wait_while_timer
== NULL
) {
1972 *ret_error
= ENOMEM
;
1975 p
->po_transmit_timer
= devtimer_create(bondport_timer_process_func
, p
);
1976 if (p
->po_transmit_timer
== NULL
) {
1977 *ret_error
= ENOMEM
;
1980 p
->po_receive_state
= ReceiveState_none
;
1981 p
->po_mux_state
= MuxState_none
;
1982 p
->po_priority
= priority
;
1984 s
= lacp_actor_partner_state_set_aggregatable(s
);
1985 if (short_timeout
) {
1986 s
= lacp_actor_partner_state_set_short_timeout(s
);
1989 s
= lacp_actor_partner_state_set_active_lacp(s
);
1991 p
->po_actor_state
= s
;
2000 bondport_start(bondport_ref p
)
2002 bondport_receive_machine(p
, LAEventStart
, NULL
);
2003 bondport_mux_machine(p
, LAEventStart
, NULL
);
2004 bondport_periodic_transmit_machine(p
, LAEventStart
, NULL
);
2005 bondport_transmit_machine(p
, LAEventStart
, NULL
);
2010 * Function: bondport_invalidate_timers
2012 * Invalidate all of the timers for the bondport.
2015 bondport_invalidate_timers(bondport_ref p
)
2017 devtimer_invalidate(p
->po_current_while_timer
);
2018 devtimer_invalidate(p
->po_periodic_timer
);
2019 devtimer_invalidate(p
->po_wait_while_timer
);
2020 devtimer_invalidate(p
->po_transmit_timer
);
2024 * Function: bondport_cancel_timers
2026 * Cancel all of the timers for the bondport.
2029 bondport_cancel_timers(bondport_ref p
)
2031 devtimer_cancel(p
->po_current_while_timer
);
2032 devtimer_cancel(p
->po_periodic_timer
);
2033 devtimer_cancel(p
->po_wait_while_timer
);
2034 devtimer_cancel(p
->po_transmit_timer
);
2038 bondport_free(bondport_ref p
)
2040 multicast_list_remove(&p
->po_multicast
);
2041 devtimer_release(p
->po_current_while_timer
);
2042 devtimer_release(p
->po_periodic_timer
);
2043 devtimer_release(p
->po_wait_while_timer
);
2044 devtimer_release(p
->po_transmit_timer
);
2049 static __inline__
int
2050 bond_device_mtu(struct ifnet
* ifp
, ifbond_ref ifb
)
2052 return ((int)ifnet_mtu(ifp
) > ifb
->ifb_altmtu
)
2053 ? (int)ifnet_mtu(ifp
) : ifb
->ifb_altmtu
;
2057 bond_add_interface(struct ifnet
* ifp
, struct ifnet
* port_ifp
)
2060 uint32_t control_flags
= 0;
2064 interface_filter_t filter
= NULL
;
2067 bondport_ref
* new_array
= NULL
;
2068 bondport_ref
* old_array
= NULL
;
2071 if (IFNET_IS_INTCOPROC(port_ifp
)) {
2075 /* pre-allocate space for new port */
2076 p
= bondport_create(port_ifp
, 0x8000, 1, 0, &error
);
2081 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2082 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2085 return ifb
== NULL
? EOPNOTSUPP
: EBUSY
;
2088 /* make sure this interface can handle our current MTU */
2089 devmtu
= bond_device_mtu(ifp
, ifb
);
2091 && (devmtu
> p
->po_devmtu
.ifdm_max
|| devmtu
< p
->po_devmtu
.ifdm_min
)) {
2093 printf("if_bond: interface %s doesn't support mtu %d",
2094 bondport_get_name(p
), devmtu
);
2099 /* make sure ifb doesn't get de-allocated while we wait */
2102 /* wait for other add or remove to complete */
2103 ifbond_wait(ifb
, __func__
);
2105 if (ifbond_flags_if_detaching(ifb
)) {
2106 /* someone destroyed the bond while we were waiting */
2110 if (bond_lookup_port(port_ifp
) != NULL
) {
2111 /* port is already part of a bond */
2115 if ((ifnet_eflags(port_ifp
) & (IFEF_VLAN
| IFEF_BOND
)) != 0) {
2116 /* interface already has VLAN's, or is part of bond */
2121 /* mark the interface busy */
2122 eflags
= if_set_eflags(port_ifp
, IFEF_BOND
);
2123 if ((eflags
& IFEF_VLAN
) != 0) {
2124 /* vlan got in ahead of us */
2125 if_clear_eflags(port_ifp
, IFEF_BOND
);
2130 if (TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
2131 ifnet_set_offload(ifp
, ifnet_offload(port_ifp
));
2132 ifnet_set_flags(ifp
, IFF_RUNNING
, IFF_RUNNING
);
2133 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2137 ifnet_offload_t ifp_offload
;
2138 ifnet_offload_t port_ifp_offload
;
2140 ifp_offload
= ifnet_offload(ifp
);
2141 port_ifp_offload
= ifnet_offload(port_ifp
);
2142 if (ifp_offload
!= port_ifp_offload
) {
2143 ifnet_offload_t offload
;
2145 offload
= ifp_offload
& port_ifp_offload
;
2146 printf("%s(%s, %s) "
2147 "hwassist values don't match 0x%x != 0x%x, using 0x%x instead\n",
2149 ifb
->ifb_name
, bondport_get_name(p
),
2150 ifp_offload
, port_ifp_offload
, offload
);
2153 * if the bond has VLAN's, we can't simply change the hwassist
2154 * field behind its back: this needs work
2156 ifnet_set_offload(ifp
, offload
);
2161 /* remember the port's ethernet address so it can be restored */
2162 ether_addr_copy(&p
->po_saved_addr
, IF_LLADDR(port_ifp
));
2164 /* add it to the list of ports */
2165 TAILQ_INSERT_TAIL(&ifb
->ifb_port_list
, p
, po_port_list
);
2166 ifb
->ifb_port_count
++;
2171 /* first port added to bond determines bond's ethernet address */
2173 ifnet_set_lladdr_and_type(ifp
, IF_LLADDR(port_ifp
), ETHER_ADDR_LEN
,
2177 control_flags
|= PORT_CONTROL_FLAGS_IN_LIST
;
2179 /* allocate a larger distributing array */
2180 new_array
= (bondport_ref
*)
2181 _MALLOC(sizeof(*new_array
) * ifb
->ifb_port_count
, M_BOND
, M_WAITOK
);
2182 if (new_array
== NULL
) {
2187 /* attach our BOND "protocol" to the interface */
2188 error
= bond_attach_protocol(port_ifp
);
2192 control_flags
|= PORT_CONTROL_FLAGS_PROTO_ATTACHED
;
2194 /* attach our BOND interface filter */
2195 error
= bond_attach_filter(port_ifp
, &filter
);
2199 control_flags
|= PORT_CONTROL_FLAGS_FILTER_ATTACHED
;
2201 /* set the interface MTU */
2202 devmtu
= bond_device_mtu(ifp
, ifb
);
2203 error
= siocsifmtu(port_ifp
, devmtu
);
2205 printf("%s(%s, %s):"
2206 " SIOCSIFMTU %d failed %d\n",
2208 ifb
->ifb_name
, bondport_get_name(p
), devmtu
, error
);
2211 control_flags
|= PORT_CONTROL_FLAGS_MTU_SET
;
2213 /* program the port with our multicast addresses */
2214 error
= multicast_list_program(&p
->po_multicast
, ifp
, port_ifp
);
2216 printf("%s(%s, %s): multicast_list_program failed %d\n",
2218 ifb
->ifb_name
, bondport_get_name(p
), error
);
2222 /* mark the interface up */
2223 ifnet_set_flags(port_ifp
, IFF_UP
, IFF_UP
);
2225 error
= ifnet_ioctl(port_ifp
, 0, SIOCSIFFLAGS
, NULL
);
2227 printf("%s(%s, %s): SIOCSIFFLAGS failed %d\n",
2229 ifb
->ifb_name
, bondport_get_name(p
), error
);
2233 /* re-program the port's ethernet address */
2234 error
= if_siflladdr(port_ifp
,
2235 (const struct ether_addr
*)IF_LLADDR(ifp
));
2237 if (memcmp(IF_LLADDR(ifp
), IF_LLADDR(port_ifp
), ETHER_ADDR_LEN
)
2239 /* it lied, it really doesn't support setting lladdr */
2244 /* port doesn't support setting the link address */
2245 printf("%s(%s, %s): if_siflladdr failed %d\n",
2247 ifb
->ifb_name
, bondport_get_name(p
), error
);
2248 error
= ifnet_set_promiscuous(port_ifp
, 1);
2250 /* port doesn't support setting promiscuous mode */
2251 printf("%s(%s, %s): set promiscuous failed %d\n",
2253 ifb
->ifb_name
, bondport_get_name(p
), error
);
2256 control_flags
|= PORT_CONTROL_FLAGS_PROMISCUOUS_SET
;
2258 control_flags
|= PORT_CONTROL_FLAGS_LLADDR_SET
;
2263 /* no failures past this point */
2265 p
->po_control_flags
= control_flags
;
2267 /* copy the contents of the existing distributing array */
2268 if (ifb
->ifb_distributing_count
) {
2269 bcopy(ifb
->ifb_distributing_array
, new_array
,
2270 sizeof(*new_array
) * ifb
->ifb_distributing_count
);
2272 old_array
= ifb
->ifb_distributing_array
;
2273 ifb
->ifb_distributing_array
= new_array
;
2275 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
2278 /* check if we need to generate a link status event */
2279 if (ifbond_selection(ifb
)) {
2280 event_code
= (ifb
->ifb_active_lag
== NULL
)
2283 ifb
->ifb_last_link_event
= event_code
;
2286 /* are we adding the first distributing interface? */
2287 if (media_active(&p
->po_media_info
)) {
2288 if (ifb
->ifb_distributing_count
== 0) {
2289 ifb
->ifb_last_link_event
= event_code
= KEV_DL_LINK_ON
;
2291 bondport_enable_distributing(p
);
2293 bondport_disable_distributing(p
);
2296 p
->po_filter
= filter
;
2298 /* clear the busy state, and wakeup anyone waiting */
2299 ifbond_signal(ifb
, __func__
);
2301 if (event_code
!= 0) {
2302 interface_link_event(ifp
, event_code
);
2304 if (old_array
!= NULL
) {
2305 FREE(old_array
, M_BOND
);
2310 bond_assert_lock_not_held();
2312 /* if this was the first port to be added, clear our address */
2314 ifnet_set_lladdr_and_type(ifp
, NULL
, 0, IFT_IEEE8023ADLAG
);
2317 if (new_array
!= NULL
) {
2318 FREE(new_array
, M_BOND
);
2320 if ((control_flags
& PORT_CONTROL_FLAGS_LLADDR_SET
) != 0) {
2323 error1
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2325 printf("%s(%s, %s): if_siflladdr restore failed %d\n",
2327 ifb
->ifb_name
, bondport_get_name(p
), error1
);
2330 if ((control_flags
& PORT_CONTROL_FLAGS_PROMISCUOUS_SET
) != 0) {
2333 error1
= ifnet_set_promiscuous(port_ifp
, 0);
2335 printf("%s(%s, %s): promiscous mode disable failed %d\n",
2337 ifb
->ifb_name
, bondport_get_name(p
), error1
);
2340 if ((control_flags
& PORT_CONTROL_FLAGS_PROTO_ATTACHED
) != 0) {
2341 (void)bond_detach_protocol(port_ifp
);
2343 if ((control_flags
& PORT_CONTROL_FLAGS_FILTER_ATTACHED
) != 0) {
2344 iflt_detach(filter
);
2346 if ((control_flags
& PORT_CONTROL_FLAGS_MTU_SET
) != 0) {
2349 error1
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
2351 printf("%s(%s, %s): SIOCSIFMTU %d failed %d\n",
2353 ifb
->ifb_name
, bondport_get_name(p
),
2354 p
->po_devmtu
.ifdm_current
, error1
);
2358 if ((control_flags
& PORT_CONTROL_FLAGS_IN_LIST
) != 0) {
2359 TAILQ_REMOVE(&ifb
->ifb_port_list
, p
, po_port_list
);
2360 ifb
->ifb_port_count
--;
2362 if_clear_eflags(ifp
, IFEF_BOND
);
2363 if (TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
2364 ifb
->ifb_altmtu
= 0;
2365 ifnet_set_mtu(ifp
, ETHERMTU
);
2366 ifnet_set_offload(ifp
, 0);
2370 ifbond_signal(ifb
, __func__
);
2372 ifbond_release(ifb
);
2378 bond_remove_interface(ifbond_ref ifb
, struct ifnet
* port_ifp
)
2383 bondport_ref head_port
;
2385 interface_filter_t filter
;
2387 int new_link_address
= FALSE
;
2389 lacp_actor_partner_state s
;
2390 int was_distributing
;
2392 bond_assert_lock_held();
2395 ifbond_wait(ifb
, "bond_remove_interface");
2397 p
= ifbond_lookup_port(ifb
, port_ifp
);
2400 /* it got removed by another thread */
2404 /* de-select it and remove it from the lists */
2405 was_distributing
= bondport_flags_distributing(p
);
2406 bondport_disable_distributing(p
);
2407 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
2408 bondport_set_selected(p
, SelectedState_UNSELECTED
);
2409 active_lag
= bondport_remove_from_LAG(p
);
2410 /* invalidate timers here while holding the bond_lock */
2411 bondport_invalidate_timers(p
);
2413 /* announce that we're Individual now */
2414 s
= p
->po_actor_state
;
2415 s
= lacp_actor_partner_state_set_individual(s
);
2416 s
= lacp_actor_partner_state_set_not_collecting(s
);
2417 s
= lacp_actor_partner_state_set_not_distributing(s
);
2418 s
= lacp_actor_partner_state_set_out_of_sync(s
);
2419 p
->po_actor_state
= s
;
2420 bondport_flags_set_ntt(p
);
2423 TAILQ_REMOVE(&ifb
->ifb_port_list
, p
, po_port_list
);
2424 ifb
->ifb_port_count
--;
2427 head_port
= TAILQ_FIRST(&ifb
->ifb_port_list
);
2428 if (head_port
== NULL
) {
2429 ifnet_set_flags(ifp
, 0, IFF_RUNNING
);
2430 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2433 ifnet_set_offload(ifp
, 0);
2434 ifnet_set_mtu(ifp
, ETHERMTU
);
2435 ifb
->ifb_altmtu
= 0;
2436 } else if (ifbond_flags_lladdr(ifb
) == FALSE
2437 && bcmp(&p
->po_saved_addr
, IF_LLADDR(ifp
),
2438 ETHER_ADDR_LEN
) == 0) {
2439 new_link_address
= TRUE
;
2441 /* check if we need to generate a link status event */
2442 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
2443 if (ifbond_selection(ifb
) || active_lag
) {
2444 event_code
= (ifb
->ifb_active_lag
== NULL
)
2447 ifb
->ifb_last_link_event
= event_code
;
2449 bondport_transmit_machine(p
, LAEventStart
,
2450 TRANSMIT_MACHINE_TX_IMMEDIATE
);
2452 /* are we removing the last distributing interface? */
2453 if (was_distributing
&& ifb
->ifb_distributing_count
== 0) {
2454 ifb
->ifb_last_link_event
= event_code
= KEV_DL_LINK_OFF
;
2457 filter
= p
->po_filter
;
2461 ifnet_set_lladdr_and_type(ifp
, NULL
, 0, IFT_IEEE8023ADLAG
);
2462 } else if (new_link_address
) {
2463 struct ifnet
* scan_ifp
;
2464 bondport_ref scan_port
;
2466 /* ifbond_wait() allows port list traversal without holding the lock */
2468 /* this port gave the bond its ethernet address, switch to new one */
2469 ifnet_set_lladdr_and_type(ifp
,
2470 &head_port
->po_saved_addr
, ETHER_ADDR_LEN
,
2473 /* re-program each port with the new link address */
2474 TAILQ_FOREACH(scan_port
, &ifb
->ifb_port_list
, po_port_list
) {
2475 scan_ifp
= scan_port
->po_ifp
;
2477 if ((scan_port
->po_control_flags
&
2478 PORT_CONTROL_FLAGS_LLADDR_SET
) == 0) {
2479 /* port doesn't support setting lladdr */
2482 error
= if_siflladdr(scan_ifp
,
2483 (const struct ether_addr
*) IF_LLADDR(ifp
));
2485 printf("%s(%s, %s): "
2486 "if_siflladdr (%s) failed %d\n",
2488 ifb
->ifb_name
, bondport_get_name(p
),
2489 bondport_get_name(scan_port
), error
);
2494 /* restore the port's ethernet address */
2495 if ((p
->po_control_flags
& PORT_CONTROL_FLAGS_LLADDR_SET
) != 0) {
2496 error
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2498 printf("%s(%s, %s): if_siflladdr failed %d\n",
2500 ifb
->ifb_name
, bondport_get_name(p
), error
);
2504 /* disable promiscous mode (if we enabled it) */
2505 if ((p
->po_control_flags
& PORT_CONTROL_FLAGS_PROMISCUOUS_SET
) != 0) {
2506 error
= ifnet_set_promiscuous(port_ifp
, 0);
2508 printf("%s(%s, %s): disable promiscuous failed %d\n",
2510 ifb
->ifb_name
, bondport_get_name(p
), error
);
2514 /* restore the port's MTU */
2515 error
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
2517 printf("%s(%s, %s): SIOCSIFMTU %d failed %d\n",
2519 ifb
->ifb_name
, bondport_get_name(p
),
2520 p
->po_devmtu
.ifdm_current
, error
);
2523 /* remove the bond "protocol" */
2524 bond_detach_protocol(port_ifp
);
2526 /* detach the filter */
2527 if (filter
!= NULL
) {
2528 iflt_detach(filter
);
2531 /* generate link event */
2532 if (event_code
!= 0) {
2533 interface_link_event(ifp
, event_code
);
2538 if_clear_eflags(port_ifp
, IFEF_BOND
);
2539 /* release this bondport's reference to the ifbond */
2540 ifbond_release(ifb
);
2543 ifbond_signal(ifb
, __func__
);
2544 ifbond_release(ifb
);
2549 bond_set_lacp_mode(ifbond_ref ifb
)
2553 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2554 bondport_disable_distributing(p
);
2561 bond_set_static_mode(ifbond_ref ifb
)
2564 lacp_actor_partner_state s
;
2566 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2567 bondport_disable_distributing(p
);
2568 bondport_set_selected(p
, SelectedState_UNSELECTED
);
2569 (void)bondport_remove_from_LAG(p
);
2570 bondport_cancel_timers(p
);
2572 /* announce that we're Individual now */
2573 s
= p
->po_actor_state
;
2574 s
= lacp_actor_partner_state_set_individual(s
);
2575 s
= lacp_actor_partner_state_set_not_collecting(s
);
2576 s
= lacp_actor_partner_state_set_not_distributing(s
);
2577 s
= lacp_actor_partner_state_set_out_of_sync(s
);
2578 p
->po_actor_state
= s
;
2579 bondport_flags_set_ntt(p
);
2580 bondport_transmit_machine(p
, LAEventStart
,
2581 TRANSMIT_MACHINE_TX_IMMEDIATE
);
2583 p
->po_actor_state
= 0;
2584 bzero(&p
->po_partner_state
, sizeof(p
->po_partner_state
));
2586 if (media_active(&p
->po_media_info
)) {
2587 bondport_enable_distributing(p
);
2589 bondport_disable_distributing(p
);
2596 bond_set_mode(struct ifnet
* ifp
, int mode
)
2603 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2604 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2606 return (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2608 if (ifb
->ifb_mode
== mode
) {
2614 ifbond_wait(ifb
, "bond_set_mode");
2616 /* verify (again) that the mode is actually different */
2617 if (ifb
->ifb_mode
== mode
) {
2622 ifb
->ifb_mode
= mode
;
2623 if (mode
== IF_BOND_MODE_LACP
) {
2624 bond_set_lacp_mode(ifb
);
2626 /* check if we need to generate a link status event */
2627 if (ifbond_selection(ifb
)) {
2628 event_code
= (ifb
->ifb_active_lag
== NULL
)
2633 bond_set_static_mode(ifb
);
2634 event_code
= (ifb
->ifb_distributing_count
== 0)
2638 ifb
->ifb_last_link_event
= event_code
;
2641 ifbond_signal(ifb
, __func__
);
2643 ifbond_release(ifb
);
2645 if (event_code
!= 0) {
2646 interface_link_event(ifp
, event_code
);
2652 bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
, user_addr_t datap
)
2657 struct if_bond_status_req
* ibsr
;
2658 struct if_bond_status ibs
;
2661 ibsr
= &(ibr_p
->ibr_ibru
.ibru_status
);
2662 if (ibsr
->ibsr_version
!= IF_BOND_STATUS_REQ_VERSION
) {
2665 ibsr
->ibsr_key
= ifb
->ifb_key
;
2666 ibsr
->ibsr_mode
= ifb
->ifb_mode
;
2667 ibsr
->ibsr_total
= ifb
->ifb_port_count
;
2668 dst
= proc_is64bit(current_proc())
2669 ? ibsr
->ibsr_ibsru
.ibsru_buffer64
2670 : CAST_USER_ADDR_T(ibsr
->ibsr_ibsru
.ibsru_buffer
);
2671 if (dst
== USER_ADDR_NULL
) {
2672 /* just want to know how many there are */
2675 if (ibsr
->ibsr_count
< 0) {
2678 count
= (ifb
->ifb_port_count
< ibsr
->ibsr_count
)
2679 ? ifb
->ifb_port_count
: ibsr
->ibsr_count
;
2680 TAILQ_FOREACH(port
, &ifb
->ifb_port_list
, po_port_list
) {
2681 struct if_bond_partner_state
* ibps_p
;
2682 partner_state_ref ps
;
2687 bzero(&ibs
, sizeof(ibs
));
2688 strlcpy(ibs
.ibs_if_name
, port
->po_name
, sizeof(ibs
.ibs_if_name
));
2689 ibs
.ibs_port_priority
= port
->po_priority
;
2690 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
2691 ibs
.ibs_state
= port
->po_actor_state
;
2692 ibs
.ibs_selected_state
= port
->po_selected
;
2693 ps
= &port
->po_partner_state
;
2694 ibps_p
= &ibs
.ibs_partner_state
;
2695 ibps_p
->ibps_system
= ps
->ps_lag_info
.li_system
;
2696 ibps_p
->ibps_system_priority
= ps
->ps_lag_info
.li_system_priority
;
2697 ibps_p
->ibps_key
= ps
->ps_lag_info
.li_key
;
2698 ibps_p
->ibps_port
= ps
->ps_port
;
2699 ibps_p
->ibps_port_priority
= ps
->ps_port_priority
;
2700 ibps_p
->ibps_state
= ps
->ps_state
;
2702 /* fake the selected information */
2703 ibs
.ibs_selected_state
= bondport_flags_distributing(port
)
2704 ? SelectedState_SELECTED
: SelectedState_UNSELECTED
;
2706 error
= copyout(&ibs
, dst
, sizeof(ibs
));
2716 error
= copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2718 (void)copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2724 bond_set_promisc(__unused
struct ifnet
*ifp
)
2731 bond_get_mtu_values(ifbond_ref ifb
, int * ret_min
, int * ret_max
)
2737 if (TAILQ_FIRST(&ifb
->ifb_port_list
) != NULL
) {
2738 mtu_min
= IF_MINMTU
;
2740 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2741 struct ifdevmtu
* devmtu_p
= &p
->po_devmtu
;
2743 if (devmtu_p
->ifdm_min
> mtu_min
) {
2744 mtu_min
= devmtu_p
->ifdm_min
;
2746 if (mtu_max
== 0 || devmtu_p
->ifdm_max
< mtu_max
) {
2747 mtu_max
= devmtu_p
->ifdm_max
;
2756 bond_set_mtu_on_ports(ifbond_ref ifb
, int mtu
)
2761 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2762 error
= siocsifmtu(p
->po_ifp
, mtu
);
2764 printf("if_bond(%s): SIOCSIFMTU %s failed, %d\n",
2765 ifb
->ifb_name
, bondport_get_name(p
), error
);
2773 bond_set_mtu(struct ifnet
* ifp
, int mtu
, int isdevmtu
)
2783 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2784 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2785 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2789 ifbond_wait(ifb
, "bond_set_mtu");
2792 if (ifnet_softc(ifp
) == NULL
|| ifbond_flags_if_detaching(ifb
)) {
2796 bond_get_mtu_values(ifb
, &mtu_min
, &mtu_max
);
2797 if (mtu
> mtu_max
) {
2801 if (mtu
< mtu_min
&& (isdevmtu
== 0 || mtu
!= 0)) {
2802 /* allow SIOCSIFALTMTU to set the mtu to 0 */
2807 new_max
= (mtu
> (int)ifnet_mtu(ifp
)) ? mtu
: (int)ifnet_mtu(ifp
);
2809 new_max
= (mtu
> ifb
->ifb_altmtu
) ? mtu
: ifb
->ifb_altmtu
;
2811 old_max
= ((int)ifnet_mtu(ifp
) > ifb
->ifb_altmtu
)
2812 ? (int)ifnet_mtu(ifp
) : ifb
->ifb_altmtu
;
2813 if (new_max
!= old_max
) {
2814 /* we can safely walk the list of port without the lock held */
2816 error
= bond_set_mtu_on_ports(ifb
, new_max
);
2818 /* try our best to back out of it */
2819 (void)bond_set_mtu_on_ports(ifb
, old_max
);
2825 ifb
->ifb_altmtu
= mtu
;
2827 ifnet_set_mtu(ifp
, mtu
);
2832 ifbond_signal(ifb
, __func__
);
2833 ifbond_release(ifb
);
2841 bond_ioctl(struct ifnet
*ifp
, u_long cmd
, void * data
)
2844 struct if_bond_req ibr
;
2845 struct ifaddr
* ifa
;
2848 struct ifmediareq
*ifmr
;
2849 struct ifnet
* port_ifp
= NULL
;
2850 user_addr_t user_addr
;
2852 if (ifnet_type(ifp
) != IFT_IEEE8023ADLAG
) {
2855 ifr
= (struct ifreq
*)data
;
2856 ifa
= (struct ifaddr
*)data
;
2860 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
2863 case SIOCGIFMEDIA32
:
2864 case SIOCGIFMEDIA64
:
2866 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2867 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2869 return ifb
== NULL
? EOPNOTSUPP
: EBUSY
;
2871 ifmr
= (struct ifmediareq
*)data
;
2872 ifmr
->ifm_current
= IFM_ETHER
;
2874 ifmr
->ifm_status
= IFM_AVALID
;
2875 ifmr
->ifm_active
= IFM_ETHER
;
2876 ifmr
->ifm_count
= 1;
2877 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
2878 if (ifb
->ifb_active_lag
!= NULL
) {
2879 ifmr
->ifm_active
= ifb
->ifb_active_lag
->lag_active_media
;
2880 ifmr
->ifm_status
|= IFM_ACTIVE
;
2882 } else if (ifb
->ifb_distributing_count
> 0) {
2884 = ifb
->ifb_distributing_array
[0]->po_media_info
.mi_active
;
2885 ifmr
->ifm_status
|= IFM_ACTIVE
;
2888 user_addr
= (cmd
== SIOCGIFMEDIA64
) ?
2889 ((struct ifmediareq64
*)ifmr
)->ifmu_ulist
:
2890 CAST_USER_ADDR_T(((struct ifmediareq32
*)ifmr
)->ifmu_ulist
);
2891 if (user_addr
!= USER_ADDR_NULL
) {
2892 error
= copyout(&ifmr
->ifm_current
,
2899 /* XXX send the SIFMEDIA to all children? Or force autoselect? */
2905 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2906 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2908 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2911 ifr
->ifr_devmtu
.ifdm_current
= bond_device_mtu(ifp
, ifb
);
2912 bond_get_mtu_values(ifb
, &ifr
->ifr_devmtu
.ifdm_min
,
2913 &ifr
->ifr_devmtu
.ifdm_max
);
2919 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2920 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2922 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2925 ifr
->ifr_mtu
= ifb
->ifb_altmtu
;
2930 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 1);
2934 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 0);
2938 user_addr
= proc_is64bit(current_proc())
2939 ? ifr
->ifr_data64
: CAST_USER_ADDR_T(ifr
->ifr_data
);
2940 error
= copyin(user_addr
, &ibr
, sizeof(ibr
));
2944 switch (ibr
.ibr_op
) {
2945 case IF_BOND_OP_ADD_INTERFACE
:
2946 case IF_BOND_OP_REMOVE_INTERFACE
:
2947 port_ifp
= ifunit(ibr
.ibr_ibru
.ibru_if_name
);
2948 if (port_ifp
== NULL
) {
2952 if (ifnet_type(port_ifp
) != IFT_ETHER
) {
2953 error
= EPROTONOSUPPORT
;
2957 case IF_BOND_OP_SET_VERBOSE
:
2958 case IF_BOND_OP_SET_MODE
:
2967 switch (ibr
.ibr_op
) {
2968 case IF_BOND_OP_ADD_INTERFACE
:
2969 error
= bond_add_interface(ifp
, port_ifp
);
2971 case IF_BOND_OP_REMOVE_INTERFACE
:
2973 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2974 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2976 return ifb
== NULL
? EOPNOTSUPP
: EBUSY
;
2978 error
= bond_remove_interface(ifb
, port_ifp
);
2981 case IF_BOND_OP_SET_VERBOSE
:
2983 if_bond_debug
= ibr
.ibr_ibru
.ibru_int_val
;
2986 case IF_BOND_OP_SET_MODE
:
2987 switch (ibr
.ibr_ibru
.ibru_int_val
) {
2988 case IF_BOND_MODE_LACP
:
2989 case IF_BOND_MODE_STATIC
:
2998 error
= bond_set_mode(ifp
, ibr
.ibr_ibru
.ibru_int_val
);
3001 break; /* SIOCSIFBOND */
3004 user_addr
= proc_is64bit(current_proc())
3005 ? ifr
->ifr_data64
: CAST_USER_ADDR_T(ifr
->ifr_data
);
3006 error
= copyin(user_addr
, &ibr
, sizeof(ibr
));
3010 switch (ibr
.ibr_op
) {
3011 case IF_BOND_OP_GET_STATUS
:
3021 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
3022 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
3024 return ifb
== NULL
? EOPNOTSUPP
: EBUSY
;
3026 switch (ibr
.ibr_op
) {
3027 case IF_BOND_OP_GET_STATUS
:
3028 error
= bond_get_status(ifb
, &ibr
, user_addr
);
3032 break; /* SIOCGIFBOND */
3039 /* enable/disable promiscuous mode */
3041 error
= bond_set_promisc(ifp
);
3047 error
= bond_setmulti(ifp
);
3056 bond_if_free(struct ifnet
* ifp
)
3064 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
3069 ifbond_release(ifb
);
3076 bond_handle_event(struct ifnet
* port_ifp
, int event_code
)
3078 struct ifnet
* bond_ifp
= NULL
;
3080 int old_distributing_count
;
3082 struct media_info media_info
= { .mi_active
= 0, .mi_status
= 0 };
3084 switch (event_code
) {
3085 case KEV_DL_IF_DETACHED
:
3086 case KEV_DL_IF_DETACHING
:
3088 case KEV_DL_LINK_OFF
:
3089 case KEV_DL_LINK_ON
:
3090 media_info
= interface_media_info(port_ifp
);
3096 p
= bond_lookup_port(port_ifp
);
3102 old_distributing_count
= ifb
->ifb_distributing_count
;
3103 switch (event_code
) {
3104 case KEV_DL_IF_DETACHED
:
3105 case KEV_DL_IF_DETACHING
:
3106 bond_remove_interface(ifb
, p
->po_ifp
);
3108 case KEV_DL_LINK_OFF
:
3109 case KEV_DL_LINK_ON
:
3110 p
->po_media_info
= media_info
;
3111 if (p
->po_enabled
) {
3112 bondport_link_status_changed(p
);
3116 /* generate a link-event */
3117 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
3118 if (ifbond_selection(ifb
)) {
3119 event_code
= (ifb
->ifb_active_lag
== NULL
)
3122 /* XXX need to take a reference on bond_ifp */
3123 bond_ifp
= ifb
->ifb_ifp
;
3124 ifb
->ifb_last_link_event
= event_code
;
3126 event_code
= (ifb
->ifb_active_lag
== NULL
)
3129 if (event_code
!= ifb
->ifb_last_link_event
) {
3130 if (if_bond_debug
) {
3131 timestamp_printf("%s: (event) generating LINK event\n",
3134 bond_ifp
= ifb
->ifb_ifp
;
3135 ifb
->ifb_last_link_event
= event_code
;
3140 * if the distributing array membership changed from 0 <-> !0
3141 * generate a link event
3143 if (old_distributing_count
== 0
3144 && ifb
->ifb_distributing_count
!= 0) {
3145 event_code
= KEV_DL_LINK_ON
;
3146 } else if (old_distributing_count
!= 0
3147 && ifb
->ifb_distributing_count
== 0) {
3148 event_code
= KEV_DL_LINK_OFF
;
3150 if (event_code
!= 0 && event_code
!= ifb
->ifb_last_link_event
) {
3151 bond_ifp
= ifb
->ifb_ifp
;
3152 ifb
->ifb_last_link_event
= event_code
;
3157 if (bond_ifp
!= NULL
) {
3158 interface_link_event(bond_ifp
, event_code
);
3164 bond_iff_event(__unused
void *cookie
, ifnet_t port_ifp
,
3165 __unused protocol_family_t protocol
,
3166 const struct kev_msg
*event
)
3170 if (event
->vendor_code
!= KEV_VENDOR_APPLE
3171 || event
->kev_class
!= KEV_NETWORK_CLASS
3172 || event
->kev_subclass
!= KEV_DL_SUBCLASS
) {
3175 event_code
= event
->event_code
;
3176 switch (event_code
) {
3177 case KEV_DL_LINK_OFF
:
3178 case KEV_DL_LINK_ON
:
3179 case KEV_DL_IF_DETACHING
:
3180 case KEV_DL_IF_DETACHED
:
3181 bond_handle_event(port_ifp
, event_code
);
3190 bond_iff_detached(__unused
void *cookie
, ifnet_t port_ifp
)
3192 bond_handle_event(port_ifp
, KEV_DL_IF_DETACHED
);
3197 interface_link_event(struct ifnet
* ifp
, u_int32_t event_code
)
3200 u_int32_t ifnet_family
;
3202 char if_name
[IFNAMSIZ
];
3204 _Alignas(struct kern_event_msg
) char message
[sizeof(struct kern_event_msg
) + sizeof(struct event
)] = { 0 };
3205 struct kern_event_msg
*header
= (struct kern_event_msg
*)message
;
3206 struct event
*data
= (struct event
*)(header
+ 1);
3208 header
->total_size
= sizeof(message
);
3209 header
->vendor_code
= KEV_VENDOR_APPLE
;
3210 header
->kev_class
= KEV_NETWORK_CLASS
;
3211 header
->kev_subclass
= KEV_DL_SUBCLASS
;
3212 header
->event_code
= event_code
;
3213 data
->ifnet_family
= ifnet_family(ifp
);
3214 data
->unit
= (u_int32_t
)ifnet_unit(ifp
);
3215 strlcpy(data
->if_name
, ifnet_name(ifp
), IFNAMSIZ
);
3216 ifnet_event(ifp
, header
);
3220 bond_proto_input(ifnet_t ifp
, protocol_family_t protocol
, mbuf_t packet
,
3223 #pragma unused(protocol, packet, header)
3224 if (if_bond_debug
!= 0) {
3225 printf("%s: unexpected packet from %s\n", __func__
,
3233 * Function: bond_attach_protocol
3235 * Attach a DLIL protocol to the interface.
3237 * The ethernet demux special cases to always return PF_BOND if the
3238 * interface is bonded. That means we receive all traffic from that
3239 * interface without passing any of the traffic to any other attached
3243 bond_attach_protocol(struct ifnet
*ifp
)
3246 struct ifnet_attach_proto_param reg
;
3248 bzero(®
, sizeof(reg
));
3249 reg
.input
= bond_proto_input
;
3251 error
= ifnet_attach_protocol(ifp
, PF_BOND
, ®
);
3253 printf("bond over %s%d: ifnet_attach_protocol failed, %d\n",
3254 ifnet_name(ifp
), ifnet_unit(ifp
), error
);
3260 * Function: bond_detach_protocol
3262 * Detach our DLIL protocol from an interface
3265 bond_detach_protocol(struct ifnet
*ifp
)
3269 error
= ifnet_detach_protocol(ifp
, PF_BOND
);
3271 printf("bond over %s%d: ifnet_detach_protocol failed, %d\n",
3272 ifnet_name(ifp
), ifnet_unit(ifp
), error
);
3278 * Function: bond_attach_filter
3280 * Attach our DLIL interface filter.
3283 bond_attach_filter(struct ifnet
*ifp
, interface_filter_t
* filter_p
)
3286 struct iff_filter iff
;
3289 * install an interface filter
3291 memset(&iff
, 0, sizeof(struct iff_filter
));
3292 iff
.iff_name
= "com.apple.kernel.bsd.net.if_bond";
3293 iff
.iff_input
= bond_iff_input
;
3294 iff
.iff_event
= bond_iff_event
;
3295 iff
.iff_detached
= bond_iff_detached
;
3296 error
= iflt_attach_internal(ifp
, &iff
, filter_p
);
3298 printf("%s: iflt_attach_internal failed %d\n", __func__
, error
);
3305 * DLIL interface family functions
3307 extern int ether_attach_inet(ifnet_t ifp
, protocol_family_t protocol_family
);
3308 extern void ether_detach_inet(ifnet_t ifp
, protocol_family_t protocol_family
);
3309 extern int ether_attach_inet6(ifnet_t ifp
, protocol_family_t protocol_family
);
3310 extern void ether_detach_inet6(ifnet_t ifp
, protocol_family_t protocol_family
);
3311 extern int ether_attach_at(ifnet_t ifp
, protocol_family_t protocol_family
);
3312 extern void ether_detach_at(ifnet_t ifp
, protocol_family_t protocol_family
);
3314 __private_extern__
int
3315 bond_family_init(void)
3319 error
= proto_register_plumber(PF_INET
, APPLE_IF_FAM_BOND
,
3323 printf("bond: proto_register_plumber failed for AF_INET error=%d\n",
3327 error
= proto_register_plumber(PF_INET6
, APPLE_IF_FAM_BOND
,
3329 ether_detach_inet6
);
3331 printf("bond: proto_register_plumber failed for AF_INET6 error=%d\n",
3335 error
= bond_clone_attach();
3337 printf("bond: proto_register_plumber failed bond_clone_attach error=%d\n",
3352 ** LACP ifbond_list routines
3355 ifbond_list_find_moved_port(bondport_ref rx_port
,
3356 const lacp_actor_partner_tlv_ref atlv
)
3360 partner_state_ref ps
;
3363 TAILQ_FOREACH(bond
, &g_bond
->ifbond_list
, ifb_bond_list
) {
3364 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3366 /* no point in comparing against ourselves */
3369 if (p
->po_receive_state
!= ReceiveState_PORT_DISABLED
) {
3370 /* it's not clear that we should be checking this */
3373 ps
= &p
->po_partner_state
;
3374 if (lacp_actor_partner_state_defaulted(ps
->ps_state
)) {
3377 ps_li
= &ps
->ps_lag_info
;
3378 if (ps
->ps_port
== lacp_actor_partner_tlv_get_port(atlv
)
3379 && bcmp(&ps_li
->li_system
, atlv
->lap_system
,
3380 sizeof(ps_li
->li_system
)) == 0) {
3381 if (if_bond_debug
) {
3382 timestamp_printf("System " EA_FORMAT
3383 " Port 0x%x moved from %s to %s\n",
3384 EA_LIST(&ps_li
->li_system
), ps
->ps_port
,
3385 bondport_get_name(p
),
3386 bondport_get_name(rx_port
));
3396 ** LACP ifbond, LAG routines
3400 ifbond_selection(ifbond_ref bond
)
3402 int all_ports_ready
= 0;
3403 int active_media
= 0;
3405 int lag_changed
= 0;
3409 lag
= ifbond_find_best_LAG(bond
, &active_media
);
3410 if (lag
!= bond
->ifb_active_lag
) {
3411 if (bond
->ifb_active_lag
!= NULL
) {
3412 ifbond_deactivate_LAG(bond
, bond
->ifb_active_lag
);
3413 bond
->ifb_active_lag
= NULL
;
3415 bond
->ifb_active_lag
= lag
;
3417 ifbond_activate_LAG(bond
, lag
, active_media
);
3420 } else if (lag
!= NULL
) {
3421 if (lag
->lag_active_media
!= active_media
) {
3422 if (if_bond_debug
) {
3423 timestamp_printf("LAG PORT SPEED CHANGED from %d to %d\n",
3424 link_speed(lag
->lag_active_media
),
3425 link_speed(active_media
));
3427 ifbond_deactivate_LAG(bond
, lag
);
3428 ifbond_activate_LAG(bond
, lag
, active_media
);
3433 port_speed
= link_speed(active_media
);
3434 all_ports_ready
= ifbond_all_ports_ready(bond
);
3436 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3437 if (lag
!= NULL
&& p
->po_lag
== lag
3438 && media_speed(&p
->po_media_info
) == port_speed
3439 && (p
->po_mux_state
== MuxState_DETACHED
3440 || p
->po_selected
== SelectedState_SELECTED
3441 || p
->po_selected
== SelectedState_STANDBY
)
3442 && bondport_aggregatable(p
)) {
3443 if (bond
->ifb_max_active
> 0) {
3444 if (lag
->lag_selected_port_count
< bond
->ifb_max_active
) {
3445 if (p
->po_selected
== SelectedState_STANDBY
3446 || p
->po_selected
== SelectedState_UNSELECTED
) {
3447 bondport_set_selected(p
, SelectedState_SELECTED
);
3449 } else if (p
->po_selected
== SelectedState_UNSELECTED
) {
3450 bondport_set_selected(p
, SelectedState_STANDBY
);
3453 bondport_set_selected(p
, SelectedState_SELECTED
);
3456 if (bondport_flags_selected_changed(p
)) {
3457 bondport_flags_clear_selected_changed(p
);
3458 bondport_mux_machine(p
, LAEventSelectedChange
, NULL
);
3461 && bondport_flags_ready(p
)
3462 && p
->po_mux_state
== MuxState_WAITING
) {
3463 bondport_mux_machine(p
, LAEventReady
, NULL
);
3465 bondport_transmit_machine(p
, LAEventStart
, NULL
);
3471 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
)
3473 int best_active
= 0;
3474 LAG_ref best_lag
= NULL
;
3479 if (bond
->ifb_active_lag
!= NULL
) {
3480 best_lag
= bond
->ifb_active_lag
;
3481 best_count
= LAG_get_aggregatable_port_count(best_lag
, &best_active
);
3482 if (bond
->ifb_max_active
> 0
3483 && best_count
> bond
->ifb_max_active
) {
3484 best_count
= bond
->ifb_max_active
;
3486 best_speed
= link_speed(best_active
);
3488 TAILQ_FOREACH(lag
, &bond
->ifb_lag_list
, lag_list
) {
3493 if (lag
== bond
->ifb_active_lag
) {
3494 /* we've already computed it */
3497 count
= LAG_get_aggregatable_port_count(lag
, &active
);
3501 if (bond
->ifb_max_active
> 0
3502 && count
> bond
->ifb_max_active
) {
3503 /* if there's a limit, don't count extra links */
3504 count
= bond
->ifb_max_active
;
3506 speed
= link_speed(active
);
3507 if ((count
* speed
) > (best_count
* best_speed
)) {
3510 best_active
= active
;
3514 if (best_count
== 0) {
3517 *active_media
= best_active
;
3522 ifbond_deactivate_LAG(__unused ifbond_ref bond
, LAG_ref lag
)
3526 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3527 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3533 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
)
3538 if (bond
->ifb_max_active
> 0) {
3539 need
= bond
->ifb_max_active
;
3541 lag
->lag_active_media
= active_media
;
3542 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3543 if (bondport_aggregatable(p
) == 0) {
3544 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3545 } else if (media_speed(&p
->po_media_info
) != link_speed(active_media
)) {
3546 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3547 } else if (p
->po_mux_state
== MuxState_DETACHED
) {
3548 if (bond
->ifb_max_active
> 0) {
3550 bondport_set_selected(p
, SelectedState_SELECTED
);
3553 bondport_set_selected(p
, SelectedState_STANDBY
);
3556 bondport_set_selected(p
, SelectedState_SELECTED
);
3559 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3567 ifbond_set_max_active(ifbond_ref bond
, int max_active
)
3569 LAG_ref lag
= bond
->ifb_active_lag
;
3571 bond
->ifb_max_active
= max_active
;
3572 if (bond
->ifb_max_active
<= 0 || lag
== NULL
) {
3575 if (lag
->lag_selected_port_count
> bond
->ifb_max_active
) {
3579 remove_count
= lag
->lag_selected_port_count
- bond
->ifb_max_active
;
3580 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3581 if (p
->po_selected
== SelectedState_SELECTED
) {
3582 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3584 if (remove_count
== 0) {
3595 ifbond_all_ports_ready(ifbond_ref bond
)
3600 if (bond
->ifb_active_lag
== NULL
) {
3603 TAILQ_FOREACH(p
, &bond
->ifb_active_lag
->lag_port_list
, po_lag_port_list
) {
3604 if (p
->po_mux_state
== MuxState_WAITING
3605 && p
->po_selected
== SelectedState_SELECTED
) {
3606 if (bondport_flags_ready(p
) == 0) {
3610 /* note that there was at least one ready port */
3617 ifbond_all_ports_attached(ifbond_ref bond
, bondport_ref this_port
)
3621 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3622 if (this_port
== p
) {
3625 if (bondport_flags_mux_attached(p
) == 0) {
3633 ifbond_get_LAG_matching_port(ifbond_ref bond
, bondport_ref p
)
3637 TAILQ_FOREACH(lag
, &bond
->ifb_lag_list
, lag_list
) {
3638 if (bcmp(&lag
->lag_info
, &p
->po_partner_state
.ps_lag_info
,
3639 sizeof(lag
->lag_info
)) == 0) {
3647 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
)
3657 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3658 if (bondport_aggregatable(p
)) {
3661 this_speed
= media_speed(&p
->po_media_info
);
3662 if (this_speed
== 0) {
3665 if (this_speed
> speed
) {
3666 active
= p
->po_media_info
.mi_active
;
3669 } else if (this_speed
== speed
) {
3674 *active_media
= active
;
3680 ** LACP bondport routines
3683 bondport_link_status_changed(bondport_ref p
)
3685 ifbond_ref bond
= p
->po_bond
;
3687 if (if_bond_debug
) {
3688 if (media_active(&p
->po_media_info
)) {
3689 const char * duplex_string
;
3691 if (media_full_duplex(&p
->po_media_info
)) {
3692 duplex_string
= "full";
3693 } else if (media_type_unknown(&p
->po_media_info
)) {
3694 duplex_string
= "unknown";
3696 duplex_string
= "half";
3698 timestamp_printf("[%s] Link UP %d Mbit/s %s duplex\n",
3699 bondport_get_name(p
),
3700 media_speed(&p
->po_media_info
),
3703 timestamp_printf("[%s] Link DOWN\n",
3704 bondport_get_name(p
));
3707 if (bond
->ifb_mode
== IF_BOND_MODE_LACP
) {
3708 if (media_active(&p
->po_media_info
)
3709 && bond
->ifb_active_lag
!= NULL
3710 && p
->po_lag
== bond
->ifb_active_lag
3711 && p
->po_selected
!= SelectedState_UNSELECTED
) {
3712 if (media_speed(&p
->po_media_info
) != p
->po_lag
->lag_active_media
) {
3713 if (if_bond_debug
) {
3714 timestamp_printf("[%s] Port speed %d differs from LAG %d\n",
3715 bondport_get_name(p
),
3716 media_speed(&p
->po_media_info
),
3717 link_speed(p
->po_lag
->lag_active_media
));
3719 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3722 bondport_receive_machine(p
, LAEventMediaChange
, NULL
);
3723 bondport_mux_machine(p
, LAEventMediaChange
, NULL
);
3724 bondport_periodic_transmit_machine(p
, LAEventMediaChange
, NULL
);
3726 if (media_active(&p
->po_media_info
)) {
3727 bondport_enable_distributing(p
);
3729 bondport_disable_distributing(p
);
3736 bondport_aggregatable(bondport_ref p
)
3738 partner_state_ref ps
= &p
->po_partner_state
;
3740 if (lacp_actor_partner_state_aggregatable(p
->po_actor_state
) == 0
3741 || lacp_actor_partner_state_aggregatable(ps
->ps_state
) == 0) {
3742 /* we and/or our partner are individual */
3745 if (p
->po_lag
== NULL
) {
3748 switch (p
->po_receive_state
) {
3750 if (if_bond_debug
) {
3751 timestamp_printf("[%s] Port is not selectable\n",
3752 bondport_get_name(p
));
3755 case ReceiveState_CURRENT
:
3756 case ReceiveState_EXPIRED
:
3763 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
)
3765 LAG_info_ref lag_li
;
3766 partner_state_ref ps
;
3769 ps
= &p
->po_partner_state
;
3770 ps_li
= &ps
->ps_lag_info
;
3771 lag_li
= &lag
->lag_info
;
3772 if (ps_li
->li_system_priority
== lag_li
->li_system_priority
3773 && ps_li
->li_key
== lag_li
->li_key
3774 && (bcmp(&ps_li
->li_system
, &lag_li
->li_system
,
3775 sizeof(lag_li
->li_system
))
3783 bondport_remove_from_LAG(bondport_ref p
)
3786 ifbond_ref bond
= p
->po_bond
;
3787 LAG_ref lag
= p
->po_lag
;
3792 TAILQ_REMOVE(&lag
->lag_port_list
, p
, po_lag_port_list
);
3793 if (if_bond_debug
) {
3794 timestamp_printf("[%s] Removed from LAG (0x%04x," EA_FORMAT
3796 bondport_get_name(p
),
3797 lag
->lag_info
.li_system_priority
,
3798 EA_LIST(&lag
->lag_info
.li_system
),
3799 lag
->lag_info
.li_key
);
3802 lag
->lag_port_count
--;
3803 if (lag
->lag_port_count
> 0) {
3804 return bond
->ifb_active_lag
== lag
;
3806 if (if_bond_debug
) {
3807 timestamp_printf("Key 0x%04x: LAG Released (%04x," EA_FORMAT
3810 lag
->lag_info
.li_system_priority
,
3811 EA_LIST(&lag
->lag_info
.li_system
),
3812 lag
->lag_info
.li_key
);
3814 TAILQ_REMOVE(&bond
->ifb_lag_list
, lag
, lag_list
);
3815 if (bond
->ifb_active_lag
== lag
) {
3816 bond
->ifb_active_lag
= NULL
;
3824 bondport_add_to_LAG(bondport_ref p
, LAG_ref lag
)
3826 TAILQ_INSERT_TAIL(&lag
->lag_port_list
, p
, po_lag_port_list
);
3828 lag
->lag_port_count
++;
3829 if (if_bond_debug
) {
3830 timestamp_printf("[%s] Added to LAG (0x%04x," EA_FORMAT
"0x%04x)\n",
3831 bondport_get_name(p
),
3832 lag
->lag_info
.li_system_priority
,
3833 EA_LIST(&lag
->lag_info
.li_system
),
3834 lag
->lag_info
.li_key
);
3840 bondport_assign_to_LAG(bondport_ref p
)
3842 ifbond_ref bond
= p
->po_bond
;
3845 if (lacp_actor_partner_state_defaulted(p
->po_actor_state
)) {
3846 bondport_remove_from_LAG(p
);
3851 if (bondport_matches_LAG(p
, lag
)) {
3855 bondport_remove_from_LAG(p
);
3857 lag
= ifbond_get_LAG_matching_port(bond
, p
);
3859 bondport_add_to_LAG(p
, lag
);
3862 lag
= (LAG_ref
)_MALLOC(sizeof(*lag
), M_BOND
, M_WAITOK
);
3863 TAILQ_INIT(&lag
->lag_port_list
);
3864 lag
->lag_port_count
= 0;
3865 lag
->lag_selected_port_count
= 0;
3866 lag
->lag_info
= p
->po_partner_state
.ps_lag_info
;
3867 TAILQ_INSERT_TAIL(&bond
->ifb_lag_list
, lag
, lag_list
);
3868 if (if_bond_debug
) {
3869 timestamp_printf("Key 0x%04x: LAG Created (0x%04x," EA_FORMAT
3872 lag
->lag_info
.li_system_priority
,
3873 EA_LIST(&lag
->lag_info
.li_system
),
3874 lag
->lag_info
.li_key
);
3876 bondport_add_to_LAG(p
, lag
);
3881 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
)
3883 bondport_ref moved_port
;
3886 = ifbond_list_find_moved_port(p
, (const lacp_actor_partner_tlv_ref
)
3887 &in_lacpdu_p
->la_actor_tlv
);
3888 if (moved_port
!= NULL
) {
3889 bondport_receive_machine(moved_port
, LAEventPortMoved
, NULL
);
3891 bondport_receive_machine(p
, LAEventPacket
, in_lacpdu_p
);
3892 bondport_mux_machine(p
, LAEventPacket
, in_lacpdu_p
);
3893 bondport_periodic_transmit_machine(p
, LAEventPacket
, in_lacpdu_p
);
3898 bondport_set_selected(bondport_ref p
, SelectedState s
)
3900 if (s
!= p
->po_selected
) {
3901 ifbond_ref bond
= p
->po_bond
;
3902 LAG_ref lag
= p
->po_lag
;
3904 bondport_flags_set_selected_changed(p
);
3905 if (lag
!= NULL
&& bond
->ifb_active_lag
== lag
) {
3906 if (p
->po_selected
== SelectedState_SELECTED
) {
3907 lag
->lag_selected_port_count
--;
3908 } else if (s
== SelectedState_SELECTED
) {
3909 lag
->lag_selected_port_count
++;
3911 if (if_bond_debug
) {
3912 timestamp_printf("[%s] SetSelected: %s (was %s)\n",
3913 bondport_get_name(p
),
3914 SelectedStateString(s
),
3915 SelectedStateString(p
->po_selected
));
3928 bondport_UpdateDefaultSelected(bondport_ref p
)
3930 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3935 bondport_RecordDefault(bondport_ref p
)
3937 bzero(&p
->po_partner_state
, sizeof(p
->po_partner_state
));
3939 = lacp_actor_partner_state_set_defaulted(p
->po_actor_state
);
3940 bondport_assign_to_LAG(p
);
3945 bondport_UpdateSelected(bondport_ref p
, lacpdu_ref lacpdu_p
)
3947 lacp_actor_partner_tlv_ref actor
;
3948 partner_state_ref ps
;
3951 /* compare the PDU's Actor information to our Partner state */
3952 actor
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_actor_tlv
;
3953 ps
= &p
->po_partner_state
;
3954 ps_li
= &ps
->ps_lag_info
;
3955 if (lacp_actor_partner_tlv_get_port(actor
) != ps
->ps_port
3956 || (lacp_actor_partner_tlv_get_port_priority(actor
)
3957 != ps
->ps_port_priority
)
3958 || bcmp(actor
->lap_system
, &ps_li
->li_system
, sizeof(ps_li
->li_system
))
3959 || (lacp_actor_partner_tlv_get_system_priority(actor
)
3960 != ps_li
->li_system_priority
)
3961 || (lacp_actor_partner_tlv_get_key(actor
) != ps_li
->li_key
)
3962 || (lacp_actor_partner_state_aggregatable(actor
->lap_state
)
3963 != lacp_actor_partner_state_aggregatable(ps
->ps_state
))) {
3964 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3965 if (if_bond_debug
) {
3966 timestamp_printf("[%s] updateSelected UNSELECTED\n",
3967 bondport_get_name(p
));
3974 bondport_RecordPDU(bondport_ref p
, lacpdu_ref lacpdu_p
)
3976 lacp_actor_partner_tlv_ref actor
;
3977 ifbond_ref bond
= p
->po_bond
;
3978 int lacp_maintain
= 0;
3979 partner_state_ref ps
;
3980 lacp_actor_partner_tlv_ref partner
;
3983 /* copy the PDU's Actor information into our Partner state */
3984 actor
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_actor_tlv
;
3985 ps
= &p
->po_partner_state
;
3986 ps_li
= &ps
->ps_lag_info
;
3987 ps
->ps_port
= lacp_actor_partner_tlv_get_port(actor
);
3988 ps
->ps_port_priority
= lacp_actor_partner_tlv_get_port_priority(actor
);
3989 ps_li
->li_system
= *((lacp_system_ref
)actor
->lap_system
);
3990 ps_li
->li_system_priority
3991 = lacp_actor_partner_tlv_get_system_priority(actor
);
3992 ps_li
->li_key
= lacp_actor_partner_tlv_get_key(actor
);
3993 ps
->ps_state
= lacp_actor_partner_state_set_out_of_sync(actor
->lap_state
);
3995 = lacp_actor_partner_state_set_not_defaulted(p
->po_actor_state
);
3997 /* compare the PDU's Partner information to our own information */
3998 partner
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_partner_tlv
;
4000 if (lacp_actor_partner_state_active_lacp(ps
->ps_state
)
4001 || (lacp_actor_partner_state_active_lacp(p
->po_actor_state
)
4002 && lacp_actor_partner_state_active_lacp(partner
->lap_state
))) {
4003 if (if_bond_debug
) {
4004 timestamp_printf("[%s] recordPDU: LACP will maintain\n",
4005 bondport_get_name(p
));
4009 if ((lacp_actor_partner_tlv_get_port(partner
)
4010 == bondport_get_index(p
))
4011 && lacp_actor_partner_tlv_get_port_priority(partner
) == p
->po_priority
4012 && bcmp(partner
->lap_system
, &g_bond
->system
,
4013 sizeof(g_bond
->system
)) == 0
4014 && (lacp_actor_partner_tlv_get_system_priority(partner
)
4015 == g_bond
->system_priority
)
4016 && lacp_actor_partner_tlv_get_key(partner
) == bond
->ifb_key
4017 && (lacp_actor_partner_state_aggregatable(partner
->lap_state
)
4018 == lacp_actor_partner_state_aggregatable(p
->po_actor_state
))
4019 && lacp_actor_partner_state_in_sync(actor
->lap_state
)
4021 ps
->ps_state
= lacp_actor_partner_state_set_in_sync(ps
->ps_state
);
4022 if (if_bond_debug
) {
4023 timestamp_printf("[%s] recordPDU: LACP partner in sync\n",
4024 bondport_get_name(p
));
4026 } else if (lacp_actor_partner_state_aggregatable(actor
->lap_state
) == 0
4027 && lacp_actor_partner_state_in_sync(actor
->lap_state
)
4029 ps
->ps_state
= lacp_actor_partner_state_set_in_sync(ps
->ps_state
);
4030 if (if_bond_debug
) {
4031 timestamp_printf("[%s] recordPDU: LACP partner in sync (ind)\n",
4032 bondport_get_name(p
));
4035 bondport_assign_to_LAG(p
);
4039 static __inline__ lacp_actor_partner_state
4040 updateNTTBits(lacp_actor_partner_state s
)
4042 return s
& (LACP_ACTOR_PARTNER_STATE_LACP_ACTIVITY
4043 | LACP_ACTOR_PARTNER_STATE_LACP_TIMEOUT
4044 | LACP_ACTOR_PARTNER_STATE_AGGREGATION
4045 | LACP_ACTOR_PARTNER_STATE_SYNCHRONIZATION
);
4049 bondport_UpdateNTT(bondport_ref p
, lacpdu_ref lacpdu_p
)
4051 ifbond_ref bond
= p
->po_bond
;
4052 lacp_actor_partner_tlv_ref partner
;
4054 /* compare the PDU's Actor information to our Partner state */
4055 partner
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_partner_tlv
;
4056 if ((lacp_actor_partner_tlv_get_port(partner
) != bondport_get_index(p
))
4057 || lacp_actor_partner_tlv_get_port_priority(partner
) != p
->po_priority
4058 || bcmp(partner
->lap_system
, &g_bond
->system
, sizeof(g_bond
->system
))
4059 || (lacp_actor_partner_tlv_get_system_priority(partner
)
4060 != g_bond
->system_priority
)
4061 || lacp_actor_partner_tlv_get_key(partner
) != bond
->ifb_key
4062 || (updateNTTBits(partner
->lap_state
)
4063 != updateNTTBits(p
->po_actor_state
))) {
4064 bondport_flags_set_ntt(p
);
4065 if (if_bond_debug
) {
4066 timestamp_printf("[%s] updateNTT: Need To Transmit\n",
4067 bondport_get_name(p
));
4074 bondport_AttachMuxToAggregator(bondport_ref p
)
4076 if (bondport_flags_mux_attached(p
) == 0) {
4077 if (if_bond_debug
) {
4078 timestamp_printf("[%s] Attached Mux To Aggregator\n",
4079 bondport_get_name(p
));
4081 bondport_flags_set_mux_attached(p
);
4087 bondport_DetachMuxFromAggregator(bondport_ref p
)
4089 if (bondport_flags_mux_attached(p
)) {
4090 if (if_bond_debug
) {
4091 timestamp_printf("[%s] Detached Mux From Aggregator\n",
4092 bondport_get_name(p
));
4094 bondport_flags_clear_mux_attached(p
);
4100 bondport_enable_distributing(bondport_ref p
)
4102 if (bondport_flags_distributing(p
) == 0) {
4103 ifbond_ref bond
= p
->po_bond
;
4105 bond
->ifb_distributing_array
[bond
->ifb_distributing_count
++] = p
;
4106 if (if_bond_debug
) {
4107 timestamp_printf("[%s] Distribution Enabled\n",
4108 bondport_get_name(p
));
4110 bondport_flags_set_distributing(p
);
4116 bondport_disable_distributing(bondport_ref p
)
4118 if (bondport_flags_distributing(p
)) {
4119 bondport_ref
* array
;
4125 array
= bond
->ifb_distributing_array
;
4126 count
= bond
->ifb_distributing_count
;
4127 for (i
= 0; i
< count
; i
++) {
4128 if (array
[i
] == p
) {
4131 for (j
= i
; j
< (count
- 1); j
++) {
4132 array
[j
] = array
[j
+ 1];
4137 bond
->ifb_distributing_count
--;
4138 if (if_bond_debug
) {
4139 timestamp_printf("[%s] Distribution Disabled\n",
4140 bondport_get_name(p
));
4142 bondport_flags_clear_distributing(p
);
4148 ** Receive machine functions
4151 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
4154 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
4157 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
4160 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
4163 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
4166 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
4170 bondport_receive_machine_event(bondport_ref p
, LAEvent event
,
4173 switch (p
->po_receive_state
) {
4174 case ReceiveState_none
:
4175 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
4177 case ReceiveState_INITIALIZE
:
4178 bondport_receive_machine_initialize(p
, event
, event_data
);
4180 case ReceiveState_PORT_DISABLED
:
4181 bondport_receive_machine_port_disabled(p
, event
, event_data
);
4183 case ReceiveState_EXPIRED
:
4184 bondport_receive_machine_expired(p
, event
, event_data
);
4186 case ReceiveState_LACP_DISABLED
:
4187 bondport_receive_machine_lacp_disabled(p
, event
, event_data
);
4189 case ReceiveState_DEFAULTED
:
4190 bondport_receive_machine_defaulted(p
, event
, event_data
);
4192 case ReceiveState_CURRENT
:
4193 bondport_receive_machine_current(p
, event
, event_data
);
4202 bondport_receive_machine(bondport_ref p
, LAEvent event
,
4207 if (p
->po_receive_state
!= ReceiveState_LACP_DISABLED
) {
4208 bondport_receive_machine_current(p
, event
, event_data
);
4211 case LAEventMediaChange
:
4212 if (media_active(&p
->po_media_info
)) {
4213 switch (p
->po_receive_state
) {
4214 case ReceiveState_PORT_DISABLED
:
4215 case ReceiveState_LACP_DISABLED
:
4216 bondport_receive_machine_port_disabled(p
, LAEventMediaChange
, NULL
);
4222 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
4226 bondport_receive_machine_event(p
, event
, event_data
);
4233 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
4234 __unused
void * event_data
)
4238 devtimer_cancel(p
->po_current_while_timer
);
4239 if (if_bond_debug
) {
4240 timestamp_printf("[%s] Receive INITIALIZE\n",
4241 bondport_get_name(p
));
4243 p
->po_receive_state
= ReceiveState_INITIALIZE
;
4244 bondport_set_selected(p
, SelectedState_UNSELECTED
);
4245 bondport_RecordDefault(p
);
4247 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4248 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
4257 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
4258 __unused
void * event_data
)
4260 partner_state_ref ps
;
4264 devtimer_cancel(p
->po_current_while_timer
);
4265 if (if_bond_debug
) {
4266 timestamp_printf("[%s] Receive PORT_DISABLED\n",
4267 bondport_get_name(p
));
4269 p
->po_receive_state
= ReceiveState_PORT_DISABLED
;
4270 ps
= &p
->po_partner_state
;
4271 ps
->ps_state
= lacp_actor_partner_state_set_out_of_sync(ps
->ps_state
);
4273 case LAEventMediaChange
:
4274 if (media_active(&p
->po_media_info
)) {
4275 if (media_ok(&p
->po_media_info
)) {
4276 bondport_receive_machine_expired(p
, LAEventStart
, NULL
);
4278 bondport_receive_machine_lacp_disabled(p
, LAEventStart
, NULL
);
4280 } else if (p
->po_selected
== SelectedState_SELECTED
) {
4283 if (if_bond_debug
) {
4284 timestamp_printf("[%s] Receive PORT_DISABLED: "
4285 "link timer started\n",
4286 bondport_get_name(p
));
4290 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4291 (devtimer_timeout_func
)
4292 bondport_receive_machine_port_disabled
,
4293 (void *)LAEventTimeout
, NULL
);
4294 } else if (p
->po_selected
== SelectedState_STANDBY
) {
4295 bondport_set_selected(p
, SelectedState_UNSELECTED
);
4298 case LAEventTimeout
:
4299 if (p
->po_selected
== SelectedState_SELECTED
) {
4300 if (if_bond_debug
) {
4301 timestamp_printf("[%s] Receive PORT_DISABLED: "
4302 "link timer completed, marking UNSELECTED\n",
4303 bondport_get_name(p
));
4305 bondport_set_selected(p
, SelectedState_UNSELECTED
);
4308 case LAEventPortMoved
:
4309 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
4318 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
4319 __unused
void * event_data
)
4321 lacp_actor_partner_state s
;
4326 devtimer_cancel(p
->po_current_while_timer
);
4327 if (if_bond_debug
) {
4328 timestamp_printf("[%s] Receive EXPIRED\n",
4329 bondport_get_name(p
));
4331 p
->po_receive_state
= ReceiveState_EXPIRED
;
4332 s
= p
->po_partner_state
.ps_state
;
4333 s
= lacp_actor_partner_state_set_out_of_sync(s
);
4334 s
= lacp_actor_partner_state_set_short_timeout(s
);
4335 p
->po_partner_state
.ps_state
= s
;
4337 = lacp_actor_partner_state_set_expired(p
->po_actor_state
);
4338 /* start current_while timer */
4339 tv
.tv_sec
= LACP_SHORT_TIMEOUT_TIME
;
4341 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4342 (devtimer_timeout_func
)
4343 bondport_receive_machine_expired
,
4344 (void *)LAEventTimeout
, NULL
);
4347 case LAEventTimeout
:
4348 bondport_receive_machine_defaulted(p
, LAEventStart
, NULL
);
4357 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
4358 __unused
void * event_data
)
4360 partner_state_ref ps
;
4363 devtimer_cancel(p
->po_current_while_timer
);
4364 if (if_bond_debug
) {
4365 timestamp_printf("[%s] Receive LACP_DISABLED\n",
4366 bondport_get_name(p
));
4368 p
->po_receive_state
= ReceiveState_LACP_DISABLED
;
4369 bondport_set_selected(p
, SelectedState_UNSELECTED
);
4370 bondport_RecordDefault(p
);
4371 ps
= &p
->po_partner_state
;
4372 ps
->ps_state
= lacp_actor_partner_state_set_individual(ps
->ps_state
);
4374 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4383 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
4384 __unused
void * event_data
)
4388 devtimer_cancel(p
->po_current_while_timer
);
4389 if (if_bond_debug
) {
4390 timestamp_printf("[%s] Receive DEFAULTED\n",
4391 bondport_get_name(p
));
4393 p
->po_receive_state
= ReceiveState_DEFAULTED
;
4394 bondport_UpdateDefaultSelected(p
);
4395 bondport_RecordDefault(p
);
4397 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4406 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
4409 partner_state_ref ps
;
4414 devtimer_cancel(p
->po_current_while_timer
);
4415 if (if_bond_debug
) {
4416 timestamp_printf("[%s] Receive CURRENT\n",
4417 bondport_get_name(p
));
4419 p
->po_receive_state
= ReceiveState_CURRENT
;
4420 bondport_UpdateSelected(p
, event_data
);
4421 bondport_UpdateNTT(p
, event_data
);
4422 bondport_RecordPDU(p
, event_data
);
4424 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4425 bondport_assign_to_LAG(p
);
4426 /* start current_while timer */
4427 ps
= &p
->po_partner_state
;
4428 if (lacp_actor_partner_state_short_timeout(ps
->ps_state
)) {
4429 tv
.tv_sec
= LACP_SHORT_TIMEOUT_TIME
;
4431 tv
.tv_sec
= LACP_LONG_TIMEOUT_TIME
;
4434 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4435 (devtimer_timeout_func
)
4436 bondport_receive_machine_current
,
4437 (void *)LAEventTimeout
, NULL
);
4439 case LAEventTimeout
:
4440 bondport_receive_machine_expired(p
, LAEventStart
, NULL
);
4449 ** Periodic Transmission machine
4453 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
4454 __unused
void * event_data
)
4457 partner_state_ref ps
;
4462 if (if_bond_debug
) {
4463 timestamp_printf("[%s] periodic_transmit Start\n",
4464 bondport_get_name(p
));
4467 case LAEventMediaChange
:
4468 devtimer_cancel(p
->po_periodic_timer
);
4469 p
->po_periodic_interval
= 0;
4470 if (media_active(&p
->po_media_info
) == 0
4471 || media_ok(&p
->po_media_info
) == 0) {
4476 /* Neither Partner nor Actor are LACP Active, no periodic tx */
4477 ps
= &p
->po_partner_state
;
4478 if (lacp_actor_partner_state_active_lacp(p
->po_actor_state
) == 0
4479 && (lacp_actor_partner_state_active_lacp(ps
->ps_state
)
4481 devtimer_cancel(p
->po_periodic_timer
);
4482 p
->po_periodic_interval
= 0;
4485 if (lacp_actor_partner_state_short_timeout(ps
->ps_state
)) {
4486 interval
= LACP_FAST_PERIODIC_TIME
;
4488 interval
= LACP_SLOW_PERIODIC_TIME
;
4490 if (p
->po_periodic_interval
!= interval
) {
4491 if (interval
== LACP_FAST_PERIODIC_TIME
4492 && p
->po_periodic_interval
== LACP_SLOW_PERIODIC_TIME
) {
4493 if (if_bond_debug
) {
4494 timestamp_printf("[%s] periodic_transmit:"
4495 " Need To Transmit\n",
4496 bondport_get_name(p
));
4498 bondport_flags_set_ntt(p
);
4500 p
->po_periodic_interval
= interval
;
4502 tv
.tv_sec
= interval
;
4503 devtimer_set_relative(p
->po_periodic_timer
, tv
,
4504 (devtimer_timeout_func
)
4505 bondport_periodic_transmit_machine
,
4506 (void *)LAEventTimeout
, NULL
);
4507 if (if_bond_debug
) {
4508 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4509 bondport_get_name(p
),
4510 p
->po_periodic_interval
);
4514 case LAEventTimeout
:
4515 bondport_flags_set_ntt(p
);
4516 tv
.tv_sec
= p
->po_periodic_interval
;
4518 devtimer_set_relative(p
->po_periodic_timer
, tv
, (devtimer_timeout_func
)
4519 bondport_periodic_transmit_machine
,
4520 (void *)LAEventTimeout
, NULL
);
4521 if (if_bond_debug
> 1) {
4522 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4523 bondport_get_name(p
), p
->po_periodic_interval
);
4536 bondport_can_transmit(bondport_ref p
, int32_t current_secs
,
4537 __darwin_time_t
* next_secs
)
4539 if (p
->po_last_transmit_secs
!= current_secs
) {
4540 p
->po_last_transmit_secs
= current_secs
;
4541 p
->po_n_transmit
= 0;
4543 if (p
->po_n_transmit
< LACP_PACKET_RATE
) {
4547 if (next_secs
!= NULL
) {
4548 *next_secs
= current_secs
+ 1;
4554 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
4557 lacp_actor_partner_tlv_ref aptlv
;
4558 lacp_collector_tlv_ref ctlv
;
4559 struct timeval next_tick_time
= {.tv_sec
= 0, .tv_usec
= 0};
4560 lacpdu_ref out_lacpdu_p
;
4561 packet_buffer_ref pkt
;
4562 partner_state_ref ps
;
4566 case LAEventTimeout
:
4568 if (p
->po_periodic_interval
== 0 || bondport_flags_ntt(p
) == 0) {
4571 if (event_data
== TRANSMIT_MACHINE_TX_IMMEDIATE
) {
4572 /* we're going away, transmit the packet no matter what */
4573 } else if (bondport_can_transmit(p
, devtimer_current_secs(),
4574 &next_tick_time
.tv_sec
) == 0) {
4575 if (devtimer_enabled(p
->po_transmit_timer
)) {
4576 if (if_bond_debug
> 0) {
4577 timestamp_printf("[%s] Transmit Timer Already Set\n",
4578 bondport_get_name(p
));
4581 devtimer_set_absolute(p
->po_transmit_timer
, next_tick_time
,
4582 (devtimer_timeout_func
)
4583 bondport_transmit_machine
,
4584 (void *)LAEventTimeout
, NULL
);
4585 if (if_bond_debug
> 0) {
4586 timestamp_printf("[%s] Transmit Timer Deadline %d secs\n",
4587 bondport_get_name(p
),
4588 (int)next_tick_time
.tv_sec
);
4593 if (if_bond_debug
> 0) {
4594 if (event
== LAEventTimeout
) {
4595 timestamp_printf("[%s] Transmit Timer Complete\n",
4596 bondport_get_name(p
));
4599 pkt
= packet_buffer_allocate(sizeof(*out_lacpdu_p
));
4601 printf("[%s] Transmit: failed to allocate packet buffer\n",
4602 bondport_get_name(p
));
4605 out_lacpdu_p
= (lacpdu_ref
)packet_buffer_byteptr(pkt
);
4606 bzero(out_lacpdu_p
, sizeof(*out_lacpdu_p
));
4607 out_lacpdu_p
->la_subtype
= IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP
;
4608 out_lacpdu_p
->la_version
= LACPDU_VERSION_1
;
4611 aptlv
= (lacp_actor_partner_tlv_ref
)out_lacpdu_p
->la_actor_tlv
;
4612 aptlv
->lap_tlv_type
= LACPDU_TLV_TYPE_ACTOR
;
4613 aptlv
->lap_length
= LACPDU_ACTOR_TLV_LENGTH
;
4614 *((lacp_system_ref
)aptlv
->lap_system
) = g_bond
->system
;
4615 lacp_actor_partner_tlv_set_system_priority(aptlv
,
4616 g_bond
->system_priority
);
4617 lacp_actor_partner_tlv_set_port_priority(aptlv
, p
->po_priority
);
4618 lacp_actor_partner_tlv_set_port(aptlv
, bondport_get_index(p
));
4619 lacp_actor_partner_tlv_set_key(aptlv
, p
->po_bond
->ifb_key
);
4620 aptlv
->lap_state
= p
->po_actor_state
;
4623 aptlv
= (lacp_actor_partner_tlv_ref
)out_lacpdu_p
->la_partner_tlv
;
4624 aptlv
->lap_tlv_type
= LACPDU_TLV_TYPE_PARTNER
;
4625 aptlv
->lap_length
= LACPDU_PARTNER_TLV_LENGTH
;
4626 ps
= &p
->po_partner_state
;
4627 ps_li
= &ps
->ps_lag_info
;
4628 lacp_actor_partner_tlv_set_port(aptlv
, ps
->ps_port
);
4629 lacp_actor_partner_tlv_set_port_priority(aptlv
, ps
->ps_port_priority
);
4630 *((lacp_system_ref
)aptlv
->lap_system
) = ps_li
->li_system
;
4631 lacp_actor_partner_tlv_set_system_priority(aptlv
,
4632 ps_li
->li_system_priority
);
4633 lacp_actor_partner_tlv_set_key(aptlv
, ps_li
->li_key
);
4634 aptlv
->lap_state
= ps
->ps_state
;
4637 ctlv
= (lacp_collector_tlv_ref
)out_lacpdu_p
->la_collector_tlv
;
4638 ctlv
->lac_tlv_type
= LACPDU_TLV_TYPE_COLLECTOR
;
4639 ctlv
->lac_length
= LACPDU_COLLECTOR_TLV_LENGTH
;
4641 bondport_slow_proto_transmit(p
, pkt
);
4642 bondport_flags_clear_ntt(p
);
4643 if (if_bond_debug
> 0) {
4644 timestamp_printf("[%s] Transmit Packet %d\n",
4645 bondport_get_name(p
), p
->po_n_transmit
);
4655 ** Mux machine functions
4659 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4662 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4665 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4669 bondport_mux_machine_collecting_distributing(bondport_ref p
, LAEvent event
,
4673 bondport_mux_machine(bondport_ref p
, LAEvent event
, void * event_data
)
4675 switch (p
->po_mux_state
) {
4677 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4679 case MuxState_DETACHED
:
4680 bondport_mux_machine_detached(p
, event
, event_data
);
4682 case MuxState_WAITING
:
4683 bondport_mux_machine_waiting(p
, event
, event_data
);
4685 case MuxState_ATTACHED
:
4686 bondport_mux_machine_attached(p
, event
, event_data
);
4688 case MuxState_COLLECTING_DISTRIBUTING
:
4689 bondport_mux_machine_collecting_distributing(p
, event
, event_data
);
4698 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4699 __unused
void * event_data
)
4701 lacp_actor_partner_state s
;
4705 devtimer_cancel(p
->po_wait_while_timer
);
4706 if (if_bond_debug
) {
4707 timestamp_printf("[%s] Mux DETACHED\n",
4708 bondport_get_name(p
));
4710 p
->po_mux_state
= MuxState_DETACHED
;
4711 bondport_flags_clear_ready(p
);
4712 bondport_DetachMuxFromAggregator(p
);
4713 bondport_disable_distributing(p
);
4714 s
= p
->po_actor_state
;
4715 s
= lacp_actor_partner_state_set_out_of_sync(s
);
4716 s
= lacp_actor_partner_state_set_not_collecting(s
);
4717 s
= lacp_actor_partner_state_set_not_distributing(s
);
4718 p
->po_actor_state
= s
;
4719 bondport_flags_set_ntt(p
);
4721 case LAEventSelectedChange
:
4723 case LAEventMediaChange
:
4724 if (p
->po_selected
== SelectedState_SELECTED
4725 || p
->po_selected
== SelectedState_STANDBY
) {
4726 bondport_mux_machine_waiting(p
, LAEventStart
, NULL
);
4736 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4737 __unused
void * event_data
)
4743 devtimer_cancel(p
->po_wait_while_timer
);
4744 if (if_bond_debug
) {
4745 timestamp_printf("[%s] Mux WAITING\n",
4746 bondport_get_name(p
));
4748 p
->po_mux_state
= MuxState_WAITING
;
4751 case LAEventSelectedChange
:
4752 if (p
->po_selected
== SelectedState_UNSELECTED
) {
4753 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4756 if (p
->po_selected
== SelectedState_STANDBY
) {
4757 devtimer_cancel(p
->po_wait_while_timer
);
4758 /* wait until state changes to SELECTED */
4759 if (if_bond_debug
) {
4760 timestamp_printf("[%s] Mux WAITING: Standby\n",
4761 bondport_get_name(p
));
4765 if (bondport_flags_ready(p
)) {
4766 if (if_bond_debug
) {
4767 timestamp_printf("[%s] Mux WAITING: Port is already ready\n",
4768 bondport_get_name(p
));
4772 if (devtimer_enabled(p
->po_wait_while_timer
)) {
4773 if (if_bond_debug
) {
4774 timestamp_printf("[%s] Mux WAITING: Timer already set\n",
4775 bondport_get_name(p
));
4779 if (ifbond_all_ports_attached(p
->po_bond
, p
)) {
4780 devtimer_cancel(p
->po_wait_while_timer
);
4781 if (if_bond_debug
) {
4782 timestamp_printf("[%s] Mux WAITING: No waiting\n",
4783 bondport_get_name(p
));
4785 bondport_flags_set_ready(p
);
4788 if (if_bond_debug
) {
4789 timestamp_printf("[%s] Mux WAITING: 2 seconds\n",
4790 bondport_get_name(p
));
4792 tv
.tv_sec
= LACP_AGGREGATE_WAIT_TIME
;
4794 devtimer_set_relative(p
->po_wait_while_timer
, tv
,
4795 (devtimer_timeout_func
)
4796 bondport_mux_machine_waiting
,
4797 (void *)LAEventTimeout
, NULL
);
4799 case LAEventTimeout
:
4800 if (if_bond_debug
) {
4801 timestamp_printf("[%s] Mux WAITING: Ready\n",
4802 bondport_get_name(p
));
4804 bondport_flags_set_ready(p
);
4808 if (bondport_flags_ready(p
)) {
4809 if (if_bond_debug
) {
4810 timestamp_printf("[%s] Mux WAITING: All Ports Ready\n",
4811 bondport_get_name(p
));
4813 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);
4822 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4823 __unused
void * event_data
)
4825 lacp_actor_partner_state s
;
4829 devtimer_cancel(p
->po_wait_while_timer
);
4830 if (if_bond_debug
) {
4831 timestamp_printf("[%s] Mux ATTACHED\n",
4832 bondport_get_name(p
));
4834 p
->po_mux_state
= MuxState_ATTACHED
;
4835 bondport_AttachMuxToAggregator(p
);
4836 s
= p
->po_actor_state
;
4837 s
= lacp_actor_partner_state_set_in_sync(s
);
4838 s
= lacp_actor_partner_state_set_not_collecting(s
);
4839 s
= lacp_actor_partner_state_set_not_distributing(s
);
4840 bondport_disable_distributing(p
);
4841 p
->po_actor_state
= s
;
4842 bondport_flags_set_ntt(p
);
4845 switch (p
->po_selected
) {
4846 case SelectedState_SELECTED
:
4847 s
= p
->po_partner_state
.ps_state
;
4848 if (lacp_actor_partner_state_in_sync(s
)) {
4849 bondport_mux_machine_collecting_distributing(p
, LAEventStart
,
4854 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4863 bondport_mux_machine_collecting_distributing(bondport_ref p
,
4865 __unused
void * event_data
)
4867 lacp_actor_partner_state s
;
4871 devtimer_cancel(p
->po_wait_while_timer
);
4872 if (if_bond_debug
) {
4873 timestamp_printf("[%s] Mux COLLECTING_DISTRIBUTING\n",
4874 bondport_get_name(p
));
4876 p
->po_mux_state
= MuxState_COLLECTING_DISTRIBUTING
;
4877 bondport_enable_distributing(p
);
4878 s
= p
->po_actor_state
;
4879 s
= lacp_actor_partner_state_set_collecting(s
);
4880 s
= lacp_actor_partner_state_set_distributing(s
);
4881 p
->po_actor_state
= s
;
4882 bondport_flags_set_ntt(p
);
4885 s
= p
->po_partner_state
.ps_state
;
4886 if (lacp_actor_partner_state_in_sync(s
) == 0) {
4887 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);
4890 switch (p
->po_selected
) {
4891 case SelectedState_UNSELECTED
:
4892 case SelectedState_STANDBY
:
4893 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);