2 * Copyright (c) 2004-2006 Apple Computer, 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>
54 #include <net/ethernet.h>
56 #include <net/kpi_interface.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>
70 #include <kern/locks.h>
71 #include <libkern/OSAtomic.h>
73 #include <netinet/in.h>
74 #include <netinet/if_ether.h>
75 #include <netinet/in_systm.h>
76 #include <netinet/ip.h>
77 #include <netinet/ip6.h>
79 #include <net/if_media.h>
80 #include <net/multicast_list.h>
82 extern void dlil_input_packet_list(struct ifnet
*, struct mbuf
*);
84 static struct ether_addr slow_proto_multicast
= {
85 IEEE8023AD_SLOW_PROTO_MULTICAST
88 #define BOND_MAXUNIT 128
89 #define BONDNAME "bond"
90 #define M_BOND M_DEVBUF
92 #define EA_FORMAT "%x:%x:%x:%x:%x:%x"
93 #define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)])
94 #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)
96 #define timestamp_printf printf
101 static __inline__ lck_grp_t
*
102 my_lck_grp_alloc_init(const char * grp_name
)
105 lck_grp_attr_t
* grp_attrs
;
107 grp_attrs
= lck_grp_attr_alloc_init();
108 grp
= lck_grp_alloc_init(grp_name
, grp_attrs
);
109 lck_grp_attr_free(grp_attrs
);
113 static __inline__ lck_mtx_t
*
114 my_lck_mtx_alloc_init(lck_grp_t
* lck_grp
)
116 lck_attr_t
* lck_attrs
;
119 lck_attrs
= lck_attr_alloc_init();
120 lck_mtx
= lck_mtx_alloc_init(lck_grp
, lck_attrs
);
121 lck_attr_free(lck_attrs
);
125 static lck_mtx_t
* bond_lck_mtx
;
127 static __inline__
void
130 lck_grp_t
* bond_lck_grp
;
132 bond_lck_grp
= my_lck_grp_alloc_init("if_bond");
133 bond_lck_mtx
= my_lck_mtx_alloc_init(bond_lck_grp
);
136 static __inline__
void
137 bond_assert_lock_held(void)
139 lck_mtx_assert(bond_lck_mtx
, LCK_MTX_ASSERT_OWNED
);
143 static __inline__
void
144 bond_assert_lock_not_held(void)
146 lck_mtx_assert(bond_lck_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
150 static __inline__
void
153 lck_mtx_lock(bond_lck_mtx
);
157 static __inline__
void
160 lck_mtx_unlock(bond_lck_mtx
);
165 ** bond structures, types
169 lacp_system li_system
;
170 lacp_system_priority li_system_priority
;
173 typedef struct LAG_info_s LAG_info
, * LAG_info_ref
;
176 TAILQ_HEAD(port_list
, bondport_s
);
178 TAILQ_HEAD(ifbond_list
, ifbond_s
);
180 TAILQ_HEAD(lag_list
, LAG_s
);
182 typedef struct ifbond_s ifbond
, * ifbond_ref
;
183 typedef struct bondport_s bondport
, * bondport_ref
;
186 TAILQ_ENTRY(LAG_s
) lag_list
;
187 struct port_list lag_port_list
;
188 short lag_port_count
;
189 short lag_selected_port_count
;
190 int lag_active_media
;
193 typedef struct LAG_s LAG
, * LAG_ref
;
195 typedef struct partner_state_s
{
196 LAG_info ps_lag_info
;
198 lacp_port_priority ps_port_priority
;
199 lacp_actor_partner_state ps_state
;
200 } partner_state
, * partner_state_ref
;
203 TAILQ_ENTRY(ifbond_s
) ifb_bond_list
;
205 SInt32 ifb_retain_count
;
206 char ifb_name
[IFNAMSIZ
];
207 struct ifnet
* ifb_ifp
;
208 bpf_packet_func ifb_bpf_input
;
209 bpf_packet_func ifb_bpf_output
;
211 struct port_list ifb_port_list
;
212 short ifb_port_count
;
213 struct lag_list ifb_lag_list
;
215 short ifb_max_active
; /* 0 == unlimited */
216 LAG_ref ifb_active_lag
;
217 struct ifmultiaddr
* ifb_ifma_slow_proto
;
218 bondport_ref
* ifb_distributing_array
;
219 int ifb_distributing_count
;
220 int ifb_last_link_event
;
221 int ifb_mode
; /* LACP, STATIC */
230 ReceiveState_none
= 0,
231 ReceiveState_INITIALIZE
= 1,
232 ReceiveState_PORT_DISABLED
= 2,
233 ReceiveState_EXPIRED
= 3,
234 ReceiveState_LACP_DISABLED
= 4,
235 ReceiveState_DEFAULTED
= 5,
236 ReceiveState_CURRENT
= 6,
239 typedef u_char ReceiveState
;
242 SelectedState_UNSELECTED
= IF_BOND_STATUS_SELECTED_STATE_UNSELECTED
,
243 SelectedState_SELECTED
= IF_BOND_STATUS_SELECTED_STATE_SELECTED
,
244 SelectedState_STANDBY
= IF_BOND_STATUS_SELECTED_STATE_STANDBY
246 typedef u_char SelectedState
;
248 static __inline__
const char *
249 SelectedStateString(SelectedState s
)
251 static const char * names
[] = { "UNSELECTED", "SELECTED", "STANDBY" };
253 if (s
<= SelectedState_STANDBY
) {
256 return ("<unknown>");
261 MuxState_DETACHED
= 1,
262 MuxState_WAITING
= 2,
263 MuxState_ATTACHED
= 3,
264 MuxState_COLLECTING_DISTRIBUTING
= 4,
267 typedef u_char MuxState
;
270 TAILQ_ENTRY(bondport_s
) po_port_list
;
272 struct multicast_list po_multicast
;
273 struct ifnet
* po_ifp
;
274 struct ether_addr po_saved_addr
;
276 char po_name
[IFNAMSIZ
];
277 struct ifdevmtu po_devmtu
;
280 TAILQ_ENTRY(bondport_s
) po_lag_port_list
;
281 devtimer_ref po_current_while_timer
;
282 devtimer_ref po_periodic_timer
;
283 devtimer_ref po_wait_while_timer
;
284 devtimer_ref po_transmit_timer
;
285 partner_state po_partner_state
;
286 lacp_port_priority po_priority
;
287 lacp_actor_partner_state po_actor_state
;
289 u_char po_periodic_interval
;
290 u_char po_n_transmit
;
291 ReceiveState po_receive_state
;
292 MuxState po_mux_state
;
293 SelectedState po_selected
;
294 int32_t po_last_transmit_secs
;
295 struct media_info po_media_info
;
299 #define IFBF_PROMISC 0x1 /* promiscuous mode */
300 #define IFBF_IF_DETACHING 0x2 /* interface is detaching */
301 #define IFBF_LLADDR 0x4 /* specific link address requested */
302 #define IFBF_CHANGE_IN_PROGRESS 0x8 /* interface add/remove in progress */
304 static int bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
,
307 static __inline__
int
308 ifbond_flags_promisc(ifbond_ref ifb
)
310 return ((ifb
->ifb_flags
& IFBF_PROMISC
) != 0);
313 static __inline__
void
314 ifbond_flags_set_promisc(ifbond_ref ifb
)
316 ifb
->ifb_flags
|= IFBF_PROMISC
;
320 static __inline__
void
321 ifbond_flags_clear_promisc(ifbond_ref ifb
)
323 ifb
->ifb_flags
&= ~IFBF_PROMISC
;
327 static __inline__
int
328 ifbond_flags_if_detaching(ifbond_ref ifb
)
330 return ((ifb
->ifb_flags
& IFBF_IF_DETACHING
) != 0);
333 static __inline__
void
334 ifbond_flags_set_if_detaching(ifbond_ref ifb
)
336 ifb
->ifb_flags
|= IFBF_IF_DETACHING
;
340 static __inline__
int
341 ifbond_flags_lladdr(ifbond_ref ifb
)
343 return ((ifb
->ifb_flags
& IFBF_LLADDR
) != 0);
346 static __inline__
void
347 ifbond_flags_set_lladdr(ifbond_ref ifb
)
349 ifb
->ifb_flags
|= IFBF_LLADDR
;
353 static __inline__
void
354 ifbond_flags_clear_lladdr(ifbond_ref ifb
)
356 ifb
->ifb_flags
&= ~IFBF_LLADDR
;
360 static __inline__
int
361 ifbond_flags_change_in_progress(ifbond_ref ifb
)
363 return ((ifb
->ifb_flags
& IFBF_CHANGE_IN_PROGRESS
) != 0);
366 static __inline__
void
367 ifbond_flags_set_change_in_progress(ifbond_ref ifb
)
369 ifb
->ifb_flags
|= IFBF_CHANGE_IN_PROGRESS
;
373 static __inline__
void
374 ifbond_flags_clear_change_in_progress(ifbond_ref ifb
)
376 ifb
->ifb_flags
&= ~IFBF_CHANGE_IN_PROGRESS
;
381 * bondport_ref->po_flags bits
383 #define BONDPORT_FLAGS_NTT 0x01
384 #define BONDPORT_FLAGS_READY 0x02
385 #define BONDPORT_FLAGS_SELECTED_CHANGED 0x04
386 #define BONDPORT_FLAGS_MUX_ATTACHED 0x08
387 #define BONDPORT_FLAGS_DISTRIBUTING 0x10
388 #define BONDPORT_FLAGS_UNUSED2 0x20
389 #define BONDPORT_FLAGS_UNUSED3 0x40
390 #define BONDPORT_FLAGS_UNUSED4 0x80
392 static __inline__
void
393 bondport_flags_set_ntt(bondport_ref p
)
395 p
->po_flags
|= BONDPORT_FLAGS_NTT
;
399 static __inline__
void
400 bondport_flags_clear_ntt(bondport_ref p
)
402 p
->po_flags
&= ~BONDPORT_FLAGS_NTT
;
406 static __inline__
int
407 bondport_flags_ntt(bondport_ref p
)
409 return ((p
->po_flags
& BONDPORT_FLAGS_NTT
) != 0);
412 static __inline__
void
413 bondport_flags_set_ready(bondport_ref p
)
415 p
->po_flags
|= BONDPORT_FLAGS_READY
;
419 static __inline__
void
420 bondport_flags_clear_ready(bondport_ref p
)
422 p
->po_flags
&= ~BONDPORT_FLAGS_READY
;
426 static __inline__
int
427 bondport_flags_ready(bondport_ref p
)
429 return ((p
->po_flags
& BONDPORT_FLAGS_READY
) != 0);
432 static __inline__
void
433 bondport_flags_set_selected_changed(bondport_ref p
)
435 p
->po_flags
|= BONDPORT_FLAGS_SELECTED_CHANGED
;
439 static __inline__
void
440 bondport_flags_clear_selected_changed(bondport_ref p
)
442 p
->po_flags
&= ~BONDPORT_FLAGS_SELECTED_CHANGED
;
446 static __inline__
int
447 bondport_flags_selected_changed(bondport_ref p
)
449 return ((p
->po_flags
& BONDPORT_FLAGS_SELECTED_CHANGED
) != 0);
452 static __inline__
void
453 bondport_flags_set_mux_attached(bondport_ref p
)
455 p
->po_flags
|= BONDPORT_FLAGS_MUX_ATTACHED
;
459 static __inline__
void
460 bondport_flags_clear_mux_attached(bondport_ref p
)
462 p
->po_flags
&= ~BONDPORT_FLAGS_MUX_ATTACHED
;
466 static __inline__
int
467 bondport_flags_mux_attached(bondport_ref p
)
469 return ((p
->po_flags
& BONDPORT_FLAGS_MUX_ATTACHED
) != 0);
472 static __inline__
void
473 bondport_flags_set_distributing(bondport_ref p
)
475 p
->po_flags
|= BONDPORT_FLAGS_DISTRIBUTING
;
479 static __inline__
void
480 bondport_flags_clear_distributing(bondport_ref p
)
482 p
->po_flags
&= ~BONDPORT_FLAGS_DISTRIBUTING
;
486 static __inline__
int
487 bondport_flags_distributing(bondport_ref p
)
489 return ((p
->po_flags
& BONDPORT_FLAGS_DISTRIBUTING
) != 0);
492 typedef struct bond_globals_s
{
493 struct ifbond_list ifbond_list
;
495 lacp_system_priority system_priority
;
497 } * bond_globals_ref
;
499 static bond_globals_ref g_bond
;
502 ** packet_buffer routines
503 ** - thin wrapper for mbuf
506 typedef struct mbuf
* packet_buffer_ref
;
508 static packet_buffer_ref
509 packet_buffer_allocate(int length
)
514 /* leave room for ethernet header */
515 size
= length
+ sizeof(struct ether_header
);
516 if (size
> (int)MHLEN
) {
517 /* XXX doesn't handle large payloads */
518 printf("bond: packet_buffer_allocate size %d > max %lu\n", size
, MHLEN
);
521 m
= m_gethdr(M_WAITOK
, MT_DATA
);
526 m
->m_pkthdr
.len
= size
;
531 packet_buffer_byteptr(packet_buffer_ref buf
)
533 return (buf
->m_data
+ sizeof(struct ether_header
));
541 LAEventSelectedChange
,
550 bondport_receive_machine(bondport_ref p
, LAEvent event
,
553 ** Periodic Transmission machine
556 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
562 #define TRANSMIT_MACHINE_TX_IMMEDIATE ((void *)1)
565 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
572 bondport_mux_machine(bondport_ref p
, LAEvent event
,
579 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
);
582 ifbond_deactivate_LAG(ifbond_ref bond
, LAG_ref lag
);
585 ifbond_all_ports_ready(ifbond_ref bond
);
588 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
);
591 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
);
594 ifbond_selection(ifbond_ref bond
);
602 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
);
605 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
);
608 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
609 int active
, int short_timeout
, int * error
);
611 bondport_start(bondport_ref p
);
614 bondport_free(bondport_ref p
);
617 bondport_aggregatable(bondport_ref p
);
620 bondport_remove_from_LAG(bondport_ref p
);
623 bondport_set_selected(bondport_ref p
, SelectedState s
);
626 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
);
629 bondport_link_status_changed(bondport_ref p
);
632 bondport_enable_distributing(bondport_ref p
);
635 bondport_disable_distributing(bondport_ref p
);
637 static __inline__
int
638 bondport_collecting(bondport_ref p
)
640 if (p
->po_bond
->ifb_mode
== IF_BOND_MODE_LACP
) {
641 return (lacp_actor_partner_state_collecting(p
->po_actor_state
));
647 ** bond interface/dlil specific routines
649 static int bond_clone_create(struct if_clone
*, int);
650 static void bond_clone_destroy(struct ifnet
*);
651 static int bond_input(ifnet_t ifp
, protocol_family_t protocol
, mbuf_t m
,
653 static int bond_output(struct ifnet
*ifp
, struct mbuf
*m
);
654 static int bond_ioctl(struct ifnet
*ifp
, u_int32_t cmd
, void * addr
);
655 static int bond_set_bpf_tap(struct ifnet
* ifp
, bpf_tap_mode mode
,
656 bpf_packet_func func
);
657 static int bond_attach_protocol(struct ifnet
*ifp
);
658 static int bond_detach_protocol(struct ifnet
*ifp
);
659 static int bond_setmulti(struct ifnet
*ifp
);
660 static int bond_add_interface(struct ifnet
* ifp
, struct ifnet
* port_ifp
);
661 static int bond_remove_interface(ifbond_ref ifb
, struct ifnet
* port_ifp
);
662 static void bond_if_free(struct ifnet
* ifp
);
664 static struct if_clone bond_cloner
= IF_CLONE_INITIALIZER(BONDNAME
,
669 static void interface_link_event(struct ifnet
* ifp
, u_long event_code
);
672 siocsifmtu(struct ifnet
* ifp
, int mtu
)
676 bzero(&ifr
, sizeof(ifr
));
678 return (ifnet_ioctl(ifp
, 0, SIOCSIFMTU
, &ifr
));
682 siocgifdevmtu(struct ifnet
* ifp
, struct ifdevmtu
* ifdm_p
)
687 bzero(&ifr
, sizeof(ifr
));
688 error
= ifnet_ioctl(ifp
, 0, SIOCGIFDEVMTU
, &ifr
);
690 *ifdm_p
= ifr
.ifr_devmtu
;
695 static __inline__
void
696 ether_addr_copy(void * dest
, const void * source
)
698 bcopy(source
, dest
, ETHER_ADDR_LEN
);
702 static __inline__
void
703 ifbond_retain(ifbond_ref ifb
)
705 OSIncrementAtomic(&ifb
->ifb_retain_count
);
708 static __inline__
void
709 ifbond_release(ifbond_ref ifb
)
711 UInt32 old_retain_count
;
713 old_retain_count
= OSDecrementAtomic(&ifb
->ifb_retain_count
);
714 switch (old_retain_count
) {
716 panic("ifbond_release: retain count is 0\n");
719 if (g_bond
->verbose
) {
720 printf("ifbond_release(%s)\n", ifb
->ifb_name
);
722 if (ifb
->ifb_ifma_slow_proto
!= NULL
) {
723 if (g_bond
->verbose
) {
724 printf("ifbond_release(%s) removing multicast\n",
727 (void)if_delmultiaddr(ifb
->ifb_ifma_slow_proto
, 0);
728 ifma_release(ifb
->ifb_ifma_slow_proto
);
730 if (ifb
->ifb_distributing_array
!= NULL
) {
731 FREE(ifb
->ifb_distributing_array
, M_BOND
);
742 * Function: ifbond_wait
744 * Allows a single thread to gain exclusive access to the ifbond
745 * data structure. Some operations take a long time to complete,
746 * and some have side-effects that we can't predict. Holding the
747 * bond_lock() across such operations is not possible.
750 * 1) The SIOCSIFLLADDR ioctl takes a long time (several seconds) to
751 * complete. Simply holding the bond_lock() would freeze all other
752 * data structure accesses during that time.
753 * 2) When we attach our protocol to the interface, a dlil event is
754 * generated and invokes our bond_event() function. bond_event()
755 * needs to take the bond_lock(), but we're already holding it, so
756 * we're deadlocked against ourselves.
758 * Before calling, you must be holding the bond_lock and have taken
759 * a reference on the ifbond_ref.
762 ifbond_wait(ifbond_ref ifb
, const char * msg
)
766 /* other add/remove in progress */
767 while (ifbond_flags_change_in_progress(ifb
)) {
768 if (g_bond
->verbose
) {
769 printf("%s: %s msleep\n", ifb
->ifb_name
, msg
);
772 (void)msleep(ifb
, bond_lck_mtx
, PZERO
, msg
, 0);
774 /* prevent other bond list remove/add from taking place */
775 ifbond_flags_set_change_in_progress(ifb
);
776 if (g_bond
->verbose
&& waited
) {
777 printf("%s: %s woke up\n", ifb
->ifb_name
, msg
);
783 * Function: ifbond_signal
785 * Allows the thread that previously invoked ifbond_wait() to
786 * give up exclusive access to the ifbond data structure, and wake up
787 * any other threads waiting to access
789 * Before calling, you must be holding the bond_lock and have taken
790 * a reference on the ifbond_ref.
793 ifbond_signal(ifbond_ref ifb
, const char * msg
)
795 ifbond_flags_clear_change_in_progress(ifb
);
796 wakeup((caddr_t
)ifb
);
797 if (g_bond
->verbose
) {
798 printf("%s: %s wakeup\n", ifb
->ifb_name
, msg
);
808 link_speed(int active
)
810 switch (IFM_SUBTYPE(active
)) {
831 /* assume that new defined types are going to be at least 10GigE */
838 static __inline__
int
839 media_active(const struct media_info
* mi
)
841 if ((mi
->mi_status
& IFM_AVALID
) == 0) {
844 return ((mi
->mi_status
& IFM_ACTIVE
) != 0);
847 static __inline__
int
848 media_full_duplex(const struct media_info
* mi
)
850 return ((mi
->mi_active
& IFM_FDX
) != 0);
853 static __inline__
int
854 media_speed(const struct media_info
* mi
)
856 return (link_speed(mi
->mi_active
));
859 static struct media_info
860 interface_media_info(struct ifnet
* ifp
)
862 struct ifmediareq ifmr
;
863 struct media_info mi
;
865 bzero(&mi
, sizeof(mi
));
866 bzero(&ifmr
, sizeof(ifmr
));
867 if (ifnet_ioctl(ifp
, 0, SIOCGIFMEDIA
, &ifmr
) == 0) {
868 if (ifmr
.ifm_count
!= 0) {
869 mi
.mi_status
= ifmr
.ifm_status
;
870 mi
.mi_active
= ifmr
.ifm_active
;
877 ** interface utility functions
879 static __inline__
struct ifaddr
*
880 ifindex_get_ifaddr(int i
)
882 if (i
> if_index
|| i
== 0) {
885 return (ifnet_addrs
[i
- 1]);
888 static __inline__
struct ifaddr
*
889 ifp_get_ifaddr(struct ifnet
* ifp
)
891 return (ifindex_get_ifaddr(ifnet_index(ifp
)));
894 static __inline__
struct sockaddr_dl
*
895 ifp_get_sdl(struct ifnet
* ifp
)
899 ifa
= ifp_get_ifaddr(ifp
);
900 return ((struct sockaddr_dl
*)(ifa
->ifa_addr
));
904 if_siflladdr(struct ifnet
* ifp
, const struct ether_addr
* ea_p
)
909 * XXX setting the sa_len to ETHER_ADDR_LEN is wrong, but the driver
910 * currently expects it that way
912 ifr
.ifr_addr
.sa_family
= AF_UNSPEC
;
913 ifr
.ifr_addr
.sa_len
= ETHER_ADDR_LEN
;
914 ether_addr_copy(ifr
.ifr_addr
.sa_data
, ea_p
);
916 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s%d", ifnet_name(ifp
),
919 return (ifnet_ioctl(ifp
, 0, SIOCSIFLLADDR
, &ifr
));
925 static bond_globals_ref
926 bond_globals_create(lacp_system_priority sys_pri
,
931 b
= _MALLOC(sizeof(*b
), M_BOND
, M_WAITOK
);
935 bzero(b
, sizeof(*b
));
936 TAILQ_INIT(&b
->ifbond_list
);
938 b
->system_priority
= sys_pri
;
946 bond_globals_init(void)
952 bond_assert_lock_not_held();
954 if (g_bond
!= NULL
) {
959 * use en0's ethernet address as the system identifier, and if it's not
960 * there, use en1 .. en3
963 for (i
= 0; i
< 4; i
++) {
964 char ifname
[IFNAMSIZ
+1];
965 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
966 /* XXX ifunit() needs to return a reference on the ifp */
967 ifp
= ifunit(ifname
);
974 b
= bond_globals_create(0x8000, (lacp_system_ref
)ifnet_lladdr(ifp
));
977 if (g_bond
!= NULL
) {
994 bond_bpf_vlan(struct ifnet
* ifp
, struct mbuf
* m
,
995 const struct ether_header
* eh_p
,
996 u_int16_t vlan_tag
, bpf_packet_func func
)
998 struct ether_vlan_header
* vlh_p
;
1001 vl_m
= m_get(M_DONTWAIT
, MT_DATA
);
1005 /* populate a new mbuf containing the vlan ethernet header */
1006 vl_m
->m_len
= ETHER_HDR_LEN
+ ETHER_VLAN_ENCAP_LEN
;
1007 vlh_p
= mtod(vl_m
, struct ether_vlan_header
*);
1008 bcopy(eh_p
, vlh_p
, offsetof(struct ether_header
, ether_type
));
1009 vlh_p
->evl_encap_proto
= htons(ETHERTYPE_VLAN
);
1010 vlh_p
->evl_tag
= htons(vlan_tag
);
1011 vlh_p
->evl_proto
= eh_p
->ether_type
;
1014 vl_m
->m_next
= NULL
;
1019 static __inline__
void
1020 bond_bpf_output(struct ifnet
* ifp
, struct mbuf
* m
,
1021 bpf_packet_func func
)
1024 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1025 const struct ether_header
* eh_p
;
1026 eh_p
= mtod(m
, const struct ether_header
*);
1027 m
->m_data
+= ETHER_HDR_LEN
;
1028 m
->m_len
-= ETHER_HDR_LEN
;
1029 bond_bpf_vlan(ifp
, m
, eh_p
, m
->m_pkthdr
.vlan_tag
, func
);
1030 m
->m_data
-= ETHER_HDR_LEN
;
1031 m
->m_len
+= ETHER_HDR_LEN
;
1039 static __inline__
void
1040 bond_bpf_input(ifnet_t ifp
, mbuf_t m
, const struct ether_header
* eh_p
,
1041 bpf_packet_func func
)
1044 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1045 bond_bpf_vlan(ifp
, m
, eh_p
, m
->m_pkthdr
.vlan_tag
, func
);
1047 /* restore the header */
1048 m
->m_data
-= ETHER_HDR_LEN
;
1049 m
->m_len
+= ETHER_HDR_LEN
;
1051 m
->m_data
+= ETHER_HDR_LEN
;
1052 m
->m_len
-= ETHER_HDR_LEN
;
1059 * Function: bond_setmulti
1061 * Enable multicast reception on "our" interface by enabling multicasts on
1062 * each of the member ports.
1065 bond_setmulti(struct ifnet
* ifp
)
1073 ifb
= ifnet_softc(ifp
);
1074 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1075 || TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
1080 ifbond_wait(ifb
, "bond_setmulti");
1082 if (ifbond_flags_if_detaching(ifb
)) {
1083 /* someone destroyed the bond while we were waiting */
1089 /* ifbond_wait() let's us safely walk the list without holding the lock */
1090 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
1091 struct ifnet
* port_ifp
= p
->po_ifp
;
1093 error
= multicast_list_program(&p
->po_multicast
,
1096 printf("bond_setmulti(%s): "
1097 "multicast_list_program(%s%d) failed, %d\n",
1098 ifb
->ifb_name
, ifnet_name(port_ifp
),
1099 ifnet_unit(port_ifp
), error
);
1105 ifbond_signal(ifb
, "bond_setmulti");
1107 ifbond_release(ifb
);
1112 bond_clone_attach(void)
1114 if_clone_attach(&bond_cloner
);
1120 ifbond_add_slow_proto_multicast(ifbond_ref ifb
)
1123 struct ifmultiaddr
* ifma
= NULL
;
1124 struct sockaddr_dl sdl
;
1126 bond_assert_lock_not_held();
1128 bzero(&sdl
, sizeof(sdl
));
1129 sdl
.sdl_len
= sizeof(sdl
);
1130 sdl
.sdl_family
= AF_LINK
;
1131 sdl
.sdl_type
= IFT_ETHER
;
1133 sdl
.sdl_alen
= sizeof(slow_proto_multicast
);
1134 bcopy(&slow_proto_multicast
, sdl
.sdl_data
, sizeof(slow_proto_multicast
));
1135 error
= if_addmulti(ifb
->ifb_ifp
, (struct sockaddr
*)&sdl
,
1138 ifb
->ifb_ifma_slow_proto
= ifma
;
1144 bond_clone_create(struct if_clone
* ifc
, int unit
)
1149 struct ifnet_init_params bond_init
;
1151 error
= bond_globals_init();
1156 ifb
= _MALLOC(sizeof(ifbond
), M_BOND
, M_WAITOK
);
1160 bzero(ifb
, sizeof(*ifb
));
1163 TAILQ_INIT(&ifb
->ifb_port_list
);
1164 TAILQ_INIT(&ifb
->ifb_lag_list
);
1165 ifb
->ifb_key
= unit
+ 1;
1167 /* use the interface name as the unique id for ifp recycle */
1168 if ((u_long
)snprintf(ifb
->ifb_name
, sizeof(ifb
->ifb_name
), "%s%d",
1169 ifc
->ifc_name
, unit
) >= sizeof(ifb
->ifb_name
)) {
1170 ifbond_release(ifb
);
1174 bzero(&bond_init
, sizeof(bond_init
));
1175 bond_init
.uniqueid
= ifb
->ifb_name
;
1176 bond_init
.uniqueid_len
= strlen(ifb
->ifb_name
);
1177 bond_init
.name
= ifc
->ifc_name
;
1178 bond_init
.unit
= unit
;
1179 bond_init
.family
= IFNET_FAMILY_BOND
;
1180 bond_init
.type
= IFT_IEEE8023ADLAG
;
1181 bond_init
.output
= bond_output
;
1182 bond_init
.demux
= ether_demux
;
1183 bond_init
.add_proto
= ether_add_proto
;
1184 bond_init
.del_proto
= ether_del_proto
;
1185 bond_init
.check_multi
= ether_check_multi
;
1186 bond_init
.framer
= ether_frameout
;
1187 bond_init
.ioctl
= bond_ioctl
;
1188 bond_init
.set_bpf_tap
= bond_set_bpf_tap
;
1189 bond_init
.detach
= bond_if_free
;
1190 bond_init
.broadcast_addr
= etherbroadcastaddr
;
1191 bond_init
.broadcast_len
= ETHER_ADDR_LEN
;
1192 bond_init
.softc
= ifb
;
1193 error
= ifnet_allocate(&bond_init
, &ifp
);
1196 ifbond_release(ifb
);
1201 ifnet_set_offload(ifp
, 0);
1202 ifnet_set_addrlen(ifp
, ETHER_ADDR_LEN
); /* XXX ethernet specific */
1203 ifnet_set_flags(ifp
, IFF_BROADCAST
| IFF_MULTICAST
| IFF_SIMPLEX
, 0xffff);
1204 ifnet_set_baudrate(ifp
, 0);
1205 ifnet_set_mtu(ifp
, 0);
1207 error
= ifnet_attach(ifp
, NULL
);
1210 ifbond_release(ifb
);
1213 error
= ifbond_add_slow_proto_multicast(ifb
);
1215 printf("bond_clone_create(%s): "
1216 "failed to add slow_proto multicast, %d\n",
1217 ifb
->ifb_name
, error
);
1220 /* attach as ethernet */
1221 bpfattach(ifp
, DLT_EN10MB
, sizeof(struct ether_header
));
1224 TAILQ_INSERT_HEAD(&g_bond
->ifbond_list
, ifb
, ifb_bond_list
);
1231 bond_remove_all_interfaces(ifbond_ref ifb
)
1235 bond_assert_lock_held();
1238 * do this in reverse order to avoid re-programming the mac address
1239 * as each head interface is removed
1241 while ((p
= TAILQ_LAST(&ifb
->ifb_port_list
, port_list
)) != NULL
) {
1242 bond_remove_interface(ifb
, p
->po_ifp
);
1248 bond_remove(ifbond_ref ifb
)
1250 bond_assert_lock_held();
1251 ifbond_flags_set_if_detaching(ifb
);
1252 TAILQ_REMOVE(&g_bond
->ifbond_list
, ifb
, ifb_bond_list
);
1253 bond_remove_all_interfaces(ifb
);
1258 bond_if_detach(struct ifnet
* ifp
)
1262 error
= ifnet_detach(ifp
);
1264 printf("bond_if_detach %s%d: ifnet_detach failed, %d\n",
1265 ifnet_name(ifp
), ifnet_unit(ifp
), error
);
1272 bond_clone_destroy(struct ifnet
* ifp
)
1277 ifb
= ifnet_softc(ifp
);
1278 if (ifb
== NULL
|| ifnet_type(ifp
) != IFT_IEEE8023ADLAG
) {
1282 if (ifbond_flags_if_detaching(ifb
)) {
1288 bond_if_detach(ifp
);
1293 bond_set_bpf_tap(struct ifnet
* ifp
, bpf_tap_mode mode
, bpf_packet_func func
)
1298 ifb
= ifnet_softc(ifp
);
1299 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
1304 case BPF_TAP_DISABLE
:
1305 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= NULL
;
1309 ifb
->ifb_bpf_input
= func
;
1312 case BPF_TAP_OUTPUT
:
1313 ifb
->ifb_bpf_output
= func
;
1316 case BPF_TAP_INPUT_OUTPUT
:
1317 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= func
;
1327 ether_header_hash(struct ether_header
* eh_p
)
1331 /* get 32-bits from destination ether and ether type */
1332 h
= (*((uint16_t *)&eh_p
->ether_dhost
[4]) << 16)
1334 h
^= *((uint32_t *)&eh_p
->ether_dhost
[0]);
1338 static struct mbuf
*
1339 S_mbuf_skip_to_offset(struct mbuf
* m
, long * offset
)
1344 while (*offset
>= len
) {
1355 #if BYTE_ORDER == BIG_ENDIAN
1356 static __inline__
uint32_t
1357 make_uint32(u_char c0
, u_char c1
, u_char c2
, u_char c3
)
1359 return (((uint32_t)c0
<< 24) | ((uint32_t)c1
<< 16)
1360 | ((uint32_t)c2
<< 8) | (uint32_t)c3
);
1362 #else /* BYTE_ORDER == LITTLE_ENDIAN */
1363 static __inline__
uint32_t
1364 make_uint32(u_char c0
, u_char c1
, u_char c2
, u_char c3
)
1366 return (((uint32_t)c3
<< 24) | ((uint32_t)c2
<< 16)
1367 | ((uint32_t)c1
<< 8) | (uint32_t)c0
);
1369 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1372 S_mbuf_copy_uint32(struct mbuf
* m
, long offset
, uint32_t * val
)
1374 struct mbuf
* current
;
1375 u_char
* current_data
;
1380 current
= S_mbuf_skip_to_offset(m
, &offset
);
1381 if (current
== NULL
) {
1384 current_data
= mtod(current
, u_char
*) + offset
;
1385 space_current
= current
->m_len
- offset
;
1386 if (space_current
>= (int)sizeof(uint32_t)) {
1387 *val
= *((uint32_t *)current_data
);
1390 next
= current
->m_next
;
1391 if (next
== NULL
|| (next
->m_len
+ space_current
) < (int)sizeof(uint32_t)) {
1394 next_data
= mtod(next
, u_char
*);
1395 switch (space_current
) {
1397 *val
= make_uint32(current_data
[0], next_data
[0],
1398 next_data
[1], next_data
[2]);
1401 *val
= make_uint32(current_data
[0], current_data
[1],
1402 next_data
[0], next_data
[1]);
1405 *val
= make_uint32(current_data
[0], current_data
[1],
1406 current_data
[2], next_data
[0]);
1412 #define IP_SRC_OFFSET (offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p))
1413 #define IP_DST_OFFSET (offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p))
1416 ip_header_hash(struct mbuf
* m
)
1419 struct in_addr ip_dst
;
1420 struct in_addr ip_src
;
1423 struct mbuf
* orig_m
= m
;
1425 /* find the IP protocol field relative to the start of the packet */
1426 offset
= offsetof(struct ip
, ip_p
) + sizeof(struct ether_header
);
1427 m
= S_mbuf_skip_to_offset(m
, &offset
);
1428 if (m
== NULL
|| m
->m_len
< 1) {
1431 data
= mtod(m
, u_char
*) + offset
;
1434 /* find the IP src relative to the IP protocol */
1435 if ((m
->m_len
- offset
)
1436 >= (int)(IP_SRC_OFFSET
+ sizeof(struct in_addr
) * 2)) {
1437 /* this should be the normal case */
1438 ip_src
= *(struct in_addr
*)(data
+ IP_SRC_OFFSET
);
1439 ip_dst
= *(struct in_addr
*)(data
+ IP_DST_OFFSET
);
1442 if (S_mbuf_copy_uint32(m
, offset
+ IP_SRC_OFFSET
,
1443 (uint32_t *)&ip_src
.s_addr
)) {
1446 if (S_mbuf_copy_uint32(m
, offset
+ IP_DST_OFFSET
,
1447 (uint32_t *)&ip_dst
.s_addr
)) {
1451 return (ntohl(ip_dst
.s_addr
) ^ ntohl(ip_src
.s_addr
) ^ ((uint32_t)ip_p
));
1454 return (ether_header_hash(mtod(orig_m
, struct ether_header
*)));
1457 #define IP6_ADDRS_LEN (sizeof(struct in6_addr) * 2)
1459 ipv6_header_hash(struct mbuf
* m
)
1464 struct mbuf
* orig_m
= m
;
1468 /* find the IP protocol field relative to the start of the packet */
1469 offset
= offsetof(struct ip6_hdr
, ip6_src
) + sizeof(struct ether_header
);
1470 m
= S_mbuf_skip_to_offset(m
, &offset
);
1472 goto bad_ipv6_packet
;
1474 data
= mtod(m
, u_char
*) + offset
;
1476 if ((m
->m_len
- offset
) >= (int)IP6_ADDRS_LEN
) {
1477 /* this should be the normal case */
1478 for (i
= 0, scan
= (uint32_t *)data
;
1479 i
< (int)(IP6_ADDRS_LEN
/ sizeof(uint32_t));
1485 for (i
= 0; i
< (int)(IP6_ADDRS_LEN
/ sizeof(uint32_t)); i
++) {
1487 if (S_mbuf_copy_uint32(m
, offset
+ i
* sizeof(uint32_t),
1488 (uint32_t *)&tmp
)) {
1489 goto bad_ipv6_packet
;
1494 return (ntohl(val
));
1497 return (ether_header_hash(mtod(orig_m
, struct ether_header
*)));
1501 bond_output(struct ifnet
* ifp
, struct mbuf
* m
)
1503 bpf_packet_func bpf_func
;
1506 struct ifnet
* port_ifp
= NULL
;
1511 if ((m
->m_flags
& M_PKTHDR
) == 0) {
1515 if (m
->m_pkthdr
.socket_id
!= 0) {
1516 h
= m
->m_pkthdr
.socket_id
;
1519 struct ether_header
* eh_p
;
1521 eh_p
= mtod(m
, struct ether_header
*);
1522 switch (ntohs(eh_p
->ether_type
)) {
1524 h
= ip_header_hash(m
);
1526 case ETHERTYPE_IPV6
:
1527 h
= ipv6_header_hash(m
);
1530 h
= ether_header_hash(eh_p
);
1535 ifb
= ifnet_softc(ifp
);
1536 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1537 || ifb
->ifb_distributing_count
== 0) {
1540 h
%= ifb
->ifb_distributing_count
;
1541 port_ifp
= ifb
->ifb_distributing_array
[h
]->po_ifp
;
1542 bpf_func
= ifb
->ifb_bpf_output
;
1545 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1546 (void)ifnet_stat_increment_out(ifp
, 1,
1547 m
->m_pkthdr
.len
+ ETHER_VLAN_ENCAP_LEN
,
1550 (void)ifnet_stat_increment_out(ifp
, 1, m
->m_pkthdr
.len
, 0);
1552 bond_bpf_output(ifp
, m
, bpf_func
);
1554 return (ifnet_output_raw(port_ifp
, PF_BOND
, m
));
1563 ifbond_lookup_port(ifbond_ref ifb
, struct ifnet
* port_ifp
)
1566 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
1567 if (p
->po_ifp
== port_ifp
) {
1575 bond_lookup_port(struct ifnet
* port_ifp
)
1580 TAILQ_FOREACH(ifb
, &g_bond
->ifbond_list
, ifb_bond_list
) {
1581 port
= ifbond_lookup_port(ifb
, port_ifp
);
1590 bond_receive_lacpdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1592 struct ifnet
* bond_ifp
= NULL
;
1598 if ((ifnet_eflags(port_ifp
) & IFEF_BOND
) == 0) {
1601 p
= bond_lookup_port(port_ifp
);
1605 if (p
->po_enabled
== 0) {
1609 if (ifb
->ifb_mode
!= IF_BOND_MODE_LACP
) {
1612 bondport_receive_lacpdu(p
, (lacpdu_ref
)m
->m_data
);
1613 if (ifbond_selection(ifb
)) {
1614 event_code
= (ifb
->ifb_active_lag
== NULL
)
1617 /* XXX need to take a reference on bond_ifp */
1618 bond_ifp
= ifb
->ifb_ifp
;
1619 ifb
->ifb_last_link_event
= event_code
;
1622 event_code
= (ifb
->ifb_active_lag
== NULL
)
1625 if (event_code
!= ifb
->ifb_last_link_event
) {
1626 if (g_bond
->verbose
) {
1627 timestamp_printf("%s: (receive) generating LINK event\n",
1630 bond_ifp
= ifb
->ifb_ifp
;
1631 ifb
->ifb_last_link_event
= event_code
;
1637 if (bond_ifp
!= NULL
) {
1638 interface_link_event(bond_ifp
, event_code
);
1645 bond_receive_la_marker_pdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1647 la_marker_pdu_ref marker_p
;
1650 marker_p
= (la_marker_pdu_ref
)(m
->m_data
+ ETHER_HDR_LEN
);
1651 if (marker_p
->lm_marker_tlv_type
!= LA_MARKER_TLV_TYPE_MARKER
) {
1655 if ((ifnet_eflags(port_ifp
) & IFEF_BOND
) == 0) {
1659 p
= bond_lookup_port(port_ifp
);
1660 if (p
== NULL
|| p
->po_enabled
== 0
1661 || p
->po_bond
->ifb_mode
!= IF_BOND_MODE_LACP
) {
1665 /* echo back the same packet as a marker response */
1666 marker_p
->lm_marker_tlv_type
= LA_MARKER_TLV_TYPE_MARKER_RESPONSE
;
1667 bondport_slow_proto_transmit(p
, (packet_buffer_ref
)m
);
1677 bond_input(ifnet_t port_ifp
, __unused protocol_family_t protocol
, mbuf_t m
,
1678 char * frame_header
)
1680 bpf_packet_func bpf_func
;
1681 const struct ether_header
* eh_p
;
1686 eh_p
= (const struct ether_header
*)frame_header
;
1687 if ((m
->m_flags
& M_MCAST
) != 0
1688 && bcmp(eh_p
->ether_dhost
, &slow_proto_multicast
,
1689 sizeof(eh_p
->ether_dhost
)) == 0
1690 && ntohs(eh_p
->ether_type
) == IEEE8023AD_SLOW_PROTO_ETHERTYPE
) {
1691 u_char subtype
= *mtod(m
, u_char
*);
1693 if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP
) {
1694 if (m
->m_pkthdr
.len
< (int)offsetof(lacpdu
, la_reserved
)) {
1699 if (m
->m_len
< (int)offsetof(lacpdu
, la_reserved
)) {
1700 m
= m_pullup(m
, offsetof(lacpdu
, la_reserved
));
1705 bond_receive_lacpdu(m
, port_ifp
);
1708 else if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LA_MARKER_PROTOCOL
) {
1711 /* restore the ethernet header pointer in the mbuf */
1712 m
->m_pkthdr
.len
+= ETHER_HDR_LEN
;
1713 m
->m_data
-= ETHER_HDR_LEN
;
1714 m
->m_len
+= ETHER_HDR_LEN
;
1715 min_size
= ETHER_HDR_LEN
+ offsetof(la_marker_pdu
, lm_reserved
);
1716 if (m
->m_pkthdr
.len
< min_size
) {
1721 if (m
->m_len
< min_size
) {
1722 m
= m_pullup(m
, min_size
);
1727 /* send to marker responder */
1728 bond_receive_la_marker_pdu(m
, port_ifp
);
1731 else if (subtype
== 0
1732 || subtype
> IEEE8023AD_SLOW_PROTO_SUBTYPE_RESERVED_END
) {
1733 /* invalid subtype, discard the frame */
1739 if ((ifnet_eflags(port_ifp
) & IFEF_BOND
) == 0) {
1742 p
= bond_lookup_port(port_ifp
);
1743 if (p
== NULL
|| bondport_collecting(p
) == 0) {
1747 /* make the packet appear as if it arrived on the bonded interface */
1750 bpf_func
= ifb
->ifb_bpf_input
;
1753 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1754 (void)ifnet_stat_increment_in(ifp
, 1,
1755 (m
->m_pkthdr
.len
+ ETHER_HDR_LEN
1756 + ETHER_VLAN_ENCAP_LEN
), 0);
1759 (void)ifnet_stat_increment_in(ifp
, 1,
1760 (m
->m_pkthdr
.len
+ ETHER_HDR_LEN
), 0);
1762 m
->m_pkthdr
.rcvif
= ifp
;
1763 bond_bpf_input(ifp
, m
, eh_p
, bpf_func
);
1764 m
->m_pkthdr
.header
= frame_header
;
1765 dlil_input_packet_list(ifp
, m
);
1774 static __inline__
const char *
1775 bondport_get_name(bondport_ref p
)
1777 return (p
->po_name
);
1780 static __inline__
int
1781 bondport_get_index(bondport_ref p
)
1783 return (ifnet_index(p
->po_ifp
));
1787 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
)
1789 struct ether_header
* eh_p
;
1792 /* packet_buffer_allocate leaves room for ethernet header */
1793 eh_p
= mtod(buf
, struct ether_header
*);
1794 bcopy(&slow_proto_multicast
, &eh_p
->ether_dhost
, sizeof(eh_p
->ether_dhost
));
1795 bcopy(&p
->po_saved_addr
, eh_p
->ether_shost
, sizeof(eh_p
->ether_shost
));
1796 eh_p
->ether_type
= htons(IEEE8023AD_SLOW_PROTO_ETHERTYPE
);
1797 error
= ifnet_output_raw(p
->po_ifp
, PF_BOND
, buf
);
1799 printf("bondport_slow_proto_transmit(%s) failed %d\n",
1800 bondport_get_name(p
), error
);
1806 bondport_timer_process_func(devtimer_ref timer
,
1807 devtimer_process_func_event event
)
1812 case devtimer_process_func_event_lock
:
1814 devtimer_retain(timer
);
1816 case devtimer_process_func_event_unlock
:
1817 if (devtimer_valid(timer
)) {
1818 /* as long as the devtimer is valid, we can look at arg0 */
1820 struct ifnet
* bond_ifp
= NULL
;
1822 p
= (bondport_ref
)devtimer_arg0(timer
);
1823 if (ifbond_selection(p
->po_bond
)) {
1824 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
1827 /* XXX need to take a reference on bond_ifp */
1828 bond_ifp
= p
->po_bond
->ifb_ifp
;
1829 p
->po_bond
->ifb_last_link_event
= event_code
;
1832 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
1835 if (event_code
!= p
->po_bond
->ifb_last_link_event
) {
1836 if (g_bond
->verbose
) {
1837 timestamp_printf("%s: (timer) generating LINK event\n",
1838 p
->po_bond
->ifb_name
);
1840 bond_ifp
= p
->po_bond
->ifb_ifp
;
1841 p
->po_bond
->ifb_last_link_event
= event_code
;
1844 devtimer_release(timer
);
1846 if (bond_ifp
!= NULL
) {
1847 interface_link_event(bond_ifp
, event_code
);
1851 /* timer is going away */
1852 devtimer_release(timer
);
1862 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
1863 int active
, int short_timeout
, int * ret_error
)
1866 bondport_ref p
= NULL
;
1867 lacp_actor_partner_state s
;
1870 p
= _MALLOC(sizeof(*p
), M_BOND
, M_WAITOK
);
1872 *ret_error
= ENOMEM
;
1875 bzero(p
, sizeof(*p
));
1876 multicast_list_init(&p
->po_multicast
);
1877 if ((u_long
)snprintf(p
->po_name
, sizeof(p
->po_name
), "%s%d",
1878 ifnet_name(port_ifp
), ifnet_unit(port_ifp
))
1879 >= sizeof(p
->po_name
)) {
1880 printf("if_bond: name too large\n");
1881 *ret_error
= EINVAL
;
1884 error
= siocgifdevmtu(port_ifp
, &p
->po_devmtu
);
1886 printf("if_bond: SIOCGIFDEVMTU %s failed, %d\n",
1887 bondport_get_name(p
), error
);
1890 /* remember the current interface MTU so it can be restored */
1891 p
->po_devmtu
.ifdm_current
= ifnet_mtu(port_ifp
);
1892 p
->po_ifp
= port_ifp
;
1893 p
->po_media_info
= interface_media_info(port_ifp
);
1894 p
->po_current_while_timer
= devtimer_create(bondport_timer_process_func
, p
);
1895 if (p
->po_current_while_timer
== NULL
) {
1896 *ret_error
= ENOMEM
;
1899 p
->po_periodic_timer
= devtimer_create(bondport_timer_process_func
, p
);
1900 if (p
->po_periodic_timer
== NULL
) {
1901 *ret_error
= ENOMEM
;
1904 p
->po_wait_while_timer
= devtimer_create(bondport_timer_process_func
, p
);
1905 if (p
->po_wait_while_timer
== NULL
) {
1906 *ret_error
= ENOMEM
;
1909 p
->po_transmit_timer
= devtimer_create(bondport_timer_process_func
, p
);
1910 if (p
->po_transmit_timer
== NULL
) {
1911 *ret_error
= ENOMEM
;
1914 p
->po_receive_state
= ReceiveState_none
;
1915 p
->po_mux_state
= MuxState_none
;
1916 p
->po_priority
= priority
;
1918 s
= lacp_actor_partner_state_set_aggregatable(s
);
1919 if (short_timeout
) {
1920 s
= lacp_actor_partner_state_set_short_timeout(s
);
1923 s
= lacp_actor_partner_state_set_active_lacp(s
);
1925 p
->po_actor_state
= s
;
1934 bondport_start(bondport_ref p
)
1936 bondport_receive_machine(p
, LAEventStart
, NULL
);
1937 bondport_mux_machine(p
, LAEventStart
, NULL
);
1938 bondport_periodic_transmit_machine(p
, LAEventStart
, NULL
);
1939 bondport_transmit_machine(p
, LAEventStart
, NULL
);
1944 * Function: bondport_invalidate_timers
1946 * Invalidate all of the timers for the bondport.
1949 bondport_invalidate_timers(bondport_ref p
)
1951 devtimer_invalidate(p
->po_current_while_timer
);
1952 devtimer_invalidate(p
->po_periodic_timer
);
1953 devtimer_invalidate(p
->po_wait_while_timer
);
1954 devtimer_invalidate(p
->po_transmit_timer
);
1958 * Function: bondport_cancel_timers
1960 * Cancel all of the timers for the bondport.
1963 bondport_cancel_timers(bondport_ref p
)
1965 devtimer_cancel(p
->po_current_while_timer
);
1966 devtimer_cancel(p
->po_periodic_timer
);
1967 devtimer_cancel(p
->po_wait_while_timer
);
1968 devtimer_cancel(p
->po_transmit_timer
);
1972 bondport_free(bondport_ref p
)
1974 multicast_list_remove(&p
->po_multicast
);
1975 devtimer_release(p
->po_current_while_timer
);
1976 devtimer_release(p
->po_periodic_timer
);
1977 devtimer_release(p
->po_wait_while_timer
);
1978 devtimer_release(p
->po_transmit_timer
);
1983 #define BOND_ADD_PROGRESS_IN_LIST 0x1
1984 #define BOND_ADD_PROGRESS_PROTO_ATTACHED 0x2
1985 #define BOND_ADD_PROGRESS_LLADDR_SET 0x4
1986 #define BOND_ADD_PROGRESS_MTU_SET 0x8
1988 static __inline__
int
1989 bond_device_mtu(struct ifnet
* ifp
, ifbond_ref ifb
)
1991 return (((int)ifnet_mtu(ifp
) > ifb
->ifb_altmtu
)
1992 ? (int)ifnet_mtu(ifp
) : ifb
->ifb_altmtu
);
1996 bond_add_interface(struct ifnet
* ifp
, struct ifnet
* port_ifp
)
2003 bondport_ref
* new_array
= NULL
;
2004 bondport_ref
* old_array
= NULL
;
2008 /* pre-allocate space for new port */
2009 p
= bondport_create(port_ifp
, 0x8000, 1, 0, &error
);
2014 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2015 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2018 return ((ifb
== NULL
? EOPNOTSUPP
: EBUSY
));
2021 /* make sure this interface can handle our current MTU */
2022 devmtu
= bond_device_mtu(ifp
, ifb
);
2024 && (devmtu
> p
->po_devmtu
.ifdm_max
|| devmtu
< p
->po_devmtu
.ifdm_min
)) {
2026 printf("if_bond: interface %s doesn't support mtu %d",
2027 bondport_get_name(p
), devmtu
);
2032 /* make sure ifb doesn't get de-allocated while we wait */
2035 /* wait for other add or remove to complete */
2036 ifbond_wait(ifb
, "bond_add_interface");
2038 if (ifbond_flags_if_detaching(ifb
)) {
2039 /* someone destroyed the bond while we were waiting */
2043 if (bond_lookup_port(port_ifp
) != NULL
) {
2044 /* port is already part of a bond */
2048 ifnet_lock_exclusive(port_ifp
);
2049 if ((ifnet_eflags(port_ifp
) & (IFEF_VLAN
| IFEF_BOND
)) != 0) {
2050 /* interface already has VLAN's, or is part of bond */
2051 ifnet_lock_done(port_ifp
);
2056 /* mark the interface busy */
2057 /* can't use ifnet_set_eflags because that takes the lock */
2058 port_ifp
->if_eflags
|= IFEF_BOND
;
2059 ifnet_lock_done(port_ifp
);
2061 if (TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
2062 ifnet_set_offload(ifp
, ifnet_offload(port_ifp
));
2063 ifnet_set_flags(ifp
, IFF_RUNNING
, IFF_RUNNING
);
2064 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2068 ifnet_offload_t ifp_offload
;
2069 ifnet_offload_t port_ifp_offload
;
2071 ifp_offload
= ifnet_offload(ifp
);
2072 port_ifp_offload
= ifnet_offload(port_ifp
);
2073 if (ifp_offload
!= port_ifp_offload
) {
2074 ifnet_offload_t offload
;
2076 offload
= ifp_offload
& port_ifp_offload
;
2077 printf("bond_add_interface(%s, %s) "
2078 "hwassist values don't match 0x%x != 0x%x, using 0x%x instead\n",
2079 ifb
->ifb_name
, bondport_get_name(p
),
2080 ifp_offload
, port_ifp_offload
, offload
);
2083 * if the bond has VLAN's, we can't simply change the hwassist
2084 * field behind its back: this needs work
2086 ifnet_set_offload(ifp
, offload
);
2091 /* remember the port's ethernet address so it can be restored */
2092 ether_addr_copy(&p
->po_saved_addr
, ifnet_lladdr(port_ifp
));
2094 /* add it to the list of ports */
2095 TAILQ_INSERT_TAIL(&ifb
->ifb_port_list
, p
, po_port_list
);
2096 ifb
->ifb_port_count
++;
2098 /* set the default MTU */
2099 if (ifnet_mtu(ifp
) == 0) {
2100 ifnet_set_mtu(ifp
, ETHERMTU
);
2105 /* first port added to bond determines bond's ethernet address */
2107 ifnet_set_lladdr_and_type(ifp
, ifnet_lladdr(port_ifp
), ETHER_ADDR_LEN
,
2111 progress
|= BOND_ADD_PROGRESS_IN_LIST
;
2113 /* allocate a larger distributing array */
2114 new_array
= (bondport_ref
*)
2115 _MALLOC(sizeof(*new_array
) * ifb
->ifb_port_count
, M_BOND
, M_WAITOK
);
2116 if (new_array
== NULL
) {
2121 /* attach our BOND "protocol" to the interface */
2122 error
= bond_attach_protocol(port_ifp
);
2126 progress
|= BOND_ADD_PROGRESS_PROTO_ATTACHED
;
2128 /* set the interface MTU */
2129 devmtu
= bond_device_mtu(ifp
, ifb
);
2130 error
= siocsifmtu(port_ifp
, devmtu
);
2132 printf("bond_add_interface(%s, %s):"
2133 " SIOCSIFMTU %d failed %d\n",
2134 ifb
->ifb_name
, bondport_get_name(p
), devmtu
, error
);
2137 progress
|= BOND_ADD_PROGRESS_MTU_SET
;
2139 /* program the port with our multicast addresses */
2140 error
= multicast_list_program(&p
->po_multicast
, ifp
, port_ifp
);
2142 printf("bond_add_interface(%s, %s):"
2143 " multicast_list_program failed %d\n",
2144 ifb
->ifb_name
, bondport_get_name(p
), error
);
2148 /* mark the interface up */
2149 ifnet_set_flags(port_ifp
, IFF_UP
, IFF_UP
);
2151 error
= ifnet_ioctl(port_ifp
, 0, SIOCSIFFLAGS
, NULL
);
2153 printf("bond_add_interface(%s, %s): SIOCSIFFLAGS failed %d\n",
2154 ifb
->ifb_name
, bondport_get_name(p
), error
);
2158 /* re-program the port's ethernet address */
2159 error
= if_siflladdr(port_ifp
,
2160 (const struct ether_addr
*)ifnet_lladdr(ifp
));
2162 /* port doesn't support setting the link address */
2163 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2164 ifb
->ifb_name
, bondport_get_name(p
), error
);
2167 progress
|= BOND_ADD_PROGRESS_LLADDR_SET
;
2171 /* no failures past this point */
2174 /* copy the contents of the existing distributing array */
2175 if (ifb
->ifb_distributing_count
) {
2176 bcopy(ifb
->ifb_distributing_array
, new_array
,
2177 sizeof(*new_array
) * ifb
->ifb_distributing_count
);
2179 old_array
= ifb
->ifb_distributing_array
;
2180 ifb
->ifb_distributing_array
= new_array
;
2182 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
2185 /* check if we need to generate a link status event */
2186 if (ifbond_selection(ifb
)) {
2187 event_code
= (ifb
->ifb_active_lag
== NULL
)
2190 ifb
->ifb_last_link_event
= event_code
;
2194 /* are we adding the first distributing interface? */
2195 if (media_active(&p
->po_media_info
)) {
2196 if (ifb
->ifb_distributing_count
== 0) {
2197 ifb
->ifb_last_link_event
= event_code
= KEV_DL_LINK_ON
;
2199 bondport_enable_distributing(p
);
2202 bondport_disable_distributing(p
);
2205 /* clear the busy state, and wakeup anyone waiting */
2206 ifbond_signal(ifb
, "bond_add_interface");
2208 if (event_code
!= 0) {
2209 interface_link_event(ifp
, event_code
);
2211 if (old_array
!= NULL
) {
2212 FREE(old_array
, M_BOND
);
2217 bond_assert_lock_not_held();
2219 /* if this was the first port to be added, clear our address */
2221 ifnet_set_lladdr_and_type(ifp
, NULL
, 0, IFT_IEEE8023ADLAG
);
2224 if (new_array
!= NULL
) {
2225 FREE(new_array
, M_BOND
);
2227 if ((progress
& BOND_ADD_PROGRESS_LLADDR_SET
) != 0) {
2230 error1
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2232 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2233 ifb
->ifb_name
, bondport_get_name(p
), error1
);
2236 if ((progress
& BOND_ADD_PROGRESS_PROTO_ATTACHED
) != 0) {
2237 (void)bond_detach_protocol(port_ifp
);
2239 if ((progress
& BOND_ADD_PROGRESS_MTU_SET
) != 0) {
2242 error1
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
2244 printf("bond_add_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2245 ifb
->ifb_name
, bondport_get_name(p
),
2246 p
->po_devmtu
.ifdm_current
, error1
);
2250 if ((progress
& BOND_ADD_PROGRESS_IN_LIST
) != 0) {
2251 TAILQ_REMOVE(&ifb
->ifb_port_list
, p
, po_port_list
);
2252 ifb
->ifb_port_count
--;
2254 ifnet_set_eflags(ifp
, 0, IFEF_BOND
);
2255 if (TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
2256 ifb
->ifb_altmtu
= 0;
2257 ifnet_set_mtu(ifp
, 0);
2258 ifnet_set_offload(ifp
, 0);
2262 ifbond_signal(ifb
, "bond_add_interface");
2264 ifbond_release(ifb
);
2270 bond_remove_interface(ifbond_ref ifb
, struct ifnet
* port_ifp
)
2275 bondport_ref head_port
;
2278 int new_link_address
= FALSE
;
2280 lacp_actor_partner_state s
;
2281 int was_distributing
;
2283 bond_assert_lock_held();
2286 ifbond_wait(ifb
, "bond_remove_interface");
2288 p
= ifbond_lookup_port(ifb
, port_ifp
);
2291 /* it got removed by another thread */
2295 /* de-select it and remove it from the lists */
2296 was_distributing
= bondport_flags_distributing(p
);
2297 bondport_disable_distributing(p
);
2298 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
2299 bondport_set_selected(p
, SelectedState_UNSELECTED
);
2300 active_lag
= bondport_remove_from_LAG(p
);
2301 /* invalidate timers here while holding the bond_lock */
2302 bondport_invalidate_timers(p
);
2304 /* announce that we're Individual now */
2305 s
= p
->po_actor_state
;
2306 s
= lacp_actor_partner_state_set_individual(s
);
2307 s
= lacp_actor_partner_state_set_not_collecting(s
);
2308 s
= lacp_actor_partner_state_set_not_distributing(s
);
2309 s
= lacp_actor_partner_state_set_out_of_sync(s
);
2310 p
->po_actor_state
= s
;
2311 bondport_flags_set_ntt(p
);
2314 TAILQ_REMOVE(&ifb
->ifb_port_list
, p
, po_port_list
);
2315 ifb
->ifb_port_count
--;
2318 head_port
= TAILQ_FIRST(&ifb
->ifb_port_list
);
2319 if (head_port
== NULL
) {
2320 ifnet_set_flags(ifp
, 0, IFF_RUNNING
);
2321 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2324 ifnet_set_offload(ifp
, 0);
2325 ifnet_set_mtu(ifp
, 0);
2326 ifb
->ifb_altmtu
= 0;
2327 } else if (ifbond_flags_lladdr(ifb
) == FALSE
2328 && bcmp(&p
->po_saved_addr
, ifnet_lladdr(ifp
),
2329 ETHER_ADDR_LEN
) == 0) {
2330 new_link_address
= TRUE
;
2332 /* check if we need to generate a link status event */
2333 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
2334 if (ifbond_selection(ifb
) || active_lag
) {
2335 event_code
= (ifb
->ifb_active_lag
== NULL
)
2338 ifb
->ifb_last_link_event
= event_code
;
2340 bondport_transmit_machine(p
, LAEventStart
,
2341 TRANSMIT_MACHINE_TX_IMMEDIATE
);
2344 /* are we removing the last distributing interface? */
2345 if (was_distributing
&& ifb
->ifb_distributing_count
== 0) {
2346 ifb
->ifb_last_link_event
= event_code
= KEV_DL_LINK_OFF
;
2353 ifnet_set_lladdr_and_type(ifp
, NULL
, 0, IFT_IEEE8023ADLAG
);
2355 else if (new_link_address
) {
2356 struct ifnet
* scan_ifp
;
2357 bondport_ref scan_port
;
2359 /* ifbond_wait() allows port list traversal without holding the lock */
2361 /* this port gave the bond its ethernet address, switch to new one */
2362 ifnet_set_lladdr_and_type(ifp
,
2363 &head_port
->po_saved_addr
, ETHER_ADDR_LEN
,
2366 /* re-program each port with the new link address */
2367 TAILQ_FOREACH(scan_port
, &ifb
->ifb_port_list
, po_port_list
) {
2368 scan_ifp
= scan_port
->po_ifp
;
2370 error
= if_siflladdr(scan_ifp
,
2371 (const struct ether_addr
*) ifnet_lladdr(ifp
));
2373 printf("bond_remove_interface(%s, %s): "
2374 "if_siflladdr (%s) failed %d\n",
2375 ifb
->ifb_name
, bondport_get_name(p
),
2376 bondport_get_name(scan_port
), error
);
2381 /* restore the port's ethernet address */
2382 error
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2384 printf("bond_remove_interface(%s, %s): if_siflladdr failed %d\n",
2385 ifb
->ifb_name
, bondport_get_name(p
), error
);
2388 /* restore the port's MTU */
2389 error
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
2391 printf("bond_remove_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2392 ifb
->ifb_name
, bondport_get_name(p
),
2393 p
->po_devmtu
.ifdm_current
, error
);
2396 /* remove the bond "protocol" */
2397 bond_detach_protocol(port_ifp
);
2399 /* generate link event */
2400 if (event_code
!= 0) {
2401 interface_link_event(ifp
, event_code
);
2406 ifnet_set_eflags(port_ifp
, 0, IFEF_BOND
);
2407 /* release this bondport's reference to the ifbond */
2408 ifbond_release(ifb
);
2411 ifbond_signal(ifb
, "bond_remove_interface");
2412 ifbond_release(ifb
);
2417 bond_set_lacp_mode(ifbond_ref ifb
)
2421 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2422 bondport_disable_distributing(p
);
2429 bond_set_static_mode(ifbond_ref ifb
)
2432 lacp_actor_partner_state s
;
2434 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2435 bondport_disable_distributing(p
);
2436 bondport_set_selected(p
, SelectedState_UNSELECTED
);
2437 (void)bondport_remove_from_LAG(p
);
2438 bondport_cancel_timers(p
);
2440 /* announce that we're Individual now */
2441 s
= p
->po_actor_state
;
2442 s
= lacp_actor_partner_state_set_individual(s
);
2443 s
= lacp_actor_partner_state_set_not_collecting(s
);
2444 s
= lacp_actor_partner_state_set_not_distributing(s
);
2445 s
= lacp_actor_partner_state_set_out_of_sync(s
);
2446 p
->po_actor_state
= s
;
2447 bondport_flags_set_ntt(p
);
2448 bondport_transmit_machine(p
, LAEventStart
,
2449 TRANSMIT_MACHINE_TX_IMMEDIATE
);
2451 p
->po_actor_state
= 0;
2452 bzero(&p
->po_partner_state
, sizeof(p
->po_partner_state
));
2454 if (media_active(&p
->po_media_info
)) {
2455 bondport_enable_distributing(p
);
2458 bondport_disable_distributing(p
);
2465 bond_set_mode(struct ifnet
* ifp
, int mode
)
2472 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2473 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2475 return ((ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
);
2477 if (ifb
->ifb_mode
== mode
) {
2483 ifbond_wait(ifb
, "bond_set_mode");
2485 /* verify (again) that the mode is actually different */
2486 if (ifb
->ifb_mode
== mode
) {
2491 ifb
->ifb_mode
= mode
;
2492 if (mode
== IF_BOND_MODE_LACP
) {
2493 bond_set_lacp_mode(ifb
);
2495 /* check if we need to generate a link status event */
2496 if (ifbond_selection(ifb
)) {
2497 event_code
= (ifb
->ifb_active_lag
== NULL
)
2502 bond_set_static_mode(ifb
);
2503 event_code
= (ifb
->ifb_distributing_count
== 0)
2507 ifb
->ifb_last_link_event
= event_code
;
2510 ifbond_signal(ifb
, "bond_set_mode");
2512 ifbond_release(ifb
);
2514 if (event_code
!= 0) {
2515 interface_link_event(ifp
, event_code
);
2521 bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
, user_addr_t datap
)
2526 struct if_bond_status_req
* ibsr
;
2527 struct if_bond_status ibs
;
2530 ibsr
= &(ibr_p
->ibr_ibru
.ibru_status
);
2531 if (ibsr
->ibsr_version
!= IF_BOND_STATUS_REQ_VERSION
) {
2534 ibsr
->ibsr_key
= ifb
->ifb_key
;
2535 ibsr
->ibsr_mode
= ifb
->ifb_mode
;
2536 ibsr
->ibsr_total
= ifb
->ifb_port_count
;
2537 dst
= proc_is64bit(current_proc())
2538 ? ibsr
->ibsr_ibsru
.ibsru_buffer64
2539 : CAST_USER_ADDR_T(ibsr
->ibsr_ibsru
.ibsru_buffer
);
2540 if (dst
== USER_ADDR_NULL
) {
2541 /* just want to know how many there are */
2544 if (ibsr
->ibsr_count
< 0) {
2547 count
= (ifb
->ifb_port_count
< ibsr
->ibsr_count
)
2548 ? ifb
->ifb_port_count
: ibsr
->ibsr_count
;
2549 TAILQ_FOREACH(port
, &ifb
->ifb_port_list
, po_port_list
) {
2550 struct if_bond_partner_state
* ibps_p
;
2551 partner_state_ref ps
;
2556 bzero(&ibs
, sizeof(ibs
));
2557 strncpy(ibs
.ibs_if_name
, port
->po_name
, sizeof(ibs
.ibs_if_name
));
2558 ibs
.ibs_port_priority
= port
->po_priority
;
2559 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
2560 ibs
.ibs_state
= port
->po_actor_state
;
2561 ibs
.ibs_selected_state
= port
->po_selected
;
2562 ps
= &port
->po_partner_state
;
2563 ibps_p
= &ibs
.ibs_partner_state
;
2564 ibps_p
->ibps_system
= ps
->ps_lag_info
.li_system
;
2565 ibps_p
->ibps_system_priority
= ps
->ps_lag_info
.li_system_priority
;
2566 ibps_p
->ibps_key
= ps
->ps_lag_info
.li_key
;
2567 ibps_p
->ibps_port
= ps
->ps_port
;
2568 ibps_p
->ibps_port_priority
= ps
->ps_port_priority
;
2569 ibps_p
->ibps_state
= ps
->ps_state
;
2572 /* fake the selected information */
2573 ibs
.ibs_selected_state
= bondport_flags_distributing(port
)
2574 ? SelectedState_SELECTED
: SelectedState_UNSELECTED
;
2576 error
= copyout(&ibs
, dst
, sizeof(ibs
));
2586 error
= copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2589 (void)copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2595 bond_set_promisc(__unused
struct ifnet
*ifp
)
2599 ifbond_ref ifb
= ifnet_softc(ifp
);
2602 if ((ifnet_flags(ifp
) & IFF_PROMISC
) != 0) {
2603 if ((ifb
->ifb_flags
& IFBF_PROMISC
) == 0) {
2604 error
= ifnet_set_promiscuous(ifb
->ifb_p
, 1);
2606 ifb
->ifb_flags
|= IFBF_PROMISC
;
2609 if ((ifb
->ifb_flags
& IFBF_PROMISC
) != 0) {
2610 error
= ifnet_set_promiscuous(ifb
->ifb_p
, 0);
2612 ifb
->ifb_flags
&= ~IFBF_PROMISC
;
2620 bond_get_mtu_values(ifbond_ref ifb
, int * ret_min
, int * ret_max
)
2626 if (TAILQ_FIRST(&ifb
->ifb_port_list
) != NULL
) {
2627 mtu_min
= IF_MINMTU
;
2629 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2630 struct ifdevmtu
* devmtu_p
= &p
->po_devmtu
;
2632 if (devmtu_p
->ifdm_min
> mtu_min
) {
2633 mtu_min
= devmtu_p
->ifdm_min
;
2635 if (mtu_max
== 0 || devmtu_p
->ifdm_max
< mtu_max
) {
2636 mtu_max
= devmtu_p
->ifdm_max
;
2645 bond_set_mtu_on_ports(ifbond_ref ifb
, int mtu
)
2650 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2651 error
= siocsifmtu(p
->po_ifp
, mtu
);
2653 printf("if_bond(%s): SIOCSIFMTU %s failed, %d\n",
2654 ifb
->ifb_name
, bondport_get_name(p
), error
);
2662 bond_set_mtu(struct ifnet
* ifp
, int mtu
, int isdevmtu
)
2672 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2673 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2674 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2678 ifbond_wait(ifb
, "bond_set_mtu");
2681 if (ifnet_softc(ifp
) == NULL
|| ifbond_flags_if_detaching(ifb
)) {
2685 bond_get_mtu_values(ifb
, &mtu_min
, &mtu_max
);
2686 if (mtu
> mtu_max
) {
2690 if (mtu
< mtu_min
&& (isdevmtu
== 0 || mtu
!= 0)) {
2691 /* allow SIOCSIFALTMTU to set the mtu to 0 */
2696 new_max
= (mtu
> (int)ifnet_mtu(ifp
)) ? mtu
: (int)ifnet_mtu(ifp
);
2699 new_max
= (mtu
> ifb
->ifb_altmtu
) ? mtu
: ifb
->ifb_altmtu
;
2701 old_max
= ((int)ifnet_mtu(ifp
) > ifb
->ifb_altmtu
)
2702 ? (int)ifnet_mtu(ifp
) : ifb
->ifb_altmtu
;
2703 if (new_max
!= old_max
) {
2704 /* we can safely walk the list of port without the lock held */
2706 error
= bond_set_mtu_on_ports(ifb
, new_max
);
2708 /* try our best to back out of it */
2709 (void)bond_set_mtu_on_ports(ifb
, old_max
);
2715 ifb
->ifb_altmtu
= mtu
;
2718 ifnet_set_mtu(ifp
, mtu
);
2723 ifbond_signal(ifb
, "bond_set_mtu");
2724 ifbond_release(ifb
);
2732 bond_ioctl(struct ifnet
*ifp
, u_int32_t cmd
, void * data
)
2735 struct if_bond_req ibr
;
2736 struct ifaddr
* ifa
;
2739 struct ifmediareq64
*ifmr
;
2740 struct ifnet
* port_ifp
= NULL
;
2741 user_addr_t user_addr
;
2743 if (ifnet_type(ifp
) != IFT_IEEE8023ADLAG
) {
2744 return (EOPNOTSUPP
);
2746 ifr
= (struct ifreq
*)data
;
2747 ifa
= (struct ifaddr
*)data
;
2751 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
2754 case SIOCGIFMEDIA64
:
2757 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2758 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2760 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2762 ifmr
= (struct ifmediareq64
*)data
;
2763 ifmr
->ifm_current
= IFM_ETHER
;
2765 ifmr
->ifm_status
= IFM_AVALID
;
2766 ifmr
->ifm_active
= IFM_ETHER
;
2767 ifmr
->ifm_count
= 1;
2768 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
2769 if (ifb
->ifb_active_lag
!= NULL
) {
2770 ifmr
->ifm_active
= ifb
->ifb_active_lag
->lag_active_media
;
2771 ifmr
->ifm_status
|= IFM_ACTIVE
;
2774 else if (ifb
->ifb_distributing_count
> 0) {
2776 = ifb
->ifb_distributing_array
[0]->po_media_info
.mi_active
;
2777 ifmr
->ifm_status
|= IFM_ACTIVE
;
2780 user_addr
= proc_is64bit(current_proc())
2781 ? ifmr
->ifm_ifmu
.ifmu_ulist64
2782 : CAST_USER_ADDR_T(ifmr
->ifm_ifmu
.ifmu_ulist32
);
2783 if (user_addr
!= USER_ADDR_NULL
) {
2784 error
= copyout(&ifmr
->ifm_current
,
2791 /* XXX send the SIFMEDIA to all children? Or force autoselect? */
2797 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2798 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2800 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2803 ifr
->ifr_devmtu
.ifdm_current
= bond_device_mtu(ifp
, ifb
);
2804 bond_get_mtu_values(ifb
, &ifr
->ifr_devmtu
.ifdm_min
,
2805 &ifr
->ifr_devmtu
.ifdm_max
);
2811 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2812 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2814 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2817 ifr
->ifr_mtu
= ifb
->ifb_altmtu
;
2822 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 1);
2826 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 0);
2830 user_addr
= proc_is64bit(current_proc())
2831 ? ifr
->ifr_data64
: CAST_USER_ADDR_T(ifr
->ifr_data
);
2832 error
= copyin(user_addr
, &ibr
, sizeof(ibr
));
2836 switch (ibr
.ibr_op
) {
2837 case IF_BOND_OP_ADD_INTERFACE
:
2838 case IF_BOND_OP_REMOVE_INTERFACE
:
2839 /* XXX ifunit() needs to return a reference on the ifp */
2840 port_ifp
= ifunit(ibr
.ibr_ibru
.ibru_if_name
);
2841 if (port_ifp
== NULL
) {
2845 if (ifnet_type(port_ifp
) != IFT_ETHER
) {
2846 error
= EPROTONOSUPPORT
;
2850 case IF_BOND_OP_SET_VERBOSE
:
2851 case IF_BOND_OP_SET_MODE
:
2860 switch (ibr
.ibr_op
) {
2861 case IF_BOND_OP_ADD_INTERFACE
:
2862 error
= bond_add_interface(ifp
, port_ifp
);
2864 case IF_BOND_OP_REMOVE_INTERFACE
:
2866 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2867 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2869 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2871 error
= bond_remove_interface(ifb
, port_ifp
);
2874 case IF_BOND_OP_SET_VERBOSE
:
2876 if (g_bond
== NULL
) {
2881 g_bond
->verbose
= ibr
.ibr_ibru
.ibru_int_val
;
2884 case IF_BOND_OP_SET_MODE
:
2885 switch (ibr
.ibr_ibru
.ibru_int_val
) {
2886 case IF_BOND_MODE_LACP
:
2887 case IF_BOND_MODE_STATIC
:
2896 error
= bond_set_mode(ifp
, ibr
.ibr_ibru
.ibru_int_val
);
2899 break; /* SIOCSIFBOND */
2902 user_addr
= proc_is64bit(current_proc())
2903 ? ifr
->ifr_data64
: CAST_USER_ADDR_T(ifr
->ifr_data
);
2904 error
= copyin(user_addr
, &ibr
, sizeof(ibr
));
2908 switch (ibr
.ibr_op
) {
2909 case IF_BOND_OP_GET_STATUS
:
2919 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2920 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2922 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2924 switch (ibr
.ibr_op
) {
2925 case IF_BOND_OP_GET_STATUS
:
2926 error
= bond_get_status(ifb
, &ibr
, user_addr
);
2930 break; /* SIOCGIFBOND */
2937 /* enable/disable promiscuous mode */
2939 error
= bond_set_promisc(ifp
);
2945 error
= bond_setmulti(ifp
);
2954 bond_if_free(struct ifnet
* ifp
)
2962 ifb
= (ifbond_ref
)ifnet_softc(ifp
);
2967 ifbond_release(ifb
);
2974 bond_event(struct ifnet
* port_ifp
, __unused protocol_family_t protocol
,
2975 const struct kev_msg
* event
)
2977 struct ifnet
* bond_ifp
= NULL
;
2980 int old_distributing_count
;
2982 struct media_info media_info
= { 0, 0};
2984 if (event
->vendor_code
!= KEV_VENDOR_APPLE
2985 || event
->kev_class
!= KEV_NETWORK_CLASS
2986 || event
->kev_subclass
!= KEV_DL_SUBCLASS
) {
2989 switch (event
->event_code
) {
2990 case KEV_DL_IF_DETACHING
:
2992 case KEV_DL_LINK_OFF
:
2993 case KEV_DL_LINK_ON
:
2994 media_info
= interface_media_info(port_ifp
);
3000 p
= bond_lookup_port(port_ifp
);
3006 old_distributing_count
= ifb
->ifb_distributing_count
;
3007 switch (event
->event_code
) {
3008 case KEV_DL_IF_DETACHING
:
3009 bond_remove_interface(ifb
, p
->po_ifp
);
3011 case KEV_DL_LINK_OFF
:
3012 case KEV_DL_LINK_ON
:
3013 p
->po_media_info
= media_info
;
3014 if (p
->po_enabled
) {
3015 bondport_link_status_changed(p
);
3019 /* generate a link-event */
3020 if (ifb
->ifb_mode
== IF_BOND_MODE_LACP
) {
3021 if (ifbond_selection(ifb
)) {
3022 event_code
= (ifb
->ifb_active_lag
== NULL
)
3025 /* XXX need to take a reference on bond_ifp */
3026 bond_ifp
= ifb
->ifb_ifp
;
3027 ifb
->ifb_last_link_event
= event_code
;
3030 event_code
= (ifb
->ifb_active_lag
== NULL
)
3033 if (event_code
!= ifb
->ifb_last_link_event
) {
3034 if (g_bond
->verbose
) {
3035 timestamp_printf("%s: (event) generating LINK event\n",
3038 bond_ifp
= ifb
->ifb_ifp
;
3039 ifb
->ifb_last_link_event
= event_code
;
3045 * if the distributing array membership changed from 0 <-> !0
3046 * generate a link event
3048 if (old_distributing_count
== 0
3049 && ifb
->ifb_distributing_count
!= 0) {
3050 event_code
= KEV_DL_LINK_ON
;
3052 else if (old_distributing_count
!= 0
3053 && ifb
->ifb_distributing_count
== 0) {
3054 event_code
= KEV_DL_LINK_OFF
;
3056 if (event_code
!= 0 && event_code
!= ifb
->ifb_last_link_event
) {
3057 bond_ifp
= ifb
->ifb_ifp
;
3058 ifb
->ifb_last_link_event
= event_code
;
3063 if (bond_ifp
!= NULL
) {
3064 interface_link_event(bond_ifp
, event_code
);
3070 interface_link_event(struct ifnet
* ifp
, u_long event_code
)
3073 struct kern_event_msg header
;
3075 char if_name
[IFNAMSIZ
];
3078 event
.header
.total_size
= sizeof(event
);
3079 event
.header
.vendor_code
= KEV_VENDOR_APPLE
;
3080 event
.header
.kev_class
= KEV_NETWORK_CLASS
;
3081 event
.header
.kev_subclass
= KEV_DL_SUBCLASS
;
3082 event
.header
.event_code
= event_code
;
3083 event
.header
.event_data
[0] = ifnet_family(ifp
);
3084 event
.unit
= (u_long
) ifnet_unit(ifp
);
3085 strncpy(event
.if_name
, ifnet_name(ifp
), IFNAMSIZ
);
3086 ifnet_event(ifp
, &event
.header
);
3091 * Function: bond_attach_protocol
3093 * Attach a DLIL protocol to the interface.
3095 * The ethernet demux special cases to always return PF_BOND if the
3096 * interface is bonded. That means we receive all traffic from that
3097 * interface without passing any of the traffic to any other attached
3101 bond_attach_protocol(struct ifnet
*ifp
)
3104 struct ifnet_attach_proto_param reg
;
3106 bzero(®
, sizeof(reg
));
3107 reg
.input
= bond_input
;
3108 reg
.event
= bond_event
;
3110 error
= ifnet_attach_protocol(ifp
, PF_BOND
, ®
);
3112 printf("bond over %s%d: ifnet_attach_protocol failed, %d\n",
3113 ifnet_name(ifp
), ifnet_unit(ifp
), error
);
3119 * Function: bond_detach_protocol
3121 * Detach our DLIL protocol from an interface
3124 bond_detach_protocol(struct ifnet
*ifp
)
3128 error
= ifnet_detach_protocol(ifp
, PF_BOND
);
3130 printf("bond over %s%d: ifnet_detach_protocol failed, %d\n",
3131 ifnet_name(ifp
), ifnet_unit(ifp
), error
);
3137 * DLIL interface family functions
3139 extern int ether_attach_inet(ifnet_t ifp
, protocol_family_t protocol_family
);
3140 extern void ether_detach_inet(ifnet_t ifp
, protocol_family_t protocol_family
);
3141 extern int ether_attach_inet6(ifnet_t ifp
, protocol_family_t protocol_family
);
3142 extern void ether_detach_inet6(ifnet_t ifp
, protocol_family_t protocol_family
);
3143 extern int ether_attach_at(ifnet_t ifp
, protocol_family_t protocol_family
);
3144 extern void ether_detach_at(ifnet_t ifp
, protocol_family_t protocol_family
);
3146 __private_extern__
int
3147 bond_family_init(void)
3151 error
= proto_register_plumber(PF_INET
, APPLE_IF_FAM_BOND
,
3155 printf("bond: proto_register_plumber failed for AF_INET error=%d\n",
3160 error
= proto_register_plumber(PF_INET6
, APPLE_IF_FAM_BOND
,
3162 ether_detach_inet6
);
3164 printf("bond: proto_register_plumber failed for AF_INET6 error=%d\n",
3169 error
= proto_register_plumber(PF_APPLETALK
, APPLE_IF_FAM_BOND
,
3173 printf("bond: proto_register_plumber failed for AppleTalk error=%d\n",
3177 bond_clone_attach();
3189 ** LACP ifbond_list routines
3192 ifbond_list_find_moved_port(bondport_ref rx_port
,
3193 const lacp_actor_partner_tlv_ref atlv
)
3197 partner_state_ref ps
;
3200 TAILQ_FOREACH(bond
, &g_bond
->ifbond_list
, ifb_bond_list
) {
3201 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3204 /* no point in comparing against ourselves */
3207 if (p
->po_receive_state
!= ReceiveState_PORT_DISABLED
) {
3208 /* it's not clear that we should be checking this */
3211 ps
= &p
->po_partner_state
;
3212 if (lacp_actor_partner_state_defaulted(ps
->ps_state
)) {
3215 ps_li
= &ps
->ps_lag_info
;
3216 if (ps
->ps_port
== lacp_actor_partner_tlv_get_port(atlv
)
3217 && bcmp(&ps_li
->li_system
, atlv
->lap_system
,
3218 sizeof(ps_li
->li_system
)) == 0) {
3219 if (g_bond
->verbose
) {
3220 timestamp_printf("System " EA_FORMAT
3221 " Port 0x%x moved from %s to %s\n",
3222 EA_LIST(&ps_li
->li_system
), ps
->ps_port
,
3223 bondport_get_name(p
),
3224 bondport_get_name(rx_port
));
3234 ** LACP ifbond, LAG routines
3238 ifbond_selection(ifbond_ref bond
)
3240 int all_ports_ready
= 0;
3241 int active_media
= 0;
3243 int lag_changed
= 0;
3247 lag
= ifbond_find_best_LAG(bond
, &active_media
);
3248 if (lag
!= bond
->ifb_active_lag
) {
3249 if (bond
->ifb_active_lag
!= NULL
) {
3250 ifbond_deactivate_LAG(bond
, bond
->ifb_active_lag
);
3251 bond
->ifb_active_lag
= NULL
;
3253 bond
->ifb_active_lag
= lag
;
3255 ifbond_activate_LAG(bond
, lag
, active_media
);
3259 else if (lag
!= NULL
) {
3260 if (lag
->lag_active_media
!= active_media
) {
3261 if (g_bond
->verbose
) {
3262 timestamp_printf("LAG PORT SPEED CHANGED from %d to %d\n",
3263 link_speed(lag
->lag_active_media
),
3264 link_speed(active_media
));
3266 ifbond_deactivate_LAG(bond
, lag
);
3267 ifbond_activate_LAG(bond
, lag
, active_media
);
3272 port_speed
= link_speed(active_media
);
3273 all_ports_ready
= ifbond_all_ports_ready(bond
);
3275 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3276 if (lag
!= NULL
&& p
->po_lag
== lag
3277 && media_speed(&p
->po_media_info
) == port_speed
3278 && (p
->po_mux_state
== MuxState_DETACHED
3279 || p
->po_selected
== SelectedState_SELECTED
3280 || p
->po_selected
== SelectedState_STANDBY
)
3281 && bondport_aggregatable(p
)) {
3282 if (bond
->ifb_max_active
> 0) {
3283 if (lag
->lag_selected_port_count
< bond
->ifb_max_active
) {
3284 if (p
->po_selected
== SelectedState_STANDBY
3285 || p
->po_selected
== SelectedState_UNSELECTED
) {
3286 bondport_set_selected(p
, SelectedState_SELECTED
);
3289 else if (p
->po_selected
== SelectedState_UNSELECTED
) {
3290 bondport_set_selected(p
, SelectedState_STANDBY
);
3294 bondport_set_selected(p
, SelectedState_SELECTED
);
3297 if (bondport_flags_selected_changed(p
)) {
3298 bondport_flags_clear_selected_changed(p
);
3299 bondport_mux_machine(p
, LAEventSelectedChange
, NULL
);
3302 && bondport_flags_ready(p
)
3303 && p
->po_mux_state
== MuxState_WAITING
) {
3304 bondport_mux_machine(p
, LAEventReady
, NULL
);
3306 bondport_transmit_machine(p
, LAEventStart
, NULL
);
3308 return (lag_changed
);
3312 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
)
3314 int best_active
= 0;
3315 LAG_ref best_lag
= NULL
;
3320 if (bond
->ifb_active_lag
!= NULL
) {
3321 best_lag
= bond
->ifb_active_lag
;
3322 best_count
= LAG_get_aggregatable_port_count(best_lag
, &best_active
);
3323 if (bond
->ifb_max_active
> 0
3324 && best_count
> bond
->ifb_max_active
) {
3325 best_count
= bond
->ifb_max_active
;
3327 best_speed
= link_speed(best_active
);
3329 TAILQ_FOREACH(lag
, &bond
->ifb_lag_list
, lag_list
) {
3334 if (lag
== bond
->ifb_active_lag
) {
3335 /* we've already computed it */
3338 count
= LAG_get_aggregatable_port_count(lag
, &active
);
3342 if (bond
->ifb_max_active
> 0
3343 && count
> bond
->ifb_max_active
) {
3344 /* if there's a limit, don't count extra links */
3345 count
= bond
->ifb_max_active
;
3347 speed
= link_speed(active
);
3348 if ((count
* speed
) > (best_count
* best_speed
)) {
3351 best_active
= active
;
3355 if (best_count
== 0) {
3358 *active_media
= best_active
;
3363 ifbond_deactivate_LAG(__unused ifbond_ref bond
, LAG_ref lag
)
3367 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3368 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3374 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
)
3379 if (bond
->ifb_max_active
> 0) {
3380 need
= bond
->ifb_max_active
;
3382 lag
->lag_active_media
= active_media
;
3383 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3384 if (bondport_aggregatable(p
) == 0) {
3385 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3387 else if (media_speed(&p
->po_media_info
) != link_speed(active_media
)) {
3388 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3390 else if (p
->po_mux_state
== MuxState_DETACHED
) {
3391 if (bond
->ifb_max_active
> 0) {
3393 bondport_set_selected(p
, SelectedState_SELECTED
);
3397 bondport_set_selected(p
, SelectedState_STANDBY
);
3401 bondport_set_selected(p
, SelectedState_SELECTED
);
3405 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3413 ifbond_set_max_active(ifbond_ref bond
, int max_active
)
3415 LAG_ref lag
= bond
->ifb_active_lag
;
3417 bond
->ifb_max_active
= max_active
;
3418 if (bond
->ifb_max_active
<= 0 || lag
== NULL
) {
3421 if (lag
->lag_selected_port_count
> bond
->ifb_max_active
) {
3425 remove_count
= lag
->lag_selected_port_count
- bond
->ifb_max_active
;
3426 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3427 if (p
->po_selected
== SelectedState_SELECTED
) {
3428 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3430 if (remove_count
== 0) {
3441 ifbond_all_ports_ready(ifbond_ref bond
)
3446 if (bond
->ifb_active_lag
== NULL
) {
3449 TAILQ_FOREACH(p
, &bond
->ifb_active_lag
->lag_port_list
, po_lag_port_list
) {
3450 if (p
->po_mux_state
== MuxState_WAITING
3451 && p
->po_selected
== SelectedState_SELECTED
) {
3452 if (bondport_flags_ready(p
) == 0) {
3456 /* note that there was at least one ready port */
3463 ifbond_all_ports_attached(ifbond_ref bond
, bondport_ref this_port
)
3467 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3468 if (this_port
== p
) {
3471 if (bondport_flags_mux_attached(p
) == 0) {
3479 ifbond_get_LAG_matching_port(ifbond_ref bond
, bondport_ref p
)
3483 TAILQ_FOREACH(lag
, &bond
->ifb_lag_list
, lag_list
) {
3484 if (bcmp(&lag
->lag_info
, &p
->po_partner_state
.ps_lag_info
,
3485 sizeof(lag
->lag_info
)) == 0) {
3493 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
)
3503 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3504 if (bondport_aggregatable(p
)) {
3507 this_speed
= media_speed(&p
->po_media_info
);
3508 if (this_speed
== 0) {
3511 if (this_speed
> speed
) {
3512 active
= p
->po_media_info
.mi_active
;
3516 else if (this_speed
== speed
) {
3521 *active_media
= active
;
3527 ** LACP bondport routines
3530 bondport_link_status_changed(bondport_ref p
)
3532 ifbond_ref bond
= p
->po_bond
;
3534 if (g_bond
->verbose
) {
3535 if (media_active(&p
->po_media_info
)) {
3536 timestamp_printf("[%s] Link UP %d Mbit/s %s duplex\n",
3537 bondport_get_name(p
),
3538 media_speed(&p
->po_media_info
),
3539 media_full_duplex(&p
->po_media_info
)
3543 timestamp_printf("[%s] Link DOWN\n", bondport_get_name(p
));
3546 if (bond
->ifb_mode
== IF_BOND_MODE_LACP
) {
3547 if (media_active(&p
->po_media_info
)
3548 && bond
->ifb_active_lag
!= NULL
3549 && p
->po_lag
== bond
->ifb_active_lag
3550 && p
->po_selected
!= SelectedState_UNSELECTED
) {
3551 if (media_speed(&p
->po_media_info
) != p
->po_lag
->lag_active_media
) {
3552 if (g_bond
->verbose
) {
3553 timestamp_printf("[%s] Port speed %d differs from LAG %d\n",
3554 bondport_get_name(p
),
3555 media_speed(&p
->po_media_info
),
3556 link_speed(p
->po_lag
->lag_active_media
));
3558 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3561 bondport_receive_machine(p
, LAEventMediaChange
, NULL
);
3562 bondport_mux_machine(p
, LAEventMediaChange
, NULL
);
3563 bondport_periodic_transmit_machine(p
, LAEventMediaChange
, NULL
);
3566 if (media_active(&p
->po_media_info
)) {
3567 bondport_enable_distributing(p
);
3570 bondport_disable_distributing(p
);
3577 bondport_aggregatable(bondport_ref p
)
3579 partner_state_ref ps
= &p
->po_partner_state
;
3581 if (lacp_actor_partner_state_aggregatable(p
->po_actor_state
) == 0
3582 || lacp_actor_partner_state_aggregatable(ps
->ps_state
) == 0) {
3583 /* we and/or our partner are individual */
3586 if (p
->po_lag
== NULL
) {
3589 switch (p
->po_receive_state
) {
3591 if (g_bond
->verbose
) {
3592 timestamp_printf("[%s] Port is not selectable\n",
3593 bondport_get_name(p
));
3596 case ReceiveState_CURRENT
:
3597 case ReceiveState_EXPIRED
:
3604 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
)
3606 LAG_info_ref lag_li
;
3607 partner_state_ref ps
;
3610 ps
= &p
->po_partner_state
;
3611 ps_li
= &ps
->ps_lag_info
;
3612 lag_li
= &lag
->lag_info
;
3613 if (ps_li
->li_system_priority
== lag_li
->li_system_priority
3614 && ps_li
->li_key
== lag_li
->li_key
3615 && (bcmp(&ps_li
->li_system
, &lag_li
->li_system
,
3616 sizeof(lag_li
->li_system
))
3624 bondport_remove_from_LAG(bondport_ref p
)
3627 ifbond_ref bond
= p
->po_bond
;
3628 LAG_ref lag
= p
->po_lag
;
3633 TAILQ_REMOVE(&lag
->lag_port_list
, p
, po_lag_port_list
);
3634 if (g_bond
->verbose
) {
3635 timestamp_printf("[%s] Removed from LAG (0x%04x," EA_FORMAT
3637 bondport_get_name(p
),
3638 lag
->lag_info
.li_system_priority
,
3639 EA_LIST(&lag
->lag_info
.li_system
),
3640 lag
->lag_info
.li_key
);
3643 lag
->lag_port_count
--;
3644 if (lag
->lag_port_count
> 0) {
3645 return (bond
->ifb_active_lag
== lag
);
3647 if (g_bond
->verbose
) {
3648 timestamp_printf("Key 0x%04x: LAG Released (%04x," EA_FORMAT
3651 lag
->lag_info
.li_system_priority
,
3652 EA_LIST(&lag
->lag_info
.li_system
),
3653 lag
->lag_info
.li_key
);
3655 TAILQ_REMOVE(&bond
->ifb_lag_list
, lag
, lag_list
);
3656 if (bond
->ifb_active_lag
== lag
) {
3657 bond
->ifb_active_lag
= NULL
;
3661 return (active_lag
);
3665 bondport_add_to_LAG(bondport_ref p
, LAG_ref lag
)
3667 TAILQ_INSERT_TAIL(&lag
->lag_port_list
, p
, po_lag_port_list
);
3669 lag
->lag_port_count
++;
3670 if (g_bond
->verbose
) {
3671 timestamp_printf("[%s] Added to LAG (0x%04x," EA_FORMAT
"0x%04x)\n",
3672 bondport_get_name(p
),
3673 lag
->lag_info
.li_system_priority
,
3674 EA_LIST(&lag
->lag_info
.li_system
),
3675 lag
->lag_info
.li_key
);
3681 bondport_assign_to_LAG(bondport_ref p
)
3683 ifbond_ref bond
= p
->po_bond
;
3686 if (lacp_actor_partner_state_defaulted(p
->po_actor_state
)) {
3687 bondport_remove_from_LAG(p
);
3692 if (bondport_matches_LAG(p
, lag
)) {
3696 bondport_remove_from_LAG(p
);
3698 lag
= ifbond_get_LAG_matching_port(bond
, p
);
3700 bondport_add_to_LAG(p
, lag
);
3703 lag
= (LAG_ref
)_MALLOC(sizeof(*lag
), M_BOND
, M_WAITOK
);
3704 TAILQ_INIT(&lag
->lag_port_list
);
3705 lag
->lag_port_count
= 0;
3706 lag
->lag_selected_port_count
= 0;
3707 lag
->lag_info
= p
->po_partner_state
.ps_lag_info
;
3708 TAILQ_INSERT_TAIL(&bond
->ifb_lag_list
, lag
, lag_list
);
3709 if (g_bond
->verbose
) {
3710 timestamp_printf("Key 0x%04x: LAG Created (0x%04x," EA_FORMAT
3713 lag
->lag_info
.li_system_priority
,
3714 EA_LIST(&lag
->lag_info
.li_system
),
3715 lag
->lag_info
.li_key
);
3717 bondport_add_to_LAG(p
, lag
);
3722 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
)
3724 bondport_ref moved_port
;
3727 = ifbond_list_find_moved_port(p
, (const lacp_actor_partner_tlv_ref
)
3728 &in_lacpdu_p
->la_actor_tlv
);
3729 if (moved_port
!= NULL
) {
3730 bondport_receive_machine(moved_port
, LAEventPortMoved
, NULL
);
3732 bondport_receive_machine(p
, LAEventPacket
, in_lacpdu_p
);
3733 bondport_mux_machine(p
, LAEventPacket
, in_lacpdu_p
);
3734 bondport_periodic_transmit_machine(p
, LAEventPacket
, in_lacpdu_p
);
3739 bondport_set_selected(bondport_ref p
, SelectedState s
)
3741 if (s
!= p
->po_selected
) {
3742 ifbond_ref bond
= p
->po_bond
;
3743 LAG_ref lag
= p
->po_lag
;
3745 bondport_flags_set_selected_changed(p
);
3746 if (lag
!= NULL
&& bond
->ifb_active_lag
== lag
) {
3747 if (p
->po_selected
== SelectedState_SELECTED
) {
3748 lag
->lag_selected_port_count
--;
3750 else if (s
== SelectedState_SELECTED
) {
3751 lag
->lag_selected_port_count
++;
3753 if (g_bond
->verbose
) {
3754 timestamp_printf("[%s] SetSelected: %s (was %s)\n",
3755 bondport_get_name(p
),
3756 SelectedStateString(s
),
3757 SelectedStateString(p
->po_selected
));
3770 bondport_UpdateDefaultSelected(bondport_ref p
)
3772 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3777 bondport_RecordDefault(bondport_ref p
)
3779 bzero(&p
->po_partner_state
, sizeof(p
->po_partner_state
));
3781 = lacp_actor_partner_state_set_defaulted(p
->po_actor_state
);
3782 bondport_assign_to_LAG(p
);
3787 bondport_UpdateSelected(bondport_ref p
, lacpdu_ref lacpdu_p
)
3789 lacp_actor_partner_tlv_ref actor
;
3790 partner_state_ref ps
;
3793 /* compare the PDU's Actor information to our Partner state */
3794 actor
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_actor_tlv
;
3795 ps
= &p
->po_partner_state
;
3796 ps_li
= &ps
->ps_lag_info
;
3797 if (lacp_actor_partner_tlv_get_port(actor
) != ps
->ps_port
3798 || (lacp_actor_partner_tlv_get_port_priority(actor
)
3799 != ps
->ps_port_priority
)
3800 || bcmp(actor
->lap_system
, &ps_li
->li_system
, sizeof(ps_li
->li_system
))
3801 || (lacp_actor_partner_tlv_get_system_priority(actor
)
3802 != ps_li
->li_system_priority
)
3803 || (lacp_actor_partner_tlv_get_key(actor
) != ps_li
->li_key
)
3804 || (lacp_actor_partner_state_aggregatable(actor
->lap_state
)
3805 != lacp_actor_partner_state_aggregatable(ps
->ps_state
))) {
3806 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3807 if (g_bond
->verbose
) {
3808 timestamp_printf("[%s] updateSelected UNSELECTED\n",
3809 bondport_get_name(p
));
3816 bondport_RecordPDU(bondport_ref p
, lacpdu_ref lacpdu_p
)
3818 lacp_actor_partner_tlv_ref actor
;
3819 ifbond_ref bond
= p
->po_bond
;
3820 int lacp_maintain
= 0;
3821 partner_state_ref ps
;
3822 lacp_actor_partner_tlv_ref partner
;
3825 /* copy the PDU's Actor information into our Partner state */
3826 actor
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_actor_tlv
;
3827 ps
= &p
->po_partner_state
;
3828 ps_li
= &ps
->ps_lag_info
;
3829 ps
->ps_port
= lacp_actor_partner_tlv_get_port(actor
);
3830 ps
->ps_port_priority
= lacp_actor_partner_tlv_get_port_priority(actor
);
3831 ps_li
->li_system
= *((lacp_system_ref
)actor
->lap_system
);
3832 ps_li
->li_system_priority
3833 = lacp_actor_partner_tlv_get_system_priority(actor
);
3834 ps_li
->li_key
= lacp_actor_partner_tlv_get_key(actor
);
3835 ps
->ps_state
= lacp_actor_partner_state_set_out_of_sync(actor
->lap_state
);
3837 = lacp_actor_partner_state_set_not_defaulted(p
->po_actor_state
);
3839 /* compare the PDU's Partner information to our own information */
3840 partner
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_partner_tlv
;
3842 if (lacp_actor_partner_state_active_lacp(ps
->ps_state
)
3843 || (lacp_actor_partner_state_active_lacp(p
->po_actor_state
)
3844 && lacp_actor_partner_state_active_lacp(partner
->lap_state
))) {
3845 if (g_bond
->verbose
) {
3846 timestamp_printf("[%s] recordPDU: LACP will maintain\n",
3847 bondport_get_name(p
));
3851 if ((lacp_actor_partner_tlv_get_port(partner
)
3852 == bondport_get_index(p
))
3853 && lacp_actor_partner_tlv_get_port_priority(partner
) == p
->po_priority
3854 && bcmp(partner
->lap_system
, &g_bond
->system
,
3855 sizeof(g_bond
->system
)) == 0
3856 && (lacp_actor_partner_tlv_get_system_priority(partner
)
3857 == g_bond
->system_priority
)
3858 && lacp_actor_partner_tlv_get_key(partner
) == bond
->ifb_key
3859 && (lacp_actor_partner_state_aggregatable(partner
->lap_state
)
3860 == lacp_actor_partner_state_aggregatable(p
->po_actor_state
))
3861 && lacp_actor_partner_state_in_sync(actor
->lap_state
)
3863 ps
->ps_state
= lacp_actor_partner_state_set_in_sync(ps
->ps_state
);
3864 if (g_bond
->verbose
) {
3865 timestamp_printf("[%s] recordPDU: LACP partner in sync\n",
3866 bondport_get_name(p
));
3869 else if (lacp_actor_partner_state_aggregatable(actor
->lap_state
) == 0
3870 && lacp_actor_partner_state_in_sync(actor
->lap_state
)
3872 ps
->ps_state
= lacp_actor_partner_state_set_in_sync(ps
->ps_state
);
3873 if (g_bond
->verbose
) {
3874 timestamp_printf("[%s] recordPDU: LACP partner in sync (ind)\n",
3875 bondport_get_name(p
));
3878 bondport_assign_to_LAG(p
);
3882 static __inline__ lacp_actor_partner_state
3883 updateNTTBits(lacp_actor_partner_state s
)
3885 return (s
& (LACP_ACTOR_PARTNER_STATE_LACP_ACTIVITY
3886 | LACP_ACTOR_PARTNER_STATE_LACP_TIMEOUT
3887 | LACP_ACTOR_PARTNER_STATE_AGGREGATION
3888 | LACP_ACTOR_PARTNER_STATE_SYNCHRONIZATION
));
3892 bondport_UpdateNTT(bondport_ref p
, lacpdu_ref lacpdu_p
)
3894 ifbond_ref bond
= p
->po_bond
;
3895 lacp_actor_partner_tlv_ref partner
;
3897 /* compare the PDU's Actor information to our Partner state */
3898 partner
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_partner_tlv
;
3899 if ((lacp_actor_partner_tlv_get_port(partner
) != bondport_get_index(p
))
3900 || lacp_actor_partner_tlv_get_port_priority(partner
) != p
->po_priority
3901 || bcmp(partner
->lap_system
, &g_bond
->system
, sizeof(g_bond
->system
))
3902 || (lacp_actor_partner_tlv_get_system_priority(partner
)
3903 != g_bond
->system_priority
)
3904 || lacp_actor_partner_tlv_get_key(partner
) != bond
->ifb_key
3905 || (updateNTTBits(partner
->lap_state
)
3906 != updateNTTBits(p
->po_actor_state
))) {
3907 bondport_flags_set_ntt(p
);
3908 if (g_bond
->verbose
) {
3909 timestamp_printf("[%s] updateNTT: Need To Transmit\n",
3910 bondport_get_name(p
));
3917 bondport_AttachMuxToAggregator(bondport_ref p
)
3919 if (bondport_flags_mux_attached(p
) == 0) {
3920 if (g_bond
->verbose
) {
3921 timestamp_printf("[%s] Attached Mux To Aggregator\n",
3922 bondport_get_name(p
));
3924 bondport_flags_set_mux_attached(p
);
3930 bondport_DetachMuxFromAggregator(bondport_ref p
)
3932 if (bondport_flags_mux_attached(p
)) {
3933 if (g_bond
->verbose
) {
3934 timestamp_printf("[%s] Detached Mux From Aggregator\n",
3935 bondport_get_name(p
));
3937 bondport_flags_clear_mux_attached(p
);
3943 bondport_enable_distributing(bondport_ref p
)
3945 if (bondport_flags_distributing(p
) == 0) {
3946 ifbond_ref bond
= p
->po_bond
;
3948 bond
->ifb_distributing_array
[bond
->ifb_distributing_count
++] = p
;
3949 if (g_bond
->verbose
) {
3950 timestamp_printf("[%s] Distribution Enabled\n",
3951 bondport_get_name(p
));
3953 bondport_flags_set_distributing(p
);
3959 bondport_disable_distributing(bondport_ref p
)
3961 if (bondport_flags_distributing(p
)) {
3962 bondport_ref
* array
;
3968 array
= bond
->ifb_distributing_array
;
3969 count
= bond
->ifb_distributing_count
;
3970 for (i
= 0; i
< count
; i
++) {
3971 if (array
[i
] == p
) {
3974 for (j
= i
; j
< (count
- 1); j
++) {
3975 array
[j
] = array
[j
+ 1];
3980 bond
->ifb_distributing_count
--;
3981 if (g_bond
->verbose
) {
3982 timestamp_printf("[%s] Distribution Disabled\n",
3983 bondport_get_name(p
));
3985 bondport_flags_clear_distributing(p
);
3991 ** Receive machine functions
3994 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
3997 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
4000 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
4003 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
4006 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
4009 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
4013 bondport_receive_machine_event(bondport_ref p
, LAEvent event
,
4016 switch (p
->po_receive_state
) {
4017 case ReceiveState_none
:
4018 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
4020 case ReceiveState_INITIALIZE
:
4021 bondport_receive_machine_initialize(p
, event
, event_data
);
4023 case ReceiveState_PORT_DISABLED
:
4024 bondport_receive_machine_port_disabled(p
, event
, event_data
);
4026 case ReceiveState_EXPIRED
:
4027 bondport_receive_machine_expired(p
, event
, event_data
);
4029 case ReceiveState_LACP_DISABLED
:
4030 bondport_receive_machine_lacp_disabled(p
, event
, event_data
);
4032 case ReceiveState_DEFAULTED
:
4033 bondport_receive_machine_defaulted(p
, event
, event_data
);
4035 case ReceiveState_CURRENT
:
4036 bondport_receive_machine_current(p
, event
, event_data
);
4045 bondport_receive_machine(bondport_ref p
, LAEvent event
,
4050 if (p
->po_receive_state
!= ReceiveState_LACP_DISABLED
) {
4051 bondport_receive_machine_current(p
, event
, event_data
);
4054 case LAEventMediaChange
:
4055 if (media_active(&p
->po_media_info
)) {
4056 switch (p
->po_receive_state
) {
4057 case ReceiveState_PORT_DISABLED
:
4058 case ReceiveState_LACP_DISABLED
:
4059 bondport_receive_machine_port_disabled(p
, LAEventMediaChange
, NULL
);
4066 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
4070 bondport_receive_machine_event(p
, event
, event_data
);
4077 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
4078 __unused
void * event_data
)
4082 devtimer_cancel(p
->po_current_while_timer
);
4083 if (g_bond
->verbose
) {
4084 timestamp_printf("[%s] Receive INITIALIZE\n",
4085 bondport_get_name(p
));
4087 p
->po_receive_state
= ReceiveState_INITIALIZE
;
4088 bondport_set_selected(p
, SelectedState_UNSELECTED
);
4089 bondport_RecordDefault(p
);
4091 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4092 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
4101 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
4102 __unused
void * event_data
)
4104 partner_state_ref ps
;
4108 devtimer_cancel(p
->po_current_while_timer
);
4109 if (g_bond
->verbose
) {
4110 timestamp_printf("[%s] Receive PORT_DISABLED\n",
4111 bondport_get_name(p
));
4113 p
->po_receive_state
= ReceiveState_PORT_DISABLED
;
4114 ps
= &p
->po_partner_state
;
4115 ps
->ps_state
= lacp_actor_partner_state_set_out_of_sync(ps
->ps_state
);
4117 case LAEventMediaChange
:
4118 if (media_active(&p
->po_media_info
)) {
4119 if (media_full_duplex(&p
->po_media_info
)) {
4120 bondport_receive_machine_expired(p
, LAEventStart
, NULL
);
4123 bondport_receive_machine_lacp_disabled(p
, LAEventStart
, NULL
);
4126 else if (p
->po_selected
== SelectedState_SELECTED
) {
4129 if (g_bond
->verbose
) {
4130 timestamp_printf("[%s] Receive PORT_DISABLED: "
4131 "link timer started\n",
4132 bondport_get_name(p
));
4136 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4137 (devtimer_timeout_func
)
4138 bondport_receive_machine_port_disabled
,
4139 (void *)LAEventTimeout
, NULL
);
4141 else if (p
->po_selected
== SelectedState_STANDBY
) {
4142 bondport_set_selected(p
, SelectedState_UNSELECTED
);
4145 case LAEventTimeout
:
4146 if (p
->po_selected
== SelectedState_SELECTED
) {
4147 if (g_bond
->verbose
) {
4148 timestamp_printf("[%s] Receive PORT_DISABLED: "
4149 "link timer completed, marking UNSELECTED\n",
4150 bondport_get_name(p
));
4152 bondport_set_selected(p
, SelectedState_UNSELECTED
);
4155 case LAEventPortMoved
:
4156 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
4165 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
4166 __unused
void * event_data
)
4168 lacp_actor_partner_state s
;
4173 devtimer_cancel(p
->po_current_while_timer
);
4174 if (g_bond
->verbose
) {
4175 timestamp_printf("[%s] Receive EXPIRED\n",
4176 bondport_get_name(p
));
4178 p
->po_receive_state
= ReceiveState_EXPIRED
;
4179 s
= p
->po_partner_state
.ps_state
;
4180 s
= lacp_actor_partner_state_set_out_of_sync(s
);
4181 s
= lacp_actor_partner_state_set_short_timeout(s
);
4182 p
->po_partner_state
.ps_state
= s
;
4184 = lacp_actor_partner_state_set_expired(p
->po_actor_state
);
4185 /* start current_while timer */
4186 tv
.tv_sec
= LACP_SHORT_TIMEOUT_TIME
;
4188 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4189 (devtimer_timeout_func
)
4190 bondport_receive_machine_expired
,
4191 (void *)LAEventTimeout
, NULL
);
4194 case LAEventTimeout
:
4195 bondport_receive_machine_defaulted(p
, LAEventStart
, NULL
);
4204 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
4205 __unused
void * event_data
)
4207 partner_state_ref ps
;
4210 devtimer_cancel(p
->po_current_while_timer
);
4211 if (g_bond
->verbose
) {
4212 timestamp_printf("[%s] Receive LACP_DISABLED\n",
4213 bondport_get_name(p
));
4215 p
->po_receive_state
= ReceiveState_LACP_DISABLED
;
4216 bondport_set_selected(p
, SelectedState_UNSELECTED
);
4217 bondport_RecordDefault(p
);
4218 ps
= &p
->po_partner_state
;
4219 ps
->ps_state
= lacp_actor_partner_state_set_individual(ps
->ps_state
);
4221 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4230 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
4231 __unused
void * event_data
)
4235 devtimer_cancel(p
->po_current_while_timer
);
4236 if (g_bond
->verbose
) {
4237 timestamp_printf("[%s] Receive DEFAULTED\n",
4238 bondport_get_name(p
));
4240 p
->po_receive_state
= ReceiveState_DEFAULTED
;
4241 bondport_UpdateDefaultSelected(p
);
4242 bondport_RecordDefault(p
);
4244 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4253 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
4256 partner_state_ref ps
;
4261 devtimer_cancel(p
->po_current_while_timer
);
4262 if (g_bond
->verbose
) {
4263 timestamp_printf("[%s] Receive CURRENT\n",
4264 bondport_get_name(p
));
4266 p
->po_receive_state
= ReceiveState_CURRENT
;
4267 bondport_UpdateSelected(p
, event_data
);
4268 bondport_UpdateNTT(p
, event_data
);
4269 bondport_RecordPDU(p
, event_data
);
4271 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4272 bondport_assign_to_LAG(p
);
4273 /* start current_while timer */
4274 ps
= &p
->po_partner_state
;
4275 if (lacp_actor_partner_state_short_timeout(ps
->ps_state
)) {
4276 tv
.tv_sec
= LACP_SHORT_TIMEOUT_TIME
;
4279 tv
.tv_sec
= LACP_LONG_TIMEOUT_TIME
;
4282 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4283 (devtimer_timeout_func
)
4284 bondport_receive_machine_current
,
4285 (void *)LAEventTimeout
, NULL
);
4287 case LAEventTimeout
:
4288 bondport_receive_machine_expired(p
, LAEventStart
, NULL
);
4297 ** Periodic Transmission machine
4301 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
4302 __unused
void * event_data
)
4305 partner_state_ref ps
;
4310 if (g_bond
->verbose
) {
4311 timestamp_printf("[%s] periodic_transmit Start\n",
4312 bondport_get_name(p
));
4315 case LAEventMediaChange
:
4316 devtimer_cancel(p
->po_periodic_timer
);
4317 p
->po_periodic_interval
= 0;
4318 if (media_active(&p
->po_media_info
) == 0
4319 || media_full_duplex(&p
->po_media_info
) == 0) {
4323 /* Neither Partner nor Actor are LACP Active, no periodic tx */
4324 ps
= &p
->po_partner_state
;
4325 if (lacp_actor_partner_state_active_lacp(p
->po_actor_state
) == 0
4326 && (lacp_actor_partner_state_active_lacp(ps
->ps_state
)
4328 devtimer_cancel(p
->po_periodic_timer
);
4329 p
->po_periodic_interval
= 0;
4332 if (lacp_actor_partner_state_short_timeout(ps
->ps_state
)) {
4333 interval
= LACP_FAST_PERIODIC_TIME
;
4336 interval
= LACP_SLOW_PERIODIC_TIME
;
4338 if (p
->po_periodic_interval
!= interval
) {
4339 if (interval
== LACP_FAST_PERIODIC_TIME
4340 && p
->po_periodic_interval
== LACP_SLOW_PERIODIC_TIME
) {
4341 if (g_bond
->verbose
) {
4342 timestamp_printf("[%s] periodic_transmit:"
4343 " Need To Transmit\n",
4344 bondport_get_name(p
));
4346 bondport_flags_set_ntt(p
);
4348 p
->po_periodic_interval
= interval
;
4350 tv
.tv_sec
= interval
;
4351 devtimer_set_relative(p
->po_periodic_timer
, tv
,
4352 (devtimer_timeout_func
)
4353 bondport_periodic_transmit_machine
,
4354 (void *)LAEventTimeout
, NULL
);
4355 if (g_bond
->verbose
) {
4356 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4357 bondport_get_name(p
),
4358 p
->po_periodic_interval
);
4362 case LAEventTimeout
:
4363 bondport_flags_set_ntt(p
);
4364 tv
.tv_sec
= p
->po_periodic_interval
;
4366 devtimer_set_relative(p
->po_periodic_timer
, tv
, (devtimer_timeout_func
)
4367 bondport_periodic_transmit_machine
,
4368 (void *)LAEventTimeout
, NULL
);
4369 if (g_bond
->verbose
> 1) {
4370 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4371 bondport_get_name(p
), p
->po_periodic_interval
);
4384 bondport_can_transmit(bondport_ref p
, int32_t current_secs
,
4387 if (p
->po_last_transmit_secs
!= current_secs
) {
4388 p
->po_last_transmit_secs
= current_secs
;
4389 p
->po_n_transmit
= 0;
4391 if (p
->po_n_transmit
< LACP_PACKET_RATE
) {
4395 if (next_secs
!= NULL
) {
4396 *next_secs
= current_secs
+ 1;
4402 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
4405 lacp_actor_partner_tlv_ref aptlv
;
4406 lacp_collector_tlv_ref ctlv
;
4407 struct timeval next_tick_time
= {0, 0};
4408 lacpdu_ref out_lacpdu_p
;
4409 packet_buffer_ref pkt
;
4410 partner_state_ref ps
;
4414 case LAEventTimeout
:
4416 if (p
->po_periodic_interval
== 0 || bondport_flags_ntt(p
) == 0) {
4419 if (event_data
== TRANSMIT_MACHINE_TX_IMMEDIATE
) {
4420 /* we're going away, transmit the packet no matter what */
4422 else if (bondport_can_transmit(p
, devtimer_current_secs(),
4423 &next_tick_time
.tv_sec
) == 0) {
4424 if (devtimer_enabled(p
->po_transmit_timer
)) {
4425 if (g_bond
->verbose
> 0) {
4426 timestamp_printf("[%s] Transmit Timer Already Set\n",
4427 bondport_get_name(p
));
4431 devtimer_set_absolute(p
->po_transmit_timer
, next_tick_time
,
4432 (devtimer_timeout_func
)
4433 bondport_transmit_machine
,
4434 (void *)LAEventTimeout
, NULL
);
4435 if (g_bond
->verbose
> 0) {
4436 timestamp_printf("[%s] Transmit Timer Deadline %d secs\n",
4437 bondport_get_name(p
),
4438 (int)next_tick_time
.tv_sec
);
4443 if (g_bond
->verbose
> 0) {
4444 if (event
== LAEventTimeout
) {
4445 timestamp_printf("[%s] Transmit Timer Complete\n",
4446 bondport_get_name(p
));
4449 pkt
= packet_buffer_allocate(sizeof(*out_lacpdu_p
));
4451 printf("[%s] Transmit: failed to allocate packet buffer\n",
4452 bondport_get_name(p
));
4455 out_lacpdu_p
= (lacpdu_ref
)packet_buffer_byteptr(pkt
);
4456 bzero(out_lacpdu_p
, sizeof(*out_lacpdu_p
));
4457 out_lacpdu_p
->la_subtype
= IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP
;
4458 out_lacpdu_p
->la_version
= LACPDU_VERSION_1
;
4461 aptlv
= (lacp_actor_partner_tlv_ref
)out_lacpdu_p
->la_actor_tlv
;
4462 aptlv
->lap_tlv_type
= LACPDU_TLV_TYPE_ACTOR
;
4463 aptlv
->lap_length
= LACPDU_ACTOR_TLV_LENGTH
;
4464 *((lacp_system_ref
)aptlv
->lap_system
) = g_bond
->system
;
4465 lacp_actor_partner_tlv_set_system_priority(aptlv
,
4466 g_bond
->system_priority
);
4467 lacp_actor_partner_tlv_set_port_priority(aptlv
, p
->po_priority
);
4468 lacp_actor_partner_tlv_set_port(aptlv
, bondport_get_index(p
));
4469 lacp_actor_partner_tlv_set_key(aptlv
, p
->po_bond
->ifb_key
);
4470 aptlv
->lap_state
= p
->po_actor_state
;
4473 aptlv
= (lacp_actor_partner_tlv_ref
)out_lacpdu_p
->la_partner_tlv
;
4474 aptlv
->lap_tlv_type
= LACPDU_TLV_TYPE_PARTNER
;
4475 aptlv
->lap_length
= LACPDU_PARTNER_TLV_LENGTH
;
4476 ps
= &p
->po_partner_state
;
4477 ps_li
= &ps
->ps_lag_info
;
4478 lacp_actor_partner_tlv_set_port(aptlv
, ps
->ps_port
);
4479 lacp_actor_partner_tlv_set_port_priority(aptlv
, ps
->ps_port_priority
);
4480 *((lacp_system_ref
)aptlv
->lap_system
) = ps_li
->li_system
;
4481 lacp_actor_partner_tlv_set_system_priority(aptlv
,
4482 ps_li
->li_system_priority
);
4483 lacp_actor_partner_tlv_set_key(aptlv
, ps_li
->li_key
);
4484 aptlv
->lap_state
= ps
->ps_state
;
4487 ctlv
= (lacp_collector_tlv_ref
)out_lacpdu_p
->la_collector_tlv
;
4488 ctlv
->lac_tlv_type
= LACPDU_TLV_TYPE_COLLECTOR
;
4489 ctlv
->lac_length
= LACPDU_COLLECTOR_TLV_LENGTH
;
4491 bondport_slow_proto_transmit(p
, pkt
);
4492 bondport_flags_clear_ntt(p
);
4493 if (g_bond
->verbose
> 0) {
4494 timestamp_printf("[%s] Transmit Packet %d\n",
4495 bondport_get_name(p
), p
->po_n_transmit
);
4505 ** Mux machine functions
4509 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4512 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4515 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4519 bondport_mux_machine_collecting_distributing(bondport_ref p
, LAEvent event
,
4523 bondport_mux_machine(bondport_ref p
, LAEvent event
, void * event_data
)
4525 switch (p
->po_mux_state
) {
4527 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4529 case MuxState_DETACHED
:
4530 bondport_mux_machine_detached(p
, event
, event_data
);
4532 case MuxState_WAITING
:
4533 bondport_mux_machine_waiting(p
, event
, event_data
);
4535 case MuxState_ATTACHED
:
4536 bondport_mux_machine_attached(p
, event
, event_data
);
4538 case MuxState_COLLECTING_DISTRIBUTING
:
4539 bondport_mux_machine_collecting_distributing(p
, event
, event_data
);
4548 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4549 __unused
void * event_data
)
4551 lacp_actor_partner_state s
;
4555 devtimer_cancel(p
->po_wait_while_timer
);
4556 if (g_bond
->verbose
) {
4557 timestamp_printf("[%s] Mux DETACHED\n",
4558 bondport_get_name(p
));
4560 p
->po_mux_state
= MuxState_DETACHED
;
4561 bondport_flags_clear_ready(p
);
4562 bondport_DetachMuxFromAggregator(p
);
4563 bondport_disable_distributing(p
);
4564 s
= p
->po_actor_state
;
4565 s
= lacp_actor_partner_state_set_out_of_sync(s
);
4566 s
= lacp_actor_partner_state_set_not_collecting(s
);
4567 s
= lacp_actor_partner_state_set_not_distributing(s
);
4568 p
->po_actor_state
= s
;
4569 bondport_flags_set_ntt(p
);
4571 case LAEventSelectedChange
:
4573 case LAEventMediaChange
:
4574 if (p
->po_selected
== SelectedState_SELECTED
4575 || p
->po_selected
== SelectedState_STANDBY
) {
4576 bondport_mux_machine_waiting(p
, LAEventStart
, NULL
);
4586 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4587 __unused
void * event_data
)
4593 devtimer_cancel(p
->po_wait_while_timer
);
4594 if (g_bond
->verbose
) {
4595 timestamp_printf("[%s] Mux WAITING\n",
4596 bondport_get_name(p
));
4598 p
->po_mux_state
= MuxState_WAITING
;
4601 case LAEventSelectedChange
:
4602 if (p
->po_selected
== SelectedState_UNSELECTED
) {
4603 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4606 if (p
->po_selected
== SelectedState_STANDBY
) {
4607 devtimer_cancel(p
->po_wait_while_timer
);
4608 /* wait until state changes to SELECTED */
4609 if (g_bond
->verbose
) {
4610 timestamp_printf("[%s] Mux WAITING: Standby\n",
4611 bondport_get_name(p
));
4615 if (bondport_flags_ready(p
)) {
4616 if (g_bond
->verbose
) {
4617 timestamp_printf("[%s] Mux WAITING: Port is already ready\n",
4618 bondport_get_name(p
));
4622 if (devtimer_enabled(p
->po_wait_while_timer
)) {
4623 if (g_bond
->verbose
) {
4624 timestamp_printf("[%s] Mux WAITING: Timer already set\n",
4625 bondport_get_name(p
));
4629 if (ifbond_all_ports_attached(p
->po_bond
, p
)) {
4630 devtimer_cancel(p
->po_wait_while_timer
);
4631 if (g_bond
->verbose
) {
4632 timestamp_printf("[%s] Mux WAITING: No waiting\n",
4633 bondport_get_name(p
));
4635 bondport_flags_set_ready(p
);
4638 if (g_bond
->verbose
) {
4639 timestamp_printf("[%s] Mux WAITING: 2 seconds\n",
4640 bondport_get_name(p
));
4642 tv
.tv_sec
= LACP_AGGREGATE_WAIT_TIME
;
4644 devtimer_set_relative(p
->po_wait_while_timer
, tv
,
4645 (devtimer_timeout_func
)
4646 bondport_mux_machine_waiting
,
4647 (void *)LAEventTimeout
, NULL
);
4649 case LAEventTimeout
:
4650 if (g_bond
->verbose
) {
4651 timestamp_printf("[%s] Mux WAITING: Ready\n",
4652 bondport_get_name(p
));
4654 bondport_flags_set_ready(p
);
4658 if (bondport_flags_ready(p
)){
4659 if (g_bond
->verbose
) {
4660 timestamp_printf("[%s] Mux WAITING: All Ports Ready\n",
4661 bondport_get_name(p
));
4663 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);
4672 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4673 __unused
void * event_data
)
4675 lacp_actor_partner_state s
;
4679 devtimer_cancel(p
->po_wait_while_timer
);
4680 if (g_bond
->verbose
) {
4681 timestamp_printf("[%s] Mux ATTACHED\n",
4682 bondport_get_name(p
));
4684 p
->po_mux_state
= MuxState_ATTACHED
;
4685 bondport_AttachMuxToAggregator(p
);
4686 s
= p
->po_actor_state
;
4687 s
= lacp_actor_partner_state_set_in_sync(s
);
4688 s
= lacp_actor_partner_state_set_not_collecting(s
);
4689 s
= lacp_actor_partner_state_set_not_distributing(s
);
4690 bondport_disable_distributing(p
);
4691 p
->po_actor_state
= s
;
4692 bondport_flags_set_ntt(p
);
4695 switch (p
->po_selected
) {
4696 case SelectedState_SELECTED
:
4697 s
= p
->po_partner_state
.ps_state
;
4698 if (lacp_actor_partner_state_in_sync(s
)) {
4699 bondport_mux_machine_collecting_distributing(p
, LAEventStart
,
4704 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4713 bondport_mux_machine_collecting_distributing(bondport_ref p
,
4715 __unused
void * event_data
)
4717 lacp_actor_partner_state s
;
4721 devtimer_cancel(p
->po_wait_while_timer
);
4722 if (g_bond
->verbose
) {
4723 timestamp_printf("[%s] Mux COLLECTING_DISTRIBUTING\n",
4724 bondport_get_name(p
));
4726 p
->po_mux_state
= MuxState_COLLECTING_DISTRIBUTING
;
4727 bondport_enable_distributing(p
);
4728 s
= p
->po_actor_state
;
4729 s
= lacp_actor_partner_state_set_collecting(s
);
4730 s
= lacp_actor_partner_state_set_distributing(s
);
4731 p
->po_actor_state
= s
;
4732 bondport_flags_set_ntt(p
);
4735 s
= p
->po_partner_state
.ps_state
;
4736 if (lacp_actor_partner_state_in_sync(s
) == 0) {
4737 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);
4740 switch (p
->po_selected
) {
4741 case SelectedState_UNSELECTED
:
4742 case SelectedState_STANDBY
:
4743 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);