2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 * - bond/failover interface
32 * - implements IEEE 802.3ad Link Aggregation
36 * Modification History:
38 * April 29, 2004 Dieter Siegmund (dieter@apple.com)
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/malloc.h>
46 #include <sys/queue.h>
47 #include <sys/socket.h>
48 #include <sys/sockio.h>
49 #include <sys/sysctl.h>
50 #include <sys/systm.h>
51 #include <sys/kern_event.h>
54 #include <net/ethernet.h>
56 #include <net/kpi_interface.h>
57 #include <net/if_arp.h>
58 #include <net/if_dl.h>
59 #include <net/if_ether.h>
60 #include <net/if_types.h>
61 #include <net/if_bond_var.h>
62 #include <net/ieee8023ad.h>
66 #include <net/devtimer.h>
67 #include <net/if_vlan_var.h>
69 #include <kern/locks.h>
70 #include <libkern/OSAtomic.h>
72 #include <netinet/in.h>
73 #include <netinet/if_ether.h>
74 #include <netinet/in_systm.h>
75 #include <netinet/ip.h>
76 #include <netinet/ip6.h>
78 #include <net/if_media.h>
79 #include <net/multicast_list.h>
81 extern int dlil_input_packet(struct ifnet
*, struct mbuf
*, char *);
83 static struct ether_addr slow_proto_multicast
= {
84 IEEE8023AD_SLOW_PROTO_MULTICAST
87 #define BOND_MAXUNIT 128
88 #define BONDNAME "bond"
89 #define M_BOND M_DEVBUF
91 #define EA_FORMAT "%x:%x:%x:%x:%x:%x"
92 #define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)])
93 #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)
95 #define timestamp_printf printf
100 static __inline__ lck_grp_t
*
101 my_lck_grp_alloc_init(const char * grp_name
)
104 lck_grp_attr_t
* grp_attrs
;
106 grp_attrs
= lck_grp_attr_alloc_init();
107 lck_grp_attr_setdefault(grp_attrs
);
108 lck_grp_attr_setdefault(grp_attrs
);
109 grp
= lck_grp_alloc_init(grp_name
, grp_attrs
);
110 lck_grp_attr_free(grp_attrs
);
114 static __inline__ lck_mtx_t
*
115 my_lck_mtx_alloc_init(lck_grp_t
* lck_grp
)
117 lck_attr_t
* lck_attrs
;
120 lck_attrs
= lck_attr_alloc_init();
121 lck_attr_setdefault(lck_attrs
);
122 lck_mtx
= lck_mtx_alloc_init(lck_grp
, lck_attrs
);
123 lck_attr_free(lck_attrs
);
127 static lck_mtx_t
* bond_lck_mtx
;
129 static __inline__
void
132 lck_grp_t
* bond_lck_grp
;
134 bond_lck_grp
= my_lck_grp_alloc_init("if_bond");
135 bond_lck_mtx
= my_lck_mtx_alloc_init(bond_lck_grp
);
138 static __inline__
void
139 bond_assert_lock_held(void)
141 lck_mtx_assert(bond_lck_mtx
, LCK_MTX_ASSERT_OWNED
);
145 static __inline__
void
146 bond_assert_lock_not_held(void)
148 lck_mtx_assert(bond_lck_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
152 static __inline__
void
155 lck_mtx_lock(bond_lck_mtx
);
159 static __inline__
void
162 lck_mtx_unlock(bond_lck_mtx
);
167 ** bond structures, types
171 lacp_system li_system
;
172 lacp_system_priority li_system_priority
;
175 typedef struct LAG_info_s LAG_info
, * LAG_info_ref
;
178 TAILQ_HEAD(port_list
, bondport_s
);
180 TAILQ_HEAD(ifbond_list
, ifbond_s
);
182 TAILQ_HEAD(lag_list
, LAG_s
);
184 typedef struct ifbond_s ifbond
, * ifbond_ref
;
185 typedef struct bondport_s bondport
, * bondport_ref
;
188 TAILQ_ENTRY(LAG_s
) lag_list
;
189 struct port_list lag_port_list
;
190 short lag_port_count
;
191 short lag_selected_port_count
;
192 int lag_active_media
;
195 typedef struct LAG_s LAG
, * LAG_ref
;
197 typedef struct partner_state_s
{
198 LAG_info ps_lag_info
;
200 lacp_port_priority ps_port_priority
;
201 lacp_actor_partner_state ps_state
;
202 } partner_state
, * partner_state_ref
;
205 TAILQ_ENTRY(ifbond_s
) ifb_bond_list
;
207 UInt32 ifb_retain_count
;
208 char ifb_name
[IFNAMSIZ
];
209 struct ifnet
* ifb_ifp
;
210 bpf_packet_func ifb_bpf_input
;
211 bpf_packet_func ifb_bpf_output
;
213 struct port_list ifb_port_list
;
214 short ifb_port_count
;
215 struct lag_list ifb_lag_list
;
217 short ifb_max_active
; /* 0 == unlimited */
218 LAG_ref ifb_active_lag
;
219 struct ifmultiaddr
* ifb_ifma_slow_proto
;
220 bondport_ref
* ifb_distributing_array
;
221 int ifb_distributing_count
;
230 ReceiveState_none
= 0,
231 ReceiveState_INITIALIZE
= 1,
232 ReceiveState_PORT_DISABLED
= 2,
233 ReceiveState_EXPIRED
= 3,
234 ReceiveState_LACP_DISABLED
= 4,
235 ReceiveState_DEFAULTED
= 5,
236 ReceiveState_CURRENT
= 6,
239 typedef u_char ReceiveState
;
242 SelectedState_UNSELECTED
= IF_BOND_STATUS_SELECTED_STATE_UNSELECTED
,
243 SelectedState_SELECTED
= IF_BOND_STATUS_SELECTED_STATE_SELECTED
,
244 SelectedState_STANDBY
= IF_BOND_STATUS_SELECTED_STATE_STANDBY
246 typedef u_char SelectedState
;
248 static __inline__
const char *
249 SelectedStateString(SelectedState s
)
251 static const char * names
[] = { "UNSELECTED", "SELECTED", "STANDBY" };
253 if (s
<= SelectedState_STANDBY
) {
256 return ("<unknown>");
261 MuxState_DETACHED
= 1,
262 MuxState_WAITING
= 2,
263 MuxState_ATTACHED
= 3,
264 MuxState_COLLECTING_DISTRIBUTING
= 4,
267 typedef u_char MuxState
;
270 TAILQ_ENTRY(bondport_s
) po_port_list
;
272 struct multicast_list po_multicast
;
273 struct ifnet
* po_ifp
;
274 struct ether_addr po_saved_addr
;
276 char po_name
[IFNAMSIZ
];
277 struct ifdevmtu po_devmtu
;
280 TAILQ_ENTRY(bondport_s
) po_lag_port_list
;
281 devtimer_ref po_current_while_timer
;
282 devtimer_ref po_periodic_timer
;
283 devtimer_ref po_wait_while_timer
;
284 devtimer_ref po_transmit_timer
;
285 partner_state po_partner_state
;
286 lacp_port_priority po_priority
;
287 lacp_actor_partner_state po_actor_state
;
289 u_char po_periodic_interval
;
290 u_char po_n_transmit
;
291 ReceiveState po_receive_state
;
292 MuxState po_mux_state
;
293 SelectedState po_selected
;
294 int32_t po_last_transmit_secs
;
295 struct media_info po_media_info
;
299 #define IFBF_PROMISC 0x1 /* promiscuous mode */
300 #define IFBF_IF_DETACHING 0x2 /* interface is detaching */
301 #define IFBF_LLADDR 0x4 /* specific link address requested */
302 #define IFBF_CHANGE_IN_PROGRESS 0x8 /* interface add/remove in progress */
304 static int bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
,
307 static __inline__
int
308 ifbond_flags_promisc(ifbond_ref ifb
)
310 return ((ifb
->ifb_flags
& IFBF_PROMISC
) != 0);
313 static __inline__
void
314 ifbond_flags_set_promisc(ifbond_ref ifb
)
316 ifb
->ifb_flags
|= IFBF_PROMISC
;
320 static __inline__
void
321 ifbond_flags_clear_promisc(ifbond_ref ifb
)
323 ifb
->ifb_flags
&= ~IFBF_PROMISC
;
327 static __inline__
int
328 ifbond_flags_if_detaching(ifbond_ref ifb
)
330 return ((ifb
->ifb_flags
& IFBF_IF_DETACHING
) != 0);
333 static __inline__
void
334 ifbond_flags_set_if_detaching(ifbond_ref ifb
)
336 ifb
->ifb_flags
|= IFBF_IF_DETACHING
;
340 static __inline__
int
341 ifbond_flags_lladdr(ifbond_ref ifb
)
343 return ((ifb
->ifb_flags
& IFBF_LLADDR
) != 0);
346 static __inline__
void
347 ifbond_flags_set_lladdr(ifbond_ref ifb
)
349 ifb
->ifb_flags
|= IFBF_LLADDR
;
353 static __inline__
void
354 ifbond_flags_clear_lladdr(ifbond_ref ifb
)
356 ifb
->ifb_flags
&= ~IFBF_LLADDR
;
360 static __inline__
int
361 ifbond_flags_change_in_progress(ifbond_ref ifb
)
363 return ((ifb
->ifb_flags
& IFBF_CHANGE_IN_PROGRESS
) != 0);
366 static __inline__
void
367 ifbond_flags_set_change_in_progress(ifbond_ref ifb
)
369 ifb
->ifb_flags
|= IFBF_CHANGE_IN_PROGRESS
;
373 static __inline__
void
374 ifbond_flags_clear_change_in_progress(ifbond_ref ifb
)
376 ifb
->ifb_flags
&= ~IFBF_CHANGE_IN_PROGRESS
;
381 * bondport_ref->po_flags bits
383 #define BONDPORT_FLAGS_NTT 0x01
384 #define BONDPORT_FLAGS_READY 0x02
385 #define BONDPORT_FLAGS_SELECTED_CHANGED 0x04
386 #define BONDPORT_FLAGS_MUX_ATTACHED 0x08
387 #define BONDPORT_FLAGS_DISTRIBUTING 0x10
388 #define BONDPORT_FLAGS_UNUSED2 0x20
389 #define BONDPORT_FLAGS_UNUSED3 0x40
390 #define BONDPORT_FLAGS_UNUSED4 0x80
392 static __inline__
void
393 bondport_flags_set_ntt(bondport_ref p
)
395 p
->po_flags
|= BONDPORT_FLAGS_NTT
;
399 static __inline__
void
400 bondport_flags_clear_ntt(bondport_ref p
)
402 p
->po_flags
&= ~BONDPORT_FLAGS_NTT
;
406 static __inline__
int
407 bondport_flags_ntt(bondport_ref p
)
409 return ((p
->po_flags
& BONDPORT_FLAGS_NTT
) != 0);
412 static __inline__
void
413 bondport_flags_set_ready(bondport_ref p
)
415 p
->po_flags
|= BONDPORT_FLAGS_READY
;
419 static __inline__
void
420 bondport_flags_clear_ready(bondport_ref p
)
422 p
->po_flags
&= ~BONDPORT_FLAGS_READY
;
426 static __inline__
int
427 bondport_flags_ready(bondport_ref p
)
429 return ((p
->po_flags
& BONDPORT_FLAGS_READY
) != 0);
432 static __inline__
void
433 bondport_flags_set_selected_changed(bondport_ref p
)
435 p
->po_flags
|= BONDPORT_FLAGS_SELECTED_CHANGED
;
439 static __inline__
void
440 bondport_flags_clear_selected_changed(bondport_ref p
)
442 p
->po_flags
&= ~BONDPORT_FLAGS_SELECTED_CHANGED
;
446 static __inline__
int
447 bondport_flags_selected_changed(bondport_ref p
)
449 return ((p
->po_flags
& BONDPORT_FLAGS_SELECTED_CHANGED
) != 0);
452 static __inline__
void
453 bondport_flags_set_mux_attached(bondport_ref p
)
455 p
->po_flags
|= BONDPORT_FLAGS_MUX_ATTACHED
;
459 static __inline__
void
460 bondport_flags_clear_mux_attached(bondport_ref p
)
462 p
->po_flags
&= ~BONDPORT_FLAGS_MUX_ATTACHED
;
466 static __inline__
int
467 bondport_flags_mux_attached(bondport_ref p
)
469 return ((p
->po_flags
& BONDPORT_FLAGS_MUX_ATTACHED
) != 0);
472 static __inline__
void
473 bondport_flags_set_distributing(bondport_ref p
)
475 p
->po_flags
|= BONDPORT_FLAGS_DISTRIBUTING
;
479 static __inline__
void
480 bondport_flags_clear_distributing(bondport_ref p
)
482 p
->po_flags
&= ~BONDPORT_FLAGS_DISTRIBUTING
;
486 static __inline__
int
487 bondport_flags_distributing(bondport_ref p
)
489 return ((p
->po_flags
& BONDPORT_FLAGS_DISTRIBUTING
) != 0);
492 typedef struct bond_globals_s
{
493 struct ifbond_list ifbond_list
;
495 lacp_system_priority system_priority
;
497 } * bond_globals_ref
;
499 static bond_globals_ref g_bond
;
502 ** packet_buffer routines
503 ** - thin wrapper for mbuf
506 typedef struct mbuf
* packet_buffer_ref
;
508 static packet_buffer_ref
509 packet_buffer_allocate(int length
)
514 /* leave room for ethernet header */
515 size
= length
+ sizeof(struct ether_header
);
516 if (size
> (int)MHLEN
) {
517 /* XXX doesn't handle large payloads */
518 printf("bond: packet_buffer_allocate size %d > max %d\n", size
, MHLEN
);
521 m
= m_gethdr(M_WAITOK
, MT_DATA
);
526 m
->m_pkthdr
.len
= size
;
531 packet_buffer_byteptr(packet_buffer_ref buf
)
533 return (buf
->m_data
+ sizeof(struct ether_header
));
541 LAEventSelectedChange
,
550 bondport_receive_machine(bondport_ref p
, LAEvent event
,
553 ** Periodic Transmission machine
556 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
563 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
570 bondport_mux_machine(bondport_ref p
, LAEvent event
,
577 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
);
580 ifbond_deactivate_LAG(ifbond_ref bond
, LAG_ref lag
);
583 ifbond_all_ports_ready(ifbond_ref bond
);
586 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
);
589 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
);
592 ifbond_selection(ifbond_ref bond
);
600 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
);
603 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
);
606 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
607 int active
, int short_timeout
, int * error
);
609 bondport_start(bondport_ref p
);
612 bondport_free(bondport_ref p
);
615 bondport_aggregatable(bondport_ref p
);
618 bondport_remove_from_LAG(bondport_ref p
);
621 bondport_set_selected(bondport_ref p
, SelectedState s
);
624 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
);
627 bondport_link_status_changed(bondport_ref p
);
630 bondport_enable_distributing(bondport_ref p
);
633 bondport_disable_distributing(bondport_ref p
);
635 static __inline__
int
636 bondport_collecting(bondport_ref p
)
638 return (lacp_actor_partner_state_collecting(p
->po_actor_state
));
642 ** bond interface/dlil specific routines
644 static int bond_clone_create(struct if_clone
*, int);
645 static void bond_clone_destroy(struct ifnet
*);
646 static int bond_input(struct mbuf
*m
, char *frame_header
, struct ifnet
*ifp
,
647 u_long protocol_family
, int sync_ok
);
648 static int bond_output(struct ifnet
*ifp
, struct mbuf
*m
);
649 static int bond_ioctl(struct ifnet
*ifp
, u_int32_t cmd
, void * addr
);
650 static int bond_set_bpf_tap(struct ifnet
* ifp
, bpf_tap_mode mode
,
651 bpf_packet_func func
);
652 static int bond_attach_protocol(struct ifnet
*ifp
);
653 static int bond_detach_protocol(struct ifnet
*ifp
);
654 static int bond_setmulti(struct ifnet
*ifp
);
655 static int bond_add_interface(struct ifnet
* ifp
, struct ifnet
* port_ifp
);
656 static int bond_remove_interface(ifbond_ref ifb
, struct ifnet
* port_ifp
);
657 static void bond_if_free(struct ifnet
* ifp
);
659 static struct if_clone bond_cloner
= IF_CLONE_INITIALIZER(BONDNAME
,
664 static void interface_link_event(struct ifnet
* ifp
, u_long event_code
);
667 siocsifmtu(struct ifnet
* ifp
, int mtu
)
671 bzero(&ifr
, sizeof(ifr
));
673 return (dlil_ioctl(0, ifp
, SIOCSIFMTU
, (caddr_t
)&ifr
));
677 siocgifdevmtu(struct ifnet
* ifp
, struct ifdevmtu
* ifdm_p
)
682 bzero(&ifr
, sizeof(ifr
));
683 error
= dlil_ioctl(0, ifp
, SIOCGIFDEVMTU
, (caddr_t
)&ifr
);
685 *ifdm_p
= ifr
.ifr_devmtu
;
690 static __inline__
void
691 ether_addr_copy(void * dest
, const void * source
)
693 bcopy(source
, dest
, ETHER_ADDR_LEN
);
697 static __inline__
void
698 ifbond_retain(ifbond_ref ifb
)
700 OSIncrementAtomic(&ifb
->ifb_retain_count
);
703 static __inline__
void
704 ifbond_release(ifbond_ref ifb
)
706 UInt32 old_retain_count
;
708 old_retain_count
= OSDecrementAtomic(&ifb
->ifb_retain_count
);
709 switch (old_retain_count
) {
711 panic("ifbond_release: retain count is 0\n");
714 if (g_bond
->verbose
) {
715 printf("ifbond_release(%s)\n", ifb
->ifb_name
);
717 if (ifb
->ifb_ifma_slow_proto
!= NULL
) {
718 if (g_bond
->verbose
) {
719 printf("ifbond_release(%s) removing multicast\n",
722 (void)if_delmultiaddr(ifb
->ifb_ifma_slow_proto
, 0);
723 ifma_release(ifb
->ifb_ifma_slow_proto
);
725 if (ifb
->ifb_distributing_array
!= NULL
) {
726 FREE(ifb
->ifb_distributing_array
, M_BOND
);
737 * Function: ifbond_wait
739 * Allows a single thread to gain exclusive access to the ifbond
740 * data structure. Some operations take a long time to complete,
741 * and some have side-effects that we can't predict. Holding the
742 * bond_lock() across such operations is not possible.
745 * 1) The SIOCSIFLLADDR ioctl takes a long time (several seconds) to
746 * complete. Simply holding the bond_lock() would freeze all other
747 * data structure accesses during that time.
748 * 2) When we attach our protocol to the interface, a dlil event is
749 * generated and invokes our bond_event() function. bond_event()
750 * needs to take the bond_lock(), but we're already holding it, so
751 * we're deadlocked against ourselves.
753 * Before calling, you must be holding the bond_lock and have taken
754 * a reference on the ifbond_ref.
757 ifbond_wait(ifbond_ref ifb
, const char * msg
)
761 /* other add/remove in progress */
762 while (ifbond_flags_change_in_progress(ifb
)) {
763 if (g_bond
->verbose
) {
764 printf("%s: %s msleep\n", ifb
->ifb_name
, msg
);
767 (void)msleep(ifb
, bond_lck_mtx
, PZERO
, msg
, 0);
769 /* prevent other bond list remove/add from taking place */
770 ifbond_flags_set_change_in_progress(ifb
);
771 if (g_bond
->verbose
&& waited
) {
772 printf("%s: %s woke up\n", ifb
->ifb_name
, msg
);
778 * Function: ifbond_signal
780 * Allows the thread that previously invoked ifbond_wait() to
781 * give up exclusive access to the ifbond data structure, and wake up
782 * any other threads waiting to access
784 * Before calling, you must be holding the bond_lock and have taken
785 * a reference on the ifbond_ref.
788 ifbond_signal(ifbond_ref ifb
, const char * msg
)
790 ifbond_flags_clear_change_in_progress(ifb
);
791 wakeup((caddr_t
)ifb
);
792 if (g_bond
->verbose
) {
793 printf("%s: %s wakeup\n", ifb
->ifb_name
, msg
);
803 link_speed(int active
)
805 switch (IFM_SUBTYPE(active
)) {
826 /* assume that new defined types are going to be at least 10GigE */
833 static __inline__
int
834 media_active(const struct media_info
* mi
)
836 if ((mi
->mi_status
& IFM_AVALID
) == 0) {
839 return ((mi
->mi_status
& IFM_ACTIVE
) != 0);
842 static __inline__
int
843 media_full_duplex(const struct media_info
* mi
)
845 return ((mi
->mi_active
& IFM_FDX
) != 0);
848 static __inline__
int
849 media_speed(const struct media_info
* mi
)
851 return (link_speed(mi
->mi_active
));
854 static struct media_info
855 interface_media_info(struct ifnet
* ifp
)
857 struct ifmediareq ifmr
;
858 struct media_info mi
;
860 bzero(&mi
, sizeof(mi
));
861 bzero(&ifmr
, sizeof(ifmr
));
862 if (dlil_ioctl(0, ifp
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
) == 0) {
863 if (ifmr
.ifm_count
!= 0) {
864 mi
.mi_status
= ifmr
.ifm_status
;
865 mi
.mi_active
= ifmr
.ifm_active
;
872 ** interface utility functions
874 static __inline__
struct ifaddr
*
875 ifindex_get_ifaddr(int i
)
877 if (i
> if_index
|| i
== 0) {
880 return (ifnet_addrs
[i
- 1]);
883 static __inline__
struct ifaddr
*
884 ifp_get_ifaddr(struct ifnet
* ifp
)
886 return (ifindex_get_ifaddr(ifp
->if_index
));
889 static __inline__
struct sockaddr_dl
*
890 ifp_get_sdl(struct ifnet
* ifp
)
894 ifa
= ifp_get_ifaddr(ifp
);
895 return ((struct sockaddr_dl
*)(ifa
->ifa_addr
));
899 if_siflladdr(struct ifnet
* ifp
, const struct ether_addr
* ea_p
)
904 * XXX setting the sa_len to ETHER_ADDR_LEN is wrong, but the driver
905 * currently expects it that way
907 ifr
.ifr_addr
.sa_family
= AF_UNSPEC
;
908 ifr
.ifr_addr
.sa_len
= ETHER_ADDR_LEN
;
909 ether_addr_copy(ifr
.ifr_addr
.sa_data
, ea_p
);
911 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s%d", ifp
->if_name
,
914 return (dlil_ioctl(0, ifp
, SIOCSIFLLADDR
, (caddr_t
)&ifr
));
920 static bond_globals_ref
921 bond_globals_create(lacp_system_priority sys_pri
,
926 b
= _MALLOC(sizeof(*b
), M_BOND
, M_WAITOK
);
930 bzero(b
, sizeof(*b
));
931 TAILQ_INIT(&b
->ifbond_list
);
933 b
->system_priority
= sys_pri
;
941 bond_globals_init(void)
947 bond_assert_lock_not_held();
949 if (g_bond
!= NULL
) {
954 * use en0's ethernet address as the system identifier, and if it's not
955 * there, use en1 .. en3
958 for (i
= 0; i
< 4; i
++) {
959 char ifname
[IFNAMSIZ
+1];
960 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
961 /* XXX ifunit() needs to return a reference on the ifp */
962 ifp
= ifunit(ifname
);
969 b
= bond_globals_create(0x8000,
970 (lacp_system_ref
)LLADDR(ifp_get_sdl(ifp
)));
973 if (g_bond
!= NULL
) {
990 bond_bpf_vlan(struct ifnet
* ifp
, struct mbuf
* m
,
991 const struct ether_header
* eh_p
,
992 u_int16_t vlan_tag
, bpf_packet_func func
)
994 struct ether_vlan_header
* vlh_p
;
997 vl_m
= m_get(M_DONTWAIT
, MT_DATA
);
1001 /* populate a new mbuf containing the vlan ethernet header */
1002 vl_m
->m_len
= ETHER_HDR_LEN
+ ETHER_VLAN_ENCAP_LEN
;
1003 vlh_p
= mtod(vl_m
, struct ether_vlan_header
*);
1004 bcopy(eh_p
, vlh_p
, offsetof(struct ether_header
, ether_type
));
1005 vlh_p
->evl_encap_proto
= htons(ETHERTYPE_VLAN
);
1006 vlh_p
->evl_tag
= htons(vlan_tag
);
1007 vlh_p
->evl_proto
= eh_p
->ether_type
;
1010 vl_m
->m_next
= NULL
;
1015 static __inline__
void
1016 bond_bpf_output(struct ifnet
* ifp
, struct mbuf
* m
,
1017 bpf_packet_func func
)
1020 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1021 const struct ether_header
* eh_p
;
1022 eh_p
= mtod(m
, const struct ether_header
*);
1023 m
->m_data
+= ETHER_HDR_LEN
;
1024 m
->m_len
-= ETHER_HDR_LEN
;
1025 bond_bpf_vlan(ifp
, m
, eh_p
, m
->m_pkthdr
.vlan_tag
, func
);
1026 m
->m_data
-= ETHER_HDR_LEN
;
1027 m
->m_len
+= ETHER_HDR_LEN
;
1035 static __inline__
void
1036 bond_bpf_input(ifnet_t ifp
, mbuf_t m
, const struct ether_header
* eh_p
,
1037 bpf_packet_func func
)
1040 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1041 bond_bpf_vlan(ifp
, m
, eh_p
, m
->m_pkthdr
.vlan_tag
, func
);
1043 /* restore the header */
1044 m
->m_data
-= ETHER_HDR_LEN
;
1045 m
->m_len
+= ETHER_HDR_LEN
;
1047 m
->m_data
+= ETHER_HDR_LEN
;
1048 m
->m_len
-= ETHER_HDR_LEN
;
1055 * Function: bond_setmulti
1057 * Enable multicast reception on "our" interface by enabling multicasts on
1058 * each of the member ports.
1061 bond_setmulti(struct ifnet
* ifp
)
1069 ifb
= ifp
->if_private
;
1070 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1071 || TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
1076 ifbond_wait(ifb
, "bond_setmulti");
1078 if (ifbond_flags_if_detaching(ifb
)) {
1079 /* someone destroyed the bond while we were waiting */
1085 /* ifbond_wait() let's us safely walk the list without holding the lock */
1086 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
1087 struct ifnet
* port_ifp
= p
->po_ifp
;
1089 error
= multicast_list_program(&p
->po_multicast
,
1092 printf("bond_setmulti(%s): "
1093 "multicast_list_program(%s%d) failed, %d\n",
1094 ifb
->ifb_name
, port_ifp
->if_name
,
1095 port_ifp
->if_unit
, error
);
1101 ifbond_release(ifb
);
1102 ifbond_signal(ifb
, "bond_setmulti");
1108 bond_clone_attach(void)
1110 if_clone_attach(&bond_cloner
);
1116 ifbond_add_slow_proto_multicast(ifbond_ref ifb
)
1119 struct ifmultiaddr
* ifma
= NULL
;
1120 struct sockaddr_dl sdl
;
1122 bond_assert_lock_not_held();
1124 bzero(&sdl
, sizeof(sdl
));
1125 sdl
.sdl_len
= sizeof(sdl
);
1126 sdl
.sdl_family
= AF_LINK
;
1127 sdl
.sdl_type
= IFT_ETHER
;
1129 sdl
.sdl_alen
= sizeof(slow_proto_multicast
);
1130 bcopy(&slow_proto_multicast
, sdl
.sdl_data
, sizeof(slow_proto_multicast
));
1131 error
= if_addmulti(ifb
->ifb_ifp
, (struct sockaddr
*)&sdl
,
1134 ifb
->ifb_ifma_slow_proto
= ifma
;
1140 bond_clone_create(struct if_clone
* ifc
, int unit
)
1146 error
= bond_globals_init();
1151 ifb
= _MALLOC(sizeof(ifbond
), M_BOND
, M_WAITOK
);
1155 bzero(ifb
, sizeof(*ifb
));
1158 TAILQ_INIT(&ifb
->ifb_port_list
);
1159 TAILQ_INIT(&ifb
->ifb_lag_list
);
1160 ifb
->ifb_key
= unit
+ 1;
1162 /* use the interface name as the unique id for ifp recycle */
1163 if ((u_long
)snprintf(ifb
->ifb_name
, sizeof(ifb
->ifb_name
), "%s%d",
1164 ifc
->ifc_name
, unit
) >= sizeof(ifb
->ifb_name
)) {
1165 ifbond_release(ifb
);
1168 error
= dlil_if_acquire(APPLE_IF_FAM_BOND
,
1170 strlen(ifb
->ifb_name
),
1173 ifbond_release(ifb
);
1177 ifp
->if_name
= ifc
->ifc_name
;
1178 ifp
->if_unit
= unit
;
1179 ifp
->if_family
= APPLE_IF_FAM_BOND
;
1180 ifp
->if_private
= NULL
;
1181 ifp
->if_ioctl
= bond_ioctl
;
1182 ifp
->if_set_bpf_tap
= bond_set_bpf_tap
;
1183 ifp
->if_free
= bond_if_free
;
1184 ifp
->if_output
= bond_output
;
1185 ifp
->if_hwassist
= 0;
1186 ifp
->if_addrlen
= ETHER_ADDR_LEN
;
1187 ifp
->if_baudrate
= 0;
1188 ifp
->if_type
= IFT_IEEE8023ADLAG
;
1189 ifp
->if_flags
= IFF_BROADCAST
| IFF_MULTICAST
| IFF_SIMPLEX
;
1192 /* XXX ethernet specific */
1193 ifp
->if_broadcast
.length
= ETHER_ADDR_LEN
;
1194 bcopy(etherbroadcastaddr
, ifp
->if_broadcast
.u
.buffer
, ETHER_ADDR_LEN
);
1196 error
= dlil_if_attach(ifp
);
1198 dlil_if_release(ifp
);
1199 ifbond_release(ifb
);
1202 error
= ifbond_add_slow_proto_multicast(ifb
);
1204 printf("bond_clone_create(%s): "
1205 "failed to add slow_proto multicast, %d\n",
1206 ifb
->ifb_name
, error
);
1209 /* attach as ethernet */
1210 bpfattach(ifp
, DLT_EN10MB
, sizeof(struct ether_header
));
1213 ifp
->if_private
= ifb
;
1214 TAILQ_INSERT_HEAD(&g_bond
->ifbond_list
, ifb
, ifb_bond_list
);
1221 bond_remove_all_interfaces(ifbond_ref ifb
)
1225 bond_assert_lock_held();
1228 * do this in reverse order to avoid re-programming the mac address
1229 * as each head interface is removed
1231 while ((p
= TAILQ_LAST(&ifb
->ifb_port_list
, port_list
)) != NULL
) {
1232 bond_remove_interface(ifb
, p
->po_ifp
);
1238 bond_remove(ifbond_ref ifb
)
1240 bond_assert_lock_held();
1241 ifbond_flags_set_if_detaching(ifb
);
1242 TAILQ_REMOVE(&g_bond
->ifbond_list
, ifb
, ifb_bond_list
);
1243 bond_remove_all_interfaces(ifb
);
1248 bond_if_detach(struct ifnet
* ifp
)
1252 error
= dlil_if_detach(ifp
);
1253 if (error
!= DLIL_WAIT_FOR_FREE
) {
1255 printf("bond_if_detach %s%d: dlil_if_detach failed, %d\n",
1256 ifp
->if_name
, ifp
->if_unit
, error
);
1264 bond_clone_destroy(struct ifnet
* ifp
)
1269 ifb
= ifp
->if_private
;
1270 if (ifb
== NULL
|| ifp
->if_type
!= IFT_IEEE8023ADLAG
) {
1274 if (ifbond_flags_if_detaching(ifb
)) {
1280 bond_if_detach(ifp
);
1285 bond_set_bpf_tap(struct ifnet
* ifp
, bpf_tap_mode mode
, bpf_packet_func func
)
1290 ifb
= ifp
->if_private
;
1291 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
1296 case BPF_TAP_DISABLE
:
1297 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= NULL
;
1301 ifb
->ifb_bpf_input
= func
;
1304 case BPF_TAP_OUTPUT
:
1305 ifb
->ifb_bpf_output
= func
;
1308 case BPF_TAP_INPUT_OUTPUT
:
1309 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= func
;
1319 ether_header_hash(struct ether_header
* eh_p
)
1323 /* get 32-bits from destination ether and ether type */
1324 h
= (*((uint16_t *)&eh_p
->ether_dhost
[4]) << 16)
1326 h
^= *((uint32_t *)&eh_p
->ether_dhost
[0]);
1330 static struct mbuf
*
1331 S_mbuf_skip_to_offset(struct mbuf
* m
, long * offset
)
1336 while (*offset
>= len
) {
1347 #if BYTE_ORDER == BIG_ENDIAN
1348 static __inline__
uint32_t
1349 make_uint32(u_char c0
, u_char c1
, u_char c2
, u_char c3
)
1351 return (((uint32_t)c0
<< 24) | ((uint32_t)c1
<< 16)
1352 | ((uint32_t)c2
<< 8) | (uint32_t)c3
);
1354 #else /* BYTE_ORDER == LITTLE_ENDIAN */
1355 static __inline__
uint32_t
1356 make_uint32(u_char c0
, u_char c1
, u_char c2
, u_char c3
)
1358 return (((uint32_t)c3
<< 24) | ((uint32_t)c2
<< 16)
1359 | ((uint32_t)c1
<< 8) | (uint32_t)c0
);
1361 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1364 S_mbuf_copy_uint32(struct mbuf
* m
, long offset
, uint32_t * val
)
1366 struct mbuf
* current
;
1367 u_char
* current_data
;
1372 current
= S_mbuf_skip_to_offset(m
, &offset
);
1373 if (current
== NULL
) {
1376 current_data
= mtod(current
, u_char
*) + offset
;
1377 space_current
= current
->m_len
- offset
;
1378 if (space_current
>= (int)sizeof(uint32_t)) {
1379 *val
= *((uint32_t *)current_data
);
1382 next
= current
->m_next
;
1383 if (next
== NULL
|| (next
->m_len
+ space_current
) < (int)sizeof(uint32_t)) {
1386 next_data
= mtod(next
, u_char
*);
1387 switch (space_current
) {
1389 *val
= make_uint32(current_data
[0], next_data
[0],
1390 next_data
[1], next_data
[2]);
1393 *val
= make_uint32(current_data
[0], current_data
[1],
1394 next_data
[0], next_data
[1]);
1397 *val
= make_uint32(current_data
[0], current_data
[1],
1398 current_data
[2], next_data
[0]);
1404 #define IP_SRC_OFFSET (offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p))
1405 #define IP_DST_OFFSET (offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p))
1408 ip_header_hash(struct mbuf
* m
)
1411 struct in_addr ip_dst
;
1412 struct in_addr ip_src
;
1415 struct mbuf
* orig_m
= m
;
1417 /* find the IP protocol field relative to the start of the packet */
1418 offset
= offsetof(struct ip
, ip_p
) + sizeof(struct ether_header
);
1419 m
= S_mbuf_skip_to_offset(m
, &offset
);
1420 if (m
== NULL
|| m
->m_len
< 1) {
1423 data
= mtod(m
, u_char
*) + offset
;
1426 /* find the IP src relative to the IP protocol */
1427 if ((m
->m_len
- offset
)
1428 >= (int)(IP_SRC_OFFSET
+ sizeof(struct in_addr
) * 2)) {
1429 /* this should be the normal case */
1430 ip_src
= *(struct in_addr
*)(data
+ IP_SRC_OFFSET
);
1431 ip_dst
= *(struct in_addr
*)(data
+ IP_DST_OFFSET
);
1434 if (S_mbuf_copy_uint32(m
, offset
+ IP_SRC_OFFSET
,
1435 (uint32_t *)&ip_src
.s_addr
)) {
1438 if (S_mbuf_copy_uint32(m
, offset
+ IP_DST_OFFSET
,
1439 (uint32_t *)&ip_dst
.s_addr
)) {
1443 return (ntohl(ip_dst
.s_addr
) ^ ntohl(ip_src
.s_addr
) ^ ((uint32_t)ip_p
));
1446 return (ether_header_hash(mtod(orig_m
, struct ether_header
*)));
1449 #define IP6_ADDRS_LEN (sizeof(struct in6_addr) * 2)
1451 ipv6_header_hash(struct mbuf
* m
)
1456 struct mbuf
* orig_m
= m
;
1460 /* find the IP protocol field relative to the start of the packet */
1461 offset
= offsetof(struct ip6_hdr
, ip6_src
) + sizeof(struct ether_header
);
1462 m
= S_mbuf_skip_to_offset(m
, &offset
);
1464 goto bad_ipv6_packet
;
1466 data
= mtod(m
, u_char
*) + offset
;
1468 if ((m
->m_len
- offset
) >= (int)IP6_ADDRS_LEN
) {
1469 /* this should be the normal case */
1470 for (i
= 0, scan
= (uint32_t *)data
;
1471 i
< (int)(IP6_ADDRS_LEN
/ sizeof(uint32_t));
1477 for (i
= 0; i
< (int)(IP6_ADDRS_LEN
/ sizeof(uint32_t)); i
++) {
1479 if (S_mbuf_copy_uint32(m
, offset
+ i
* sizeof(uint32_t),
1480 (uint32_t *)&tmp
)) {
1481 goto bad_ipv6_packet
;
1486 return (ntohl(val
));
1489 return (ether_header_hash(mtod(orig_m
, struct ether_header
*)));
1493 bond_output(struct ifnet
* ifp
, struct mbuf
* m
)
1495 bpf_packet_func bpf_func
;
1498 struct ifnet
* port_ifp
= NULL
;
1503 if ((m
->m_flags
& M_PKTHDR
) == 0) {
1507 if (m
->m_pkthdr
.socket_id
!= 0) {
1508 h
= m
->m_pkthdr
.socket_id
;
1511 struct ether_header
* eh_p
;
1513 eh_p
= mtod(m
, struct ether_header
*);
1514 switch (ntohs(eh_p
->ether_type
)) {
1516 h
= ip_header_hash(m
);
1518 case ETHERTYPE_IPV6
:
1519 h
= ipv6_header_hash(m
);
1522 h
= ether_header_hash(eh_p
);
1527 ifb
= ifp
->if_private
;
1528 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1529 || ifb
->ifb_distributing_count
== 0) {
1532 h
%= ifb
->ifb_distributing_count
;
1533 port_ifp
= ifb
->ifb_distributing_array
[h
]->po_ifp
;
1534 bpf_func
= ifb
->ifb_bpf_output
;
1537 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1538 (void)ifnet_stat_increment_out(ifp
, 1,
1539 m
->m_pkthdr
.len
+ ETHER_VLAN_ENCAP_LEN
,
1542 (void)ifnet_stat_increment_out(ifp
, 1, m
->m_pkthdr
.len
, 0);
1544 bond_bpf_output(ifp
, m
, bpf_func
);
1546 return (dlil_output(port_ifp
, 0, m
, NULL
, NULL
, 1));
1555 ifbond_lookup_port(ifbond_ref ifb
, struct ifnet
* port_ifp
)
1558 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
1559 if (p
->po_ifp
== port_ifp
) {
1567 bond_lookup_port(struct ifnet
* port_ifp
)
1572 TAILQ_FOREACH(ifb
, &g_bond
->ifbond_list
, ifb_bond_list
) {
1573 port
= ifbond_lookup_port(ifb
, port_ifp
);
1582 bond_receive_lacpdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1584 struct ifnet
* bond_ifp
= NULL
;
1589 if ((port_ifp
->if_eflags
& IFEF_BOND
) == 0) {
1592 p
= bond_lookup_port(port_ifp
);
1596 if (p
->po_enabled
== 0) {
1599 bondport_receive_lacpdu(p
, (lacpdu_ref
)m
->m_data
);
1600 if (ifbond_selection(p
->po_bond
)) {
1601 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
1604 /* XXX need to take a reference on bond_ifp */
1605 bond_ifp
= p
->po_bond
->ifb_ifp
;
1610 if (bond_ifp
!= NULL
) {
1611 interface_link_event(bond_ifp
, event_code
);
1618 bond_receive_la_marker_pdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1620 la_marker_pdu_ref marker_p
;
1623 marker_p
= (la_marker_pdu_ref
)(m
->m_data
+ ETHER_HDR_LEN
);
1624 if (marker_p
->lm_marker_tlv_type
!= LA_MARKER_TLV_TYPE_MARKER
) {
1628 if ((port_ifp
->if_eflags
& IFEF_BOND
) == 0) {
1632 p
= bond_lookup_port(port_ifp
);
1633 if (p
== NULL
|| p
->po_enabled
== 0) {
1637 /* echo back the same packet as a marker response */
1638 marker_p
->lm_marker_tlv_type
= LA_MARKER_TLV_TYPE_MARKER_RESPONSE
;
1639 bondport_slow_proto_transmit(p
, (packet_buffer_ref
)m
);
1649 bond_input(struct mbuf
* m
, char * frame_header
, struct ifnet
* port_ifp
,
1650 __unused u_long protocol_family
, __unused
int sync_ok
)
1652 bpf_packet_func bpf_func
;
1653 const struct ether_header
* eh_p
;
1658 eh_p
= (const struct ether_header
*)frame_header
;
1659 if ((m
->m_flags
& M_MCAST
) != 0
1660 && bcmp(eh_p
->ether_dhost
, &slow_proto_multicast
,
1661 sizeof(eh_p
->ether_dhost
)) == 0
1662 && ntohs(eh_p
->ether_type
) == IEEE8023AD_SLOW_PROTO_ETHERTYPE
) {
1663 u_char subtype
= *mtod(m
, u_char
*);
1665 if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP
) {
1666 if (m
->m_pkthdr
.len
< (int)offsetof(lacpdu
, la_reserved
)) {
1671 if (m
->m_len
< (int)offsetof(lacpdu
, la_reserved
)) {
1672 m
= m_pullup(m
, offsetof(lacpdu
, la_reserved
));
1677 bond_receive_lacpdu(m
, port_ifp
);
1680 else if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LA_MARKER_PROTOCOL
) {
1683 /* restore the ethernet header pointer in the mbuf */
1684 m
->m_pkthdr
.len
+= ETHER_HDR_LEN
;
1685 m
->m_data
-= ETHER_HDR_LEN
;
1686 m
->m_len
+= ETHER_HDR_LEN
;
1687 min_size
= ETHER_HDR_LEN
+ offsetof(la_marker_pdu
, lm_reserved
);
1688 if (m
->m_pkthdr
.len
< min_size
) {
1693 if (m
->m_len
< min_size
) {
1694 m
= m_pullup(m
, min_size
);
1699 /* send to marker responder */
1700 bond_receive_la_marker_pdu(m
, port_ifp
);
1703 else if (subtype
== 0
1704 || subtype
> IEEE8023AD_SLOW_PROTO_SUBTYPE_RESERVED_END
) {
1705 /* invalid subtype, discard the frame */
1711 if ((port_ifp
->if_eflags
& IFEF_BOND
) == 0) {
1714 p
= bond_lookup_port(port_ifp
);
1715 if (p
== NULL
|| bondport_collecting(p
) == 0) {
1719 /* make the packet appear as if it arrived on the bonded interface */
1722 bpf_func
= ifb
->ifb_bpf_input
;
1725 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1726 (void)ifnet_stat_increment_in(ifp
, 1,
1727 (m
->m_pkthdr
.len
+ ETHER_HDR_LEN
1728 + ETHER_VLAN_ENCAP_LEN
), 0);
1731 (void)ifnet_stat_increment_in(ifp
, 1,
1732 (m
->m_pkthdr
.len
+ ETHER_HDR_LEN
), 0);
1734 m
->m_pkthdr
.rcvif
= ifp
;
1735 bond_bpf_input(ifp
, m
, eh_p
, bpf_func
);
1736 dlil_input_packet(ifp
, m
, frame_header
);
1745 static __inline__
const char *
1746 bondport_get_name(bondport_ref p
)
1748 return (p
->po_name
);
1751 static __inline__
int
1752 bondport_get_index(bondport_ref p
)
1754 return (p
->po_ifp
->if_index
);
1758 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
)
1760 struct ether_header
* eh_p
;
1763 /* packet_buffer_allocate leaves room for ethernet header */
1764 eh_p
= mtod(buf
, struct ether_header
*);
1765 bcopy(&slow_proto_multicast
, &eh_p
->ether_dhost
, sizeof(eh_p
->ether_dhost
));
1766 bcopy(&p
->po_saved_addr
, eh_p
->ether_shost
, sizeof(eh_p
->ether_shost
));
1767 eh_p
->ether_type
= htons(IEEE8023AD_SLOW_PROTO_ETHERTYPE
);
1768 error
= dlil_output(p
->po_ifp
, 0, buf
, NULL
, NULL
, 1);
1770 printf("bondport_slow_proto_transmit(%s) failed %d\n",
1771 bondport_get_name(p
), error
);
1777 bondport_timer_process_func(devtimer_ref timer
,
1778 devtimer_process_func_event event
)
1783 case devtimer_process_func_event_lock
:
1785 devtimer_retain(timer
);
1787 case devtimer_process_func_event_unlock
:
1788 if (devtimer_valid(timer
)) {
1789 /* as long as the devtimer is valid, we can look at arg0 */
1791 struct ifnet
* bond_ifp
= NULL
;
1793 p
= (bondport_ref
)devtimer_arg0(timer
);
1794 if (ifbond_selection(p
->po_bond
)) {
1795 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
1798 /* XXX need to take a reference on bond_ifp */
1799 bond_ifp
= p
->po_bond
->ifb_ifp
;
1801 devtimer_release(timer
);
1803 if (bond_ifp
!= NULL
) {
1804 interface_link_event(bond_ifp
, event_code
);
1808 /* timer is going away */
1809 devtimer_release(timer
);
1819 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
1820 int active
, int short_timeout
, int * ret_error
)
1823 bondport_ref p
= NULL
;
1824 lacp_actor_partner_state s
;
1827 p
= _MALLOC(sizeof(*p
), M_BOND
, M_WAITOK
);
1829 *ret_error
= ENOMEM
;
1832 bzero(p
, sizeof(*p
));
1833 multicast_list_init(&p
->po_multicast
);
1834 if ((u_long
)snprintf(p
->po_name
, sizeof(p
->po_name
), "%s%d",
1835 port_ifp
->if_name
, port_ifp
->if_unit
)
1836 >= sizeof(p
->po_name
)) {
1837 printf("if_bond: name too large\n");
1838 *ret_error
= EINVAL
;
1841 error
= siocgifdevmtu(port_ifp
, &p
->po_devmtu
);
1843 printf("if_bond: SIOCGIFDEVMTU %s failed, %d\n",
1844 bondport_get_name(p
), error
);
1847 /* remember the current interface MTU so it can be restored */
1848 p
->po_devmtu
.ifdm_current
= port_ifp
->if_mtu
;
1849 p
->po_ifp
= port_ifp
;
1850 p
->po_media_info
= interface_media_info(port_ifp
);
1851 p
->po_current_while_timer
= devtimer_create(bondport_timer_process_func
, p
);
1852 if (p
->po_current_while_timer
== NULL
) {
1853 *ret_error
= ENOMEM
;
1856 p
->po_periodic_timer
= devtimer_create(bondport_timer_process_func
, p
);
1857 if (p
->po_periodic_timer
== NULL
) {
1858 *ret_error
= ENOMEM
;
1861 p
->po_wait_while_timer
= devtimer_create(bondport_timer_process_func
, p
);
1862 if (p
->po_wait_while_timer
== NULL
) {
1863 *ret_error
= ENOMEM
;
1866 p
->po_transmit_timer
= devtimer_create(bondport_timer_process_func
, p
);
1867 if (p
->po_transmit_timer
== NULL
) {
1868 *ret_error
= ENOMEM
;
1871 p
->po_receive_state
= ReceiveState_none
;
1872 p
->po_mux_state
= MuxState_none
;
1873 p
->po_priority
= priority
;
1875 s
= lacp_actor_partner_state_set_aggregatable(s
);
1876 if (short_timeout
) {
1877 s
= lacp_actor_partner_state_set_short_timeout(s
);
1880 s
= lacp_actor_partner_state_set_active_lacp(s
);
1882 p
->po_actor_state
= s
;
1891 bondport_start(bondport_ref p
)
1893 bondport_receive_machine(p
, LAEventStart
, NULL
);
1894 bondport_mux_machine(p
, LAEventStart
, NULL
);
1895 bondport_periodic_transmit_machine(p
, LAEventStart
, NULL
);
1896 bondport_transmit_machine(p
, LAEventStart
, NULL
);
1901 * Function: bondport_invalidate_timers
1903 * Invalidate all of the timers for the bondport.
1906 bondport_invalidate_timers(bondport_ref p
)
1908 devtimer_invalidate(p
->po_current_while_timer
);
1909 devtimer_invalidate(p
->po_periodic_timer
);
1910 devtimer_invalidate(p
->po_wait_while_timer
);
1911 devtimer_invalidate(p
->po_transmit_timer
);
1915 bondport_free(bondport_ref p
)
1917 multicast_list_remove(&p
->po_multicast
);
1918 devtimer_release(p
->po_current_while_timer
);
1919 devtimer_release(p
->po_periodic_timer
);
1920 devtimer_release(p
->po_wait_while_timer
);
1921 devtimer_release(p
->po_transmit_timer
);
1926 #define BOND_ADD_PROGRESS_IN_LIST 0x1
1927 #define BOND_ADD_PROGRESS_PROTO_ATTACHED 0x2
1928 #define BOND_ADD_PROGRESS_LLADDR_SET 0x4
1929 #define BOND_ADD_PROGRESS_MTU_SET 0x8
1931 static __inline__
int
1932 bond_device_mtu(struct ifnet
* ifp
, ifbond_ref ifb
)
1934 return (((int)ifp
->if_mtu
> ifb
->ifb_altmtu
)
1935 ? (int)ifp
->if_mtu
: ifb
->ifb_altmtu
);
1939 bond_add_interface(struct ifnet
* ifp
, struct ifnet
* port_ifp
)
1945 struct sockaddr_dl
* ifb_sdl
;
1946 bondport_ref
* new_array
= NULL
;
1947 bondport_ref
* old_array
= NULL
;
1949 struct sockaddr_dl
* port_sdl
;
1952 /* pre-allocate space for new port */
1953 p
= bondport_create(port_ifp
, 0x8000, 1, 0, &error
);
1958 ifb
= (ifbond_ref
)ifp
->if_private
;
1959 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
1962 return ((ifb
== NULL
? EOPNOTSUPP
: EBUSY
));
1965 /* make sure this interface can handle our current MTU */
1966 devmtu
= bond_device_mtu(ifp
, ifb
);
1968 && (devmtu
> p
->po_devmtu
.ifdm_max
|| devmtu
< p
->po_devmtu
.ifdm_min
)) {
1970 printf("if_bond: interface %s doesn't support mtu %d",
1971 bondport_get_name(p
), devmtu
);
1976 /* make sure ifb doesn't get de-allocated while we wait */
1979 /* wait for other add or remove to complete */
1980 ifbond_wait(ifb
, "bond_add_interface");
1982 if (ifbond_flags_if_detaching(ifb
)) {
1983 /* someone destroyed the bond while we were waiting */
1987 if (bond_lookup_port(port_ifp
) != NULL
) {
1988 /* port is already part of a bond */
1992 ifnet_lock_exclusive(port_ifp
);
1993 if ((port_ifp
->if_eflags
& (IFEF_VLAN
| IFEF_BOND
)) != 0) {
1994 /* interface already has VLAN's, or is part of bond */
1995 ifnet_lock_done(port_ifp
);
2000 /* mark the interface busy */
2001 port_ifp
->if_eflags
|= IFEF_BOND
;
2002 ifnet_lock_done(port_ifp
);
2004 port_sdl
= ifp_get_sdl(port_ifp
);
2005 ifb_sdl
= ifp_get_sdl(ifp
);
2007 if (TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
2008 ifp
->if_hwassist
= port_ifp
->if_hwassist
;
2009 ifp
->if_flags
|= IFF_RUNNING
;
2010 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2011 /* first port added to bond determines bond's ethernet address */
2012 ether_addr_copy(LLADDR(ifb_sdl
), LLADDR(port_sdl
));
2013 ifb_sdl
->sdl_type
= IFT_ETHER
;
2014 ifb_sdl
->sdl_alen
= ETHER_ADDR_LEN
;
2017 if (ifp
->if_hwassist
!= port_ifp
->if_hwassist
) {
2018 printf("bond_add_interface(%s, %s) "
2019 "hwassist values don't match 0x%x != 0x%x\n",
2020 ifb
->ifb_name
, bondport_get_name(p
),
2021 ifp
->if_hwassist
, port_ifp
->if_hwassist
);
2024 * if the bond has VLAN's, we can't simply change the hwassist
2025 * field behind its back: this needs work
2027 ifp
->if_hwassist
= 0;
2032 /* remember the port's ethernet address so it can be restored */
2033 ether_addr_copy(&p
->po_saved_addr
, LLADDR(port_sdl
));
2035 /* add it to the list of ports */
2036 TAILQ_INSERT_TAIL(&ifb
->ifb_port_list
, p
, po_port_list
);
2037 ifb
->ifb_port_count
++;
2039 /* set the default MTU */
2040 if (ifp
->if_mtu
== 0) {
2041 ifp
->if_mtu
= ETHERMTU
;
2044 progress
|= BOND_ADD_PROGRESS_IN_LIST
;
2046 /* allocate a larger distributing array */
2047 new_array
= (bondport_ref
*)
2048 _MALLOC(sizeof(*new_array
) * ifb
->ifb_port_count
, M_BOND
, M_WAITOK
);
2049 if (new_array
== NULL
) {
2054 /* attach our BOND "protocol" to the interface */
2055 error
= bond_attach_protocol(port_ifp
);
2059 progress
|= BOND_ADD_PROGRESS_PROTO_ATTACHED
;
2061 /* set the interface MTU */
2062 devmtu
= bond_device_mtu(ifp
, ifb
);
2063 error
= siocsifmtu(port_ifp
, devmtu
);
2065 printf("bond_add_interface(%s, %s):"
2066 " SIOCSIFMTU %d failed %d\n",
2067 ifb
->ifb_name
, bondport_get_name(p
), devmtu
, error
);
2070 progress
|= BOND_ADD_PROGRESS_MTU_SET
;
2072 /* program the port with our multicast addresses */
2073 error
= multicast_list_program(&p
->po_multicast
, ifp
, port_ifp
);
2075 printf("bond_add_interface(%s, %s):"
2076 " multicast_list_program failed %d\n",
2077 ifb
->ifb_name
, bondport_get_name(p
), error
);
2081 /* mark the interface up */
2082 ifnet_set_flags(port_ifp
, IFF_UP
, IFF_UP
);
2084 error
= dlil_ioctl(0, port_ifp
, SIOCSIFFLAGS
, (caddr_t
)NULL
);
2086 printf("bond_add_interface(%s, %s): SIOCSIFFLAGS failed %d\n",
2087 ifb
->ifb_name
, bondport_get_name(p
), error
);
2091 /* re-program the port's ethernet address */
2092 error
= if_siflladdr(port_ifp
,
2093 (const struct ether_addr
*)LLADDR(ifb_sdl
));
2095 /* port doesn't support setting the link address */
2096 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2097 ifb
->ifb_name
, bondport_get_name(p
), error
);
2100 progress
|= BOND_ADD_PROGRESS_LLADDR_SET
;
2104 /* no failures past this point */
2107 /* copy the contents of the existing distributing array */
2108 if (ifb
->ifb_distributing_count
) {
2109 bcopy(ifb
->ifb_distributing_array
, new_array
,
2110 sizeof(*new_array
) * ifb
->ifb_distributing_count
);
2112 old_array
= ifb
->ifb_distributing_array
;
2113 ifb
->ifb_distributing_array
= new_array
;
2115 /* clear the busy state, and wakeup anyone waiting */
2116 ifbond_signal(ifb
, "bond_add_interface");
2119 /* check if we need to generate a link status event */
2120 if (ifbond_selection(ifb
)) {
2121 event_code
= (ifb
->ifb_active_lag
== NULL
)
2126 if (event_code
!= 0) {
2127 interface_link_event(ifp
, event_code
);
2129 if (old_array
!= NULL
) {
2130 FREE(old_array
, M_BOND
);
2135 bond_assert_lock_not_held();
2137 if (new_array
!= NULL
) {
2138 FREE(new_array
, M_BOND
);
2140 if ((progress
& BOND_ADD_PROGRESS_LLADDR_SET
) != 0) {
2143 error1
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2145 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2146 ifb
->ifb_name
, bondport_get_name(p
), error1
);
2149 if ((progress
& BOND_ADD_PROGRESS_PROTO_ATTACHED
) != 0) {
2150 (void)bond_detach_protocol(port_ifp
);
2152 if ((progress
& BOND_ADD_PROGRESS_MTU_SET
) != 0) {
2155 error1
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
2157 printf("bond_add_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2158 ifb
->ifb_name
, bondport_get_name(p
), p
->po_devmtu
.ifdm_current
,
2163 if ((progress
& BOND_ADD_PROGRESS_IN_LIST
) != 0) {
2164 TAILQ_REMOVE(&ifb
->ifb_port_list
, p
, po_port_list
);
2165 ifb
->ifb_port_count
--;
2167 ifnet_lock_exclusive(port_ifp
);
2168 port_ifp
->if_eflags
&= ~IFEF_BOND
;
2169 ifnet_lock_done(port_ifp
);
2170 if (TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
2171 ifb
->ifb_altmtu
= 0;
2173 ifp
->if_hwassist
= 0;
2174 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2175 bzero(LLADDR(ifb_sdl
), ETHER_ADDR_LEN
);
2176 ifb_sdl
->sdl_type
= IFT_IEEE8023ADLAG
;
2177 ifb_sdl
->sdl_alen
= 0;
2182 ifbond_release(ifb
);
2183 ifbond_signal(ifb
, "bond_add_interface");
2190 bond_remove_interface(ifbond_ref ifb
, struct ifnet
* port_ifp
)
2195 bondport_ref head_port
;
2196 struct sockaddr_dl
* ifb_sdl
;
2198 int new_link_address
= 0;
2200 lacp_actor_partner_state s
;
2202 bond_assert_lock_held();
2205 ifbond_wait(ifb
, "bond_remove_interface");
2207 p
= ifbond_lookup_port(ifb
, port_ifp
);
2210 /* it got removed by another thread */
2214 /* de-select it and remove it from the lists */
2215 bondport_disable_distributing(p
);
2216 bondport_set_selected(p
, SelectedState_UNSELECTED
);
2217 active_lag
= bondport_remove_from_LAG(p
);
2218 TAILQ_REMOVE(&ifb
->ifb_port_list
, p
, po_port_list
);
2219 ifb
->ifb_port_count
--;
2221 /* invalidate timers here while holding the bond_lock */
2222 bondport_invalidate_timers(p
);
2224 /* announce that we're Individual now */
2225 s
= p
->po_actor_state
;
2226 s
= lacp_actor_partner_state_set_individual(s
);
2227 s
= lacp_actor_partner_state_set_not_collecting(s
);
2228 s
= lacp_actor_partner_state_set_not_distributing(s
);
2229 s
= lacp_actor_partner_state_set_out_of_sync(s
);
2230 p
->po_actor_state
= s
;
2231 bondport_flags_set_ntt(p
);
2234 ifb_sdl
= ifp_get_sdl(ifp
);
2235 head_port
= TAILQ_FIRST(&ifb
->ifb_port_list
);
2236 if (head_port
== NULL
) {
2237 ifp
->if_flags
&= ~IFF_RUNNING
;
2238 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2239 ifb_sdl
->sdl_type
= IFT_IEEE8023ADLAG
;
2240 ifb_sdl
->sdl_alen
= 0;
2241 bzero(LLADDR(ifb_sdl
), ETHER_ADDR_LEN
);
2243 ifp
->if_hwassist
= 0;
2245 ifb
->ifb_altmtu
= 0;
2246 } else if (ifbond_flags_lladdr(ifb
) == FALSE
2247 && bcmp(&p
->po_saved_addr
, LLADDR(ifb_sdl
),
2248 ETHER_ADDR_LEN
) == 0) {
2249 /* this port gave the bond its ethernet address, switch to new one */
2250 ether_addr_copy(LLADDR(ifb_sdl
), &head_port
->po_saved_addr
);
2251 ifb_sdl
->sdl_type
= IFT_ETHER
;
2252 ifb_sdl
->sdl_alen
= ETHER_ADDR_LEN
;
2253 new_link_address
= 1;
2255 /* check if we need to generate a link status event */
2256 if (ifbond_selection(ifb
) || active_lag
) {
2257 event_code
= (ifb
->ifb_active_lag
== NULL
)
2263 bondport_transmit_machine(p
, LAEventStart
, (void *)1);
2265 if (new_link_address
) {
2266 struct ifnet
* scan_ifp
;
2267 bondport_ref scan_port
;
2269 /* ifbond_wait() allows port list traversal without holding the lock */
2271 /* re-program each port with the new link address */
2272 TAILQ_FOREACH(scan_port
, &ifb
->ifb_port_list
, po_port_list
) {
2273 scan_ifp
= scan_port
->po_ifp
;
2275 error
= if_siflladdr(scan_ifp
,
2276 (const struct ether_addr
*) LLADDR(ifb_sdl
));
2278 printf("bond_remove_interface(%s, %s): "
2279 "if_siflladdr (%s) failed %d\n",
2280 ifb
->ifb_name
, bondport_get_name(p
),
2281 bondport_get_name(scan_port
), error
);
2286 /* restore the port's ethernet address */
2287 error
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2289 printf("bond_remove_interface(%s, %s): if_siflladdr failed %d\n",
2290 ifb
->ifb_name
, bondport_get_name(p
), error
);
2293 /* restore the port's MTU */
2294 error
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
2296 printf("bond_remove_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2297 ifb
->ifb_name
, bondport_get_name(p
),
2298 p
->po_devmtu
.ifdm_current
, error
);
2301 /* remove the bond "protocol" */
2302 bond_detach_protocol(port_ifp
);
2304 /* generate link event */
2305 if (event_code
!= 0) {
2306 interface_link_event(ifp
, event_code
);
2310 ifbond_release(ifb
);
2312 ifnet_lock_exclusive(port_ifp
);
2313 port_ifp
->if_eflags
&= ~IFEF_BOND
;
2314 ifnet_lock_done(port_ifp
);
2317 ifbond_signal(ifb
, "bond_remove_interface");
2318 ifbond_release(ifb
); /* a second release for the second reference */
2323 bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
, user_addr_t datap
)
2328 struct if_bond_status_req
* ibsr
;
2329 struct if_bond_status ibs
;
2332 ibsr
= &(ibr_p
->ibr_ibru
.ibru_status
);
2333 if (ibsr
->ibsr_version
!= IF_BOND_STATUS_REQ_VERSION
) {
2336 ibsr
->ibsr_key
= ifb
->ifb_key
;
2337 ibsr
->ibsr_total
= ifb
->ifb_port_count
;
2338 dst
= proc_is64bit(current_proc())
2339 ? ibsr
->ibsr_ibsru
.ibsru_buffer64
2340 : CAST_USER_ADDR_T(ibsr
->ibsr_ibsru
.ibsru_buffer32
);
2341 if (dst
== USER_ADDR_NULL
) {
2342 /* just want to know how many there are */
2345 if (ibsr
->ibsr_count
< 0) {
2348 count
= (ifb
->ifb_port_count
< ibsr
->ibsr_count
)
2349 ? ifb
->ifb_port_count
: ibsr
->ibsr_count
;
2350 TAILQ_FOREACH(port
, &ifb
->ifb_port_list
, po_port_list
) {
2351 struct if_bond_partner_state
* ibps_p
;
2352 partner_state_ref ps
;
2357 bzero(&ibs
, sizeof(ibs
));
2358 strncpy(ibs
.ibs_if_name
, port
->po_name
, sizeof(ibs
.ibs_if_name
));
2359 ibs
.ibs_port_priority
= port
->po_priority
;
2360 ibs
.ibs_state
= port
->po_actor_state
;
2361 ibs
.ibs_selected_state
= port
->po_selected
;
2362 ps
= &port
->po_partner_state
;
2363 ibps_p
= &ibs
.ibs_partner_state
;
2364 ibps_p
->ibps_system
= ps
->ps_lag_info
.li_system
;
2365 ibps_p
->ibps_system_priority
= ps
->ps_lag_info
.li_system_priority
;
2366 ibps_p
->ibps_key
= ps
->ps_lag_info
.li_key
;
2367 ibps_p
->ibps_port
= ps
->ps_port
;
2368 ibps_p
->ibps_port_priority
= ps
->ps_port_priority
;
2369 ibps_p
->ibps_state
= ps
->ps_state
;
2370 error
= copyout(&ibs
, dst
, sizeof(ibs
));
2380 error
= copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2383 (void)copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2389 bond_set_promisc(__unused
struct ifnet
*ifp
)
2393 ifbond_ref ifb
= ifp
->if_private
;
2396 if ((ifp
->if_flags
& IFF_PROMISC
) != 0) {
2397 if ((ifb
->ifb_flags
& IFBF_PROMISC
) == 0) {
2398 error
= ifnet_set_promiscuous(ifb
->ifb_p
, 1);
2400 ifb
->ifb_flags
|= IFBF_PROMISC
;
2403 if ((ifb
->ifb_flags
& IFBF_PROMISC
) != 0) {
2404 error
= ifnet_set_promiscuous(ifb
->ifb_p
, 0);
2406 ifb
->ifb_flags
&= ~IFBF_PROMISC
;
2414 bond_get_mtu_values(ifbond_ref ifb
, int * ret_min
, int * ret_max
)
2420 if (TAILQ_FIRST(&ifb
->ifb_port_list
) != NULL
) {
2421 mtu_min
= IF_MINMTU
;
2423 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2424 struct ifdevmtu
* devmtu_p
= &p
->po_devmtu
;
2426 if (devmtu_p
->ifdm_min
> mtu_min
) {
2427 mtu_min
= devmtu_p
->ifdm_min
;
2429 if (mtu_max
== 0 || devmtu_p
->ifdm_max
< mtu_max
) {
2430 mtu_max
= devmtu_p
->ifdm_max
;
2439 bond_set_mtu_on_ports(ifbond_ref ifb
, int mtu
)
2444 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2445 error
= siocsifmtu(p
->po_ifp
, mtu
);
2447 printf("if_bond(%s): SIOCSIFMTU %s failed, %d\n",
2448 ifb
->ifb_name
, bondport_get_name(p
), error
);
2456 bond_set_mtu(struct ifnet
* ifp
, int mtu
, int isdevmtu
)
2466 ifb
= (ifbond_ref
)ifp
->if_private
;
2467 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2468 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2472 ifbond_wait(ifb
, "bond_set_mtu");
2475 if (ifp
->if_private
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2479 bond_get_mtu_values(ifb
, &mtu_min
, &mtu_max
);
2480 if (mtu
> mtu_max
) {
2484 if (mtu
< mtu_min
&& (isdevmtu
== 0 || mtu
!= 0)) {
2485 /* allow SIOCSIFALTMTU to set the mtu to 0 */
2490 new_max
= (mtu
> (int)ifp
->if_mtu
) ? mtu
: (int)ifp
->if_mtu
;
2493 new_max
= (mtu
> ifb
->ifb_altmtu
) ? mtu
: ifb
->ifb_altmtu
;
2495 old_max
= ((int)ifp
->if_mtu
> ifb
->ifb_altmtu
)
2496 ? (int)ifp
->if_mtu
: ifb
->ifb_altmtu
;
2497 if (new_max
!= old_max
) {
2498 /* we can safely walk the list of port without the lock held */
2500 error
= bond_set_mtu_on_ports(ifb
, new_max
);
2502 /* try our best to back out of it */
2503 (void)bond_set_mtu_on_ports(ifb
, old_max
);
2509 ifb
->ifb_altmtu
= mtu
;
2517 ifbond_signal(ifb
, "bond_set_mtu");
2518 ifbond_release(ifb
);
2526 bond_ioctl(struct ifnet
*ifp
, u_int32_t cmd
, void * data
)
2529 struct if_bond_req ibr
;
2530 struct ifaddr
* ifa
;
2533 struct ifmediareq64
*ifmr
;
2534 struct ifnet
* port_ifp
= NULL
;
2535 user_addr_t user_addr
;
2537 if (ifp
->if_type
!= IFT_IEEE8023ADLAG
) {
2538 return (EOPNOTSUPP
);
2540 ifr
= (struct ifreq
*)data
;
2541 ifa
= (struct ifaddr
*)data
;
2545 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
2548 case SIOCGIFMEDIA64
:
2551 ifb
= (ifbond_ref
)ifp
->if_private
;
2552 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2554 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2556 ifmr
= (struct ifmediareq64
*)data
;
2557 ifmr
->ifm_current
= IFM_ETHER
;
2559 ifmr
->ifm_status
= IFM_AVALID
;
2560 ifmr
->ifm_active
= IFM_ETHER
;
2561 ifmr
->ifm_count
= 1;
2562 if (ifb
->ifb_active_lag
!= NULL
) {
2563 ifmr
->ifm_active
= ifb
->ifb_active_lag
->lag_active_media
;
2564 ifmr
->ifm_status
|= IFM_ACTIVE
;
2567 user_addr
= (cmd
== SIOCGIFMEDIA64
)
2568 ? ifmr
->ifm_ifmu
.ifmu_ulist64
2569 : CAST_USER_ADDR_T(ifmr
->ifm_ifmu
.ifmu_ulist32
);
2570 if (user_addr
!= USER_ADDR_NULL
) {
2571 error
= copyout(&ifmr
->ifm_current
,
2578 /* XXX send the SIFMEDIA to all children? Or force autoselect? */
2584 ifb
= (ifbond_ref
)ifp
->if_private
;
2585 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2587 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2590 ifr
->ifr_devmtu
.ifdm_current
= bond_device_mtu(ifp
, ifb
);
2591 bond_get_mtu_values(ifb
, &ifr
->ifr_devmtu
.ifdm_min
,
2592 &ifr
->ifr_devmtu
.ifdm_max
);
2598 ifb
= (ifbond_ref
)ifp
->if_private
;
2599 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2601 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2604 ifr
->ifr_mtu
= ifb
->ifb_altmtu
;
2609 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 1);
2613 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 0);
2617 user_addr
= proc_is64bit(current_proc())
2618 ? ifr
->ifr_data64
: CAST_USER_ADDR_T(ifr
->ifr_data
);
2619 error
= copyin(user_addr
, &ibr
, sizeof(ibr
));
2623 switch (ibr
.ibr_op
) {
2624 case IF_BOND_OP_ADD_INTERFACE
:
2625 case IF_BOND_OP_REMOVE_INTERFACE
:
2626 /* XXX ifunit() needs to return a reference on the ifp */
2627 port_ifp
= ifunit(ibr
.ibr_ibru
.ibru_if_name
);
2628 if (port_ifp
== NULL
) {
2632 if (port_ifp
->if_type
!= IFT_ETHER
) {
2633 error
= EPROTONOSUPPORT
;
2637 case IF_BOND_OP_SET_VERBOSE
:
2646 switch (ibr
.ibr_op
) {
2647 case IF_BOND_OP_ADD_INTERFACE
:
2648 error
= bond_add_interface(ifp
, port_ifp
);
2650 case IF_BOND_OP_REMOVE_INTERFACE
:
2652 ifb
= (ifbond_ref
)ifp
->if_private
;
2653 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2655 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2657 error
= bond_remove_interface(ifb
, port_ifp
);
2660 case IF_BOND_OP_SET_VERBOSE
:
2662 if (g_bond
== NULL
) {
2667 g_bond
->verbose
= ibr
.ibr_ibru
.ibru_int_val
;
2674 user_addr
= proc_is64bit(current_proc())
2675 ? ifr
->ifr_data64
: CAST_USER_ADDR_T(ifr
->ifr_data
);
2676 error
= copyin(user_addr
, &ibr
, sizeof(ibr
));
2680 switch (ibr
.ibr_op
) {
2681 case IF_BOND_OP_GET_STATUS
:
2691 ifb
= (ifbond_ref
)ifp
->if_private
;
2692 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2694 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2696 switch (ibr
.ibr_op
) {
2697 case IF_BOND_OP_GET_STATUS
:
2698 error
= bond_get_status(ifb
, &ibr
, user_addr
);
2709 /* enable/disable promiscuous mode */
2711 error
= bond_set_promisc(ifp
);
2717 error
= bond_setmulti(ifp
);
2726 bond_if_free(struct ifnet
* ifp
)
2734 ifb
= (ifbond_ref
)ifp
->if_private
;
2739 ifp
->if_private
= NULL
;
2740 ifbond_release(ifb
);
2742 dlil_if_release(ifp
);
2747 bond_event(struct ifnet
* port_ifp
, struct kev_msg
* event
)
2749 struct ifnet
* bond_ifp
= NULL
;
2752 struct media_info media_info
;
2754 if (event
->vendor_code
!= KEV_VENDOR_APPLE
2755 || event
->kev_class
!= KEV_NETWORK_CLASS
2756 || event
->kev_subclass
!= KEV_DL_SUBCLASS
) {
2759 switch (event
->event_code
) {
2760 case KEV_DL_IF_DETACHING
:
2762 case KEV_DL_LINK_OFF
:
2763 case KEV_DL_LINK_ON
:
2764 media_info
= interface_media_info(port_ifp
);
2770 p
= bond_lookup_port(port_ifp
);
2775 switch (event
->event_code
) {
2776 case KEV_DL_IF_DETACHING
:
2777 bond_remove_interface(p
->po_bond
, p
->po_ifp
);
2779 case KEV_DL_LINK_OFF
:
2780 case KEV_DL_LINK_ON
:
2781 p
->po_media_info
= media_info
;
2782 if (p
->po_enabled
) {
2783 bondport_link_status_changed(p
);
2787 /* generate a link-event */
2788 if (ifbond_selection(p
->po_bond
)) {
2789 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
2792 /* XXX need to take a reference on bond_ifp */
2793 bond_ifp
= p
->po_bond
->ifb_ifp
;
2796 if (bond_ifp
!= NULL
) {
2797 interface_link_event(bond_ifp
, event_code
);
2803 interface_link_event(struct ifnet
* ifp
, u_long event_code
)
2806 struct kern_event_msg header
;
2808 char if_name
[IFNAMSIZ
];
2811 event
.header
.total_size
= sizeof(event
);
2812 event
.header
.vendor_code
= KEV_VENDOR_APPLE
;
2813 event
.header
.kev_class
= KEV_NETWORK_CLASS
;
2814 event
.header
.kev_subclass
= KEV_DL_SUBCLASS
;
2815 event
.header
.event_code
= event_code
;
2816 event
.header
.event_data
[0] = ifp
->if_family
;
2817 event
.unit
= (u_long
) ifp
->if_unit
;
2818 strncpy(event
.if_name
, ifp
->if_name
, IFNAMSIZ
);
2819 dlil_event(ifp
, &event
.header
);
2824 * Function: bond_attach_protocol
2826 * Attach a DLIL protocol to the interface.
2828 * The ethernet demux special cases to always return PF_BOND if the
2829 * interface is bonded. That means we receive all traffic from that
2830 * interface without passing any of the traffic to any other attached
2834 bond_attach_protocol(struct ifnet
*ifp
)
2837 struct dlil_proto_reg_str reg
;
2839 bzero(®
, sizeof(reg
));
2840 TAILQ_INIT(®
.demux_desc_head
);
2841 reg
.interface_family
= ifp
->if_family
;
2842 reg
.unit_number
= ifp
->if_unit
;
2843 reg
.input
= bond_input
;
2844 reg
.event
= bond_event
;
2845 reg
.protocol_family
= PF_BOND
;
2847 error
= dlil_attach_protocol(®
);
2849 printf("bond over %s%d: dlil_attach_protocol failed, %d\n",
2850 ifp
->if_name
, ifp
->if_unit
, error
);
2856 * Function: bond_detach_protocol
2858 * Detach our DLIL protocol from an interface
2861 bond_detach_protocol(struct ifnet
*ifp
)
2865 error
= dlil_detach_protocol(ifp
, PF_BOND
);
2867 printf("bond over %s%d: dlil_detach_protocol failed, %d\n",
2868 ifp
->if_name
, ifp
->if_unit
, error
);
2874 * DLIL interface family functions
2876 extern int ether_add_if(struct ifnet
*ifp
);
2877 extern int ether_del_if(struct ifnet
*ifp
);
2878 extern int ether_init_if(struct ifnet
*ifp
);
2879 extern int ether_add_proto_old(struct ifnet
*ifp
, u_long protocol_family
,
2880 struct ddesc_head_str
*desc_head
);
2882 extern int ether_attach_inet(struct ifnet
*ifp
, u_long protocol_family
);
2883 extern int ether_detach_inet(struct ifnet
*ifp
, u_long protocol_family
);
2884 extern int ether_attach_inet6(struct ifnet
*ifp
, u_long protocol_family
);
2885 extern int ether_detach_inet6(struct ifnet
*ifp
, u_long protocol_family
);
2887 __private_extern__
int
2888 bond_family_init(void)
2891 struct dlil_ifmod_reg_str ifmod_reg
;
2893 bzero(&ifmod_reg
, sizeof(ifmod_reg
));
2894 ifmod_reg
.add_if
= ether_add_if
;
2895 ifmod_reg
.del_if
= ether_del_if
;
2896 ifmod_reg
.init_if
= NULL
;
2897 ifmod_reg
.add_proto
= ether_add_proto_old
;
2898 ifmod_reg
.del_proto
= ether_del_proto
;
2899 ifmod_reg
.ifmod_ioctl
= ether_ioctl
;
2900 ifmod_reg
.shutdown
= NULL
;
2902 if (dlil_reg_if_modules(APPLE_IF_FAM_BOND
, &ifmod_reg
)) {
2903 printf("WARNING: bond_family_init -- "
2904 "Can't register if family modules\n");
2909 error
= dlil_reg_proto_module(PF_INET
, APPLE_IF_FAM_BOND
,
2913 printf("bond: dlil_reg_proto_module failed for AF_INET6 error=%d\n",
2918 error
= dlil_reg_proto_module(PF_INET6
, APPLE_IF_FAM_BOND
,
2920 ether_detach_inet6
);
2922 printf("bond: dlil_reg_proto_module failed for AF_INET6 error=%d\n",
2926 bond_clone_attach();
2938 ** LACP ifbond_list routines
2941 ifbond_list_find_moved_port(bondport_ref rx_port
,
2942 const lacp_actor_partner_tlv_ref atlv
)
2946 partner_state_ref ps
;
2949 TAILQ_FOREACH(bond
, &g_bond
->ifbond_list
, ifb_bond_list
) {
2950 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
2953 /* no point in comparing against ourselves */
2956 if (p
->po_receive_state
!= ReceiveState_PORT_DISABLED
) {
2957 /* it's not clear that we should be checking this */
2960 ps
= &p
->po_partner_state
;
2961 if (lacp_actor_partner_state_defaulted(ps
->ps_state
)) {
2964 ps_li
= &ps
->ps_lag_info
;
2965 if (ps
->ps_port
== lacp_actor_partner_tlv_get_port(atlv
)
2966 && bcmp(&ps_li
->li_system
, atlv
->lap_system
,
2967 sizeof(ps_li
->li_system
)) == 0) {
2968 if (g_bond
->verbose
) {
2969 timestamp_printf("System " EA_FORMAT
2970 " Port 0x%x moved from %s to %s\n",
2971 EA_LIST(&ps_li
->li_system
), ps
->ps_port
,
2972 bondport_get_name(p
),
2973 bondport_get_name(rx_port
));
2983 ** LACP ifbond, LAG routines
2987 ifbond_selection(ifbond_ref bond
)
2989 int all_ports_ready
= 0;
2990 int active_media
= 0;
2992 int lag_changed
= 0;
2996 lag
= ifbond_find_best_LAG(bond
, &active_media
);
2997 if (lag
!= bond
->ifb_active_lag
) {
2998 if (bond
->ifb_active_lag
!= NULL
) {
2999 ifbond_deactivate_LAG(bond
, bond
->ifb_active_lag
);
3000 bond
->ifb_active_lag
= NULL
;
3002 bond
->ifb_active_lag
= lag
;
3004 ifbond_activate_LAG(bond
, lag
, active_media
);
3008 else if (lag
!= NULL
) {
3009 if (lag
->lag_active_media
!= active_media
) {
3010 if (g_bond
->verbose
) {
3011 timestamp_printf("LAG PORT SPEED CHANGED from %d to %d\n",
3012 link_speed(lag
->lag_active_media
),
3013 link_speed(active_media
));
3015 ifbond_deactivate_LAG(bond
, lag
);
3016 ifbond_activate_LAG(bond
, lag
, active_media
);
3021 port_speed
= link_speed(active_media
);
3022 all_ports_ready
= ifbond_all_ports_ready(bond
);
3024 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3025 if (lag
!= NULL
&& p
->po_lag
== lag
3026 && media_speed(&p
->po_media_info
) == port_speed
3027 && (p
->po_mux_state
== MuxState_DETACHED
3028 || p
->po_selected
== SelectedState_SELECTED
3029 || p
->po_selected
== SelectedState_STANDBY
)
3030 && bondport_aggregatable(p
)) {
3031 if (bond
->ifb_max_active
> 0) {
3032 if (lag
->lag_selected_port_count
< bond
->ifb_max_active
) {
3033 if (p
->po_selected
== SelectedState_STANDBY
3034 || p
->po_selected
== SelectedState_UNSELECTED
) {
3035 bondport_set_selected(p
, SelectedState_SELECTED
);
3038 else if (p
->po_selected
== SelectedState_UNSELECTED
) {
3039 bondport_set_selected(p
, SelectedState_STANDBY
);
3043 bondport_set_selected(p
, SelectedState_SELECTED
);
3046 if (bondport_flags_selected_changed(p
)) {
3047 bondport_flags_clear_selected_changed(p
);
3048 bondport_mux_machine(p
, LAEventSelectedChange
, NULL
);
3051 && bondport_flags_ready(p
)
3052 && p
->po_mux_state
== MuxState_WAITING
) {
3053 bondport_mux_machine(p
, LAEventReady
, NULL
);
3055 bondport_transmit_machine(p
, LAEventStart
, NULL
);
3057 return (lag_changed
);
3061 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
)
3063 int best_active
= 0;
3064 LAG_ref best_lag
= NULL
;
3069 if (bond
->ifb_active_lag
!= NULL
) {
3070 best_lag
= bond
->ifb_active_lag
;
3071 best_count
= LAG_get_aggregatable_port_count(best_lag
, &best_active
);
3072 if (bond
->ifb_max_active
> 0
3073 && best_count
> bond
->ifb_max_active
) {
3074 best_count
= bond
->ifb_max_active
;
3076 best_speed
= link_speed(best_active
);
3078 TAILQ_FOREACH(lag
, &bond
->ifb_lag_list
, lag_list
) {
3083 if (lag
== bond
->ifb_active_lag
) {
3084 /* we've already computed it */
3087 count
= LAG_get_aggregatable_port_count(lag
, &active
);
3091 if (bond
->ifb_max_active
> 0
3092 && count
> bond
->ifb_max_active
) {
3093 /* if there's a limit, don't count extra links */
3094 count
= bond
->ifb_max_active
;
3096 speed
= link_speed(active
);
3097 if ((count
* speed
) > (best_count
* best_speed
)) {
3100 best_active
= active
;
3104 if (best_count
== 0) {
3107 *active_media
= best_active
;
3112 ifbond_deactivate_LAG(__unused ifbond_ref bond
, LAG_ref lag
)
3116 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3117 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3123 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
)
3128 if (bond
->ifb_max_active
> 0) {
3129 need
= bond
->ifb_max_active
;
3131 lag
->lag_active_media
= active_media
;
3132 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3133 if (bondport_aggregatable(p
) == 0) {
3134 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3136 else if (media_speed(&p
->po_media_info
) != link_speed(active_media
)) {
3137 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3139 else if (p
->po_mux_state
== MuxState_DETACHED
) {
3140 if (bond
->ifb_max_active
> 0) {
3142 bondport_set_selected(p
, SelectedState_SELECTED
);
3146 bondport_set_selected(p
, SelectedState_STANDBY
);
3150 bondport_set_selected(p
, SelectedState_SELECTED
);
3154 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3162 ifbond_set_max_active(ifbond_ref bond
, int max_active
)
3164 LAG_ref lag
= bond
->ifb_active_lag
;
3166 bond
->ifb_max_active
= max_active
;
3167 if (bond
->ifb_max_active
<= 0 || lag
== NULL
) {
3170 if (lag
->lag_selected_port_count
> bond
->ifb_max_active
) {
3174 remove_count
= lag
->lag_selected_port_count
- bond
->ifb_max_active
;
3175 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3176 if (p
->po_selected
== SelectedState_SELECTED
) {
3177 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3179 if (remove_count
== 0) {
3190 ifbond_all_ports_ready(ifbond_ref bond
)
3195 if (bond
->ifb_active_lag
== NULL
) {
3198 TAILQ_FOREACH(p
, &bond
->ifb_active_lag
->lag_port_list
, po_lag_port_list
) {
3199 if (p
->po_mux_state
== MuxState_WAITING
3200 && p
->po_selected
== SelectedState_SELECTED
) {
3201 if (bondport_flags_ready(p
) == 0) {
3205 /* note that there was at least one ready port */
3212 ifbond_all_ports_attached(ifbond_ref bond
, bondport_ref this_port
)
3216 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3217 if (this_port
== p
) {
3220 if (bondport_flags_mux_attached(p
) == 0) {
3228 ifbond_get_LAG_matching_port(ifbond_ref bond
, bondport_ref p
)
3232 TAILQ_FOREACH(lag
, &bond
->ifb_lag_list
, lag_list
) {
3233 if (bcmp(&lag
->lag_info
, &p
->po_partner_state
.ps_lag_info
,
3234 sizeof(lag
->lag_info
)) == 0) {
3242 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
)
3252 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3253 if (bondport_aggregatable(p
)) {
3256 this_speed
= media_speed(&p
->po_media_info
);
3257 if (this_speed
== 0) {
3260 if (this_speed
> speed
) {
3261 active
= p
->po_media_info
.mi_active
;
3265 else if (this_speed
== speed
) {
3270 *active_media
= active
;
3276 ** LACP bondport routines
3279 bondport_link_status_changed(bondport_ref p
)
3281 ifbond_ref bond
= p
->po_bond
;
3283 if (g_bond
->verbose
) {
3284 if (media_active(&p
->po_media_info
)) {
3285 timestamp_printf("[%s] Link UP %d Mbit/s %s duplex\n",
3286 bondport_get_name(p
),
3287 media_speed(&p
->po_media_info
),
3288 media_full_duplex(&p
->po_media_info
)
3292 timestamp_printf("[%s] Link DOWN\n", bondport_get_name(p
));
3295 if (media_active(&p
->po_media_info
)
3296 && bond
->ifb_active_lag
!= NULL
3297 && p
->po_lag
== bond
->ifb_active_lag
3298 && p
->po_selected
!= SelectedState_UNSELECTED
) {
3299 if (media_speed(&p
->po_media_info
) != p
->po_lag
->lag_active_media
) {
3300 if (g_bond
->verbose
) {
3301 timestamp_printf("[%s] Port speed %d differs from LAG %d\n",
3302 bondport_get_name(p
),
3303 media_speed(&p
->po_media_info
),
3304 link_speed(p
->po_lag
->lag_active_media
));
3306 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3309 bondport_receive_machine(p
, LAEventMediaChange
, NULL
);
3310 bondport_mux_machine(p
, LAEventMediaChange
, NULL
);
3311 bondport_periodic_transmit_machine(p
, LAEventMediaChange
, NULL
);
3317 bondport_aggregatable(bondport_ref p
)
3319 partner_state_ref ps
= &p
->po_partner_state
;
3321 if (lacp_actor_partner_state_aggregatable(p
->po_actor_state
) == 0
3322 || lacp_actor_partner_state_aggregatable(ps
->ps_state
) == 0) {
3323 /* we and/or our partner are individual */
3326 if (p
->po_lag
== NULL
) {
3329 switch (p
->po_receive_state
) {
3331 if (g_bond
->verbose
) {
3332 timestamp_printf("[%s] Port is not selectable\n",
3333 bondport_get_name(p
));
3336 case ReceiveState_CURRENT
:
3337 case ReceiveState_EXPIRED
:
3344 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
)
3346 LAG_info_ref lag_li
;
3347 partner_state_ref ps
;
3350 ps
= &p
->po_partner_state
;
3351 ps_li
= &ps
->ps_lag_info
;
3352 lag_li
= &lag
->lag_info
;
3353 if (ps_li
->li_system_priority
== lag_li
->li_system_priority
3354 && ps_li
->li_key
== lag_li
->li_key
3355 && (bcmp(&ps_li
->li_system
, &lag_li
->li_system
,
3356 sizeof(lag_li
->li_system
))
3364 bondport_remove_from_LAG(bondport_ref p
)
3367 ifbond_ref bond
= p
->po_bond
;
3368 LAG_ref lag
= p
->po_lag
;
3373 TAILQ_REMOVE(&lag
->lag_port_list
, p
, po_lag_port_list
);
3374 if (g_bond
->verbose
) {
3375 timestamp_printf("[%s] Removed from LAG (0x%04x," EA_FORMAT
3377 bondport_get_name(p
),
3378 lag
->lag_info
.li_system_priority
,
3379 EA_LIST(&lag
->lag_info
.li_system
),
3380 lag
->lag_info
.li_key
);
3383 lag
->lag_port_count
--;
3384 if (lag
->lag_port_count
> 0) {
3385 return (bond
->ifb_active_lag
== lag
);
3387 if (g_bond
->verbose
) {
3388 timestamp_printf("Key 0x%04x: LAG Released (%04x," EA_FORMAT
3391 lag
->lag_info
.li_system_priority
,
3392 EA_LIST(&lag
->lag_info
.li_system
),
3393 lag
->lag_info
.li_key
);
3395 TAILQ_REMOVE(&bond
->ifb_lag_list
, lag
, lag_list
);
3396 if (bond
->ifb_active_lag
== lag
) {
3397 bond
->ifb_active_lag
= NULL
;
3401 return (active_lag
);
3405 bondport_add_to_LAG(bondport_ref p
, LAG_ref lag
)
3407 TAILQ_INSERT_TAIL(&lag
->lag_port_list
, p
, po_lag_port_list
);
3409 lag
->lag_port_count
++;
3410 if (g_bond
->verbose
) {
3411 timestamp_printf("[%s] Added to LAG (0x%04x," EA_FORMAT
"0x%04x)\n",
3412 bondport_get_name(p
),
3413 lag
->lag_info
.li_system_priority
,
3414 EA_LIST(&lag
->lag_info
.li_system
),
3415 lag
->lag_info
.li_key
);
3421 bondport_assign_to_LAG(bondport_ref p
)
3423 ifbond_ref bond
= p
->po_bond
;
3426 if (lacp_actor_partner_state_defaulted(p
->po_actor_state
)) {
3427 bondport_remove_from_LAG(p
);
3432 if (bondport_matches_LAG(p
, lag
)) {
3436 bondport_remove_from_LAG(p
);
3438 lag
= ifbond_get_LAG_matching_port(bond
, p
);
3440 bondport_add_to_LAG(p
, lag
);
3443 lag
= (LAG_ref
)_MALLOC(sizeof(*lag
), M_BOND
, M_WAITOK
);
3444 TAILQ_INIT(&lag
->lag_port_list
);
3445 lag
->lag_port_count
= 0;
3446 lag
->lag_selected_port_count
= 0;
3447 lag
->lag_info
= p
->po_partner_state
.ps_lag_info
;
3448 TAILQ_INSERT_TAIL(&bond
->ifb_lag_list
, lag
, lag_list
);
3449 if (g_bond
->verbose
) {
3450 timestamp_printf("Key 0x%04x: LAG Created (0x%04x," EA_FORMAT
3453 lag
->lag_info
.li_system_priority
,
3454 EA_LIST(&lag
->lag_info
.li_system
),
3455 lag
->lag_info
.li_key
);
3457 bondport_add_to_LAG(p
, lag
);
3462 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
)
3464 bondport_ref moved_port
;
3467 = ifbond_list_find_moved_port(p
, (const lacp_actor_partner_tlv_ref
)
3468 &in_lacpdu_p
->la_actor_tlv
);
3469 if (moved_port
!= NULL
) {
3470 bondport_receive_machine(moved_port
, LAEventPortMoved
, NULL
);
3472 bondport_receive_machine(p
, LAEventPacket
, in_lacpdu_p
);
3473 bondport_mux_machine(p
, LAEventPacket
, in_lacpdu_p
);
3474 bondport_periodic_transmit_machine(p
, LAEventPacket
, in_lacpdu_p
);
3479 bondport_set_selected(bondport_ref p
, SelectedState s
)
3481 if (s
!= p
->po_selected
) {
3482 ifbond_ref bond
= p
->po_bond
;
3483 LAG_ref lag
= p
->po_lag
;
3485 bondport_flags_set_selected_changed(p
);
3486 if (lag
!= NULL
&& bond
->ifb_active_lag
== lag
) {
3487 if (p
->po_selected
== SelectedState_SELECTED
) {
3488 lag
->lag_selected_port_count
--;
3490 else if (s
== SelectedState_SELECTED
) {
3491 lag
->lag_selected_port_count
++;
3493 if (g_bond
->verbose
) {
3494 timestamp_printf("[%s] SetSelected: %s (was %s)\n",
3495 bondport_get_name(p
),
3496 SelectedStateString(s
),
3497 SelectedStateString(p
->po_selected
));
3510 bondport_UpdateDefaultSelected(bondport_ref p
)
3512 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3517 bondport_RecordDefault(bondport_ref p
)
3519 bzero(&p
->po_partner_state
, sizeof(p
->po_partner_state
));
3521 = lacp_actor_partner_state_set_defaulted(p
->po_actor_state
);
3522 bondport_assign_to_LAG(p
);
3527 bondport_UpdateSelected(bondport_ref p
, lacpdu_ref lacpdu_p
)
3529 lacp_actor_partner_tlv_ref actor
;
3530 partner_state_ref ps
;
3533 /* compare the PDU's Actor information to our Partner state */
3534 actor
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_actor_tlv
;
3535 ps
= &p
->po_partner_state
;
3536 ps_li
= &ps
->ps_lag_info
;
3537 if (lacp_actor_partner_tlv_get_port(actor
) != ps
->ps_port
3538 || (lacp_actor_partner_tlv_get_port_priority(actor
)
3539 != ps
->ps_port_priority
)
3540 || bcmp(actor
->lap_system
, &ps_li
->li_system
, sizeof(ps_li
->li_system
))
3541 || (lacp_actor_partner_tlv_get_system_priority(actor
)
3542 != ps_li
->li_system_priority
)
3543 || (lacp_actor_partner_tlv_get_key(actor
) != ps_li
->li_key
)
3544 || (lacp_actor_partner_state_aggregatable(actor
->lap_state
)
3545 != lacp_actor_partner_state_aggregatable(ps
->ps_state
))) {
3546 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3547 if (g_bond
->verbose
) {
3548 timestamp_printf("[%s] updateSelected UNSELECTED\n",
3549 bondport_get_name(p
));
3556 bondport_RecordPDU(bondport_ref p
, lacpdu_ref lacpdu_p
)
3558 lacp_actor_partner_tlv_ref actor
;
3559 ifbond_ref bond
= p
->po_bond
;
3560 int lacp_maintain
= 0;
3561 partner_state_ref ps
;
3562 lacp_actor_partner_tlv_ref partner
;
3565 /* copy the PDU's Actor information into our Partner state */
3566 actor
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_actor_tlv
;
3567 ps
= &p
->po_partner_state
;
3568 ps_li
= &ps
->ps_lag_info
;
3569 ps
->ps_port
= lacp_actor_partner_tlv_get_port(actor
);
3570 ps
->ps_port_priority
= lacp_actor_partner_tlv_get_port_priority(actor
);
3571 ps_li
->li_system
= *((lacp_system_ref
)actor
->lap_system
);
3572 ps_li
->li_system_priority
3573 = lacp_actor_partner_tlv_get_system_priority(actor
);
3574 ps_li
->li_key
= lacp_actor_partner_tlv_get_key(actor
);
3575 ps
->ps_state
= lacp_actor_partner_state_set_out_of_sync(actor
->lap_state
);
3577 = lacp_actor_partner_state_set_not_defaulted(p
->po_actor_state
);
3579 /* compare the PDU's Partner information to our own information */
3580 partner
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_partner_tlv
;
3582 if (lacp_actor_partner_state_active_lacp(ps
->ps_state
)
3583 || (lacp_actor_partner_state_active_lacp(p
->po_actor_state
)
3584 && lacp_actor_partner_state_active_lacp(partner
->lap_state
))) {
3585 if (g_bond
->verbose
) {
3586 timestamp_printf("[%s] recordPDU: LACP will maintain\n",
3587 bondport_get_name(p
));
3591 if ((lacp_actor_partner_tlv_get_port(partner
)
3592 == bondport_get_index(p
))
3593 && lacp_actor_partner_tlv_get_port_priority(partner
) == p
->po_priority
3594 && bcmp(partner
->lap_system
, &g_bond
->system
,
3595 sizeof(g_bond
->system
)) == 0
3596 && (lacp_actor_partner_tlv_get_system_priority(partner
)
3597 == g_bond
->system_priority
)
3598 && lacp_actor_partner_tlv_get_key(partner
) == bond
->ifb_key
3599 && (lacp_actor_partner_state_aggregatable(partner
->lap_state
)
3600 == lacp_actor_partner_state_aggregatable(p
->po_actor_state
))
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\n",
3606 bondport_get_name(p
));
3609 else if (lacp_actor_partner_state_aggregatable(actor
->lap_state
) == 0
3610 && lacp_actor_partner_state_in_sync(actor
->lap_state
)
3612 ps
->ps_state
= lacp_actor_partner_state_set_in_sync(ps
->ps_state
);
3613 if (g_bond
->verbose
) {
3614 timestamp_printf("[%s] recordPDU: LACP partner in sync (ind)\n",
3615 bondport_get_name(p
));
3618 bondport_assign_to_LAG(p
);
3622 static __inline__ lacp_actor_partner_state
3623 updateNTTBits(lacp_actor_partner_state s
)
3625 return (s
& (LACP_ACTOR_PARTNER_STATE_LACP_ACTIVITY
3626 | LACP_ACTOR_PARTNER_STATE_LACP_TIMEOUT
3627 | LACP_ACTOR_PARTNER_STATE_AGGREGATION
3628 | LACP_ACTOR_PARTNER_STATE_SYNCHRONIZATION
));
3632 bondport_UpdateNTT(bondport_ref p
, lacpdu_ref lacpdu_p
)
3634 ifbond_ref bond
= p
->po_bond
;
3635 lacp_actor_partner_tlv_ref partner
;
3637 /* compare the PDU's Actor information to our Partner state */
3638 partner
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_partner_tlv
;
3639 if ((lacp_actor_partner_tlv_get_port(partner
) != bondport_get_index(p
))
3640 || lacp_actor_partner_tlv_get_port_priority(partner
) != p
->po_priority
3641 || bcmp(partner
->lap_system
, &g_bond
->system
, sizeof(g_bond
->system
))
3642 || (lacp_actor_partner_tlv_get_system_priority(partner
)
3643 != g_bond
->system_priority
)
3644 || lacp_actor_partner_tlv_get_key(partner
) != bond
->ifb_key
3645 || (updateNTTBits(partner
->lap_state
)
3646 != updateNTTBits(p
->po_actor_state
))) {
3647 bondport_flags_set_ntt(p
);
3648 if (g_bond
->verbose
) {
3649 timestamp_printf("[%s] updateNTT: Need To Transmit\n",
3650 bondport_get_name(p
));
3657 bondport_AttachMuxToAggregator(bondport_ref p
)
3659 if (bondport_flags_mux_attached(p
) == 0) {
3660 if (g_bond
->verbose
) {
3661 timestamp_printf("[%s] Attached Mux To Aggregator\n",
3662 bondport_get_name(p
));
3664 bondport_flags_set_mux_attached(p
);
3670 bondport_DetachMuxFromAggregator(bondport_ref p
)
3672 if (bondport_flags_mux_attached(p
)) {
3673 if (g_bond
->verbose
) {
3674 timestamp_printf("[%s] Detached Mux From Aggregator\n",
3675 bondport_get_name(p
));
3677 bondport_flags_clear_mux_attached(p
);
3683 bondport_enable_distributing(bondport_ref p
)
3685 if (bondport_flags_distributing(p
) == 0) {
3686 ifbond_ref bond
= p
->po_bond
;
3688 bond
->ifb_distributing_array
[bond
->ifb_distributing_count
++] = p
;
3689 if (g_bond
->verbose
) {
3690 timestamp_printf("[%s] Distribution Enabled\n",
3691 bondport_get_name(p
));
3693 bondport_flags_set_distributing(p
);
3699 bondport_disable_distributing(bondport_ref p
)
3701 if (bondport_flags_distributing(p
)) {
3702 bondport_ref
* array
;
3708 array
= bond
->ifb_distributing_array
;
3709 count
= bond
->ifb_distributing_count
;
3710 for (i
= 0; i
< count
; i
++) {
3711 if (array
[i
] == p
) {
3714 for (j
= i
; j
< (count
- 1); j
++) {
3715 array
[j
] = array
[j
+ 1];
3720 bond
->ifb_distributing_count
--;
3721 if (g_bond
->verbose
) {
3722 timestamp_printf("[%s] Distribution Disabled\n",
3723 bondport_get_name(p
));
3725 bondport_flags_clear_distributing(p
);
3731 ** Receive machine functions
3734 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
3737 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
3740 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
3743 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
3746 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
3749 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
3753 bondport_receive_machine_event(bondport_ref p
, LAEvent event
,
3756 switch (p
->po_receive_state
) {
3757 case ReceiveState_none
:
3758 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
3760 case ReceiveState_INITIALIZE
:
3761 bondport_receive_machine_initialize(p
, event
, event_data
);
3763 case ReceiveState_PORT_DISABLED
:
3764 bondport_receive_machine_port_disabled(p
, event
, event_data
);
3766 case ReceiveState_EXPIRED
:
3767 bondport_receive_machine_expired(p
, event
, event_data
);
3769 case ReceiveState_LACP_DISABLED
:
3770 bondport_receive_machine_lacp_disabled(p
, event
, event_data
);
3772 case ReceiveState_DEFAULTED
:
3773 bondport_receive_machine_defaulted(p
, event
, event_data
);
3775 case ReceiveState_CURRENT
:
3776 bondport_receive_machine_current(p
, event
, event_data
);
3785 bondport_receive_machine(bondport_ref p
, LAEvent event
,
3790 if (p
->po_receive_state
!= ReceiveState_LACP_DISABLED
) {
3791 bondport_receive_machine_current(p
, event
, event_data
);
3794 case LAEventMediaChange
:
3795 if (media_active(&p
->po_media_info
)) {
3796 switch (p
->po_receive_state
) {
3797 case ReceiveState_PORT_DISABLED
:
3798 case ReceiveState_LACP_DISABLED
:
3799 bondport_receive_machine_port_disabled(p
, LAEventMediaChange
, NULL
);
3806 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
3810 bondport_receive_machine_event(p
, event
, event_data
);
3817 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
3818 __unused
void * event_data
)
3822 devtimer_cancel(p
->po_current_while_timer
);
3823 if (g_bond
->verbose
) {
3824 timestamp_printf("[%s] Receive INITIALIZE\n",
3825 bondport_get_name(p
));
3827 p
->po_receive_state
= ReceiveState_INITIALIZE
;
3828 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3829 bondport_RecordDefault(p
);
3831 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
3832 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
3841 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
3842 __unused
void * event_data
)
3844 partner_state_ref ps
;
3848 devtimer_cancel(p
->po_current_while_timer
);
3849 if (g_bond
->verbose
) {
3850 timestamp_printf("[%s] Receive PORT_DISABLED\n",
3851 bondport_get_name(p
));
3853 p
->po_receive_state
= ReceiveState_PORT_DISABLED
;
3854 ps
= &p
->po_partner_state
;
3855 ps
->ps_state
= lacp_actor_partner_state_set_out_of_sync(ps
->ps_state
);
3857 case LAEventMediaChange
:
3858 if (media_active(&p
->po_media_info
)) {
3859 if (media_full_duplex(&p
->po_media_info
)) {
3860 bondport_receive_machine_expired(p
, LAEventStart
, NULL
);
3863 bondport_receive_machine_lacp_disabled(p
, LAEventStart
, NULL
);
3866 else if (p
->po_selected
== SelectedState_SELECTED
) {
3869 if (g_bond
->verbose
) {
3870 timestamp_printf("[%s] Receive PORT_DISABLED: "
3871 "link timer started\n",
3872 bondport_get_name(p
));
3876 devtimer_set_relative(p
->po_current_while_timer
, tv
,
3877 (devtimer_timeout_func
)
3878 bondport_receive_machine_port_disabled
,
3879 (void *)LAEventTimeout
, NULL
);
3881 else if (p
->po_selected
== SelectedState_STANDBY
) {
3882 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3885 case LAEventTimeout
:
3886 if (p
->po_selected
== SelectedState_SELECTED
) {
3887 if (g_bond
->verbose
) {
3888 timestamp_printf("[%s] Receive PORT_DISABLED: "
3889 "link timer completed, marking UNSELECTED\n",
3890 bondport_get_name(p
));
3892 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3895 case LAEventPortMoved
:
3896 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
3905 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
3906 __unused
void * event_data
)
3908 lacp_actor_partner_state s
;
3913 devtimer_cancel(p
->po_current_while_timer
);
3914 if (g_bond
->verbose
) {
3915 timestamp_printf("[%s] Receive EXPIRED\n",
3916 bondport_get_name(p
));
3918 p
->po_receive_state
= ReceiveState_EXPIRED
;
3919 s
= p
->po_partner_state
.ps_state
;
3920 s
= lacp_actor_partner_state_set_out_of_sync(s
);
3921 s
= lacp_actor_partner_state_set_short_timeout(s
);
3922 p
->po_partner_state
.ps_state
= s
;
3924 = lacp_actor_partner_state_set_expired(p
->po_actor_state
);
3925 /* start current_while timer */
3926 tv
.tv_sec
= LACP_SHORT_TIMEOUT_TIME
;
3928 devtimer_set_relative(p
->po_current_while_timer
, tv
,
3929 (devtimer_timeout_func
)
3930 bondport_receive_machine_expired
,
3931 (void *)LAEventTimeout
, NULL
);
3934 case LAEventTimeout
:
3935 bondport_receive_machine_defaulted(p
, LAEventStart
, NULL
);
3944 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
3945 __unused
void * event_data
)
3947 partner_state_ref ps
;
3950 devtimer_cancel(p
->po_current_while_timer
);
3951 if (g_bond
->verbose
) {
3952 timestamp_printf("[%s] Receive LACP_DISABLED\n",
3953 bondport_get_name(p
));
3955 p
->po_receive_state
= ReceiveState_LACP_DISABLED
;
3956 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3957 bondport_RecordDefault(p
);
3958 ps
= &p
->po_partner_state
;
3959 ps
->ps_state
= lacp_actor_partner_state_set_individual(ps
->ps_state
);
3961 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
3970 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
3971 __unused
void * event_data
)
3975 devtimer_cancel(p
->po_current_while_timer
);
3976 if (g_bond
->verbose
) {
3977 timestamp_printf("[%s] Receive DEFAULTED\n",
3978 bondport_get_name(p
));
3980 p
->po_receive_state
= ReceiveState_DEFAULTED
;
3981 bondport_UpdateDefaultSelected(p
);
3982 bondport_RecordDefault(p
);
3984 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
3993 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
3996 partner_state_ref ps
;
4001 devtimer_cancel(p
->po_current_while_timer
);
4002 if (g_bond
->verbose
) {
4003 timestamp_printf("[%s] Receive CURRENT\n",
4004 bondport_get_name(p
));
4006 p
->po_receive_state
= ReceiveState_CURRENT
;
4007 bondport_UpdateSelected(p
, event_data
);
4008 bondport_UpdateNTT(p
, event_data
);
4009 bondport_RecordPDU(p
, event_data
);
4011 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4012 bondport_assign_to_LAG(p
);
4013 /* start current_while timer */
4014 ps
= &p
->po_partner_state
;
4015 if (lacp_actor_partner_state_short_timeout(ps
->ps_state
)) {
4016 tv
.tv_sec
= LACP_SHORT_TIMEOUT_TIME
;
4019 tv
.tv_sec
= LACP_LONG_TIMEOUT_TIME
;
4022 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4023 (devtimer_timeout_func
)
4024 bondport_receive_machine_current
,
4025 (void *)LAEventTimeout
, NULL
);
4027 case LAEventTimeout
:
4028 bondport_receive_machine_expired(p
, LAEventStart
, NULL
);
4037 ** Periodic Transmission machine
4041 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
4042 __unused
void * event_data
)
4045 partner_state_ref ps
;
4050 if (g_bond
->verbose
) {
4051 timestamp_printf("[%s] periodic_transmit Start\n",
4052 bondport_get_name(p
));
4055 case LAEventMediaChange
:
4056 devtimer_cancel(p
->po_periodic_timer
);
4057 p
->po_periodic_interval
= 0;
4058 if (media_active(&p
->po_media_info
) == 0
4059 || media_full_duplex(&p
->po_media_info
) == 0) {
4063 /* Neither Partner nor Actor are LACP Active, no periodic tx */
4064 ps
= &p
->po_partner_state
;
4065 if (lacp_actor_partner_state_active_lacp(p
->po_actor_state
) == 0
4066 && (lacp_actor_partner_state_active_lacp(ps
->ps_state
)
4068 devtimer_cancel(p
->po_periodic_timer
);
4069 p
->po_periodic_interval
= 0;
4072 if (lacp_actor_partner_state_short_timeout(ps
->ps_state
)) {
4073 interval
= LACP_FAST_PERIODIC_TIME
;
4076 interval
= LACP_SLOW_PERIODIC_TIME
;
4078 if (p
->po_periodic_interval
!= interval
) {
4079 if (interval
== LACP_FAST_PERIODIC_TIME
4080 && p
->po_periodic_interval
== LACP_SLOW_PERIODIC_TIME
) {
4081 if (g_bond
->verbose
) {
4082 timestamp_printf("[%s] periodic_transmit:"
4083 " Need To Transmit\n",
4084 bondport_get_name(p
));
4086 bondport_flags_set_ntt(p
);
4088 p
->po_periodic_interval
= interval
;
4090 tv
.tv_sec
= interval
;
4091 devtimer_set_relative(p
->po_periodic_timer
, tv
,
4092 (devtimer_timeout_func
)
4093 bondport_periodic_transmit_machine
,
4094 (void *)LAEventTimeout
, NULL
);
4095 if (g_bond
->verbose
) {
4096 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4097 bondport_get_name(p
),
4098 p
->po_periodic_interval
);
4102 case LAEventTimeout
:
4103 bondport_flags_set_ntt(p
);
4104 tv
.tv_sec
= p
->po_periodic_interval
;
4106 devtimer_set_relative(p
->po_periodic_timer
, tv
, (devtimer_timeout_func
)
4107 bondport_periodic_transmit_machine
,
4108 (void *)LAEventTimeout
, NULL
);
4109 if (g_bond
->verbose
> 1) {
4110 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4111 bondport_get_name(p
), p
->po_periodic_interval
);
4124 bondport_can_transmit(bondport_ref p
, int32_t current_secs
,
4127 if (p
->po_last_transmit_secs
!= current_secs
) {
4128 p
->po_last_transmit_secs
= current_secs
;
4129 p
->po_n_transmit
= 0;
4131 if (p
->po_n_transmit
< LACP_PACKET_RATE
) {
4135 if (next_secs
!= NULL
) {
4136 *next_secs
= current_secs
+ 1;
4142 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
4145 lacp_actor_partner_tlv_ref aptlv
;
4146 lacp_collector_tlv_ref ctlv
;
4147 struct timeval next_tick_time
= {0, 0};
4148 lacpdu_ref out_lacpdu_p
;
4149 packet_buffer_ref pkt
;
4150 partner_state_ref ps
;
4154 case LAEventTimeout
:
4156 if (p
->po_periodic_interval
== 0 || bondport_flags_ntt(p
) == 0) {
4159 if (event_data
!= NULL
) {
4160 /* we're going away, transmit the packet no matter what */
4162 else if (bondport_can_transmit(p
, devtimer_current_secs(),
4163 &next_tick_time
.tv_sec
) == 0) {
4164 if (devtimer_enabled(p
->po_transmit_timer
)) {
4165 if (g_bond
->verbose
> 0) {
4166 timestamp_printf("[%s] Transmit Timer Already Set\n",
4167 bondport_get_name(p
));
4171 devtimer_set_absolute(p
->po_transmit_timer
, next_tick_time
,
4172 (devtimer_timeout_func
)
4173 bondport_transmit_machine
,
4174 (void *)LAEventTimeout
, NULL
);
4175 if (g_bond
->verbose
> 0) {
4176 timestamp_printf("[%s] Transmit Timer Deadline %d secs\n",
4177 bondport_get_name(p
),
4178 next_tick_time
.tv_sec
);
4183 if (g_bond
->verbose
> 0) {
4184 if (event
== LAEventTimeout
) {
4185 timestamp_printf("[%s] Transmit Timer Complete\n",
4186 bondport_get_name(p
));
4189 pkt
= packet_buffer_allocate(sizeof(*out_lacpdu_p
));
4191 printf("[%s] Transmit: failed to allocate packet buffer\n",
4192 bondport_get_name(p
));
4195 out_lacpdu_p
= (lacpdu_ref
)packet_buffer_byteptr(pkt
);
4196 bzero(out_lacpdu_p
, sizeof(*out_lacpdu_p
));
4197 out_lacpdu_p
->la_subtype
= IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP
;
4198 out_lacpdu_p
->la_version
= LACPDU_VERSION_1
;
4201 aptlv
= (lacp_actor_partner_tlv_ref
)out_lacpdu_p
->la_actor_tlv
;
4202 aptlv
->lap_tlv_type
= LACPDU_TLV_TYPE_ACTOR
;
4203 aptlv
->lap_length
= LACPDU_ACTOR_TLV_LENGTH
;
4204 *((lacp_system_ref
)aptlv
->lap_system
) = g_bond
->system
;
4205 lacp_actor_partner_tlv_set_system_priority(aptlv
,
4206 g_bond
->system_priority
);
4207 lacp_actor_partner_tlv_set_port_priority(aptlv
, p
->po_priority
);
4208 lacp_actor_partner_tlv_set_port(aptlv
, bondport_get_index(p
));
4209 lacp_actor_partner_tlv_set_key(aptlv
, p
->po_bond
->ifb_key
);
4210 aptlv
->lap_state
= p
->po_actor_state
;
4213 aptlv
= (lacp_actor_partner_tlv_ref
)out_lacpdu_p
->la_partner_tlv
;
4214 aptlv
->lap_tlv_type
= LACPDU_TLV_TYPE_PARTNER
;
4215 aptlv
->lap_length
= LACPDU_PARTNER_TLV_LENGTH
;
4216 ps
= &p
->po_partner_state
;
4217 ps_li
= &ps
->ps_lag_info
;
4218 lacp_actor_partner_tlv_set_port(aptlv
, ps
->ps_port
);
4219 lacp_actor_partner_tlv_set_port_priority(aptlv
, ps
->ps_port_priority
);
4220 *((lacp_system_ref
)aptlv
->lap_system
) = ps_li
->li_system
;
4221 lacp_actor_partner_tlv_set_system_priority(aptlv
,
4222 ps_li
->li_system_priority
);
4223 lacp_actor_partner_tlv_set_key(aptlv
, ps_li
->li_key
);
4224 aptlv
->lap_state
= ps
->ps_state
;
4227 ctlv
= (lacp_collector_tlv_ref
)out_lacpdu_p
->la_collector_tlv
;
4228 ctlv
->lac_tlv_type
= LACPDU_TLV_TYPE_COLLECTOR
;
4229 ctlv
->lac_length
= LACPDU_COLLECTOR_TLV_LENGTH
;
4231 bondport_slow_proto_transmit(p
, pkt
);
4232 bondport_flags_clear_ntt(p
);
4233 if (g_bond
->verbose
> 0) {
4234 timestamp_printf("[%s] Transmit Packet %d\n",
4235 bondport_get_name(p
), p
->po_n_transmit
);
4245 ** Mux machine functions
4249 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4252 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4255 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4259 bondport_mux_machine_collecting_distributing(bondport_ref p
, LAEvent event
,
4263 bondport_mux_machine(bondport_ref p
, LAEvent event
, void * event_data
)
4265 switch (p
->po_mux_state
) {
4267 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4269 case MuxState_DETACHED
:
4270 bondport_mux_machine_detached(p
, event
, event_data
);
4272 case MuxState_WAITING
:
4273 bondport_mux_machine_waiting(p
, event
, event_data
);
4275 case MuxState_ATTACHED
:
4276 bondport_mux_machine_attached(p
, event
, event_data
);
4278 case MuxState_COLLECTING_DISTRIBUTING
:
4279 bondport_mux_machine_collecting_distributing(p
, event
, event_data
);
4288 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4289 __unused
void * event_data
)
4291 lacp_actor_partner_state s
;
4295 devtimer_cancel(p
->po_wait_while_timer
);
4296 if (g_bond
->verbose
) {
4297 timestamp_printf("[%s] Mux DETACHED\n",
4298 bondport_get_name(p
));
4300 p
->po_mux_state
= MuxState_DETACHED
;
4301 bondport_flags_clear_ready(p
);
4302 bondport_DetachMuxFromAggregator(p
);
4303 bondport_disable_distributing(p
);
4304 s
= p
->po_actor_state
;
4305 s
= lacp_actor_partner_state_set_out_of_sync(s
);
4306 s
= lacp_actor_partner_state_set_not_collecting(s
);
4307 s
= lacp_actor_partner_state_set_not_distributing(s
);
4308 p
->po_actor_state
= s
;
4309 bondport_flags_set_ntt(p
);
4311 case LAEventSelectedChange
:
4313 case LAEventMediaChange
:
4314 if (p
->po_selected
== SelectedState_SELECTED
4315 || p
->po_selected
== SelectedState_STANDBY
) {
4316 bondport_mux_machine_waiting(p
, LAEventStart
, NULL
);
4326 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4327 __unused
void * event_data
)
4333 devtimer_cancel(p
->po_wait_while_timer
);
4334 if (g_bond
->verbose
) {
4335 timestamp_printf("[%s] Mux WAITING\n",
4336 bondport_get_name(p
));
4338 p
->po_mux_state
= MuxState_WAITING
;
4341 case LAEventSelectedChange
:
4342 if (p
->po_selected
== SelectedState_UNSELECTED
) {
4343 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4346 if (p
->po_selected
== SelectedState_STANDBY
) {
4347 devtimer_cancel(p
->po_wait_while_timer
);
4348 /* wait until state changes to SELECTED */
4349 if (g_bond
->verbose
) {
4350 timestamp_printf("[%s] Mux WAITING: Standby\n",
4351 bondport_get_name(p
));
4355 if (bondport_flags_ready(p
)) {
4356 if (g_bond
->verbose
) {
4357 timestamp_printf("[%s] Mux WAITING: Port is already ready\n",
4358 bondport_get_name(p
));
4362 if (devtimer_enabled(p
->po_wait_while_timer
)) {
4363 if (g_bond
->verbose
) {
4364 timestamp_printf("[%s] Mux WAITING: Timer already set\n",
4365 bondport_get_name(p
));
4369 if (ifbond_all_ports_attached(p
->po_bond
, p
)) {
4370 devtimer_cancel(p
->po_wait_while_timer
);
4371 if (g_bond
->verbose
) {
4372 timestamp_printf("[%s] Mux WAITING: No waiting\n",
4373 bondport_get_name(p
));
4375 bondport_flags_set_ready(p
);
4378 if (g_bond
->verbose
) {
4379 timestamp_printf("[%s] Mux WAITING: 2 seconds\n",
4380 bondport_get_name(p
));
4382 tv
.tv_sec
= LACP_AGGREGATE_WAIT_TIME
;
4384 devtimer_set_relative(p
->po_wait_while_timer
, tv
,
4385 (devtimer_timeout_func
)
4386 bondport_mux_machine_waiting
,
4387 (void *)LAEventTimeout
, NULL
);
4389 case LAEventTimeout
:
4390 if (g_bond
->verbose
) {
4391 timestamp_printf("[%s] Mux WAITING: Ready\n",
4392 bondport_get_name(p
));
4394 bondport_flags_set_ready(p
);
4398 if (bondport_flags_ready(p
)){
4399 if (g_bond
->verbose
) {
4400 timestamp_printf("[%s] Mux WAITING: All Ports Ready\n",
4401 bondport_get_name(p
));
4403 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);
4412 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4413 __unused
void * event_data
)
4415 lacp_actor_partner_state s
;
4419 devtimer_cancel(p
->po_wait_while_timer
);
4420 if (g_bond
->verbose
) {
4421 timestamp_printf("[%s] Mux ATTACHED\n",
4422 bondport_get_name(p
));
4424 p
->po_mux_state
= MuxState_ATTACHED
;
4425 bondport_AttachMuxToAggregator(p
);
4426 s
= p
->po_actor_state
;
4427 s
= lacp_actor_partner_state_set_in_sync(s
);
4428 s
= lacp_actor_partner_state_set_not_collecting(s
);
4429 s
= lacp_actor_partner_state_set_not_distributing(s
);
4430 bondport_disable_distributing(p
);
4431 p
->po_actor_state
= s
;
4432 bondport_flags_set_ntt(p
);
4435 switch (p
->po_selected
) {
4436 case SelectedState_SELECTED
:
4437 s
= p
->po_partner_state
.ps_state
;
4438 if (lacp_actor_partner_state_in_sync(s
)) {
4439 bondport_mux_machine_collecting_distributing(p
, LAEventStart
,
4444 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4453 bondport_mux_machine_collecting_distributing(bondport_ref p
,
4455 __unused
void * event_data
)
4457 lacp_actor_partner_state s
;
4461 devtimer_cancel(p
->po_wait_while_timer
);
4462 if (g_bond
->verbose
) {
4463 timestamp_printf("[%s] Mux COLLECTING_DISTRIBUTING\n",
4464 bondport_get_name(p
));
4466 p
->po_mux_state
= MuxState_COLLECTING_DISTRIBUTING
;
4467 bondport_enable_distributing(p
);
4468 s
= p
->po_actor_state
;
4469 s
= lacp_actor_partner_state_set_collecting(s
);
4470 s
= lacp_actor_partner_state_set_distributing(s
);
4471 p
->po_actor_state
= s
;
4472 bondport_flags_set_ntt(p
);
4475 s
= p
->po_partner_state
.ps_state
;
4476 if (lacp_actor_partner_state_in_sync(s
) == 0) {
4477 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);
4480 switch (p
->po_selected
) {
4481 case SelectedState_UNSELECTED
:
4482 case SelectedState_STANDBY
:
4483 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);