2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
25 * - bond/failover interface
26 * - implements IEEE 802.3ad Link Aggregation
30 * Modification History:
32 * April 29, 2004 Dieter Siegmund (dieter@apple.com)
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
40 #include <sys/queue.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <sys/sysctl.h>
44 #include <sys/systm.h>
45 #include <sys/kern_event.h>
48 #include <net/ethernet.h>
50 #include <net/kpi_interface.h>
51 #include <net/if_arp.h>
52 #include <net/if_dl.h>
53 #include <net/if_ether.h>
54 #include <net/if_types.h>
55 #include <net/if_bond_var.h>
56 #include <net/ieee8023ad.h>
60 #include <net/devtimer.h>
61 #include <net/if_vlan_var.h>
63 #include <kern/locks.h>
64 #include <libkern/OSAtomic.h>
66 #include <netinet/in.h>
67 #include <netinet/if_ether.h>
68 #include <netinet/in_systm.h>
69 #include <netinet/ip.h>
70 #include <netinet/ip6.h>
72 #include <net/if_media.h>
73 #include <net/multicast_list.h>
75 extern int dlil_input_packet(struct ifnet
*, struct mbuf
*, char *);
77 static struct ether_addr slow_proto_multicast
= {
78 IEEE8023AD_SLOW_PROTO_MULTICAST
81 #define BOND_MAXUNIT 128
82 #define BONDNAME "bond"
83 #define M_BOND M_DEVBUF
85 #define EA_FORMAT "%x:%x:%x:%x:%x:%x"
86 #define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)])
87 #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)
89 #define timestamp_printf printf
94 static __inline__ lck_grp_t
*
95 my_lck_grp_alloc_init(const char * grp_name
)
98 lck_grp_attr_t
* grp_attrs
;
100 grp_attrs
= lck_grp_attr_alloc_init();
101 grp
= lck_grp_alloc_init(grp_name
, grp_attrs
);
102 lck_grp_attr_free(grp_attrs
);
106 static __inline__ lck_mtx_t
*
107 my_lck_mtx_alloc_init(lck_grp_t
* lck_grp
)
109 lck_attr_t
* lck_attrs
;
112 lck_attrs
= lck_attr_alloc_init();
113 lck_mtx
= lck_mtx_alloc_init(lck_grp
, lck_attrs
);
114 lck_attr_free(lck_attrs
);
118 static lck_mtx_t
* bond_lck_mtx
;
120 static __inline__
void
123 lck_grp_t
* bond_lck_grp
;
125 bond_lck_grp
= my_lck_grp_alloc_init("if_bond");
126 bond_lck_mtx
= my_lck_mtx_alloc_init(bond_lck_grp
);
129 static __inline__
void
130 bond_assert_lock_held(void)
132 lck_mtx_assert(bond_lck_mtx
, LCK_MTX_ASSERT_OWNED
);
136 static __inline__
void
137 bond_assert_lock_not_held(void)
139 lck_mtx_assert(bond_lck_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
143 static __inline__
void
146 lck_mtx_lock(bond_lck_mtx
);
150 static __inline__
void
153 lck_mtx_unlock(bond_lck_mtx
);
158 ** bond structures, types
162 lacp_system li_system
;
163 lacp_system_priority li_system_priority
;
166 typedef struct LAG_info_s LAG_info
, * LAG_info_ref
;
169 TAILQ_HEAD(port_list
, bondport_s
);
171 TAILQ_HEAD(ifbond_list
, ifbond_s
);
173 TAILQ_HEAD(lag_list
, LAG_s
);
175 typedef struct ifbond_s ifbond
, * ifbond_ref
;
176 typedef struct bondport_s bondport
, * bondport_ref
;
179 TAILQ_ENTRY(LAG_s
) lag_list
;
180 struct port_list lag_port_list
;
181 short lag_port_count
;
182 short lag_selected_port_count
;
183 int lag_active_media
;
186 typedef struct LAG_s LAG
, * LAG_ref
;
188 typedef struct partner_state_s
{
189 LAG_info ps_lag_info
;
191 lacp_port_priority ps_port_priority
;
192 lacp_actor_partner_state ps_state
;
193 } partner_state
, * partner_state_ref
;
196 TAILQ_ENTRY(ifbond_s
) ifb_bond_list
;
198 UInt32 ifb_retain_count
;
199 char ifb_name
[IFNAMSIZ
];
200 struct ifnet
* ifb_ifp
;
201 bpf_packet_func ifb_bpf_input
;
202 bpf_packet_func ifb_bpf_output
;
204 struct port_list ifb_port_list
;
205 short ifb_port_count
;
206 struct lag_list ifb_lag_list
;
208 short ifb_max_active
; /* 0 == unlimited */
209 LAG_ref ifb_active_lag
;
210 struct ifmultiaddr
* ifb_ifma_slow_proto
;
211 bondport_ref
* ifb_distributing_array
;
212 int ifb_distributing_count
;
221 ReceiveState_none
= 0,
222 ReceiveState_INITIALIZE
= 1,
223 ReceiveState_PORT_DISABLED
= 2,
224 ReceiveState_EXPIRED
= 3,
225 ReceiveState_LACP_DISABLED
= 4,
226 ReceiveState_DEFAULTED
= 5,
227 ReceiveState_CURRENT
= 6,
230 typedef u_char ReceiveState
;
233 SelectedState_UNSELECTED
= IF_BOND_STATUS_SELECTED_STATE_UNSELECTED
,
234 SelectedState_SELECTED
= IF_BOND_STATUS_SELECTED_STATE_SELECTED
,
235 SelectedState_STANDBY
= IF_BOND_STATUS_SELECTED_STATE_STANDBY
237 typedef u_char SelectedState
;
239 static __inline__
const char *
240 SelectedStateString(SelectedState s
)
242 static const char * names
[] = { "UNSELECTED", "SELECTED", "STANDBY" };
244 if (s
<= SelectedState_STANDBY
) {
247 return ("<unknown>");
252 MuxState_DETACHED
= 1,
253 MuxState_WAITING
= 2,
254 MuxState_ATTACHED
= 3,
255 MuxState_COLLECTING_DISTRIBUTING
= 4,
258 typedef u_char MuxState
;
261 TAILQ_ENTRY(bondport_s
) po_port_list
;
263 struct multicast_list po_multicast
;
264 struct ifnet
* po_ifp
;
265 struct ether_addr po_saved_addr
;
267 char po_name
[IFNAMSIZ
];
268 struct ifdevmtu po_devmtu
;
271 TAILQ_ENTRY(bondport_s
) po_lag_port_list
;
272 devtimer_ref po_current_while_timer
;
273 devtimer_ref po_periodic_timer
;
274 devtimer_ref po_wait_while_timer
;
275 devtimer_ref po_transmit_timer
;
276 partner_state po_partner_state
;
277 lacp_port_priority po_priority
;
278 lacp_actor_partner_state po_actor_state
;
280 u_char po_periodic_interval
;
281 u_char po_n_transmit
;
282 ReceiveState po_receive_state
;
283 MuxState po_mux_state
;
284 SelectedState po_selected
;
285 int32_t po_last_transmit_secs
;
286 struct media_info po_media_info
;
290 #define IFBF_PROMISC 0x1 /* promiscuous mode */
291 #define IFBF_IF_DETACHING 0x2 /* interface is detaching */
292 #define IFBF_LLADDR 0x4 /* specific link address requested */
293 #define IFBF_CHANGE_IN_PROGRESS 0x8 /* interface add/remove in progress */
295 static int bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
,
298 static __inline__
int
299 ifbond_flags_promisc(ifbond_ref ifb
)
301 return ((ifb
->ifb_flags
& IFBF_PROMISC
) != 0);
304 static __inline__
void
305 ifbond_flags_set_promisc(ifbond_ref ifb
)
307 ifb
->ifb_flags
|= IFBF_PROMISC
;
311 static __inline__
void
312 ifbond_flags_clear_promisc(ifbond_ref ifb
)
314 ifb
->ifb_flags
&= ~IFBF_PROMISC
;
318 static __inline__
int
319 ifbond_flags_if_detaching(ifbond_ref ifb
)
321 return ((ifb
->ifb_flags
& IFBF_IF_DETACHING
) != 0);
324 static __inline__
void
325 ifbond_flags_set_if_detaching(ifbond_ref ifb
)
327 ifb
->ifb_flags
|= IFBF_IF_DETACHING
;
331 static __inline__
int
332 ifbond_flags_lladdr(ifbond_ref ifb
)
334 return ((ifb
->ifb_flags
& IFBF_LLADDR
) != 0);
337 static __inline__
void
338 ifbond_flags_set_lladdr(ifbond_ref ifb
)
340 ifb
->ifb_flags
|= IFBF_LLADDR
;
344 static __inline__
void
345 ifbond_flags_clear_lladdr(ifbond_ref ifb
)
347 ifb
->ifb_flags
&= ~IFBF_LLADDR
;
351 static __inline__
int
352 ifbond_flags_change_in_progress(ifbond_ref ifb
)
354 return ((ifb
->ifb_flags
& IFBF_CHANGE_IN_PROGRESS
) != 0);
357 static __inline__
void
358 ifbond_flags_set_change_in_progress(ifbond_ref ifb
)
360 ifb
->ifb_flags
|= IFBF_CHANGE_IN_PROGRESS
;
364 static __inline__
void
365 ifbond_flags_clear_change_in_progress(ifbond_ref ifb
)
367 ifb
->ifb_flags
&= ~IFBF_CHANGE_IN_PROGRESS
;
372 * bondport_ref->po_flags bits
374 #define BONDPORT_FLAGS_NTT 0x01
375 #define BONDPORT_FLAGS_READY 0x02
376 #define BONDPORT_FLAGS_SELECTED_CHANGED 0x04
377 #define BONDPORT_FLAGS_MUX_ATTACHED 0x08
378 #define BONDPORT_FLAGS_DISTRIBUTING 0x10
379 #define BONDPORT_FLAGS_UNUSED2 0x20
380 #define BONDPORT_FLAGS_UNUSED3 0x40
381 #define BONDPORT_FLAGS_UNUSED4 0x80
383 static __inline__
void
384 bondport_flags_set_ntt(bondport_ref p
)
386 p
->po_flags
|= BONDPORT_FLAGS_NTT
;
390 static __inline__
void
391 bondport_flags_clear_ntt(bondport_ref p
)
393 p
->po_flags
&= ~BONDPORT_FLAGS_NTT
;
397 static __inline__
int
398 bondport_flags_ntt(bondport_ref p
)
400 return ((p
->po_flags
& BONDPORT_FLAGS_NTT
) != 0);
403 static __inline__
void
404 bondport_flags_set_ready(bondport_ref p
)
406 p
->po_flags
|= BONDPORT_FLAGS_READY
;
410 static __inline__
void
411 bondport_flags_clear_ready(bondport_ref p
)
413 p
->po_flags
&= ~BONDPORT_FLAGS_READY
;
417 static __inline__
int
418 bondport_flags_ready(bondport_ref p
)
420 return ((p
->po_flags
& BONDPORT_FLAGS_READY
) != 0);
423 static __inline__
void
424 bondport_flags_set_selected_changed(bondport_ref p
)
426 p
->po_flags
|= BONDPORT_FLAGS_SELECTED_CHANGED
;
430 static __inline__
void
431 bondport_flags_clear_selected_changed(bondport_ref p
)
433 p
->po_flags
&= ~BONDPORT_FLAGS_SELECTED_CHANGED
;
437 static __inline__
int
438 bondport_flags_selected_changed(bondport_ref p
)
440 return ((p
->po_flags
& BONDPORT_FLAGS_SELECTED_CHANGED
) != 0);
443 static __inline__
void
444 bondport_flags_set_mux_attached(bondport_ref p
)
446 p
->po_flags
|= BONDPORT_FLAGS_MUX_ATTACHED
;
450 static __inline__
void
451 bondport_flags_clear_mux_attached(bondport_ref p
)
453 p
->po_flags
&= ~BONDPORT_FLAGS_MUX_ATTACHED
;
457 static __inline__
int
458 bondport_flags_mux_attached(bondport_ref p
)
460 return ((p
->po_flags
& BONDPORT_FLAGS_MUX_ATTACHED
) != 0);
463 static __inline__
void
464 bondport_flags_set_distributing(bondport_ref p
)
466 p
->po_flags
|= BONDPORT_FLAGS_DISTRIBUTING
;
470 static __inline__
void
471 bondport_flags_clear_distributing(bondport_ref p
)
473 p
->po_flags
&= ~BONDPORT_FLAGS_DISTRIBUTING
;
477 static __inline__
int
478 bondport_flags_distributing(bondport_ref p
)
480 return ((p
->po_flags
& BONDPORT_FLAGS_DISTRIBUTING
) != 0);
483 typedef struct bond_globals_s
{
484 struct ifbond_list ifbond_list
;
486 lacp_system_priority system_priority
;
488 } * bond_globals_ref
;
490 static bond_globals_ref g_bond
;
493 ** packet_buffer routines
494 ** - thin wrapper for mbuf
497 typedef struct mbuf
* packet_buffer_ref
;
499 static packet_buffer_ref
500 packet_buffer_allocate(int length
)
505 /* leave room for ethernet header */
506 size
= length
+ sizeof(struct ether_header
);
507 if (size
> (int)MHLEN
) {
508 /* XXX doesn't handle large payloads */
509 printf("bond: packet_buffer_allocate size %d > max %d\n", size
, MHLEN
);
512 m
= m_gethdr(M_WAITOK
, MT_DATA
);
517 m
->m_pkthdr
.len
= size
;
522 packet_buffer_byteptr(packet_buffer_ref buf
)
524 return (buf
->m_data
+ sizeof(struct ether_header
));
532 LAEventSelectedChange
,
541 bondport_receive_machine(bondport_ref p
, LAEvent event
,
544 ** Periodic Transmission machine
547 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
554 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
561 bondport_mux_machine(bondport_ref p
, LAEvent event
,
568 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
);
571 ifbond_deactivate_LAG(ifbond_ref bond
, LAG_ref lag
);
574 ifbond_all_ports_ready(ifbond_ref bond
);
577 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
);
580 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
);
583 ifbond_selection(ifbond_ref bond
);
591 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
);
594 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
);
597 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
598 int active
, int short_timeout
, int * error
);
600 bondport_start(bondport_ref p
);
603 bondport_free(bondport_ref p
);
606 bondport_aggregatable(bondport_ref p
);
609 bondport_remove_from_LAG(bondport_ref p
);
612 bondport_set_selected(bondport_ref p
, SelectedState s
);
615 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
);
618 bondport_link_status_changed(bondport_ref p
);
621 bondport_enable_distributing(bondport_ref p
);
624 bondport_disable_distributing(bondport_ref p
);
626 static __inline__
int
627 bondport_collecting(bondport_ref p
)
629 return (lacp_actor_partner_state_collecting(p
->po_actor_state
));
633 ** bond interface/dlil specific routines
635 static int bond_clone_create(struct if_clone
*, int);
636 static void bond_clone_destroy(struct ifnet
*);
637 static int bond_input(struct mbuf
*m
, char *frame_header
, struct ifnet
*ifp
,
638 u_long protocol_family
, int sync_ok
);
639 static int bond_output(struct ifnet
*ifp
, struct mbuf
*m
);
640 static int bond_ioctl(struct ifnet
*ifp
, u_int32_t cmd
, void * addr
);
641 static int bond_set_bpf_tap(struct ifnet
* ifp
, bpf_tap_mode mode
,
642 bpf_packet_func func
);
643 static int bond_attach_protocol(struct ifnet
*ifp
);
644 static int bond_detach_protocol(struct ifnet
*ifp
);
645 static int bond_setmulti(struct ifnet
*ifp
);
646 static int bond_add_interface(struct ifnet
* ifp
, struct ifnet
* port_ifp
);
647 static int bond_remove_interface(ifbond_ref ifb
, struct ifnet
* port_ifp
);
648 static void bond_if_free(struct ifnet
* ifp
);
650 static struct if_clone bond_cloner
= IF_CLONE_INITIALIZER(BONDNAME
,
655 static void interface_link_event(struct ifnet
* ifp
, u_long event_code
);
658 siocsifmtu(struct ifnet
* ifp
, int mtu
)
662 bzero(&ifr
, sizeof(ifr
));
664 return (dlil_ioctl(0, ifp
, SIOCSIFMTU
, (caddr_t
)&ifr
));
668 siocgifdevmtu(struct ifnet
* ifp
, struct ifdevmtu
* ifdm_p
)
673 bzero(&ifr
, sizeof(ifr
));
674 error
= dlil_ioctl(0, ifp
, SIOCGIFDEVMTU
, (caddr_t
)&ifr
);
676 *ifdm_p
= ifr
.ifr_devmtu
;
681 static __inline__
void
682 ether_addr_copy(void * dest
, const void * source
)
684 bcopy(source
, dest
, ETHER_ADDR_LEN
);
688 static __inline__
void
689 ifbond_retain(ifbond_ref ifb
)
691 OSIncrementAtomic(&ifb
->ifb_retain_count
);
694 static __inline__
void
695 ifbond_release(ifbond_ref ifb
)
697 UInt32 old_retain_count
;
699 old_retain_count
= OSDecrementAtomic(&ifb
->ifb_retain_count
);
700 switch (old_retain_count
) {
702 panic("ifbond_release: retain count is 0\n");
705 if (g_bond
->verbose
) {
706 printf("ifbond_release(%s)\n", ifb
->ifb_name
);
708 if (ifb
->ifb_ifma_slow_proto
!= NULL
) {
709 if (g_bond
->verbose
) {
710 printf("ifbond_release(%s) removing multicast\n",
713 (void)if_delmultiaddr(ifb
->ifb_ifma_slow_proto
, 0);
714 ifma_release(ifb
->ifb_ifma_slow_proto
);
716 if (ifb
->ifb_distributing_array
!= NULL
) {
717 FREE(ifb
->ifb_distributing_array
, M_BOND
);
728 * Function: ifbond_wait
730 * Allows a single thread to gain exclusive access to the ifbond
731 * data structure. Some operations take a long time to complete,
732 * and some have side-effects that we can't predict. Holding the
733 * bond_lock() across such operations is not possible.
736 * 1) The SIOCSIFLLADDR ioctl takes a long time (several seconds) to
737 * complete. Simply holding the bond_lock() would freeze all other
738 * data structure accesses during that time.
739 * 2) When we attach our protocol to the interface, a dlil event is
740 * generated and invokes our bond_event() function. bond_event()
741 * needs to take the bond_lock(), but we're already holding it, so
742 * we're deadlocked against ourselves.
744 * Before calling, you must be holding the bond_lock and have taken
745 * a reference on the ifbond_ref.
748 ifbond_wait(ifbond_ref ifb
, const char * msg
)
752 /* other add/remove in progress */
753 while (ifbond_flags_change_in_progress(ifb
)) {
754 if (g_bond
->verbose
) {
755 printf("%s: %s msleep\n", ifb
->ifb_name
, msg
);
758 (void)msleep(ifb
, bond_lck_mtx
, PZERO
, msg
, 0);
760 /* prevent other bond list remove/add from taking place */
761 ifbond_flags_set_change_in_progress(ifb
);
762 if (g_bond
->verbose
&& waited
) {
763 printf("%s: %s woke up\n", ifb
->ifb_name
, msg
);
769 * Function: ifbond_signal
771 * Allows the thread that previously invoked ifbond_wait() to
772 * give up exclusive access to the ifbond data structure, and wake up
773 * any other threads waiting to access
775 * Before calling, you must be holding the bond_lock and have taken
776 * a reference on the ifbond_ref.
779 ifbond_signal(ifbond_ref ifb
, const char * msg
)
781 ifbond_flags_clear_change_in_progress(ifb
);
782 wakeup((caddr_t
)ifb
);
783 if (g_bond
->verbose
) {
784 printf("%s: %s wakeup\n", ifb
->ifb_name
, msg
);
794 link_speed(int active
)
796 switch (IFM_SUBTYPE(active
)) {
817 /* assume that new defined types are going to be at least 10GigE */
824 static __inline__
int
825 media_active(const struct media_info
* mi
)
827 if ((mi
->mi_status
& IFM_AVALID
) == 0) {
830 return ((mi
->mi_status
& IFM_ACTIVE
) != 0);
833 static __inline__
int
834 media_full_duplex(const struct media_info
* mi
)
836 return ((mi
->mi_active
& IFM_FDX
) != 0);
839 static __inline__
int
840 media_speed(const struct media_info
* mi
)
842 return (link_speed(mi
->mi_active
));
845 static struct media_info
846 interface_media_info(struct ifnet
* ifp
)
848 struct ifmediareq ifmr
;
849 struct media_info mi
;
851 bzero(&mi
, sizeof(mi
));
852 bzero(&ifmr
, sizeof(ifmr
));
853 if (dlil_ioctl(0, ifp
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
) == 0) {
854 if (ifmr
.ifm_count
!= 0) {
855 mi
.mi_status
= ifmr
.ifm_status
;
856 mi
.mi_active
= ifmr
.ifm_active
;
863 ** interface utility functions
865 static __inline__
struct ifaddr
*
866 ifindex_get_ifaddr(int i
)
868 if (i
> if_index
|| i
== 0) {
871 return (ifnet_addrs
[i
- 1]);
874 static __inline__
struct ifaddr
*
875 ifp_get_ifaddr(struct ifnet
* ifp
)
877 return (ifindex_get_ifaddr(ifp
->if_index
));
880 static __inline__
struct sockaddr_dl
*
881 ifp_get_sdl(struct ifnet
* ifp
)
885 ifa
= ifp_get_ifaddr(ifp
);
886 return ((struct sockaddr_dl
*)(ifa
->ifa_addr
));
890 if_siflladdr(struct ifnet
* ifp
, const struct ether_addr
* ea_p
)
895 * XXX setting the sa_len to ETHER_ADDR_LEN is wrong, but the driver
896 * currently expects it that way
898 ifr
.ifr_addr
.sa_family
= AF_UNSPEC
;
899 ifr
.ifr_addr
.sa_len
= ETHER_ADDR_LEN
;
900 ether_addr_copy(ifr
.ifr_addr
.sa_data
, ea_p
);
902 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s%d", ifp
->if_name
,
905 return (dlil_ioctl(0, ifp
, SIOCSIFLLADDR
, (caddr_t
)&ifr
));
911 static bond_globals_ref
912 bond_globals_create(lacp_system_priority sys_pri
,
917 b
= _MALLOC(sizeof(*b
), M_BOND
, M_WAITOK
);
921 bzero(b
, sizeof(*b
));
922 TAILQ_INIT(&b
->ifbond_list
);
924 b
->system_priority
= sys_pri
;
932 bond_globals_init(void)
938 bond_assert_lock_not_held();
940 if (g_bond
!= NULL
) {
945 * use en0's ethernet address as the system identifier, and if it's not
946 * there, use en1 .. en3
949 for (i
= 0; i
< 4; i
++) {
950 char ifname
[IFNAMSIZ
+1];
951 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
952 /* XXX ifunit() needs to return a reference on the ifp */
953 ifp
= ifunit(ifname
);
960 b
= bond_globals_create(0x8000,
961 (lacp_system_ref
)LLADDR(ifp_get_sdl(ifp
)));
964 if (g_bond
!= NULL
) {
981 bond_bpf_vlan(struct ifnet
* ifp
, struct mbuf
* m
,
982 const struct ether_header
* eh_p
,
983 u_int16_t vlan_tag
, bpf_packet_func func
)
985 struct ether_vlan_header
* vlh_p
;
988 vl_m
= m_get(M_DONTWAIT
, MT_DATA
);
992 /* populate a new mbuf containing the vlan ethernet header */
993 vl_m
->m_len
= ETHER_HDR_LEN
+ ETHER_VLAN_ENCAP_LEN
;
994 vlh_p
= mtod(vl_m
, struct ether_vlan_header
*);
995 bcopy(eh_p
, vlh_p
, offsetof(struct ether_header
, ether_type
));
996 vlh_p
->evl_encap_proto
= htons(ETHERTYPE_VLAN
);
997 vlh_p
->evl_tag
= htons(vlan_tag
);
998 vlh_p
->evl_proto
= eh_p
->ether_type
;
1001 vl_m
->m_next
= NULL
;
1006 static __inline__
void
1007 bond_bpf_output(struct ifnet
* ifp
, struct mbuf
* m
,
1008 bpf_packet_func func
)
1011 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1012 const struct ether_header
* eh_p
;
1013 eh_p
= mtod(m
, const struct ether_header
*);
1014 m
->m_data
+= ETHER_HDR_LEN
;
1015 m
->m_len
-= ETHER_HDR_LEN
;
1016 bond_bpf_vlan(ifp
, m
, eh_p
, m
->m_pkthdr
.vlan_tag
, func
);
1017 m
->m_data
-= ETHER_HDR_LEN
;
1018 m
->m_len
+= ETHER_HDR_LEN
;
1026 static __inline__
void
1027 bond_bpf_input(ifnet_t ifp
, mbuf_t m
, const struct ether_header
* eh_p
,
1028 bpf_packet_func func
)
1031 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1032 bond_bpf_vlan(ifp
, m
, eh_p
, m
->m_pkthdr
.vlan_tag
, func
);
1034 /* restore the header */
1035 m
->m_data
-= ETHER_HDR_LEN
;
1036 m
->m_len
+= ETHER_HDR_LEN
;
1038 m
->m_data
+= ETHER_HDR_LEN
;
1039 m
->m_len
-= ETHER_HDR_LEN
;
1046 * Function: bond_setmulti
1048 * Enable multicast reception on "our" interface by enabling multicasts on
1049 * each of the member ports.
1052 bond_setmulti(struct ifnet
* ifp
)
1060 ifb
= ifp
->if_private
;
1061 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1062 || TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
1067 ifbond_wait(ifb
, "bond_setmulti");
1069 if (ifbond_flags_if_detaching(ifb
)) {
1070 /* someone destroyed the bond while we were waiting */
1076 /* ifbond_wait() let's us safely walk the list without holding the lock */
1077 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
1078 struct ifnet
* port_ifp
= p
->po_ifp
;
1080 error
= multicast_list_program(&p
->po_multicast
,
1083 printf("bond_setmulti(%s): "
1084 "multicast_list_program(%s%d) failed, %d\n",
1085 ifb
->ifb_name
, port_ifp
->if_name
,
1086 port_ifp
->if_unit
, error
);
1092 ifbond_release(ifb
);
1093 ifbond_signal(ifb
, "bond_setmulti");
1099 bond_clone_attach(void)
1101 if_clone_attach(&bond_cloner
);
1107 ifbond_add_slow_proto_multicast(ifbond_ref ifb
)
1110 struct ifmultiaddr
* ifma
= NULL
;
1111 struct sockaddr_dl sdl
;
1113 bond_assert_lock_not_held();
1115 bzero(&sdl
, sizeof(sdl
));
1116 sdl
.sdl_len
= sizeof(sdl
);
1117 sdl
.sdl_family
= AF_LINK
;
1118 sdl
.sdl_type
= IFT_ETHER
;
1120 sdl
.sdl_alen
= sizeof(slow_proto_multicast
);
1121 bcopy(&slow_proto_multicast
, sdl
.sdl_data
, sizeof(slow_proto_multicast
));
1122 error
= if_addmulti(ifb
->ifb_ifp
, (struct sockaddr
*)&sdl
,
1125 ifb
->ifb_ifma_slow_proto
= ifma
;
1131 bond_clone_create(struct if_clone
* ifc
, int unit
)
1137 error
= bond_globals_init();
1142 ifb
= _MALLOC(sizeof(ifbond
), M_BOND
, M_WAITOK
);
1146 bzero(ifb
, sizeof(*ifb
));
1149 TAILQ_INIT(&ifb
->ifb_port_list
);
1150 TAILQ_INIT(&ifb
->ifb_lag_list
);
1151 ifb
->ifb_key
= unit
+ 1;
1153 /* use the interface name as the unique id for ifp recycle */
1154 if ((u_long
)snprintf(ifb
->ifb_name
, sizeof(ifb
->ifb_name
), "%s%d",
1155 ifc
->ifc_name
, unit
) >= sizeof(ifb
->ifb_name
)) {
1156 ifbond_release(ifb
);
1159 error
= dlil_if_acquire(APPLE_IF_FAM_BOND
,
1161 strlen(ifb
->ifb_name
),
1164 ifbond_release(ifb
);
1168 ifp
->if_name
= ifc
->ifc_name
;
1169 ifp
->if_unit
= unit
;
1170 ifp
->if_family
= APPLE_IF_FAM_BOND
;
1171 ifp
->if_private
= NULL
;
1172 ifp
->if_ioctl
= bond_ioctl
;
1173 ifp
->if_set_bpf_tap
= bond_set_bpf_tap
;
1174 ifp
->if_free
= bond_if_free
;
1175 ifp
->if_output
= bond_output
;
1176 ifp
->if_hwassist
= 0;
1177 ifp
->if_addrlen
= ETHER_ADDR_LEN
;
1178 ifp
->if_baudrate
= 0;
1179 ifp
->if_type
= IFT_IEEE8023ADLAG
;
1180 ifp
->if_flags
= IFF_BROADCAST
| IFF_MULTICAST
| IFF_SIMPLEX
;
1183 /* XXX ethernet specific */
1184 ifp
->if_broadcast
.length
= ETHER_ADDR_LEN
;
1185 bcopy(etherbroadcastaddr
, ifp
->if_broadcast
.u
.buffer
, ETHER_ADDR_LEN
);
1187 error
= dlil_if_attach(ifp
);
1189 dlil_if_release(ifp
);
1190 ifbond_release(ifb
);
1193 error
= ifbond_add_slow_proto_multicast(ifb
);
1195 printf("bond_clone_create(%s): "
1196 "failed to add slow_proto multicast, %d\n",
1197 ifb
->ifb_name
, error
);
1200 /* attach as ethernet */
1201 bpfattach(ifp
, DLT_EN10MB
, sizeof(struct ether_header
));
1204 ifp
->if_private
= ifb
;
1205 TAILQ_INSERT_HEAD(&g_bond
->ifbond_list
, ifb
, ifb_bond_list
);
1212 bond_remove_all_interfaces(ifbond_ref ifb
)
1216 bond_assert_lock_held();
1219 * do this in reverse order to avoid re-programming the mac address
1220 * as each head interface is removed
1222 while ((p
= TAILQ_LAST(&ifb
->ifb_port_list
, port_list
)) != NULL
) {
1223 bond_remove_interface(ifb
, p
->po_ifp
);
1229 bond_remove(ifbond_ref ifb
)
1231 bond_assert_lock_held();
1232 ifbond_flags_set_if_detaching(ifb
);
1233 TAILQ_REMOVE(&g_bond
->ifbond_list
, ifb
, ifb_bond_list
);
1234 bond_remove_all_interfaces(ifb
);
1239 bond_if_detach(struct ifnet
* ifp
)
1243 error
= dlil_if_detach(ifp
);
1244 if (error
!= DLIL_WAIT_FOR_FREE
) {
1246 printf("bond_if_detach %s%d: dlil_if_detach failed, %d\n",
1247 ifp
->if_name
, ifp
->if_unit
, error
);
1255 bond_clone_destroy(struct ifnet
* ifp
)
1260 ifb
= ifp
->if_private
;
1261 if (ifb
== NULL
|| ifp
->if_type
!= IFT_IEEE8023ADLAG
) {
1265 if (ifbond_flags_if_detaching(ifb
)) {
1271 bond_if_detach(ifp
);
1276 bond_set_bpf_tap(struct ifnet
* ifp
, bpf_tap_mode mode
, bpf_packet_func func
)
1281 ifb
= ifp
->if_private
;
1282 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
1287 case BPF_TAP_DISABLE
:
1288 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= NULL
;
1292 ifb
->ifb_bpf_input
= func
;
1295 case BPF_TAP_OUTPUT
:
1296 ifb
->ifb_bpf_output
= func
;
1299 case BPF_TAP_INPUT_OUTPUT
:
1300 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= func
;
1310 ether_header_hash(struct ether_header
* eh_p
)
1314 /* get 32-bits from destination ether and ether type */
1315 h
= (*((uint16_t *)&eh_p
->ether_dhost
[4]) << 16)
1317 h
^= *((uint32_t *)&eh_p
->ether_dhost
[0]);
1321 static struct mbuf
*
1322 S_mbuf_skip_to_offset(struct mbuf
* m
, long * offset
)
1327 while (*offset
>= len
) {
1338 #if BYTE_ORDER == BIG_ENDIAN
1339 static __inline__
uint32_t
1340 make_uint32(u_char c0
, u_char c1
, u_char c2
, u_char c3
)
1342 return (((uint32_t)c0
<< 24) | ((uint32_t)c1
<< 16)
1343 | ((uint32_t)c2
<< 8) | (uint32_t)c3
);
1345 #else /* BYTE_ORDER == LITTLE_ENDIAN */
1346 static __inline__
uint32_t
1347 make_uint32(u_char c0
, u_char c1
, u_char c2
, u_char c3
)
1349 return (((uint32_t)c3
<< 24) | ((uint32_t)c2
<< 16)
1350 | ((uint32_t)c1
<< 8) | (uint32_t)c0
);
1352 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1355 S_mbuf_copy_uint32(struct mbuf
* m
, long offset
, uint32_t * val
)
1357 struct mbuf
* current
;
1358 u_char
* current_data
;
1363 current
= S_mbuf_skip_to_offset(m
, &offset
);
1364 if (current
== NULL
) {
1367 current_data
= mtod(current
, u_char
*) + offset
;
1368 space_current
= current
->m_len
- offset
;
1369 if (space_current
>= (int)sizeof(uint32_t)) {
1370 *val
= *((uint32_t *)current_data
);
1373 next
= current
->m_next
;
1374 if (next
== NULL
|| (next
->m_len
+ space_current
) < (int)sizeof(uint32_t)) {
1377 next_data
= mtod(next
, u_char
*);
1378 switch (space_current
) {
1380 *val
= make_uint32(current_data
[0], next_data
[0],
1381 next_data
[1], next_data
[2]);
1384 *val
= make_uint32(current_data
[0], current_data
[1],
1385 next_data
[0], next_data
[1]);
1388 *val
= make_uint32(current_data
[0], current_data
[1],
1389 current_data
[2], next_data
[0]);
1395 #define IP_SRC_OFFSET (offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p))
1396 #define IP_DST_OFFSET (offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p))
1399 ip_header_hash(struct mbuf
* m
)
1402 struct in_addr ip_dst
;
1403 struct in_addr ip_src
;
1406 struct mbuf
* orig_m
= m
;
1408 /* find the IP protocol field relative to the start of the packet */
1409 offset
= offsetof(struct ip
, ip_p
) + sizeof(struct ether_header
);
1410 m
= S_mbuf_skip_to_offset(m
, &offset
);
1411 if (m
== NULL
|| m
->m_len
< 1) {
1414 data
= mtod(m
, u_char
*) + offset
;
1417 /* find the IP src relative to the IP protocol */
1418 if ((m
->m_len
- offset
)
1419 >= (int)(IP_SRC_OFFSET
+ sizeof(struct in_addr
) * 2)) {
1420 /* this should be the normal case */
1421 ip_src
= *(struct in_addr
*)(data
+ IP_SRC_OFFSET
);
1422 ip_dst
= *(struct in_addr
*)(data
+ IP_DST_OFFSET
);
1425 if (S_mbuf_copy_uint32(m
, offset
+ IP_SRC_OFFSET
,
1426 (uint32_t *)&ip_src
.s_addr
)) {
1429 if (S_mbuf_copy_uint32(m
, offset
+ IP_DST_OFFSET
,
1430 (uint32_t *)&ip_dst
.s_addr
)) {
1434 return (ntohl(ip_dst
.s_addr
) ^ ntohl(ip_src
.s_addr
) ^ ((uint32_t)ip_p
));
1437 return (ether_header_hash(mtod(orig_m
, struct ether_header
*)));
1440 #define IP6_ADDRS_LEN (sizeof(struct in6_addr) * 2)
1442 ipv6_header_hash(struct mbuf
* m
)
1447 struct mbuf
* orig_m
= m
;
1451 /* find the IP protocol field relative to the start of the packet */
1452 offset
= offsetof(struct ip6_hdr
, ip6_src
) + sizeof(struct ether_header
);
1453 m
= S_mbuf_skip_to_offset(m
, &offset
);
1455 goto bad_ipv6_packet
;
1457 data
= mtod(m
, u_char
*) + offset
;
1459 if ((m
->m_len
- offset
) >= (int)IP6_ADDRS_LEN
) {
1460 /* this should be the normal case */
1461 for (i
= 0, scan
= (uint32_t *)data
;
1462 i
< (int)(IP6_ADDRS_LEN
/ sizeof(uint32_t));
1468 for (i
= 0; i
< (int)(IP6_ADDRS_LEN
/ sizeof(uint32_t)); i
++) {
1470 if (S_mbuf_copy_uint32(m
, offset
+ i
* sizeof(uint32_t),
1471 (uint32_t *)&tmp
)) {
1472 goto bad_ipv6_packet
;
1477 return (ntohl(val
));
1480 return (ether_header_hash(mtod(orig_m
, struct ether_header
*)));
1484 bond_output(struct ifnet
* ifp
, struct mbuf
* m
)
1486 bpf_packet_func bpf_func
;
1489 struct ifnet
* port_ifp
= NULL
;
1494 if ((m
->m_flags
& M_PKTHDR
) == 0) {
1498 if (m
->m_pkthdr
.socket_id
!= 0) {
1499 h
= m
->m_pkthdr
.socket_id
;
1502 struct ether_header
* eh_p
;
1504 eh_p
= mtod(m
, struct ether_header
*);
1505 switch (ntohs(eh_p
->ether_type
)) {
1507 h
= ip_header_hash(m
);
1509 case ETHERTYPE_IPV6
:
1510 h
= ipv6_header_hash(m
);
1513 h
= ether_header_hash(eh_p
);
1518 ifb
= ifp
->if_private
;
1519 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1520 || ifb
->ifb_distributing_count
== 0) {
1523 h
%= ifb
->ifb_distributing_count
;
1524 port_ifp
= ifb
->ifb_distributing_array
[h
]->po_ifp
;
1525 bpf_func
= ifb
->ifb_bpf_output
;
1528 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1529 (void)ifnet_stat_increment_out(ifp
, 1,
1530 m
->m_pkthdr
.len
+ ETHER_VLAN_ENCAP_LEN
,
1533 (void)ifnet_stat_increment_out(ifp
, 1, m
->m_pkthdr
.len
, 0);
1535 bond_bpf_output(ifp
, m
, bpf_func
);
1537 return (dlil_output(port_ifp
, 0, m
, NULL
, NULL
, 1));
1546 ifbond_lookup_port(ifbond_ref ifb
, struct ifnet
* port_ifp
)
1549 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
1550 if (p
->po_ifp
== port_ifp
) {
1558 bond_lookup_port(struct ifnet
* port_ifp
)
1563 TAILQ_FOREACH(ifb
, &g_bond
->ifbond_list
, ifb_bond_list
) {
1564 port
= ifbond_lookup_port(ifb
, port_ifp
);
1573 bond_receive_lacpdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1575 struct ifnet
* bond_ifp
= NULL
;
1580 if ((port_ifp
->if_eflags
& IFEF_BOND
) == 0) {
1583 p
= bond_lookup_port(port_ifp
);
1587 if (p
->po_enabled
== 0) {
1590 bondport_receive_lacpdu(p
, (lacpdu_ref
)m
->m_data
);
1591 if (ifbond_selection(p
->po_bond
)) {
1592 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
1595 /* XXX need to take a reference on bond_ifp */
1596 bond_ifp
= p
->po_bond
->ifb_ifp
;
1601 if (bond_ifp
!= NULL
) {
1602 interface_link_event(bond_ifp
, event_code
);
1609 bond_receive_la_marker_pdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1611 la_marker_pdu_ref marker_p
;
1614 marker_p
= (la_marker_pdu_ref
)(m
->m_data
+ ETHER_HDR_LEN
);
1615 if (marker_p
->lm_marker_tlv_type
!= LA_MARKER_TLV_TYPE_MARKER
) {
1619 if ((port_ifp
->if_eflags
& IFEF_BOND
) == 0) {
1623 p
= bond_lookup_port(port_ifp
);
1624 if (p
== NULL
|| p
->po_enabled
== 0) {
1628 /* echo back the same packet as a marker response */
1629 marker_p
->lm_marker_tlv_type
= LA_MARKER_TLV_TYPE_MARKER_RESPONSE
;
1630 bondport_slow_proto_transmit(p
, (packet_buffer_ref
)m
);
1640 bond_input(struct mbuf
* m
, char * frame_header
, struct ifnet
* port_ifp
,
1641 __unused u_long protocol_family
, __unused
int sync_ok
)
1643 bpf_packet_func bpf_func
;
1644 const struct ether_header
* eh_p
;
1649 eh_p
= (const struct ether_header
*)frame_header
;
1650 if ((m
->m_flags
& M_MCAST
) != 0
1651 && bcmp(eh_p
->ether_dhost
, &slow_proto_multicast
,
1652 sizeof(eh_p
->ether_dhost
)) == 0
1653 && ntohs(eh_p
->ether_type
) == IEEE8023AD_SLOW_PROTO_ETHERTYPE
) {
1654 u_char subtype
= *mtod(m
, u_char
*);
1656 if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP
) {
1657 if (m
->m_pkthdr
.len
< (int)offsetof(lacpdu
, la_reserved
)) {
1662 if (m
->m_len
< (int)offsetof(lacpdu
, la_reserved
)) {
1663 m
= m_pullup(m
, offsetof(lacpdu
, la_reserved
));
1668 bond_receive_lacpdu(m
, port_ifp
);
1671 else if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LA_MARKER_PROTOCOL
) {
1674 /* restore the ethernet header pointer in the mbuf */
1675 m
->m_pkthdr
.len
+= ETHER_HDR_LEN
;
1676 m
->m_data
-= ETHER_HDR_LEN
;
1677 m
->m_len
+= ETHER_HDR_LEN
;
1678 min_size
= ETHER_HDR_LEN
+ offsetof(la_marker_pdu
, lm_reserved
);
1679 if (m
->m_pkthdr
.len
< min_size
) {
1684 if (m
->m_len
< min_size
) {
1685 m
= m_pullup(m
, min_size
);
1690 /* send to marker responder */
1691 bond_receive_la_marker_pdu(m
, port_ifp
);
1694 else if (subtype
== 0
1695 || subtype
> IEEE8023AD_SLOW_PROTO_SUBTYPE_RESERVED_END
) {
1696 /* invalid subtype, discard the frame */
1702 if ((port_ifp
->if_eflags
& IFEF_BOND
) == 0) {
1705 p
= bond_lookup_port(port_ifp
);
1706 if (p
== NULL
|| bondport_collecting(p
) == 0) {
1710 /* make the packet appear as if it arrived on the bonded interface */
1713 bpf_func
= ifb
->ifb_bpf_input
;
1716 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1717 (void)ifnet_stat_increment_in(ifp
, 1,
1718 (m
->m_pkthdr
.len
+ ETHER_HDR_LEN
1719 + ETHER_VLAN_ENCAP_LEN
), 0);
1722 (void)ifnet_stat_increment_in(ifp
, 1,
1723 (m
->m_pkthdr
.len
+ ETHER_HDR_LEN
), 0);
1725 m
->m_pkthdr
.rcvif
= ifp
;
1726 bond_bpf_input(ifp
, m
, eh_p
, bpf_func
);
1727 dlil_input_packet(ifp
, m
, frame_header
);
1736 static __inline__
const char *
1737 bondport_get_name(bondport_ref p
)
1739 return (p
->po_name
);
1742 static __inline__
int
1743 bondport_get_index(bondport_ref p
)
1745 return (p
->po_ifp
->if_index
);
1749 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
)
1751 struct ether_header
* eh_p
;
1754 /* packet_buffer_allocate leaves room for ethernet header */
1755 eh_p
= mtod(buf
, struct ether_header
*);
1756 bcopy(&slow_proto_multicast
, &eh_p
->ether_dhost
, sizeof(eh_p
->ether_dhost
));
1757 bcopy(&p
->po_saved_addr
, eh_p
->ether_shost
, sizeof(eh_p
->ether_shost
));
1758 eh_p
->ether_type
= htons(IEEE8023AD_SLOW_PROTO_ETHERTYPE
);
1759 error
= dlil_output(p
->po_ifp
, 0, buf
, NULL
, NULL
, 1);
1761 printf("bondport_slow_proto_transmit(%s) failed %d\n",
1762 bondport_get_name(p
), error
);
1768 bondport_timer_process_func(devtimer_ref timer
,
1769 devtimer_process_func_event event
)
1774 case devtimer_process_func_event_lock
:
1776 devtimer_retain(timer
);
1778 case devtimer_process_func_event_unlock
:
1779 if (devtimer_valid(timer
)) {
1780 /* as long as the devtimer is valid, we can look at arg0 */
1782 struct ifnet
* bond_ifp
= NULL
;
1784 p
= (bondport_ref
)devtimer_arg0(timer
);
1785 if (ifbond_selection(p
->po_bond
)) {
1786 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
1789 /* XXX need to take a reference on bond_ifp */
1790 bond_ifp
= p
->po_bond
->ifb_ifp
;
1792 devtimer_release(timer
);
1794 if (bond_ifp
!= NULL
) {
1795 interface_link_event(bond_ifp
, event_code
);
1799 /* timer is going away */
1800 devtimer_release(timer
);
1810 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
1811 int active
, int short_timeout
, int * ret_error
)
1814 bondport_ref p
= NULL
;
1815 lacp_actor_partner_state s
;
1818 p
= _MALLOC(sizeof(*p
), M_BOND
, M_WAITOK
);
1820 *ret_error
= ENOMEM
;
1823 bzero(p
, sizeof(*p
));
1824 multicast_list_init(&p
->po_multicast
);
1825 if ((u_long
)snprintf(p
->po_name
, sizeof(p
->po_name
), "%s%d",
1826 port_ifp
->if_name
, port_ifp
->if_unit
)
1827 >= sizeof(p
->po_name
)) {
1828 printf("if_bond: name too large\n");
1829 *ret_error
= EINVAL
;
1832 error
= siocgifdevmtu(port_ifp
, &p
->po_devmtu
);
1834 printf("if_bond: SIOCGIFDEVMTU %s failed, %d\n",
1835 bondport_get_name(p
), error
);
1838 /* remember the current interface MTU so it can be restored */
1839 p
->po_devmtu
.ifdm_current
= port_ifp
->if_mtu
;
1840 p
->po_ifp
= port_ifp
;
1841 p
->po_media_info
= interface_media_info(port_ifp
);
1842 p
->po_current_while_timer
= devtimer_create(bondport_timer_process_func
, p
);
1843 if (p
->po_current_while_timer
== NULL
) {
1844 *ret_error
= ENOMEM
;
1847 p
->po_periodic_timer
= devtimer_create(bondport_timer_process_func
, p
);
1848 if (p
->po_periodic_timer
== NULL
) {
1849 *ret_error
= ENOMEM
;
1852 p
->po_wait_while_timer
= devtimer_create(bondport_timer_process_func
, p
);
1853 if (p
->po_wait_while_timer
== NULL
) {
1854 *ret_error
= ENOMEM
;
1857 p
->po_transmit_timer
= devtimer_create(bondport_timer_process_func
, p
);
1858 if (p
->po_transmit_timer
== NULL
) {
1859 *ret_error
= ENOMEM
;
1862 p
->po_receive_state
= ReceiveState_none
;
1863 p
->po_mux_state
= MuxState_none
;
1864 p
->po_priority
= priority
;
1866 s
= lacp_actor_partner_state_set_aggregatable(s
);
1867 if (short_timeout
) {
1868 s
= lacp_actor_partner_state_set_short_timeout(s
);
1871 s
= lacp_actor_partner_state_set_active_lacp(s
);
1873 p
->po_actor_state
= s
;
1882 bondport_start(bondport_ref p
)
1884 bondport_receive_machine(p
, LAEventStart
, NULL
);
1885 bondport_mux_machine(p
, LAEventStart
, NULL
);
1886 bondport_periodic_transmit_machine(p
, LAEventStart
, NULL
);
1887 bondport_transmit_machine(p
, LAEventStart
, NULL
);
1892 * Function: bondport_invalidate_timers
1894 * Invalidate all of the timers for the bondport.
1897 bondport_invalidate_timers(bondport_ref p
)
1899 devtimer_invalidate(p
->po_current_while_timer
);
1900 devtimer_invalidate(p
->po_periodic_timer
);
1901 devtimer_invalidate(p
->po_wait_while_timer
);
1902 devtimer_invalidate(p
->po_transmit_timer
);
1906 bondport_free(bondport_ref p
)
1908 multicast_list_remove(&p
->po_multicast
);
1909 devtimer_release(p
->po_current_while_timer
);
1910 devtimer_release(p
->po_periodic_timer
);
1911 devtimer_release(p
->po_wait_while_timer
);
1912 devtimer_release(p
->po_transmit_timer
);
1917 #define BOND_ADD_PROGRESS_IN_LIST 0x1
1918 #define BOND_ADD_PROGRESS_PROTO_ATTACHED 0x2
1919 #define BOND_ADD_PROGRESS_LLADDR_SET 0x4
1920 #define BOND_ADD_PROGRESS_MTU_SET 0x8
1922 static __inline__
int
1923 bond_device_mtu(struct ifnet
* ifp
, ifbond_ref ifb
)
1925 return (((int)ifp
->if_mtu
> ifb
->ifb_altmtu
)
1926 ? (int)ifp
->if_mtu
: ifb
->ifb_altmtu
);
1930 bond_add_interface(struct ifnet
* ifp
, struct ifnet
* port_ifp
)
1936 struct sockaddr_dl
* ifb_sdl
;
1937 bondport_ref
* new_array
= NULL
;
1938 bondport_ref
* old_array
= NULL
;
1940 struct sockaddr_dl
* port_sdl
;
1943 /* pre-allocate space for new port */
1944 p
= bondport_create(port_ifp
, 0x8000, 1, 0, &error
);
1949 ifb
= (ifbond_ref
)ifp
->if_private
;
1950 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
1953 return ((ifb
== NULL
? EOPNOTSUPP
: EBUSY
));
1956 /* make sure this interface can handle our current MTU */
1957 devmtu
= bond_device_mtu(ifp
, ifb
);
1959 && (devmtu
> p
->po_devmtu
.ifdm_max
|| devmtu
< p
->po_devmtu
.ifdm_min
)) {
1961 printf("if_bond: interface %s doesn't support mtu %d",
1962 bondport_get_name(p
), devmtu
);
1967 /* make sure ifb doesn't get de-allocated while we wait */
1970 /* wait for other add or remove to complete */
1971 ifbond_wait(ifb
, "bond_add_interface");
1973 if (ifbond_flags_if_detaching(ifb
)) {
1974 /* someone destroyed the bond while we were waiting */
1978 if (bond_lookup_port(port_ifp
) != NULL
) {
1979 /* port is already part of a bond */
1983 ifnet_lock_exclusive(port_ifp
);
1984 if ((port_ifp
->if_eflags
& (IFEF_VLAN
| IFEF_BOND
)) != 0) {
1985 /* interface already has VLAN's, or is part of bond */
1986 ifnet_lock_done(port_ifp
);
1991 /* mark the interface busy */
1992 port_ifp
->if_eflags
|= IFEF_BOND
;
1993 ifnet_lock_done(port_ifp
);
1995 port_sdl
= ifp_get_sdl(port_ifp
);
1996 ifb_sdl
= ifp_get_sdl(ifp
);
1998 if (TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
1999 ifp
->if_hwassist
= port_ifp
->if_hwassist
;
2000 ifp
->if_flags
|= IFF_RUNNING
;
2001 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2002 /* first port added to bond determines bond's ethernet address */
2003 ether_addr_copy(LLADDR(ifb_sdl
), LLADDR(port_sdl
));
2004 ifb_sdl
->sdl_type
= IFT_ETHER
;
2005 ifb_sdl
->sdl_alen
= ETHER_ADDR_LEN
;
2008 if (ifp
->if_hwassist
!= port_ifp
->if_hwassist
) {
2009 printf("bond_add_interface(%s, %s) "
2010 "hwassist values don't match 0x%x != 0x%x\n",
2011 ifb
->ifb_name
, bondport_get_name(p
),
2012 ifp
->if_hwassist
, port_ifp
->if_hwassist
);
2015 * if the bond has VLAN's, we can't simply change the hwassist
2016 * field behind its back: this needs work
2018 ifp
->if_hwassist
= 0;
2023 /* remember the port's ethernet address so it can be restored */
2024 ether_addr_copy(&p
->po_saved_addr
, LLADDR(port_sdl
));
2026 /* add it to the list of ports */
2027 TAILQ_INSERT_TAIL(&ifb
->ifb_port_list
, p
, po_port_list
);
2028 ifb
->ifb_port_count
++;
2030 /* set the default MTU */
2031 if (ifp
->if_mtu
== 0) {
2032 ifp
->if_mtu
= ETHERMTU
;
2035 progress
|= BOND_ADD_PROGRESS_IN_LIST
;
2037 /* allocate a larger distributing array */
2038 new_array
= (bondport_ref
*)
2039 _MALLOC(sizeof(*new_array
) * ifb
->ifb_port_count
, M_BOND
, M_WAITOK
);
2040 if (new_array
== NULL
) {
2045 /* attach our BOND "protocol" to the interface */
2046 error
= bond_attach_protocol(port_ifp
);
2050 progress
|= BOND_ADD_PROGRESS_PROTO_ATTACHED
;
2052 /* set the interface MTU */
2053 devmtu
= bond_device_mtu(ifp
, ifb
);
2054 error
= siocsifmtu(port_ifp
, devmtu
);
2056 printf("bond_add_interface(%s, %s):"
2057 " SIOCSIFMTU %d failed %d\n",
2058 ifb
->ifb_name
, bondport_get_name(p
), devmtu
, error
);
2061 progress
|= BOND_ADD_PROGRESS_MTU_SET
;
2063 /* program the port with our multicast addresses */
2064 error
= multicast_list_program(&p
->po_multicast
, ifp
, port_ifp
);
2066 printf("bond_add_interface(%s, %s):"
2067 " multicast_list_program failed %d\n",
2068 ifb
->ifb_name
, bondport_get_name(p
), error
);
2072 /* mark the interface up */
2073 ifnet_set_flags(port_ifp
, IFF_UP
, IFF_UP
);
2075 error
= dlil_ioctl(0, port_ifp
, SIOCSIFFLAGS
, (caddr_t
)NULL
);
2077 printf("bond_add_interface(%s, %s): SIOCSIFFLAGS failed %d\n",
2078 ifb
->ifb_name
, bondport_get_name(p
), error
);
2082 /* re-program the port's ethernet address */
2083 error
= if_siflladdr(port_ifp
,
2084 (const struct ether_addr
*)LLADDR(ifb_sdl
));
2086 /* port doesn't support setting the link address */
2087 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2088 ifb
->ifb_name
, bondport_get_name(p
), error
);
2091 progress
|= BOND_ADD_PROGRESS_LLADDR_SET
;
2095 /* no failures past this point */
2098 /* copy the contents of the existing distributing array */
2099 if (ifb
->ifb_distributing_count
) {
2100 bcopy(ifb
->ifb_distributing_array
, new_array
,
2101 sizeof(*new_array
) * ifb
->ifb_distributing_count
);
2103 old_array
= ifb
->ifb_distributing_array
;
2104 ifb
->ifb_distributing_array
= new_array
;
2106 /* clear the busy state, and wakeup anyone waiting */
2107 ifbond_signal(ifb
, "bond_add_interface");
2110 /* check if we need to generate a link status event */
2111 if (ifbond_selection(ifb
)) {
2112 event_code
= (ifb
->ifb_active_lag
== NULL
)
2117 if (event_code
!= 0) {
2118 interface_link_event(ifp
, event_code
);
2120 if (old_array
!= NULL
) {
2121 FREE(old_array
, M_BOND
);
2126 bond_assert_lock_not_held();
2128 if (new_array
!= NULL
) {
2129 FREE(new_array
, M_BOND
);
2131 if ((progress
& BOND_ADD_PROGRESS_LLADDR_SET
) != 0) {
2134 error1
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2136 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2137 ifb
->ifb_name
, bondport_get_name(p
), error1
);
2140 if ((progress
& BOND_ADD_PROGRESS_PROTO_ATTACHED
) != 0) {
2141 (void)bond_detach_protocol(port_ifp
);
2143 if ((progress
& BOND_ADD_PROGRESS_MTU_SET
) != 0) {
2146 error1
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
2148 printf("bond_add_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2149 ifb
->ifb_name
, bondport_get_name(p
), p
->po_devmtu
.ifdm_current
,
2154 if ((progress
& BOND_ADD_PROGRESS_IN_LIST
) != 0) {
2155 TAILQ_REMOVE(&ifb
->ifb_port_list
, p
, po_port_list
);
2156 ifb
->ifb_port_count
--;
2158 ifnet_lock_exclusive(port_ifp
);
2159 port_ifp
->if_eflags
&= ~IFEF_BOND
;
2160 ifnet_lock_done(port_ifp
);
2161 if (TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
2162 ifb
->ifb_altmtu
= 0;
2164 ifp
->if_hwassist
= 0;
2165 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2166 bzero(LLADDR(ifb_sdl
), ETHER_ADDR_LEN
);
2167 ifb_sdl
->sdl_type
= IFT_IEEE8023ADLAG
;
2168 ifb_sdl
->sdl_alen
= 0;
2173 ifbond_release(ifb
);
2174 ifbond_signal(ifb
, "bond_add_interface");
2181 bond_remove_interface(ifbond_ref ifb
, struct ifnet
* port_ifp
)
2186 bondport_ref head_port
;
2187 struct sockaddr_dl
* ifb_sdl
;
2189 int new_link_address
= 0;
2191 lacp_actor_partner_state s
;
2193 bond_assert_lock_held();
2196 ifbond_wait(ifb
, "bond_remove_interface");
2198 p
= ifbond_lookup_port(ifb
, port_ifp
);
2201 /* it got removed by another thread */
2205 /* de-select it and remove it from the lists */
2206 bondport_disable_distributing(p
);
2207 bondport_set_selected(p
, SelectedState_UNSELECTED
);
2208 active_lag
= bondport_remove_from_LAG(p
);
2209 TAILQ_REMOVE(&ifb
->ifb_port_list
, p
, po_port_list
);
2210 ifb
->ifb_port_count
--;
2212 /* invalidate timers here while holding the bond_lock */
2213 bondport_invalidate_timers(p
);
2215 /* announce that we're Individual now */
2216 s
= p
->po_actor_state
;
2217 s
= lacp_actor_partner_state_set_individual(s
);
2218 s
= lacp_actor_partner_state_set_not_collecting(s
);
2219 s
= lacp_actor_partner_state_set_not_distributing(s
);
2220 s
= lacp_actor_partner_state_set_out_of_sync(s
);
2221 p
->po_actor_state
= s
;
2222 bondport_flags_set_ntt(p
);
2225 ifb_sdl
= ifp_get_sdl(ifp
);
2226 head_port
= TAILQ_FIRST(&ifb
->ifb_port_list
);
2227 if (head_port
== NULL
) {
2228 ifp
->if_flags
&= ~IFF_RUNNING
;
2229 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2230 ifb_sdl
->sdl_type
= IFT_IEEE8023ADLAG
;
2231 ifb_sdl
->sdl_alen
= 0;
2232 bzero(LLADDR(ifb_sdl
), ETHER_ADDR_LEN
);
2234 ifp
->if_hwassist
= 0;
2236 ifb
->ifb_altmtu
= 0;
2237 } else if (ifbond_flags_lladdr(ifb
) == FALSE
2238 && bcmp(&p
->po_saved_addr
, LLADDR(ifb_sdl
),
2239 ETHER_ADDR_LEN
) == 0) {
2240 /* this port gave the bond its ethernet address, switch to new one */
2241 ether_addr_copy(LLADDR(ifb_sdl
), &head_port
->po_saved_addr
);
2242 ifb_sdl
->sdl_type
= IFT_ETHER
;
2243 ifb_sdl
->sdl_alen
= ETHER_ADDR_LEN
;
2244 new_link_address
= 1;
2246 /* check if we need to generate a link status event */
2247 if (ifbond_selection(ifb
) || active_lag
) {
2248 event_code
= (ifb
->ifb_active_lag
== NULL
)
2254 bondport_transmit_machine(p
, LAEventStart
, (void *)1);
2256 if (new_link_address
) {
2257 struct ifnet
* scan_ifp
;
2258 bondport_ref scan_port
;
2260 /* ifbond_wait() allows port list traversal without holding the lock */
2262 /* re-program each port with the new link address */
2263 TAILQ_FOREACH(scan_port
, &ifb
->ifb_port_list
, po_port_list
) {
2264 scan_ifp
= scan_port
->po_ifp
;
2266 error
= if_siflladdr(scan_ifp
,
2267 (const struct ether_addr
*) LLADDR(ifb_sdl
));
2269 printf("bond_remove_interface(%s, %s): "
2270 "if_siflladdr (%s) failed %d\n",
2271 ifb
->ifb_name
, bondport_get_name(p
),
2272 bondport_get_name(scan_port
), error
);
2277 /* restore the port's ethernet address */
2278 error
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2280 printf("bond_remove_interface(%s, %s): if_siflladdr failed %d\n",
2281 ifb
->ifb_name
, bondport_get_name(p
), error
);
2284 /* restore the port's MTU */
2285 error
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
2287 printf("bond_remove_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2288 ifb
->ifb_name
, bondport_get_name(p
),
2289 p
->po_devmtu
.ifdm_current
, error
);
2292 /* remove the bond "protocol" */
2293 bond_detach_protocol(port_ifp
);
2295 /* generate link event */
2296 if (event_code
!= 0) {
2297 interface_link_event(ifp
, event_code
);
2301 ifbond_release(ifb
);
2303 ifnet_lock_exclusive(port_ifp
);
2304 port_ifp
->if_eflags
&= ~IFEF_BOND
;
2305 ifnet_lock_done(port_ifp
);
2308 ifbond_signal(ifb
, "bond_remove_interface");
2309 ifbond_release(ifb
); /* a second release for the second reference */
2314 bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
, user_addr_t datap
)
2319 struct if_bond_status_req
* ibsr
;
2320 struct if_bond_status ibs
;
2323 ibsr
= &(ibr_p
->ibr_ibru
.ibru_status
);
2324 if (ibsr
->ibsr_version
!= IF_BOND_STATUS_REQ_VERSION
) {
2327 ibsr
->ibsr_key
= ifb
->ifb_key
;
2328 ibsr
->ibsr_total
= ifb
->ifb_port_count
;
2329 dst
= proc_is64bit(current_proc())
2330 ? ibsr
->ibsr_ibsru
.ibsru_buffer64
2331 : CAST_USER_ADDR_T(ibsr
->ibsr_ibsru
.ibsru_buffer32
);
2332 if (dst
== USER_ADDR_NULL
) {
2333 /* just want to know how many there are */
2336 if (ibsr
->ibsr_count
< 0) {
2339 count
= (ifb
->ifb_port_count
< ibsr
->ibsr_count
)
2340 ? ifb
->ifb_port_count
: ibsr
->ibsr_count
;
2341 TAILQ_FOREACH(port
, &ifb
->ifb_port_list
, po_port_list
) {
2342 struct if_bond_partner_state
* ibps_p
;
2343 partner_state_ref ps
;
2348 bzero(&ibs
, sizeof(ibs
));
2349 strncpy(ibs
.ibs_if_name
, port
->po_name
, sizeof(ibs
.ibs_if_name
));
2350 ibs
.ibs_port_priority
= port
->po_priority
;
2351 ibs
.ibs_state
= port
->po_actor_state
;
2352 ibs
.ibs_selected_state
= port
->po_selected
;
2353 ps
= &port
->po_partner_state
;
2354 ibps_p
= &ibs
.ibs_partner_state
;
2355 ibps_p
->ibps_system
= ps
->ps_lag_info
.li_system
;
2356 ibps_p
->ibps_system_priority
= ps
->ps_lag_info
.li_system_priority
;
2357 ibps_p
->ibps_key
= ps
->ps_lag_info
.li_key
;
2358 ibps_p
->ibps_port
= ps
->ps_port
;
2359 ibps_p
->ibps_port_priority
= ps
->ps_port_priority
;
2360 ibps_p
->ibps_state
= ps
->ps_state
;
2361 error
= copyout(&ibs
, dst
, sizeof(ibs
));
2371 error
= copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2374 (void)copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2380 bond_set_promisc(__unused
struct ifnet
*ifp
)
2384 ifbond_ref ifb
= ifp
->if_private
;
2387 if ((ifp
->if_flags
& IFF_PROMISC
) != 0) {
2388 if ((ifb
->ifb_flags
& IFBF_PROMISC
) == 0) {
2389 error
= ifnet_set_promiscuous(ifb
->ifb_p
, 1);
2391 ifb
->ifb_flags
|= IFBF_PROMISC
;
2394 if ((ifb
->ifb_flags
& IFBF_PROMISC
) != 0) {
2395 error
= ifnet_set_promiscuous(ifb
->ifb_p
, 0);
2397 ifb
->ifb_flags
&= ~IFBF_PROMISC
;
2405 bond_get_mtu_values(ifbond_ref ifb
, int * ret_min
, int * ret_max
)
2411 if (TAILQ_FIRST(&ifb
->ifb_port_list
) != NULL
) {
2412 mtu_min
= IF_MINMTU
;
2414 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2415 struct ifdevmtu
* devmtu_p
= &p
->po_devmtu
;
2417 if (devmtu_p
->ifdm_min
> mtu_min
) {
2418 mtu_min
= devmtu_p
->ifdm_min
;
2420 if (mtu_max
== 0 || devmtu_p
->ifdm_max
< mtu_max
) {
2421 mtu_max
= devmtu_p
->ifdm_max
;
2430 bond_set_mtu_on_ports(ifbond_ref ifb
, int mtu
)
2435 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2436 error
= siocsifmtu(p
->po_ifp
, mtu
);
2438 printf("if_bond(%s): SIOCSIFMTU %s failed, %d\n",
2439 ifb
->ifb_name
, bondport_get_name(p
), error
);
2447 bond_set_mtu(struct ifnet
* ifp
, int mtu
, int isdevmtu
)
2457 ifb
= (ifbond_ref
)ifp
->if_private
;
2458 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2459 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2463 ifbond_wait(ifb
, "bond_set_mtu");
2466 if (ifp
->if_private
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2470 bond_get_mtu_values(ifb
, &mtu_min
, &mtu_max
);
2471 if (mtu
> mtu_max
) {
2475 if (mtu
< mtu_min
&& (isdevmtu
== 0 || mtu
!= 0)) {
2476 /* allow SIOCSIFALTMTU to set the mtu to 0 */
2481 new_max
= (mtu
> (int)ifp
->if_mtu
) ? mtu
: (int)ifp
->if_mtu
;
2484 new_max
= (mtu
> ifb
->ifb_altmtu
) ? mtu
: ifb
->ifb_altmtu
;
2486 old_max
= ((int)ifp
->if_mtu
> ifb
->ifb_altmtu
)
2487 ? (int)ifp
->if_mtu
: ifb
->ifb_altmtu
;
2488 if (new_max
!= old_max
) {
2489 /* we can safely walk the list of port without the lock held */
2491 error
= bond_set_mtu_on_ports(ifb
, new_max
);
2493 /* try our best to back out of it */
2494 (void)bond_set_mtu_on_ports(ifb
, old_max
);
2500 ifb
->ifb_altmtu
= mtu
;
2508 ifbond_signal(ifb
, "bond_set_mtu");
2509 ifbond_release(ifb
);
2517 bond_ioctl(struct ifnet
*ifp
, u_int32_t cmd
, void * data
)
2520 struct if_bond_req ibr
;
2521 struct ifaddr
* ifa
;
2524 struct ifmediareq64
*ifmr
;
2525 struct ifnet
* port_ifp
= NULL
;
2526 user_addr_t user_addr
;
2528 if (ifp
->if_type
!= IFT_IEEE8023ADLAG
) {
2529 return (EOPNOTSUPP
);
2531 ifr
= (struct ifreq
*)data
;
2532 ifa
= (struct ifaddr
*)data
;
2536 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
2539 case SIOCGIFMEDIA64
:
2542 ifb
= (ifbond_ref
)ifp
->if_private
;
2543 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2545 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2547 ifmr
= (struct ifmediareq64
*)data
;
2548 ifmr
->ifm_current
= IFM_ETHER
;
2550 ifmr
->ifm_status
= IFM_AVALID
;
2551 ifmr
->ifm_active
= IFM_ETHER
;
2552 ifmr
->ifm_count
= 1;
2553 if (ifb
->ifb_active_lag
!= NULL
) {
2554 ifmr
->ifm_active
= ifb
->ifb_active_lag
->lag_active_media
;
2555 ifmr
->ifm_status
|= IFM_ACTIVE
;
2558 user_addr
= (cmd
== SIOCGIFMEDIA64
)
2559 ? ifmr
->ifm_ifmu
.ifmu_ulist64
2560 : CAST_USER_ADDR_T(ifmr
->ifm_ifmu
.ifmu_ulist32
);
2561 if (user_addr
!= USER_ADDR_NULL
) {
2562 error
= copyout(&ifmr
->ifm_current
,
2569 /* XXX send the SIFMEDIA to all children? Or force autoselect? */
2575 ifb
= (ifbond_ref
)ifp
->if_private
;
2576 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2578 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2581 ifr
->ifr_devmtu
.ifdm_current
= bond_device_mtu(ifp
, ifb
);
2582 bond_get_mtu_values(ifb
, &ifr
->ifr_devmtu
.ifdm_min
,
2583 &ifr
->ifr_devmtu
.ifdm_max
);
2589 ifb
= (ifbond_ref
)ifp
->if_private
;
2590 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2592 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2595 ifr
->ifr_mtu
= ifb
->ifb_altmtu
;
2600 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 1);
2604 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 0);
2608 user_addr
= proc_is64bit(current_proc())
2609 ? ifr
->ifr_data64
: CAST_USER_ADDR_T(ifr
->ifr_data
);
2610 error
= copyin(user_addr
, &ibr
, sizeof(ibr
));
2614 switch (ibr
.ibr_op
) {
2615 case IF_BOND_OP_ADD_INTERFACE
:
2616 case IF_BOND_OP_REMOVE_INTERFACE
:
2617 /* XXX ifunit() needs to return a reference on the ifp */
2618 port_ifp
= ifunit(ibr
.ibr_ibru
.ibru_if_name
);
2619 if (port_ifp
== NULL
) {
2623 if (port_ifp
->if_type
!= IFT_ETHER
) {
2624 error
= EPROTONOSUPPORT
;
2628 case IF_BOND_OP_SET_VERBOSE
:
2637 switch (ibr
.ibr_op
) {
2638 case IF_BOND_OP_ADD_INTERFACE
:
2639 error
= bond_add_interface(ifp
, port_ifp
);
2641 case IF_BOND_OP_REMOVE_INTERFACE
:
2643 ifb
= (ifbond_ref
)ifp
->if_private
;
2644 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2646 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2648 error
= bond_remove_interface(ifb
, port_ifp
);
2651 case IF_BOND_OP_SET_VERBOSE
:
2653 if (g_bond
== NULL
) {
2658 g_bond
->verbose
= ibr
.ibr_ibru
.ibru_int_val
;
2665 user_addr
= proc_is64bit(current_proc())
2666 ? ifr
->ifr_data64
: CAST_USER_ADDR_T(ifr
->ifr_data
);
2667 error
= copyin(user_addr
, &ibr
, sizeof(ibr
));
2671 switch (ibr
.ibr_op
) {
2672 case IF_BOND_OP_GET_STATUS
:
2682 ifb
= (ifbond_ref
)ifp
->if_private
;
2683 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2685 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2687 switch (ibr
.ibr_op
) {
2688 case IF_BOND_OP_GET_STATUS
:
2689 error
= bond_get_status(ifb
, &ibr
, user_addr
);
2700 /* enable/disable promiscuous mode */
2702 error
= bond_set_promisc(ifp
);
2708 error
= bond_setmulti(ifp
);
2717 bond_if_free(struct ifnet
* ifp
)
2725 ifb
= (ifbond_ref
)ifp
->if_private
;
2730 ifp
->if_private
= NULL
;
2731 ifbond_release(ifb
);
2733 dlil_if_release(ifp
);
2738 bond_event(struct ifnet
* port_ifp
, struct kev_msg
* event
)
2740 struct ifnet
* bond_ifp
= NULL
;
2743 struct media_info media_info
;
2745 if (event
->vendor_code
!= KEV_VENDOR_APPLE
2746 || event
->kev_class
!= KEV_NETWORK_CLASS
2747 || event
->kev_subclass
!= KEV_DL_SUBCLASS
) {
2750 switch (event
->event_code
) {
2751 case KEV_DL_IF_DETACHING
:
2753 case KEV_DL_LINK_OFF
:
2754 case KEV_DL_LINK_ON
:
2755 media_info
= interface_media_info(port_ifp
);
2761 p
= bond_lookup_port(port_ifp
);
2766 switch (event
->event_code
) {
2767 case KEV_DL_IF_DETACHING
:
2768 bond_remove_interface(p
->po_bond
, p
->po_ifp
);
2770 case KEV_DL_LINK_OFF
:
2771 case KEV_DL_LINK_ON
:
2772 p
->po_media_info
= media_info
;
2773 if (p
->po_enabled
) {
2774 bondport_link_status_changed(p
);
2778 /* generate a link-event */
2779 if (ifbond_selection(p
->po_bond
)) {
2780 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
2783 /* XXX need to take a reference on bond_ifp */
2784 bond_ifp
= p
->po_bond
->ifb_ifp
;
2787 if (bond_ifp
!= NULL
) {
2788 interface_link_event(bond_ifp
, event_code
);
2794 interface_link_event(struct ifnet
* ifp
, u_long event_code
)
2797 struct kern_event_msg header
;
2799 char if_name
[IFNAMSIZ
];
2802 event
.header
.total_size
= sizeof(event
);
2803 event
.header
.vendor_code
= KEV_VENDOR_APPLE
;
2804 event
.header
.kev_class
= KEV_NETWORK_CLASS
;
2805 event
.header
.kev_subclass
= KEV_DL_SUBCLASS
;
2806 event
.header
.event_code
= event_code
;
2807 event
.header
.event_data
[0] = ifp
->if_family
;
2808 event
.unit
= (u_long
) ifp
->if_unit
;
2809 strncpy(event
.if_name
, ifp
->if_name
, IFNAMSIZ
);
2810 dlil_event(ifp
, &event
.header
);
2815 * Function: bond_attach_protocol
2817 * Attach a DLIL protocol to the interface.
2819 * The ethernet demux special cases to always return PF_BOND if the
2820 * interface is bonded. That means we receive all traffic from that
2821 * interface without passing any of the traffic to any other attached
2825 bond_attach_protocol(struct ifnet
*ifp
)
2828 struct dlil_proto_reg_str reg
;
2830 bzero(®
, sizeof(reg
));
2831 TAILQ_INIT(®
.demux_desc_head
);
2832 reg
.interface_family
= ifp
->if_family
;
2833 reg
.unit_number
= ifp
->if_unit
;
2834 reg
.input
= bond_input
;
2835 reg
.event
= bond_event
;
2836 reg
.protocol_family
= PF_BOND
;
2838 error
= dlil_attach_protocol(®
);
2840 printf("bond over %s%d: dlil_attach_protocol failed, %d\n",
2841 ifp
->if_name
, ifp
->if_unit
, error
);
2847 * Function: bond_detach_protocol
2849 * Detach our DLIL protocol from an interface
2852 bond_detach_protocol(struct ifnet
*ifp
)
2856 error
= dlil_detach_protocol(ifp
, PF_BOND
);
2858 printf("bond over %s%d: dlil_detach_protocol failed, %d\n",
2859 ifp
->if_name
, ifp
->if_unit
, error
);
2865 * DLIL interface family functions
2867 extern int ether_add_if(struct ifnet
*ifp
);
2868 extern int ether_del_if(struct ifnet
*ifp
);
2869 extern int ether_init_if(struct ifnet
*ifp
);
2870 extern int ether_add_proto_old(struct ifnet
*ifp
, u_long protocol_family
,
2871 struct ddesc_head_str
*desc_head
);
2873 extern int ether_attach_inet(struct ifnet
*ifp
, u_long protocol_family
);
2874 extern int ether_detach_inet(struct ifnet
*ifp
, u_long protocol_family
);
2875 extern int ether_attach_inet6(struct ifnet
*ifp
, u_long protocol_family
);
2876 extern int ether_detach_inet6(struct ifnet
*ifp
, u_long protocol_family
);
2878 __private_extern__
int
2879 bond_family_init(void)
2882 struct dlil_ifmod_reg_str ifmod_reg
;
2884 bzero(&ifmod_reg
, sizeof(ifmod_reg
));
2885 ifmod_reg
.add_if
= ether_add_if
;
2886 ifmod_reg
.del_if
= ether_del_if
;
2887 ifmod_reg
.init_if
= NULL
;
2888 ifmod_reg
.add_proto
= ether_add_proto_old
;
2889 ifmod_reg
.del_proto
= ether_del_proto
;
2890 ifmod_reg
.ifmod_ioctl
= ether_ioctl
;
2891 ifmod_reg
.shutdown
= NULL
;
2893 if (dlil_reg_if_modules(APPLE_IF_FAM_BOND
, &ifmod_reg
)) {
2894 printf("WARNING: bond_family_init -- "
2895 "Can't register if family modules\n");
2900 error
= dlil_reg_proto_module(PF_INET
, APPLE_IF_FAM_BOND
,
2904 printf("bond: dlil_reg_proto_module failed for AF_INET6 error=%d\n",
2909 error
= dlil_reg_proto_module(PF_INET6
, APPLE_IF_FAM_BOND
,
2911 ether_detach_inet6
);
2913 printf("bond: dlil_reg_proto_module failed for AF_INET6 error=%d\n",
2917 bond_clone_attach();
2929 ** LACP ifbond_list routines
2932 ifbond_list_find_moved_port(bondport_ref rx_port
,
2933 const lacp_actor_partner_tlv_ref atlv
)
2937 partner_state_ref ps
;
2940 TAILQ_FOREACH(bond
, &g_bond
->ifbond_list
, ifb_bond_list
) {
2941 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
2944 /* no point in comparing against ourselves */
2947 if (p
->po_receive_state
!= ReceiveState_PORT_DISABLED
) {
2948 /* it's not clear that we should be checking this */
2951 ps
= &p
->po_partner_state
;
2952 if (lacp_actor_partner_state_defaulted(ps
->ps_state
)) {
2955 ps_li
= &ps
->ps_lag_info
;
2956 if (ps
->ps_port
== lacp_actor_partner_tlv_get_port(atlv
)
2957 && bcmp(&ps_li
->li_system
, atlv
->lap_system
,
2958 sizeof(ps_li
->li_system
)) == 0) {
2959 if (g_bond
->verbose
) {
2960 timestamp_printf("System " EA_FORMAT
2961 " Port 0x%x moved from %s to %s\n",
2962 EA_LIST(&ps_li
->li_system
), ps
->ps_port
,
2963 bondport_get_name(p
),
2964 bondport_get_name(rx_port
));
2974 ** LACP ifbond, LAG routines
2978 ifbond_selection(ifbond_ref bond
)
2980 int all_ports_ready
= 0;
2981 int active_media
= 0;
2983 int lag_changed
= 0;
2987 lag
= ifbond_find_best_LAG(bond
, &active_media
);
2988 if (lag
!= bond
->ifb_active_lag
) {
2989 if (bond
->ifb_active_lag
!= NULL
) {
2990 ifbond_deactivate_LAG(bond
, bond
->ifb_active_lag
);
2991 bond
->ifb_active_lag
= NULL
;
2993 bond
->ifb_active_lag
= lag
;
2995 ifbond_activate_LAG(bond
, lag
, active_media
);
2999 else if (lag
!= NULL
) {
3000 if (lag
->lag_active_media
!= active_media
) {
3001 if (g_bond
->verbose
) {
3002 timestamp_printf("LAG PORT SPEED CHANGED from %d to %d\n",
3003 link_speed(lag
->lag_active_media
),
3004 link_speed(active_media
));
3006 ifbond_deactivate_LAG(bond
, lag
);
3007 ifbond_activate_LAG(bond
, lag
, active_media
);
3012 port_speed
= link_speed(active_media
);
3013 all_ports_ready
= ifbond_all_ports_ready(bond
);
3015 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3016 if (lag
!= NULL
&& p
->po_lag
== lag
3017 && media_speed(&p
->po_media_info
) == port_speed
3018 && (p
->po_mux_state
== MuxState_DETACHED
3019 || p
->po_selected
== SelectedState_SELECTED
3020 || p
->po_selected
== SelectedState_STANDBY
)
3021 && bondport_aggregatable(p
)) {
3022 if (bond
->ifb_max_active
> 0) {
3023 if (lag
->lag_selected_port_count
< bond
->ifb_max_active
) {
3024 if (p
->po_selected
== SelectedState_STANDBY
3025 || p
->po_selected
== SelectedState_UNSELECTED
) {
3026 bondport_set_selected(p
, SelectedState_SELECTED
);
3029 else if (p
->po_selected
== SelectedState_UNSELECTED
) {
3030 bondport_set_selected(p
, SelectedState_STANDBY
);
3034 bondport_set_selected(p
, SelectedState_SELECTED
);
3037 if (bondport_flags_selected_changed(p
)) {
3038 bondport_flags_clear_selected_changed(p
);
3039 bondport_mux_machine(p
, LAEventSelectedChange
, NULL
);
3042 && bondport_flags_ready(p
)
3043 && p
->po_mux_state
== MuxState_WAITING
) {
3044 bondport_mux_machine(p
, LAEventReady
, NULL
);
3046 bondport_transmit_machine(p
, LAEventStart
, NULL
);
3048 return (lag_changed
);
3052 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
)
3054 int best_active
= 0;
3055 LAG_ref best_lag
= NULL
;
3060 if (bond
->ifb_active_lag
!= NULL
) {
3061 best_lag
= bond
->ifb_active_lag
;
3062 best_count
= LAG_get_aggregatable_port_count(best_lag
, &best_active
);
3063 if (bond
->ifb_max_active
> 0
3064 && best_count
> bond
->ifb_max_active
) {
3065 best_count
= bond
->ifb_max_active
;
3067 best_speed
= link_speed(best_active
);
3069 TAILQ_FOREACH(lag
, &bond
->ifb_lag_list
, lag_list
) {
3074 if (lag
== bond
->ifb_active_lag
) {
3075 /* we've already computed it */
3078 count
= LAG_get_aggregatable_port_count(lag
, &active
);
3082 if (bond
->ifb_max_active
> 0
3083 && count
> bond
->ifb_max_active
) {
3084 /* if there's a limit, don't count extra links */
3085 count
= bond
->ifb_max_active
;
3087 speed
= link_speed(active
);
3088 if ((count
* speed
) > (best_count
* best_speed
)) {
3091 best_active
= active
;
3095 if (best_count
== 0) {
3098 *active_media
= best_active
;
3103 ifbond_deactivate_LAG(__unused ifbond_ref bond
, LAG_ref lag
)
3107 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3108 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3114 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
)
3119 if (bond
->ifb_max_active
> 0) {
3120 need
= bond
->ifb_max_active
;
3122 lag
->lag_active_media
= active_media
;
3123 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3124 if (bondport_aggregatable(p
) == 0) {
3125 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3127 else if (media_speed(&p
->po_media_info
) != link_speed(active_media
)) {
3128 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3130 else if (p
->po_mux_state
== MuxState_DETACHED
) {
3131 if (bond
->ifb_max_active
> 0) {
3133 bondport_set_selected(p
, SelectedState_SELECTED
);
3137 bondport_set_selected(p
, SelectedState_STANDBY
);
3141 bondport_set_selected(p
, SelectedState_SELECTED
);
3145 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3153 ifbond_set_max_active(ifbond_ref bond
, int max_active
)
3155 LAG_ref lag
= bond
->ifb_active_lag
;
3157 bond
->ifb_max_active
= max_active
;
3158 if (bond
->ifb_max_active
<= 0 || lag
== NULL
) {
3161 if (lag
->lag_selected_port_count
> bond
->ifb_max_active
) {
3165 remove_count
= lag
->lag_selected_port_count
- bond
->ifb_max_active
;
3166 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3167 if (p
->po_selected
== SelectedState_SELECTED
) {
3168 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3170 if (remove_count
== 0) {
3181 ifbond_all_ports_ready(ifbond_ref bond
)
3186 if (bond
->ifb_active_lag
== NULL
) {
3189 TAILQ_FOREACH(p
, &bond
->ifb_active_lag
->lag_port_list
, po_lag_port_list
) {
3190 if (p
->po_mux_state
== MuxState_WAITING
3191 && p
->po_selected
== SelectedState_SELECTED
) {
3192 if (bondport_flags_ready(p
) == 0) {
3196 /* note that there was at least one ready port */
3203 ifbond_all_ports_attached(ifbond_ref bond
, bondport_ref this_port
)
3207 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3208 if (this_port
== p
) {
3211 if (bondport_flags_mux_attached(p
) == 0) {
3219 ifbond_get_LAG_matching_port(ifbond_ref bond
, bondport_ref p
)
3223 TAILQ_FOREACH(lag
, &bond
->ifb_lag_list
, lag_list
) {
3224 if (bcmp(&lag
->lag_info
, &p
->po_partner_state
.ps_lag_info
,
3225 sizeof(lag
->lag_info
)) == 0) {
3233 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
)
3243 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3244 if (bondport_aggregatable(p
)) {
3247 this_speed
= media_speed(&p
->po_media_info
);
3248 if (this_speed
== 0) {
3251 if (this_speed
> speed
) {
3252 active
= p
->po_media_info
.mi_active
;
3256 else if (this_speed
== speed
) {
3261 *active_media
= active
;
3267 ** LACP bondport routines
3270 bondport_link_status_changed(bondport_ref p
)
3272 ifbond_ref bond
= p
->po_bond
;
3274 if (g_bond
->verbose
) {
3275 if (media_active(&p
->po_media_info
)) {
3276 timestamp_printf("[%s] Link UP %d Mbit/s %s duplex\n",
3277 bondport_get_name(p
),
3278 media_speed(&p
->po_media_info
),
3279 media_full_duplex(&p
->po_media_info
)
3283 timestamp_printf("[%s] Link DOWN\n", bondport_get_name(p
));
3286 if (media_active(&p
->po_media_info
)
3287 && bond
->ifb_active_lag
!= NULL
3288 && p
->po_lag
== bond
->ifb_active_lag
3289 && p
->po_selected
!= SelectedState_UNSELECTED
) {
3290 if (media_speed(&p
->po_media_info
) != p
->po_lag
->lag_active_media
) {
3291 if (g_bond
->verbose
) {
3292 timestamp_printf("[%s] Port speed %d differs from LAG %d\n",
3293 bondport_get_name(p
),
3294 media_speed(&p
->po_media_info
),
3295 link_speed(p
->po_lag
->lag_active_media
));
3297 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3300 bondport_receive_machine(p
, LAEventMediaChange
, NULL
);
3301 bondport_mux_machine(p
, LAEventMediaChange
, NULL
);
3302 bondport_periodic_transmit_machine(p
, LAEventMediaChange
, NULL
);
3308 bondport_aggregatable(bondport_ref p
)
3310 partner_state_ref ps
= &p
->po_partner_state
;
3312 if (lacp_actor_partner_state_aggregatable(p
->po_actor_state
) == 0
3313 || lacp_actor_partner_state_aggregatable(ps
->ps_state
) == 0) {
3314 /* we and/or our partner are individual */
3317 if (p
->po_lag
== NULL
) {
3320 switch (p
->po_receive_state
) {
3322 if (g_bond
->verbose
) {
3323 timestamp_printf("[%s] Port is not selectable\n",
3324 bondport_get_name(p
));
3327 case ReceiveState_CURRENT
:
3328 case ReceiveState_EXPIRED
:
3335 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
)
3337 LAG_info_ref lag_li
;
3338 partner_state_ref ps
;
3341 ps
= &p
->po_partner_state
;
3342 ps_li
= &ps
->ps_lag_info
;
3343 lag_li
= &lag
->lag_info
;
3344 if (ps_li
->li_system_priority
== lag_li
->li_system_priority
3345 && ps_li
->li_key
== lag_li
->li_key
3346 && (bcmp(&ps_li
->li_system
, &lag_li
->li_system
,
3347 sizeof(lag_li
->li_system
))
3355 bondport_remove_from_LAG(bondport_ref p
)
3358 ifbond_ref bond
= p
->po_bond
;
3359 LAG_ref lag
= p
->po_lag
;
3364 TAILQ_REMOVE(&lag
->lag_port_list
, p
, po_lag_port_list
);
3365 if (g_bond
->verbose
) {
3366 timestamp_printf("[%s] Removed from LAG (0x%04x," EA_FORMAT
3368 bondport_get_name(p
),
3369 lag
->lag_info
.li_system_priority
,
3370 EA_LIST(&lag
->lag_info
.li_system
),
3371 lag
->lag_info
.li_key
);
3374 lag
->lag_port_count
--;
3375 if (lag
->lag_port_count
> 0) {
3376 return (bond
->ifb_active_lag
== lag
);
3378 if (g_bond
->verbose
) {
3379 timestamp_printf("Key 0x%04x: LAG Released (%04x," EA_FORMAT
3382 lag
->lag_info
.li_system_priority
,
3383 EA_LIST(&lag
->lag_info
.li_system
),
3384 lag
->lag_info
.li_key
);
3386 TAILQ_REMOVE(&bond
->ifb_lag_list
, lag
, lag_list
);
3387 if (bond
->ifb_active_lag
== lag
) {
3388 bond
->ifb_active_lag
= NULL
;
3392 return (active_lag
);
3396 bondport_add_to_LAG(bondport_ref p
, LAG_ref lag
)
3398 TAILQ_INSERT_TAIL(&lag
->lag_port_list
, p
, po_lag_port_list
);
3400 lag
->lag_port_count
++;
3401 if (g_bond
->verbose
) {
3402 timestamp_printf("[%s] Added to LAG (0x%04x," EA_FORMAT
"0x%04x)\n",
3403 bondport_get_name(p
),
3404 lag
->lag_info
.li_system_priority
,
3405 EA_LIST(&lag
->lag_info
.li_system
),
3406 lag
->lag_info
.li_key
);
3412 bondport_assign_to_LAG(bondport_ref p
)
3414 ifbond_ref bond
= p
->po_bond
;
3417 if (lacp_actor_partner_state_defaulted(p
->po_actor_state
)) {
3418 bondport_remove_from_LAG(p
);
3423 if (bondport_matches_LAG(p
, lag
)) {
3427 bondport_remove_from_LAG(p
);
3429 lag
= ifbond_get_LAG_matching_port(bond
, p
);
3431 bondport_add_to_LAG(p
, lag
);
3434 lag
= (LAG_ref
)_MALLOC(sizeof(*lag
), M_BOND
, M_WAITOK
);
3435 TAILQ_INIT(&lag
->lag_port_list
);
3436 lag
->lag_port_count
= 0;
3437 lag
->lag_selected_port_count
= 0;
3438 lag
->lag_info
= p
->po_partner_state
.ps_lag_info
;
3439 TAILQ_INSERT_TAIL(&bond
->ifb_lag_list
, lag
, lag_list
);
3440 if (g_bond
->verbose
) {
3441 timestamp_printf("Key 0x%04x: LAG Created (0x%04x," EA_FORMAT
3444 lag
->lag_info
.li_system_priority
,
3445 EA_LIST(&lag
->lag_info
.li_system
),
3446 lag
->lag_info
.li_key
);
3448 bondport_add_to_LAG(p
, lag
);
3453 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
)
3455 bondport_ref moved_port
;
3458 = ifbond_list_find_moved_port(p
, (const lacp_actor_partner_tlv_ref
)
3459 &in_lacpdu_p
->la_actor_tlv
);
3460 if (moved_port
!= NULL
) {
3461 bondport_receive_machine(moved_port
, LAEventPortMoved
, NULL
);
3463 bondport_receive_machine(p
, LAEventPacket
, in_lacpdu_p
);
3464 bondport_mux_machine(p
, LAEventPacket
, in_lacpdu_p
);
3465 bondport_periodic_transmit_machine(p
, LAEventPacket
, in_lacpdu_p
);
3470 bondport_set_selected(bondport_ref p
, SelectedState s
)
3472 if (s
!= p
->po_selected
) {
3473 ifbond_ref bond
= p
->po_bond
;
3474 LAG_ref lag
= p
->po_lag
;
3476 bondport_flags_set_selected_changed(p
);
3477 if (lag
!= NULL
&& bond
->ifb_active_lag
== lag
) {
3478 if (p
->po_selected
== SelectedState_SELECTED
) {
3479 lag
->lag_selected_port_count
--;
3481 else if (s
== SelectedState_SELECTED
) {
3482 lag
->lag_selected_port_count
++;
3484 if (g_bond
->verbose
) {
3485 timestamp_printf("[%s] SetSelected: %s (was %s)\n",
3486 bondport_get_name(p
),
3487 SelectedStateString(s
),
3488 SelectedStateString(p
->po_selected
));
3501 bondport_UpdateDefaultSelected(bondport_ref p
)
3503 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3508 bondport_RecordDefault(bondport_ref p
)
3510 bzero(&p
->po_partner_state
, sizeof(p
->po_partner_state
));
3512 = lacp_actor_partner_state_set_defaulted(p
->po_actor_state
);
3513 bondport_assign_to_LAG(p
);
3518 bondport_UpdateSelected(bondport_ref p
, lacpdu_ref lacpdu_p
)
3520 lacp_actor_partner_tlv_ref actor
;
3521 partner_state_ref ps
;
3524 /* compare the PDU's Actor information to our Partner state */
3525 actor
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_actor_tlv
;
3526 ps
= &p
->po_partner_state
;
3527 ps_li
= &ps
->ps_lag_info
;
3528 if (lacp_actor_partner_tlv_get_port(actor
) != ps
->ps_port
3529 || (lacp_actor_partner_tlv_get_port_priority(actor
)
3530 != ps
->ps_port_priority
)
3531 || bcmp(actor
->lap_system
, &ps_li
->li_system
, sizeof(ps_li
->li_system
))
3532 || (lacp_actor_partner_tlv_get_system_priority(actor
)
3533 != ps_li
->li_system_priority
)
3534 || (lacp_actor_partner_tlv_get_key(actor
) != ps_li
->li_key
)
3535 || (lacp_actor_partner_state_aggregatable(actor
->lap_state
)
3536 != lacp_actor_partner_state_aggregatable(ps
->ps_state
))) {
3537 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3538 if (g_bond
->verbose
) {
3539 timestamp_printf("[%s] updateSelected UNSELECTED\n",
3540 bondport_get_name(p
));
3547 bondport_RecordPDU(bondport_ref p
, lacpdu_ref lacpdu_p
)
3549 lacp_actor_partner_tlv_ref actor
;
3550 ifbond_ref bond
= p
->po_bond
;
3551 int lacp_maintain
= 0;
3552 partner_state_ref ps
;
3553 lacp_actor_partner_tlv_ref partner
;
3556 /* copy the PDU's Actor information into our Partner state */
3557 actor
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_actor_tlv
;
3558 ps
= &p
->po_partner_state
;
3559 ps_li
= &ps
->ps_lag_info
;
3560 ps
->ps_port
= lacp_actor_partner_tlv_get_port(actor
);
3561 ps
->ps_port_priority
= lacp_actor_partner_tlv_get_port_priority(actor
);
3562 ps_li
->li_system
= *((lacp_system_ref
)actor
->lap_system
);
3563 ps_li
->li_system_priority
3564 = lacp_actor_partner_tlv_get_system_priority(actor
);
3565 ps_li
->li_key
= lacp_actor_partner_tlv_get_key(actor
);
3566 ps
->ps_state
= lacp_actor_partner_state_set_out_of_sync(actor
->lap_state
);
3568 = lacp_actor_partner_state_set_not_defaulted(p
->po_actor_state
);
3570 /* compare the PDU's Partner information to our own information */
3571 partner
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_partner_tlv
;
3573 if (lacp_actor_partner_state_active_lacp(ps
->ps_state
)
3574 || (lacp_actor_partner_state_active_lacp(p
->po_actor_state
)
3575 && lacp_actor_partner_state_active_lacp(partner
->lap_state
))) {
3576 if (g_bond
->verbose
) {
3577 timestamp_printf("[%s] recordPDU: LACP will maintain\n",
3578 bondport_get_name(p
));
3582 if ((lacp_actor_partner_tlv_get_port(partner
)
3583 == bondport_get_index(p
))
3584 && lacp_actor_partner_tlv_get_port_priority(partner
) == p
->po_priority
3585 && bcmp(partner
->lap_system
, &g_bond
->system
,
3586 sizeof(g_bond
->system
)) == 0
3587 && (lacp_actor_partner_tlv_get_system_priority(partner
)
3588 == g_bond
->system_priority
)
3589 && lacp_actor_partner_tlv_get_key(partner
) == bond
->ifb_key
3590 && (lacp_actor_partner_state_aggregatable(partner
->lap_state
)
3591 == lacp_actor_partner_state_aggregatable(p
->po_actor_state
))
3592 && lacp_actor_partner_state_in_sync(actor
->lap_state
)
3594 ps
->ps_state
= lacp_actor_partner_state_set_in_sync(ps
->ps_state
);
3595 if (g_bond
->verbose
) {
3596 timestamp_printf("[%s] recordPDU: LACP partner in sync\n",
3597 bondport_get_name(p
));
3600 else if (lacp_actor_partner_state_aggregatable(actor
->lap_state
) == 0
3601 && lacp_actor_partner_state_in_sync(actor
->lap_state
)
3603 ps
->ps_state
= lacp_actor_partner_state_set_in_sync(ps
->ps_state
);
3604 if (g_bond
->verbose
) {
3605 timestamp_printf("[%s] recordPDU: LACP partner in sync (ind)\n",
3606 bondport_get_name(p
));
3609 bondport_assign_to_LAG(p
);
3613 static __inline__ lacp_actor_partner_state
3614 updateNTTBits(lacp_actor_partner_state s
)
3616 return (s
& (LACP_ACTOR_PARTNER_STATE_LACP_ACTIVITY
3617 | LACP_ACTOR_PARTNER_STATE_LACP_TIMEOUT
3618 | LACP_ACTOR_PARTNER_STATE_AGGREGATION
3619 | LACP_ACTOR_PARTNER_STATE_SYNCHRONIZATION
));
3623 bondport_UpdateNTT(bondport_ref p
, lacpdu_ref lacpdu_p
)
3625 ifbond_ref bond
= p
->po_bond
;
3626 lacp_actor_partner_tlv_ref partner
;
3628 /* compare the PDU's Actor information to our Partner state */
3629 partner
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_partner_tlv
;
3630 if ((lacp_actor_partner_tlv_get_port(partner
) != bondport_get_index(p
))
3631 || lacp_actor_partner_tlv_get_port_priority(partner
) != p
->po_priority
3632 || bcmp(partner
->lap_system
, &g_bond
->system
, sizeof(g_bond
->system
))
3633 || (lacp_actor_partner_tlv_get_system_priority(partner
)
3634 != g_bond
->system_priority
)
3635 || lacp_actor_partner_tlv_get_key(partner
) != bond
->ifb_key
3636 || (updateNTTBits(partner
->lap_state
)
3637 != updateNTTBits(p
->po_actor_state
))) {
3638 bondport_flags_set_ntt(p
);
3639 if (g_bond
->verbose
) {
3640 timestamp_printf("[%s] updateNTT: Need To Transmit\n",
3641 bondport_get_name(p
));
3648 bondport_AttachMuxToAggregator(bondport_ref p
)
3650 if (bondport_flags_mux_attached(p
) == 0) {
3651 if (g_bond
->verbose
) {
3652 timestamp_printf("[%s] Attached Mux To Aggregator\n",
3653 bondport_get_name(p
));
3655 bondport_flags_set_mux_attached(p
);
3661 bondport_DetachMuxFromAggregator(bondport_ref p
)
3663 if (bondport_flags_mux_attached(p
)) {
3664 if (g_bond
->verbose
) {
3665 timestamp_printf("[%s] Detached Mux From Aggregator\n",
3666 bondport_get_name(p
));
3668 bondport_flags_clear_mux_attached(p
);
3674 bondport_enable_distributing(bondport_ref p
)
3676 if (bondport_flags_distributing(p
) == 0) {
3677 ifbond_ref bond
= p
->po_bond
;
3679 bond
->ifb_distributing_array
[bond
->ifb_distributing_count
++] = p
;
3680 if (g_bond
->verbose
) {
3681 timestamp_printf("[%s] Distribution Enabled\n",
3682 bondport_get_name(p
));
3684 bondport_flags_set_distributing(p
);
3690 bondport_disable_distributing(bondport_ref p
)
3692 if (bondport_flags_distributing(p
)) {
3693 bondport_ref
* array
;
3699 array
= bond
->ifb_distributing_array
;
3700 count
= bond
->ifb_distributing_count
;
3701 for (i
= 0; i
< count
; i
++) {
3702 if (array
[i
] == p
) {
3705 for (j
= i
; j
< (count
- 1); j
++) {
3706 array
[j
] = array
[j
+ 1];
3711 bond
->ifb_distributing_count
--;
3712 if (g_bond
->verbose
) {
3713 timestamp_printf("[%s] Distribution Disabled\n",
3714 bondport_get_name(p
));
3716 bondport_flags_clear_distributing(p
);
3722 ** Receive machine functions
3725 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
3728 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
3731 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
3734 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
3737 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
3740 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
3744 bondport_receive_machine_event(bondport_ref p
, LAEvent event
,
3747 switch (p
->po_receive_state
) {
3748 case ReceiveState_none
:
3749 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
3751 case ReceiveState_INITIALIZE
:
3752 bondport_receive_machine_initialize(p
, event
, event_data
);
3754 case ReceiveState_PORT_DISABLED
:
3755 bondport_receive_machine_port_disabled(p
, event
, event_data
);
3757 case ReceiveState_EXPIRED
:
3758 bondport_receive_machine_expired(p
, event
, event_data
);
3760 case ReceiveState_LACP_DISABLED
:
3761 bondport_receive_machine_lacp_disabled(p
, event
, event_data
);
3763 case ReceiveState_DEFAULTED
:
3764 bondport_receive_machine_defaulted(p
, event
, event_data
);
3766 case ReceiveState_CURRENT
:
3767 bondport_receive_machine_current(p
, event
, event_data
);
3776 bondport_receive_machine(bondport_ref p
, LAEvent event
,
3781 if (p
->po_receive_state
!= ReceiveState_LACP_DISABLED
) {
3782 bondport_receive_machine_current(p
, event
, event_data
);
3785 case LAEventMediaChange
:
3786 if (media_active(&p
->po_media_info
)) {
3787 switch (p
->po_receive_state
) {
3788 case ReceiveState_PORT_DISABLED
:
3789 case ReceiveState_LACP_DISABLED
:
3790 bondport_receive_machine_port_disabled(p
, LAEventMediaChange
, NULL
);
3797 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
3801 bondport_receive_machine_event(p
, event
, event_data
);
3808 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
3809 __unused
void * event_data
)
3813 devtimer_cancel(p
->po_current_while_timer
);
3814 if (g_bond
->verbose
) {
3815 timestamp_printf("[%s] Receive INITIALIZE\n",
3816 bondport_get_name(p
));
3818 p
->po_receive_state
= ReceiveState_INITIALIZE
;
3819 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3820 bondport_RecordDefault(p
);
3822 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
3823 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
3832 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
3833 __unused
void * event_data
)
3835 partner_state_ref ps
;
3839 devtimer_cancel(p
->po_current_while_timer
);
3840 if (g_bond
->verbose
) {
3841 timestamp_printf("[%s] Receive PORT_DISABLED\n",
3842 bondport_get_name(p
));
3844 p
->po_receive_state
= ReceiveState_PORT_DISABLED
;
3845 ps
= &p
->po_partner_state
;
3846 ps
->ps_state
= lacp_actor_partner_state_set_out_of_sync(ps
->ps_state
);
3848 case LAEventMediaChange
:
3849 if (media_active(&p
->po_media_info
)) {
3850 if (media_full_duplex(&p
->po_media_info
)) {
3851 bondport_receive_machine_expired(p
, LAEventStart
, NULL
);
3854 bondport_receive_machine_lacp_disabled(p
, LAEventStart
, NULL
);
3857 else if (p
->po_selected
== SelectedState_SELECTED
) {
3860 if (g_bond
->verbose
) {
3861 timestamp_printf("[%s] Receive PORT_DISABLED: "
3862 "link timer started\n",
3863 bondport_get_name(p
));
3867 devtimer_set_relative(p
->po_current_while_timer
, tv
,
3868 (devtimer_timeout_func
)
3869 bondport_receive_machine_port_disabled
,
3870 (void *)LAEventTimeout
, NULL
);
3872 else if (p
->po_selected
== SelectedState_STANDBY
) {
3873 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3876 case LAEventTimeout
:
3877 if (p
->po_selected
== SelectedState_SELECTED
) {
3878 if (g_bond
->verbose
) {
3879 timestamp_printf("[%s] Receive PORT_DISABLED: "
3880 "link timer completed, marking UNSELECTED\n",
3881 bondport_get_name(p
));
3883 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3886 case LAEventPortMoved
:
3887 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
3896 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
3897 __unused
void * event_data
)
3899 lacp_actor_partner_state s
;
3904 devtimer_cancel(p
->po_current_while_timer
);
3905 if (g_bond
->verbose
) {
3906 timestamp_printf("[%s] Receive EXPIRED\n",
3907 bondport_get_name(p
));
3909 p
->po_receive_state
= ReceiveState_EXPIRED
;
3910 s
= p
->po_partner_state
.ps_state
;
3911 s
= lacp_actor_partner_state_set_out_of_sync(s
);
3912 s
= lacp_actor_partner_state_set_short_timeout(s
);
3913 p
->po_partner_state
.ps_state
= s
;
3915 = lacp_actor_partner_state_set_expired(p
->po_actor_state
);
3916 /* start current_while timer */
3917 tv
.tv_sec
= LACP_SHORT_TIMEOUT_TIME
;
3919 devtimer_set_relative(p
->po_current_while_timer
, tv
,
3920 (devtimer_timeout_func
)
3921 bondport_receive_machine_expired
,
3922 (void *)LAEventTimeout
, NULL
);
3925 case LAEventTimeout
:
3926 bondport_receive_machine_defaulted(p
, LAEventStart
, NULL
);
3935 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
3936 __unused
void * event_data
)
3938 partner_state_ref ps
;
3941 devtimer_cancel(p
->po_current_while_timer
);
3942 if (g_bond
->verbose
) {
3943 timestamp_printf("[%s] Receive LACP_DISABLED\n",
3944 bondport_get_name(p
));
3946 p
->po_receive_state
= ReceiveState_LACP_DISABLED
;
3947 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3948 bondport_RecordDefault(p
);
3949 ps
= &p
->po_partner_state
;
3950 ps
->ps_state
= lacp_actor_partner_state_set_individual(ps
->ps_state
);
3952 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
3961 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
3962 __unused
void * event_data
)
3966 devtimer_cancel(p
->po_current_while_timer
);
3967 if (g_bond
->verbose
) {
3968 timestamp_printf("[%s] Receive DEFAULTED\n",
3969 bondport_get_name(p
));
3971 p
->po_receive_state
= ReceiveState_DEFAULTED
;
3972 bondport_UpdateDefaultSelected(p
);
3973 bondport_RecordDefault(p
);
3975 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
3984 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
3987 partner_state_ref ps
;
3992 devtimer_cancel(p
->po_current_while_timer
);
3993 if (g_bond
->verbose
) {
3994 timestamp_printf("[%s] Receive CURRENT\n",
3995 bondport_get_name(p
));
3997 p
->po_receive_state
= ReceiveState_CURRENT
;
3998 bondport_UpdateSelected(p
, event_data
);
3999 bondport_UpdateNTT(p
, event_data
);
4000 bondport_RecordPDU(p
, event_data
);
4002 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4003 bondport_assign_to_LAG(p
);
4004 /* start current_while timer */
4005 ps
= &p
->po_partner_state
;
4006 if (lacp_actor_partner_state_short_timeout(ps
->ps_state
)) {
4007 tv
.tv_sec
= LACP_SHORT_TIMEOUT_TIME
;
4010 tv
.tv_sec
= LACP_LONG_TIMEOUT_TIME
;
4013 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4014 (devtimer_timeout_func
)
4015 bondport_receive_machine_current
,
4016 (void *)LAEventTimeout
, NULL
);
4018 case LAEventTimeout
:
4019 bondport_receive_machine_expired(p
, LAEventStart
, NULL
);
4028 ** Periodic Transmission machine
4032 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
4033 __unused
void * event_data
)
4036 partner_state_ref ps
;
4041 if (g_bond
->verbose
) {
4042 timestamp_printf("[%s] periodic_transmit Start\n",
4043 bondport_get_name(p
));
4046 case LAEventMediaChange
:
4047 devtimer_cancel(p
->po_periodic_timer
);
4048 p
->po_periodic_interval
= 0;
4049 if (media_active(&p
->po_media_info
) == 0
4050 || media_full_duplex(&p
->po_media_info
) == 0) {
4054 /* Neither Partner nor Actor are LACP Active, no periodic tx */
4055 ps
= &p
->po_partner_state
;
4056 if (lacp_actor_partner_state_active_lacp(p
->po_actor_state
) == 0
4057 && (lacp_actor_partner_state_active_lacp(ps
->ps_state
)
4059 devtimer_cancel(p
->po_periodic_timer
);
4060 p
->po_periodic_interval
= 0;
4063 if (lacp_actor_partner_state_short_timeout(ps
->ps_state
)) {
4064 interval
= LACP_FAST_PERIODIC_TIME
;
4067 interval
= LACP_SLOW_PERIODIC_TIME
;
4069 if (p
->po_periodic_interval
!= interval
) {
4070 if (interval
== LACP_FAST_PERIODIC_TIME
4071 && p
->po_periodic_interval
== LACP_SLOW_PERIODIC_TIME
) {
4072 if (g_bond
->verbose
) {
4073 timestamp_printf("[%s] periodic_transmit:"
4074 " Need To Transmit\n",
4075 bondport_get_name(p
));
4077 bondport_flags_set_ntt(p
);
4079 p
->po_periodic_interval
= interval
;
4081 tv
.tv_sec
= interval
;
4082 devtimer_set_relative(p
->po_periodic_timer
, tv
,
4083 (devtimer_timeout_func
)
4084 bondport_periodic_transmit_machine
,
4085 (void *)LAEventTimeout
, NULL
);
4086 if (g_bond
->verbose
) {
4087 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4088 bondport_get_name(p
),
4089 p
->po_periodic_interval
);
4093 case LAEventTimeout
:
4094 bondport_flags_set_ntt(p
);
4095 tv
.tv_sec
= p
->po_periodic_interval
;
4097 devtimer_set_relative(p
->po_periodic_timer
, tv
, (devtimer_timeout_func
)
4098 bondport_periodic_transmit_machine
,
4099 (void *)LAEventTimeout
, NULL
);
4100 if (g_bond
->verbose
> 1) {
4101 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4102 bondport_get_name(p
), p
->po_periodic_interval
);
4115 bondport_can_transmit(bondport_ref p
, int32_t current_secs
,
4118 if (p
->po_last_transmit_secs
!= current_secs
) {
4119 p
->po_last_transmit_secs
= current_secs
;
4120 p
->po_n_transmit
= 0;
4122 if (p
->po_n_transmit
< LACP_PACKET_RATE
) {
4126 if (next_secs
!= NULL
) {
4127 *next_secs
= current_secs
+ 1;
4133 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
4136 lacp_actor_partner_tlv_ref aptlv
;
4137 lacp_collector_tlv_ref ctlv
;
4138 struct timeval next_tick_time
= {0, 0};
4139 lacpdu_ref out_lacpdu_p
;
4140 packet_buffer_ref pkt
;
4141 partner_state_ref ps
;
4145 case LAEventTimeout
:
4147 if (p
->po_periodic_interval
== 0 || bondport_flags_ntt(p
) == 0) {
4150 if (event_data
!= NULL
) {
4151 /* we're going away, transmit the packet no matter what */
4153 else if (bondport_can_transmit(p
, devtimer_current_secs(),
4154 &next_tick_time
.tv_sec
) == 0) {
4155 if (devtimer_enabled(p
->po_transmit_timer
)) {
4156 if (g_bond
->verbose
> 0) {
4157 timestamp_printf("[%s] Transmit Timer Already Set\n",
4158 bondport_get_name(p
));
4162 devtimer_set_absolute(p
->po_transmit_timer
, next_tick_time
,
4163 (devtimer_timeout_func
)
4164 bondport_transmit_machine
,
4165 (void *)LAEventTimeout
, NULL
);
4166 if (g_bond
->verbose
> 0) {
4167 timestamp_printf("[%s] Transmit Timer Deadline %d secs\n",
4168 bondport_get_name(p
),
4169 next_tick_time
.tv_sec
);
4174 if (g_bond
->verbose
> 0) {
4175 if (event
== LAEventTimeout
) {
4176 timestamp_printf("[%s] Transmit Timer Complete\n",
4177 bondport_get_name(p
));
4180 pkt
= packet_buffer_allocate(sizeof(*out_lacpdu_p
));
4182 printf("[%s] Transmit: failed to allocate packet buffer\n",
4183 bondport_get_name(p
));
4186 out_lacpdu_p
= (lacpdu_ref
)packet_buffer_byteptr(pkt
);
4187 bzero(out_lacpdu_p
, sizeof(*out_lacpdu_p
));
4188 out_lacpdu_p
->la_subtype
= IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP
;
4189 out_lacpdu_p
->la_version
= LACPDU_VERSION_1
;
4192 aptlv
= (lacp_actor_partner_tlv_ref
)out_lacpdu_p
->la_actor_tlv
;
4193 aptlv
->lap_tlv_type
= LACPDU_TLV_TYPE_ACTOR
;
4194 aptlv
->lap_length
= LACPDU_ACTOR_TLV_LENGTH
;
4195 *((lacp_system_ref
)aptlv
->lap_system
) = g_bond
->system
;
4196 lacp_actor_partner_tlv_set_system_priority(aptlv
,
4197 g_bond
->system_priority
);
4198 lacp_actor_partner_tlv_set_port_priority(aptlv
, p
->po_priority
);
4199 lacp_actor_partner_tlv_set_port(aptlv
, bondport_get_index(p
));
4200 lacp_actor_partner_tlv_set_key(aptlv
, p
->po_bond
->ifb_key
);
4201 aptlv
->lap_state
= p
->po_actor_state
;
4204 aptlv
= (lacp_actor_partner_tlv_ref
)out_lacpdu_p
->la_partner_tlv
;
4205 aptlv
->lap_tlv_type
= LACPDU_TLV_TYPE_PARTNER
;
4206 aptlv
->lap_length
= LACPDU_PARTNER_TLV_LENGTH
;
4207 ps
= &p
->po_partner_state
;
4208 ps_li
= &ps
->ps_lag_info
;
4209 lacp_actor_partner_tlv_set_port(aptlv
, ps
->ps_port
);
4210 lacp_actor_partner_tlv_set_port_priority(aptlv
, ps
->ps_port_priority
);
4211 *((lacp_system_ref
)aptlv
->lap_system
) = ps_li
->li_system
;
4212 lacp_actor_partner_tlv_set_system_priority(aptlv
,
4213 ps_li
->li_system_priority
);
4214 lacp_actor_partner_tlv_set_key(aptlv
, ps_li
->li_key
);
4215 aptlv
->lap_state
= ps
->ps_state
;
4218 ctlv
= (lacp_collector_tlv_ref
)out_lacpdu_p
->la_collector_tlv
;
4219 ctlv
->lac_tlv_type
= LACPDU_TLV_TYPE_COLLECTOR
;
4220 ctlv
->lac_length
= LACPDU_COLLECTOR_TLV_LENGTH
;
4222 bondport_slow_proto_transmit(p
, pkt
);
4223 bondport_flags_clear_ntt(p
);
4224 if (g_bond
->verbose
> 0) {
4225 timestamp_printf("[%s] Transmit Packet %d\n",
4226 bondport_get_name(p
), p
->po_n_transmit
);
4236 ** Mux machine functions
4240 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4243 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4246 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4250 bondport_mux_machine_collecting_distributing(bondport_ref p
, LAEvent event
,
4254 bondport_mux_machine(bondport_ref p
, LAEvent event
, void * event_data
)
4256 switch (p
->po_mux_state
) {
4258 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4260 case MuxState_DETACHED
:
4261 bondport_mux_machine_detached(p
, event
, event_data
);
4263 case MuxState_WAITING
:
4264 bondport_mux_machine_waiting(p
, event
, event_data
);
4266 case MuxState_ATTACHED
:
4267 bondport_mux_machine_attached(p
, event
, event_data
);
4269 case MuxState_COLLECTING_DISTRIBUTING
:
4270 bondport_mux_machine_collecting_distributing(p
, event
, event_data
);
4279 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4280 __unused
void * event_data
)
4282 lacp_actor_partner_state s
;
4286 devtimer_cancel(p
->po_wait_while_timer
);
4287 if (g_bond
->verbose
) {
4288 timestamp_printf("[%s] Mux DETACHED\n",
4289 bondport_get_name(p
));
4291 p
->po_mux_state
= MuxState_DETACHED
;
4292 bondport_flags_clear_ready(p
);
4293 bondport_DetachMuxFromAggregator(p
);
4294 bondport_disable_distributing(p
);
4295 s
= p
->po_actor_state
;
4296 s
= lacp_actor_partner_state_set_out_of_sync(s
);
4297 s
= lacp_actor_partner_state_set_not_collecting(s
);
4298 s
= lacp_actor_partner_state_set_not_distributing(s
);
4299 p
->po_actor_state
= s
;
4300 bondport_flags_set_ntt(p
);
4302 case LAEventSelectedChange
:
4304 case LAEventMediaChange
:
4305 if (p
->po_selected
== SelectedState_SELECTED
4306 || p
->po_selected
== SelectedState_STANDBY
) {
4307 bondport_mux_machine_waiting(p
, LAEventStart
, NULL
);
4317 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4318 __unused
void * event_data
)
4324 devtimer_cancel(p
->po_wait_while_timer
);
4325 if (g_bond
->verbose
) {
4326 timestamp_printf("[%s] Mux WAITING\n",
4327 bondport_get_name(p
));
4329 p
->po_mux_state
= MuxState_WAITING
;
4332 case LAEventSelectedChange
:
4333 if (p
->po_selected
== SelectedState_UNSELECTED
) {
4334 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4337 if (p
->po_selected
== SelectedState_STANDBY
) {
4338 devtimer_cancel(p
->po_wait_while_timer
);
4339 /* wait until state changes to SELECTED */
4340 if (g_bond
->verbose
) {
4341 timestamp_printf("[%s] Mux WAITING: Standby\n",
4342 bondport_get_name(p
));
4346 if (bondport_flags_ready(p
)) {
4347 if (g_bond
->verbose
) {
4348 timestamp_printf("[%s] Mux WAITING: Port is already ready\n",
4349 bondport_get_name(p
));
4353 if (devtimer_enabled(p
->po_wait_while_timer
)) {
4354 if (g_bond
->verbose
) {
4355 timestamp_printf("[%s] Mux WAITING: Timer already set\n",
4356 bondport_get_name(p
));
4360 if (ifbond_all_ports_attached(p
->po_bond
, p
)) {
4361 devtimer_cancel(p
->po_wait_while_timer
);
4362 if (g_bond
->verbose
) {
4363 timestamp_printf("[%s] Mux WAITING: No waiting\n",
4364 bondport_get_name(p
));
4366 bondport_flags_set_ready(p
);
4369 if (g_bond
->verbose
) {
4370 timestamp_printf("[%s] Mux WAITING: 2 seconds\n",
4371 bondport_get_name(p
));
4373 tv
.tv_sec
= LACP_AGGREGATE_WAIT_TIME
;
4375 devtimer_set_relative(p
->po_wait_while_timer
, tv
,
4376 (devtimer_timeout_func
)
4377 bondport_mux_machine_waiting
,
4378 (void *)LAEventTimeout
, NULL
);
4380 case LAEventTimeout
:
4381 if (g_bond
->verbose
) {
4382 timestamp_printf("[%s] Mux WAITING: Ready\n",
4383 bondport_get_name(p
));
4385 bondport_flags_set_ready(p
);
4389 if (bondport_flags_ready(p
)){
4390 if (g_bond
->verbose
) {
4391 timestamp_printf("[%s] Mux WAITING: All Ports Ready\n",
4392 bondport_get_name(p
));
4394 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);
4403 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4404 __unused
void * event_data
)
4406 lacp_actor_partner_state s
;
4410 devtimer_cancel(p
->po_wait_while_timer
);
4411 if (g_bond
->verbose
) {
4412 timestamp_printf("[%s] Mux ATTACHED\n",
4413 bondport_get_name(p
));
4415 p
->po_mux_state
= MuxState_ATTACHED
;
4416 bondport_AttachMuxToAggregator(p
);
4417 s
= p
->po_actor_state
;
4418 s
= lacp_actor_partner_state_set_in_sync(s
);
4419 s
= lacp_actor_partner_state_set_not_collecting(s
);
4420 s
= lacp_actor_partner_state_set_not_distributing(s
);
4421 bondport_disable_distributing(p
);
4422 p
->po_actor_state
= s
;
4423 bondport_flags_set_ntt(p
);
4426 switch (p
->po_selected
) {
4427 case SelectedState_SELECTED
:
4428 s
= p
->po_partner_state
.ps_state
;
4429 if (lacp_actor_partner_state_in_sync(s
)) {
4430 bondport_mux_machine_collecting_distributing(p
, LAEventStart
,
4435 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4444 bondport_mux_machine_collecting_distributing(bondport_ref p
,
4446 __unused
void * event_data
)
4448 lacp_actor_partner_state s
;
4452 devtimer_cancel(p
->po_wait_while_timer
);
4453 if (g_bond
->verbose
) {
4454 timestamp_printf("[%s] Mux COLLECTING_DISTRIBUTING\n",
4455 bondport_get_name(p
));
4457 p
->po_mux_state
= MuxState_COLLECTING_DISTRIBUTING
;
4458 bondport_enable_distributing(p
);
4459 s
= p
->po_actor_state
;
4460 s
= lacp_actor_partner_state_set_collecting(s
);
4461 s
= lacp_actor_partner_state_set_distributing(s
);
4462 p
->po_actor_state
= s
;
4463 bondport_flags_set_ntt(p
);
4466 s
= p
->po_partner_state
.ps_state
;
4467 if (lacp_actor_partner_state_in_sync(s
) == 0) {
4468 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);
4471 switch (p
->po_selected
) {
4472 case SelectedState_UNSELECTED
:
4473 case SelectedState_STANDBY
:
4474 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);