2 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
25 * - bond/failover interface
26 * - implements IEEE 802.3ad Link Aggregation
30 * Modification History:
32 * April 29, 2004 Dieter Siegmund (dieter@apple.com)
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
40 #include <sys/queue.h>
41 #include <sys/socket.h>
42 #include <sys/sockio.h>
43 #include <sys/sysctl.h>
44 #include <sys/systm.h>
45 #include <sys/kern_event.h>
48 #include <net/ethernet.h>
50 #include <net/kpi_interface.h>
51 #include <net/if_arp.h>
52 #include <net/if_dl.h>
53 #include <net/if_ether.h>
54 #include <net/if_types.h>
55 #include <net/if_bond_var.h>
56 #include <net/ieee8023ad.h>
60 #include <net/devtimer.h>
61 #include <net/if_vlan_var.h>
63 #include <kern/locks.h>
64 #include <libkern/OSAtomic.h>
66 #include <netinet/in.h>
67 #include <netinet/if_ether.h>
68 #include <netinet/in_systm.h>
69 #include <netinet/ip.h>
70 #include <netinet/ip6.h>
72 #include <net/if_media.h>
73 #include <net/multicast_list.h>
75 extern int dlil_input_packet(struct ifnet
*, struct mbuf
*, char *);
77 static struct ether_addr slow_proto_multicast
= {
78 IEEE8023AD_SLOW_PROTO_MULTICAST
81 #define BOND_MAXUNIT 128
82 #define BONDNAME "bond"
83 #define M_BOND M_DEVBUF
85 #define EA_FORMAT "%x:%x:%x:%x:%x:%x"
86 #define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)])
87 #define EA_LIST(ea) EA_CH(ea,0),EA_CH(ea,1),EA_CH(ea,2),EA_CH(ea,3),EA_CH(ea,4),EA_CH(ea,5)
89 #define timestamp_printf printf
94 static __inline__ lck_grp_t
*
95 my_lck_grp_alloc_init(const char * grp_name
)
98 lck_grp_attr_t
* grp_attrs
;
100 grp_attrs
= lck_grp_attr_alloc_init();
101 lck_grp_attr_setdefault(grp_attrs
);
102 lck_grp_attr_setdefault(grp_attrs
);
103 grp
= lck_grp_alloc_init(grp_name
, grp_attrs
);
104 lck_grp_attr_free(grp_attrs
);
108 static __inline__ lck_mtx_t
*
109 my_lck_mtx_alloc_init(lck_grp_t
* lck_grp
)
111 lck_attr_t
* lck_attrs
;
114 lck_attrs
= lck_attr_alloc_init();
115 lck_attr_setdefault(lck_attrs
);
116 lck_mtx
= lck_mtx_alloc_init(lck_grp
, lck_attrs
);
117 lck_attr_free(lck_attrs
);
121 static lck_mtx_t
* bond_lck_mtx
;
123 static __inline__
void
126 lck_grp_t
* bond_lck_grp
;
128 bond_lck_grp
= my_lck_grp_alloc_init("if_bond");
129 bond_lck_mtx
= my_lck_mtx_alloc_init(bond_lck_grp
);
132 static __inline__
void
133 bond_assert_lock_held(void)
135 lck_mtx_assert(bond_lck_mtx
, LCK_MTX_ASSERT_OWNED
);
139 static __inline__
void
140 bond_assert_lock_not_held(void)
142 lck_mtx_assert(bond_lck_mtx
, LCK_MTX_ASSERT_NOTOWNED
);
146 static __inline__
void
149 lck_mtx_lock(bond_lck_mtx
);
153 static __inline__
void
156 lck_mtx_unlock(bond_lck_mtx
);
161 ** bond structures, types
165 lacp_system li_system
;
166 lacp_system_priority li_system_priority
;
169 typedef struct LAG_info_s LAG_info
, * LAG_info_ref
;
172 TAILQ_HEAD(port_list
, bondport_s
);
174 TAILQ_HEAD(ifbond_list
, ifbond_s
);
176 TAILQ_HEAD(lag_list
, LAG_s
);
178 typedef struct ifbond_s ifbond
, * ifbond_ref
;
179 typedef struct bondport_s bondport
, * bondport_ref
;
182 TAILQ_ENTRY(LAG_s
) lag_list
;
183 struct port_list lag_port_list
;
184 short lag_port_count
;
185 short lag_selected_port_count
;
186 int lag_active_media
;
189 typedef struct LAG_s LAG
, * LAG_ref
;
191 typedef struct partner_state_s
{
192 LAG_info ps_lag_info
;
194 lacp_port_priority ps_port_priority
;
195 lacp_actor_partner_state ps_state
;
196 } partner_state
, * partner_state_ref
;
199 TAILQ_ENTRY(ifbond_s
) ifb_bond_list
;
201 UInt32 ifb_retain_count
;
202 char ifb_name
[IFNAMSIZ
];
203 struct ifnet
* ifb_ifp
;
204 bpf_packet_func ifb_bpf_input
;
205 bpf_packet_func ifb_bpf_output
;
207 struct port_list ifb_port_list
;
208 short ifb_port_count
;
209 struct lag_list ifb_lag_list
;
211 short ifb_max_active
; /* 0 == unlimited */
212 LAG_ref ifb_active_lag
;
213 struct ifmultiaddr
* ifb_ifma_slow_proto
;
214 bondport_ref
* ifb_distributing_array
;
215 int ifb_distributing_count
;
224 ReceiveState_none
= 0,
225 ReceiveState_INITIALIZE
= 1,
226 ReceiveState_PORT_DISABLED
= 2,
227 ReceiveState_EXPIRED
= 3,
228 ReceiveState_LACP_DISABLED
= 4,
229 ReceiveState_DEFAULTED
= 5,
230 ReceiveState_CURRENT
= 6,
233 typedef u_char ReceiveState
;
236 SelectedState_UNSELECTED
= IF_BOND_STATUS_SELECTED_STATE_UNSELECTED
,
237 SelectedState_SELECTED
= IF_BOND_STATUS_SELECTED_STATE_SELECTED
,
238 SelectedState_STANDBY
= IF_BOND_STATUS_SELECTED_STATE_STANDBY
240 typedef u_char SelectedState
;
242 static __inline__
const char *
243 SelectedStateString(SelectedState s
)
245 static const char * names
[] = { "UNSELECTED", "SELECTED", "STANDBY" };
247 if (s
<= SelectedState_STANDBY
) {
250 return ("<unknown>");
255 MuxState_DETACHED
= 1,
256 MuxState_WAITING
= 2,
257 MuxState_ATTACHED
= 3,
258 MuxState_COLLECTING_DISTRIBUTING
= 4,
261 typedef u_char MuxState
;
264 TAILQ_ENTRY(bondport_s
) po_port_list
;
266 struct multicast_list po_multicast
;
267 struct ifnet
* po_ifp
;
268 struct ether_addr po_saved_addr
;
270 char po_name
[IFNAMSIZ
];
271 struct ifdevmtu po_devmtu
;
274 TAILQ_ENTRY(bondport_s
) po_lag_port_list
;
275 devtimer_ref po_current_while_timer
;
276 devtimer_ref po_periodic_timer
;
277 devtimer_ref po_wait_while_timer
;
278 devtimer_ref po_transmit_timer
;
279 partner_state po_partner_state
;
280 lacp_port_priority po_priority
;
281 lacp_actor_partner_state po_actor_state
;
283 u_char po_periodic_interval
;
284 u_char po_n_transmit
;
285 ReceiveState po_receive_state
;
286 MuxState po_mux_state
;
287 SelectedState po_selected
;
288 int32_t po_last_transmit_secs
;
289 struct media_info po_media_info
;
293 #define IFBF_PROMISC 0x1 /* promiscuous mode */
294 #define IFBF_IF_DETACHING 0x2 /* interface is detaching */
295 #define IFBF_LLADDR 0x4 /* specific link address requested */
296 #define IFBF_CHANGE_IN_PROGRESS 0x8 /* interface add/remove in progress */
298 static int bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
,
301 static __inline__
int
302 ifbond_flags_promisc(ifbond_ref ifb
)
304 return ((ifb
->ifb_flags
& IFBF_PROMISC
) != 0);
307 static __inline__
void
308 ifbond_flags_set_promisc(ifbond_ref ifb
)
310 ifb
->ifb_flags
|= IFBF_PROMISC
;
314 static __inline__
void
315 ifbond_flags_clear_promisc(ifbond_ref ifb
)
317 ifb
->ifb_flags
&= ~IFBF_PROMISC
;
321 static __inline__
int
322 ifbond_flags_if_detaching(ifbond_ref ifb
)
324 return ((ifb
->ifb_flags
& IFBF_IF_DETACHING
) != 0);
327 static __inline__
void
328 ifbond_flags_set_if_detaching(ifbond_ref ifb
)
330 ifb
->ifb_flags
|= IFBF_IF_DETACHING
;
334 static __inline__
int
335 ifbond_flags_lladdr(ifbond_ref ifb
)
337 return ((ifb
->ifb_flags
& IFBF_LLADDR
) != 0);
340 static __inline__
void
341 ifbond_flags_set_lladdr(ifbond_ref ifb
)
343 ifb
->ifb_flags
|= IFBF_LLADDR
;
347 static __inline__
void
348 ifbond_flags_clear_lladdr(ifbond_ref ifb
)
350 ifb
->ifb_flags
&= ~IFBF_LLADDR
;
354 static __inline__
int
355 ifbond_flags_change_in_progress(ifbond_ref ifb
)
357 return ((ifb
->ifb_flags
& IFBF_CHANGE_IN_PROGRESS
) != 0);
360 static __inline__
void
361 ifbond_flags_set_change_in_progress(ifbond_ref ifb
)
363 ifb
->ifb_flags
|= IFBF_CHANGE_IN_PROGRESS
;
367 static __inline__
void
368 ifbond_flags_clear_change_in_progress(ifbond_ref ifb
)
370 ifb
->ifb_flags
&= ~IFBF_CHANGE_IN_PROGRESS
;
375 * bondport_ref->po_flags bits
377 #define BONDPORT_FLAGS_NTT 0x01
378 #define BONDPORT_FLAGS_READY 0x02
379 #define BONDPORT_FLAGS_SELECTED_CHANGED 0x04
380 #define BONDPORT_FLAGS_MUX_ATTACHED 0x08
381 #define BONDPORT_FLAGS_DISTRIBUTING 0x10
382 #define BONDPORT_FLAGS_UNUSED2 0x20
383 #define BONDPORT_FLAGS_UNUSED3 0x40
384 #define BONDPORT_FLAGS_UNUSED4 0x80
386 static __inline__
void
387 bondport_flags_set_ntt(bondport_ref p
)
389 p
->po_flags
|= BONDPORT_FLAGS_NTT
;
393 static __inline__
void
394 bondport_flags_clear_ntt(bondport_ref p
)
396 p
->po_flags
&= ~BONDPORT_FLAGS_NTT
;
400 static __inline__
int
401 bondport_flags_ntt(bondport_ref p
)
403 return ((p
->po_flags
& BONDPORT_FLAGS_NTT
) != 0);
406 static __inline__
void
407 bondport_flags_set_ready(bondport_ref p
)
409 p
->po_flags
|= BONDPORT_FLAGS_READY
;
413 static __inline__
void
414 bondport_flags_clear_ready(bondport_ref p
)
416 p
->po_flags
&= ~BONDPORT_FLAGS_READY
;
420 static __inline__
int
421 bondport_flags_ready(bondport_ref p
)
423 return ((p
->po_flags
& BONDPORT_FLAGS_READY
) != 0);
426 static __inline__
void
427 bondport_flags_set_selected_changed(bondport_ref p
)
429 p
->po_flags
|= BONDPORT_FLAGS_SELECTED_CHANGED
;
433 static __inline__
void
434 bondport_flags_clear_selected_changed(bondport_ref p
)
436 p
->po_flags
&= ~BONDPORT_FLAGS_SELECTED_CHANGED
;
440 static __inline__
int
441 bondport_flags_selected_changed(bondport_ref p
)
443 return ((p
->po_flags
& BONDPORT_FLAGS_SELECTED_CHANGED
) != 0);
446 static __inline__
void
447 bondport_flags_set_mux_attached(bondport_ref p
)
449 p
->po_flags
|= BONDPORT_FLAGS_MUX_ATTACHED
;
453 static __inline__
void
454 bondport_flags_clear_mux_attached(bondport_ref p
)
456 p
->po_flags
&= ~BONDPORT_FLAGS_MUX_ATTACHED
;
460 static __inline__
int
461 bondport_flags_mux_attached(bondport_ref p
)
463 return ((p
->po_flags
& BONDPORT_FLAGS_MUX_ATTACHED
) != 0);
466 static __inline__
void
467 bondport_flags_set_distributing(bondport_ref p
)
469 p
->po_flags
|= BONDPORT_FLAGS_DISTRIBUTING
;
473 static __inline__
void
474 bondport_flags_clear_distributing(bondport_ref p
)
476 p
->po_flags
&= ~BONDPORT_FLAGS_DISTRIBUTING
;
480 static __inline__
int
481 bondport_flags_distributing(bondport_ref p
)
483 return ((p
->po_flags
& BONDPORT_FLAGS_DISTRIBUTING
) != 0);
486 typedef struct bond_globals_s
{
487 struct ifbond_list ifbond_list
;
489 lacp_system_priority system_priority
;
491 } * bond_globals_ref
;
493 static bond_globals_ref g_bond
;
496 ** packet_buffer routines
497 ** - thin wrapper for mbuf
500 typedef struct mbuf
* packet_buffer_ref
;
502 static packet_buffer_ref
503 packet_buffer_allocate(int length
)
508 /* leave room for ethernet header */
509 size
= length
+ sizeof(struct ether_header
);
510 if (size
> (int)MHLEN
) {
511 /* XXX doesn't handle large payloads */
512 printf("bond: packet_buffer_allocate size %d > max %d\n", size
, MHLEN
);
515 m
= m_gethdr(M_WAITOK
, MT_DATA
);
520 m
->m_pkthdr
.len
= size
;
525 packet_buffer_byteptr(packet_buffer_ref buf
)
527 return (buf
->m_data
+ sizeof(struct ether_header
));
535 LAEventSelectedChange
,
544 bondport_receive_machine(bondport_ref p
, LAEvent event
,
547 ** Periodic Transmission machine
550 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
557 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
564 bondport_mux_machine(bondport_ref p
, LAEvent event
,
571 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
);
574 ifbond_deactivate_LAG(ifbond_ref bond
, LAG_ref lag
);
577 ifbond_all_ports_ready(ifbond_ref bond
);
580 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
);
583 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
);
586 ifbond_selection(ifbond_ref bond
);
594 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
);
597 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
);
600 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
601 int active
, int short_timeout
, int * error
);
603 bondport_start(bondport_ref p
);
606 bondport_free(bondport_ref p
);
609 bondport_aggregatable(bondport_ref p
);
612 bondport_remove_from_LAG(bondport_ref p
);
615 bondport_set_selected(bondport_ref p
, SelectedState s
);
618 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
);
621 bondport_link_status_changed(bondport_ref p
);
624 bondport_enable_distributing(bondport_ref p
);
627 bondport_disable_distributing(bondport_ref p
);
629 static __inline__
int
630 bondport_collecting(bondport_ref p
)
632 return (lacp_actor_partner_state_collecting(p
->po_actor_state
));
636 ** bond interface/dlil specific routines
638 static int bond_clone_create(struct if_clone
*, int);
639 static void bond_clone_destroy(struct ifnet
*);
640 static int bond_input(struct mbuf
*m
, char *frame_header
, struct ifnet
*ifp
,
641 u_long protocol_family
, int sync_ok
);
642 static int bond_output(struct ifnet
*ifp
, struct mbuf
*m
);
643 static int bond_ioctl(struct ifnet
*ifp
, u_int32_t cmd
, void * addr
);
644 static int bond_set_bpf_tap(struct ifnet
* ifp
, bpf_tap_mode mode
,
645 bpf_packet_func func
);
646 static int bond_attach_protocol(struct ifnet
*ifp
);
647 static int bond_detach_protocol(struct ifnet
*ifp
);
648 static int bond_setmulti(struct ifnet
*ifp
);
649 static int bond_add_interface(struct ifnet
* ifp
, struct ifnet
* port_ifp
);
650 static int bond_remove_interface(ifbond_ref ifb
, struct ifnet
* port_ifp
);
651 static void bond_if_free(struct ifnet
* ifp
);
653 static struct if_clone bond_cloner
= IF_CLONE_INITIALIZER(BONDNAME
,
658 static void interface_link_event(struct ifnet
* ifp
, u_long event_code
);
661 siocsifmtu(struct ifnet
* ifp
, int mtu
)
665 bzero(&ifr
, sizeof(ifr
));
667 return (dlil_ioctl(0, ifp
, SIOCSIFMTU
, (caddr_t
)&ifr
));
671 siocgifdevmtu(struct ifnet
* ifp
, struct ifdevmtu
* ifdm_p
)
676 bzero(&ifr
, sizeof(ifr
));
677 error
= dlil_ioctl(0, ifp
, SIOCGIFDEVMTU
, (caddr_t
)&ifr
);
679 *ifdm_p
= ifr
.ifr_devmtu
;
684 static __inline__
void
685 ether_addr_copy(void * dest
, const void * source
)
687 bcopy(source
, dest
, ETHER_ADDR_LEN
);
691 static __inline__
void
692 ifbond_retain(ifbond_ref ifb
)
694 OSIncrementAtomic(&ifb
->ifb_retain_count
);
697 static __inline__
void
698 ifbond_release(ifbond_ref ifb
)
700 UInt32 old_retain_count
;
702 old_retain_count
= OSDecrementAtomic(&ifb
->ifb_retain_count
);
703 switch (old_retain_count
) {
705 panic("ifbond_release: retain count is 0\n");
708 if (g_bond
->verbose
) {
709 printf("ifbond_release(%s)\n", ifb
->ifb_name
);
711 if (ifb
->ifb_ifma_slow_proto
!= NULL
) {
712 if (g_bond
->verbose
) {
713 printf("ifbond_release(%s) removing multicast\n",
716 (void)if_delmultiaddr(ifb
->ifb_ifma_slow_proto
, 0);
717 ifma_release(ifb
->ifb_ifma_slow_proto
);
719 if (ifb
->ifb_distributing_array
!= NULL
) {
720 FREE(ifb
->ifb_distributing_array
, M_BOND
);
731 * Function: ifbond_wait
733 * Allows a single thread to gain exclusive access to the ifbond
734 * data structure. Some operations take a long time to complete,
735 * and some have side-effects that we can't predict. Holding the
736 * bond_lock() across such operations is not possible.
739 * 1) The SIOCSIFLLADDR ioctl takes a long time (several seconds) to
740 * complete. Simply holding the bond_lock() would freeze all other
741 * data structure accesses during that time.
742 * 2) When we attach our protocol to the interface, a dlil event is
743 * generated and invokes our bond_event() function. bond_event()
744 * needs to take the bond_lock(), but we're already holding it, so
745 * we're deadlocked against ourselves.
747 * Before calling, you must be holding the bond_lock and have taken
748 * a reference on the ifbond_ref.
751 ifbond_wait(ifbond_ref ifb
, const char * msg
)
755 /* other add/remove in progress */
756 while (ifbond_flags_change_in_progress(ifb
)) {
757 if (g_bond
->verbose
) {
758 printf("%s: %s msleep\n", ifb
->ifb_name
, msg
);
761 (void)msleep(ifb
, bond_lck_mtx
, PZERO
, msg
, 0);
763 /* prevent other bond list remove/add from taking place */
764 ifbond_flags_set_change_in_progress(ifb
);
765 if (g_bond
->verbose
&& waited
) {
766 printf("%s: %s woke up\n", ifb
->ifb_name
, msg
);
772 * Function: ifbond_signal
774 * Allows the thread that previously invoked ifbond_wait() to
775 * give up exclusive access to the ifbond data structure, and wake up
776 * any other threads waiting to access
778 * Before calling, you must be holding the bond_lock and have taken
779 * a reference on the ifbond_ref.
782 ifbond_signal(ifbond_ref ifb
, const char * msg
)
784 ifbond_flags_clear_change_in_progress(ifb
);
785 wakeup((caddr_t
)ifb
);
786 if (g_bond
->verbose
) {
787 printf("%s: %s wakeup\n", ifb
->ifb_name
, msg
);
797 link_speed(int active
)
799 switch (IFM_SUBTYPE(active
)) {
820 /* assume that new defined types are going to be at least 10GigE */
827 static __inline__
int
828 media_active(const struct media_info
* mi
)
830 if ((mi
->mi_status
& IFM_AVALID
) == 0) {
833 return ((mi
->mi_status
& IFM_ACTIVE
) != 0);
836 static __inline__
int
837 media_full_duplex(const struct media_info
* mi
)
839 return ((mi
->mi_active
& IFM_FDX
) != 0);
842 static __inline__
int
843 media_speed(const struct media_info
* mi
)
845 return (link_speed(mi
->mi_active
));
848 static struct media_info
849 interface_media_info(struct ifnet
* ifp
)
851 struct ifmediareq ifmr
;
852 struct media_info mi
;
854 bzero(&mi
, sizeof(mi
));
855 bzero(&ifmr
, sizeof(ifmr
));
856 if (dlil_ioctl(0, ifp
, SIOCGIFMEDIA
, (caddr_t
)&ifmr
) == 0) {
857 if (ifmr
.ifm_count
!= 0) {
858 mi
.mi_status
= ifmr
.ifm_status
;
859 mi
.mi_active
= ifmr
.ifm_active
;
866 ** interface utility functions
868 static __inline__
struct ifaddr
*
869 ifindex_get_ifaddr(int i
)
871 if (i
> if_index
|| i
== 0) {
874 return (ifnet_addrs
[i
- 1]);
877 static __inline__
struct ifaddr
*
878 ifp_get_ifaddr(struct ifnet
* ifp
)
880 return (ifindex_get_ifaddr(ifp
->if_index
));
883 static __inline__
struct sockaddr_dl
*
884 ifp_get_sdl(struct ifnet
* ifp
)
888 ifa
= ifp_get_ifaddr(ifp
);
889 return ((struct sockaddr_dl
*)(ifa
->ifa_addr
));
893 if_siflladdr(struct ifnet
* ifp
, const struct ether_addr
* ea_p
)
898 * XXX setting the sa_len to ETHER_ADDR_LEN is wrong, but the driver
899 * currently expects it that way
901 ifr
.ifr_addr
.sa_family
= AF_UNSPEC
;
902 ifr
.ifr_addr
.sa_len
= ETHER_ADDR_LEN
;
903 ether_addr_copy(ifr
.ifr_addr
.sa_data
, ea_p
);
905 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s%d", ifp
->if_name
,
908 return (dlil_ioctl(0, ifp
, SIOCSIFLLADDR
, (caddr_t
)&ifr
));
914 static bond_globals_ref
915 bond_globals_create(lacp_system_priority sys_pri
,
920 b
= _MALLOC(sizeof(*b
), M_BOND
, M_WAITOK
);
924 bzero(b
, sizeof(*b
));
925 TAILQ_INIT(&b
->ifbond_list
);
927 b
->system_priority
= sys_pri
;
935 bond_globals_init(void)
941 bond_assert_lock_not_held();
943 if (g_bond
!= NULL
) {
948 * use en0's ethernet address as the system identifier, and if it's not
949 * there, use en1 .. en3
952 for (i
= 0; i
< 4; i
++) {
953 char ifname
[IFNAMSIZ
+1];
954 snprintf(ifname
, sizeof(ifname
), "en%d", i
);
955 /* XXX ifunit() needs to return a reference on the ifp */
956 ifp
= ifunit(ifname
);
963 b
= bond_globals_create(0x8000,
964 (lacp_system_ref
)LLADDR(ifp_get_sdl(ifp
)));
967 if (g_bond
!= NULL
) {
984 bond_bpf_vlan(struct ifnet
* ifp
, struct mbuf
* m
,
985 const struct ether_header
* eh_p
,
986 u_int16_t vlan_tag
, bpf_packet_func func
)
988 struct ether_vlan_header
* vlh_p
;
991 vl_m
= m_get(M_DONTWAIT
, MT_DATA
);
995 /* populate a new mbuf containing the vlan ethernet header */
996 vl_m
->m_len
= ETHER_HDR_LEN
+ ETHER_VLAN_ENCAP_LEN
;
997 vlh_p
= mtod(vl_m
, struct ether_vlan_header
*);
998 bcopy(eh_p
, vlh_p
, offsetof(struct ether_header
, ether_type
));
999 vlh_p
->evl_encap_proto
= htons(ETHERTYPE_VLAN
);
1000 vlh_p
->evl_tag
= htons(vlan_tag
);
1001 vlh_p
->evl_proto
= eh_p
->ether_type
;
1004 vl_m
->m_next
= NULL
;
1009 static __inline__
void
1010 bond_bpf_output(struct ifnet
* ifp
, struct mbuf
* m
,
1011 bpf_packet_func func
)
1014 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1015 const struct ether_header
* eh_p
;
1016 eh_p
= mtod(m
, const struct ether_header
*);
1017 m
->m_data
+= ETHER_HDR_LEN
;
1018 m
->m_len
-= ETHER_HDR_LEN
;
1019 bond_bpf_vlan(ifp
, m
, eh_p
, m
->m_pkthdr
.vlan_tag
, func
);
1020 m
->m_data
-= ETHER_HDR_LEN
;
1021 m
->m_len
+= ETHER_HDR_LEN
;
1029 static __inline__
void
1030 bond_bpf_input(ifnet_t ifp
, mbuf_t m
, const struct ether_header
* eh_p
,
1031 bpf_packet_func func
)
1034 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1035 bond_bpf_vlan(ifp
, m
, eh_p
, m
->m_pkthdr
.vlan_tag
, func
);
1037 /* restore the header */
1038 m
->m_data
-= ETHER_HDR_LEN
;
1039 m
->m_len
+= ETHER_HDR_LEN
;
1041 m
->m_data
+= ETHER_HDR_LEN
;
1042 m
->m_len
-= ETHER_HDR_LEN
;
1049 * Function: bond_setmulti
1051 * Enable multicast reception on "our" interface by enabling multicasts on
1052 * each of the member ports.
1055 bond_setmulti(struct ifnet
* ifp
)
1063 ifb
= ifp
->if_private
;
1064 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1065 || TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
1070 ifbond_wait(ifb
, "bond_setmulti");
1072 if (ifbond_flags_if_detaching(ifb
)) {
1073 /* someone destroyed the bond while we were waiting */
1079 /* ifbond_wait() let's us safely walk the list without holding the lock */
1080 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
1081 struct ifnet
* port_ifp
= p
->po_ifp
;
1083 error
= multicast_list_program(&p
->po_multicast
,
1086 printf("bond_setmulti(%s): "
1087 "multicast_list_program(%s%d) failed, %d\n",
1088 ifb
->ifb_name
, port_ifp
->if_name
,
1089 port_ifp
->if_unit
, error
);
1095 ifbond_release(ifb
);
1096 ifbond_signal(ifb
, "bond_setmulti");
1102 bond_clone_attach(void)
1104 if_clone_attach(&bond_cloner
);
1110 ifbond_add_slow_proto_multicast(ifbond_ref ifb
)
1113 struct ifmultiaddr
* ifma
= NULL
;
1114 struct sockaddr_dl sdl
;
1116 bond_assert_lock_not_held();
1118 bzero(&sdl
, sizeof(sdl
));
1119 sdl
.sdl_len
= sizeof(sdl
);
1120 sdl
.sdl_family
= AF_LINK
;
1121 sdl
.sdl_type
= IFT_ETHER
;
1123 sdl
.sdl_alen
= sizeof(slow_proto_multicast
);
1124 bcopy(&slow_proto_multicast
, sdl
.sdl_data
, sizeof(slow_proto_multicast
));
1125 error
= if_addmulti(ifb
->ifb_ifp
, (struct sockaddr
*)&sdl
,
1128 ifb
->ifb_ifma_slow_proto
= ifma
;
1134 bond_clone_create(struct if_clone
* ifc
, int unit
)
1140 error
= bond_globals_init();
1145 ifb
= _MALLOC(sizeof(ifbond
), M_BOND
, M_WAITOK
);
1149 bzero(ifb
, sizeof(*ifb
));
1152 TAILQ_INIT(&ifb
->ifb_port_list
);
1153 TAILQ_INIT(&ifb
->ifb_lag_list
);
1154 ifb
->ifb_key
= unit
+ 1;
1156 /* use the interface name as the unique id for ifp recycle */
1157 if ((u_long
)snprintf(ifb
->ifb_name
, sizeof(ifb
->ifb_name
), "%s%d",
1158 ifc
->ifc_name
, unit
) >= sizeof(ifb
->ifb_name
)) {
1159 ifbond_release(ifb
);
1162 error
= dlil_if_acquire(APPLE_IF_FAM_BOND
,
1164 strlen(ifb
->ifb_name
),
1167 ifbond_release(ifb
);
1171 ifp
->if_name
= ifc
->ifc_name
;
1172 ifp
->if_unit
= unit
;
1173 ifp
->if_family
= APPLE_IF_FAM_BOND
;
1174 ifp
->if_private
= NULL
;
1175 ifp
->if_ioctl
= bond_ioctl
;
1176 ifp
->if_set_bpf_tap
= bond_set_bpf_tap
;
1177 ifp
->if_free
= bond_if_free
;
1178 ifp
->if_output
= bond_output
;
1179 ifp
->if_hwassist
= 0;
1180 ifp
->if_addrlen
= ETHER_ADDR_LEN
;
1181 ifp
->if_baudrate
= 0;
1182 ifp
->if_type
= IFT_IEEE8023ADLAG
;
1183 ifp
->if_flags
= IFF_BROADCAST
| IFF_MULTICAST
| IFF_SIMPLEX
;
1186 /* XXX ethernet specific */
1187 ifp
->if_broadcast
.length
= ETHER_ADDR_LEN
;
1188 bcopy(etherbroadcastaddr
, ifp
->if_broadcast
.u
.buffer
, ETHER_ADDR_LEN
);
1190 error
= dlil_if_attach(ifp
);
1192 dlil_if_release(ifp
);
1193 ifbond_release(ifb
);
1196 error
= ifbond_add_slow_proto_multicast(ifb
);
1198 printf("bond_clone_create(%s): "
1199 "failed to add slow_proto multicast, %d\n",
1200 ifb
->ifb_name
, error
);
1203 /* attach as ethernet */
1204 bpfattach(ifp
, DLT_EN10MB
, sizeof(struct ether_header
));
1207 ifp
->if_private
= ifb
;
1208 TAILQ_INSERT_HEAD(&g_bond
->ifbond_list
, ifb
, ifb_bond_list
);
1215 bond_remove_all_interfaces(ifbond_ref ifb
)
1219 bond_assert_lock_held();
1222 * do this in reverse order to avoid re-programming the mac address
1223 * as each head interface is removed
1225 while ((p
= TAILQ_LAST(&ifb
->ifb_port_list
, port_list
)) != NULL
) {
1226 bond_remove_interface(ifb
, p
->po_ifp
);
1232 bond_remove(ifbond_ref ifb
)
1234 bond_assert_lock_held();
1235 ifbond_flags_set_if_detaching(ifb
);
1236 TAILQ_REMOVE(&g_bond
->ifbond_list
, ifb
, ifb_bond_list
);
1237 bond_remove_all_interfaces(ifb
);
1242 bond_if_detach(struct ifnet
* ifp
)
1246 error
= dlil_if_detach(ifp
);
1247 if (error
!= DLIL_WAIT_FOR_FREE
) {
1249 printf("bond_if_detach %s%d: dlil_if_detach failed, %d\n",
1250 ifp
->if_name
, ifp
->if_unit
, error
);
1258 bond_clone_destroy(struct ifnet
* ifp
)
1263 ifb
= ifp
->if_private
;
1264 if (ifb
== NULL
|| ifp
->if_type
!= IFT_IEEE8023ADLAG
) {
1268 if (ifbond_flags_if_detaching(ifb
)) {
1274 bond_if_detach(ifp
);
1279 bond_set_bpf_tap(struct ifnet
* ifp
, bpf_tap_mode mode
, bpf_packet_func func
)
1284 ifb
= ifp
->if_private
;
1285 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
1290 case BPF_TAP_DISABLE
:
1291 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= NULL
;
1295 ifb
->ifb_bpf_input
= func
;
1298 case BPF_TAP_OUTPUT
:
1299 ifb
->ifb_bpf_output
= func
;
1302 case BPF_TAP_INPUT_OUTPUT
:
1303 ifb
->ifb_bpf_input
= ifb
->ifb_bpf_output
= func
;
1313 ether_header_hash(struct ether_header
* eh_p
)
1317 /* get 32-bits from destination ether and ether type */
1318 h
= (*((uint16_t *)&eh_p
->ether_dhost
[4]) << 16)
1320 h
^= *((uint32_t *)&eh_p
->ether_dhost
[0]);
1324 static struct mbuf
*
1325 S_mbuf_skip_to_offset(struct mbuf
* m
, long * offset
)
1330 while (*offset
>= len
) {
1341 #if BYTE_ORDER == BIG_ENDIAN
1342 static __inline__
uint32_t
1343 make_uint32(u_char c0
, u_char c1
, u_char c2
, u_char c3
)
1345 return (((uint32_t)c0
<< 24) | ((uint32_t)c1
<< 16)
1346 | ((uint32_t)c2
<< 8) | (uint32_t)c3
);
1348 #else /* BYTE_ORDER == LITTLE_ENDIAN */
1349 static __inline__
uint32_t
1350 make_uint32(u_char c0
, u_char c1
, u_char c2
, u_char c3
)
1352 return (((uint32_t)c3
<< 24) | ((uint32_t)c2
<< 16)
1353 | ((uint32_t)c1
<< 8) | (uint32_t)c0
);
1355 #endif /* BYTE_ORDER == LITTLE_ENDIAN */
1358 S_mbuf_copy_uint32(struct mbuf
* m
, long offset
, uint32_t * val
)
1360 struct mbuf
* current
;
1361 u_char
* current_data
;
1366 current
= S_mbuf_skip_to_offset(m
, &offset
);
1367 if (current
== NULL
) {
1370 current_data
= mtod(current
, u_char
*) + offset
;
1371 space_current
= current
->m_len
- offset
;
1372 if (space_current
>= (int)sizeof(uint32_t)) {
1373 *val
= *((uint32_t *)current_data
);
1376 next
= current
->m_next
;
1377 if (next
== NULL
|| (next
->m_len
+ space_current
) < (int)sizeof(uint32_t)) {
1380 next_data
= mtod(next
, u_char
*);
1381 switch (space_current
) {
1383 *val
= make_uint32(current_data
[0], next_data
[0],
1384 next_data
[1], next_data
[2]);
1387 *val
= make_uint32(current_data
[0], current_data
[1],
1388 next_data
[0], next_data
[1]);
1391 *val
= make_uint32(current_data
[0], current_data
[1],
1392 current_data
[2], next_data
[0]);
1398 #define IP_SRC_OFFSET (offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p))
1399 #define IP_DST_OFFSET (offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p))
1402 ip_header_hash(struct mbuf
* m
)
1405 struct in_addr ip_dst
;
1406 struct in_addr ip_src
;
1409 struct mbuf
* orig_m
= m
;
1411 /* find the IP protocol field relative to the start of the packet */
1412 offset
= offsetof(struct ip
, ip_p
) + sizeof(struct ether_header
);
1413 m
= S_mbuf_skip_to_offset(m
, &offset
);
1414 if (m
== NULL
|| m
->m_len
< 1) {
1417 data
= mtod(m
, u_char
*) + offset
;
1420 /* find the IP src relative to the IP protocol */
1421 if ((m
->m_len
- offset
)
1422 >= (int)(IP_SRC_OFFSET
+ sizeof(struct in_addr
) * 2)) {
1423 /* this should be the normal case */
1424 ip_src
= *(struct in_addr
*)(data
+ IP_SRC_OFFSET
);
1425 ip_dst
= *(struct in_addr
*)(data
+ IP_DST_OFFSET
);
1428 if (S_mbuf_copy_uint32(m
, offset
+ IP_SRC_OFFSET
,
1429 (uint32_t *)&ip_src
.s_addr
)) {
1432 if (S_mbuf_copy_uint32(m
, offset
+ IP_DST_OFFSET
,
1433 (uint32_t *)&ip_dst
.s_addr
)) {
1437 return (ntohl(ip_dst
.s_addr
) ^ ntohl(ip_src
.s_addr
) ^ ((uint32_t)ip_p
));
1440 return (ether_header_hash(mtod(orig_m
, struct ether_header
*)));
1443 #define IP6_ADDRS_LEN (sizeof(struct in6_addr) * 2)
1445 ipv6_header_hash(struct mbuf
* m
)
1450 struct mbuf
* orig_m
= m
;
1454 /* find the IP protocol field relative to the start of the packet */
1455 offset
= offsetof(struct ip6_hdr
, ip6_src
) + sizeof(struct ether_header
);
1456 m
= S_mbuf_skip_to_offset(m
, &offset
);
1458 goto bad_ipv6_packet
;
1460 data
= mtod(m
, u_char
*) + offset
;
1462 if ((m
->m_len
- offset
) >= (int)IP6_ADDRS_LEN
) {
1463 /* this should be the normal case */
1464 for (i
= 0, scan
= (uint32_t *)data
;
1465 i
< (int)(IP6_ADDRS_LEN
/ sizeof(uint32_t));
1471 for (i
= 0; i
< (int)(IP6_ADDRS_LEN
/ sizeof(uint32_t)); i
++) {
1473 if (S_mbuf_copy_uint32(m
, offset
+ i
* sizeof(uint32_t),
1474 (uint32_t *)&tmp
)) {
1475 goto bad_ipv6_packet
;
1480 return (ntohl(val
));
1483 return (ether_header_hash(mtod(orig_m
, struct ether_header
*)));
1487 bond_output(struct ifnet
* ifp
, struct mbuf
* m
)
1489 bpf_packet_func bpf_func
;
1492 struct ifnet
* port_ifp
= NULL
;
1497 if ((m
->m_flags
& M_PKTHDR
) == 0) {
1501 if (m
->m_pkthdr
.socket_id
!= 0) {
1502 h
= m
->m_pkthdr
.socket_id
;
1505 struct ether_header
* eh_p
;
1507 eh_p
= mtod(m
, struct ether_header
*);
1508 switch (ntohs(eh_p
->ether_type
)) {
1510 h
= ip_header_hash(m
);
1512 case ETHERTYPE_IPV6
:
1513 h
= ipv6_header_hash(m
);
1516 h
= ether_header_hash(eh_p
);
1521 ifb
= ifp
->if_private
;
1522 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)
1523 || ifb
->ifb_distributing_count
== 0) {
1526 h
%= ifb
->ifb_distributing_count
;
1527 port_ifp
= ifb
->ifb_distributing_array
[h
]->po_ifp
;
1528 bpf_func
= ifb
->ifb_bpf_output
;
1531 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1532 (void)ifnet_stat_increment_out(ifp
, 1,
1533 m
->m_pkthdr
.len
+ ETHER_VLAN_ENCAP_LEN
,
1536 (void)ifnet_stat_increment_out(ifp
, 1, m
->m_pkthdr
.len
, 0);
1538 bond_bpf_output(ifp
, m
, bpf_func
);
1540 return (dlil_output(port_ifp
, 0, m
, NULL
, NULL
, 1));
1549 ifbond_lookup_port(ifbond_ref ifb
, struct ifnet
* port_ifp
)
1552 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
1553 if (p
->po_ifp
== port_ifp
) {
1561 bond_lookup_port(struct ifnet
* port_ifp
)
1566 TAILQ_FOREACH(ifb
, &g_bond
->ifbond_list
, ifb_bond_list
) {
1567 port
= ifbond_lookup_port(ifb
, port_ifp
);
1576 bond_receive_lacpdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1578 struct ifnet
* bond_ifp
= NULL
;
1583 if ((port_ifp
->if_eflags
& IFEF_BOND
) == 0) {
1586 p
= bond_lookup_port(port_ifp
);
1590 if (p
->po_enabled
== 0) {
1593 bondport_receive_lacpdu(p
, (lacpdu_ref
)m
->m_data
);
1594 if (ifbond_selection(p
->po_bond
)) {
1595 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
1598 /* XXX need to take a reference on bond_ifp */
1599 bond_ifp
= p
->po_bond
->ifb_ifp
;
1604 if (bond_ifp
!= NULL
) {
1605 interface_link_event(bond_ifp
, event_code
);
1612 bond_receive_la_marker_pdu(struct mbuf
* m
, struct ifnet
* port_ifp
)
1614 la_marker_pdu_ref marker_p
;
1617 marker_p
= (la_marker_pdu_ref
)(m
->m_data
+ ETHER_HDR_LEN
);
1618 if (marker_p
->lm_marker_tlv_type
!= LA_MARKER_TLV_TYPE_MARKER
) {
1622 if ((port_ifp
->if_eflags
& IFEF_BOND
) == 0) {
1626 p
= bond_lookup_port(port_ifp
);
1627 if (p
== NULL
|| p
->po_enabled
== 0) {
1631 /* echo back the same packet as a marker response */
1632 marker_p
->lm_marker_tlv_type
= LA_MARKER_TLV_TYPE_MARKER_RESPONSE
;
1633 bondport_slow_proto_transmit(p
, (packet_buffer_ref
)m
);
1643 bond_input(struct mbuf
* m
, char * frame_header
, struct ifnet
* port_ifp
,
1644 __unused u_long protocol_family
, __unused
int sync_ok
)
1646 bpf_packet_func bpf_func
;
1647 const struct ether_header
* eh_p
;
1652 eh_p
= (const struct ether_header
*)frame_header
;
1653 if ((m
->m_flags
& M_MCAST
) != 0
1654 && bcmp(eh_p
->ether_dhost
, &slow_proto_multicast
,
1655 sizeof(eh_p
->ether_dhost
)) == 0
1656 && ntohs(eh_p
->ether_type
) == IEEE8023AD_SLOW_PROTO_ETHERTYPE
) {
1657 u_char subtype
= *mtod(m
, u_char
*);
1659 if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP
) {
1660 if (m
->m_pkthdr
.len
< (int)offsetof(lacpdu
, la_reserved
)) {
1665 if (m
->m_len
< (int)offsetof(lacpdu
, la_reserved
)) {
1666 m
= m_pullup(m
, offsetof(lacpdu
, la_reserved
));
1671 bond_receive_lacpdu(m
, port_ifp
);
1674 else if (subtype
== IEEE8023AD_SLOW_PROTO_SUBTYPE_LA_MARKER_PROTOCOL
) {
1677 /* restore the ethernet header pointer in the mbuf */
1678 m
->m_pkthdr
.len
+= ETHER_HDR_LEN
;
1679 m
->m_data
-= ETHER_HDR_LEN
;
1680 m
->m_len
+= ETHER_HDR_LEN
;
1681 min_size
= ETHER_HDR_LEN
+ offsetof(la_marker_pdu
, lm_reserved
);
1682 if (m
->m_pkthdr
.len
< min_size
) {
1687 if (m
->m_len
< min_size
) {
1688 m
= m_pullup(m
, min_size
);
1693 /* send to marker responder */
1694 bond_receive_la_marker_pdu(m
, port_ifp
);
1697 else if (subtype
== 0
1698 || subtype
> IEEE8023AD_SLOW_PROTO_SUBTYPE_RESERVED_END
) {
1699 /* invalid subtype, discard the frame */
1705 if ((port_ifp
->if_eflags
& IFEF_BOND
) == 0) {
1708 p
= bond_lookup_port(port_ifp
);
1709 if (p
== NULL
|| bondport_collecting(p
) == 0) {
1713 /* make the packet appear as if it arrived on the bonded interface */
1716 bpf_func
= ifb
->ifb_bpf_input
;
1719 if (m
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) {
1720 (void)ifnet_stat_increment_in(ifp
, 1,
1721 (m
->m_pkthdr
.len
+ ETHER_HDR_LEN
1722 + ETHER_VLAN_ENCAP_LEN
), 0);
1725 (void)ifnet_stat_increment_in(ifp
, 1,
1726 (m
->m_pkthdr
.len
+ ETHER_HDR_LEN
), 0);
1728 m
->m_pkthdr
.rcvif
= ifp
;
1729 bond_bpf_input(ifp
, m
, eh_p
, bpf_func
);
1730 dlil_input_packet(ifp
, m
, frame_header
);
1739 static __inline__
const char *
1740 bondport_get_name(bondport_ref p
)
1742 return (p
->po_name
);
1745 static __inline__
int
1746 bondport_get_index(bondport_ref p
)
1748 return (p
->po_ifp
->if_index
);
1752 bondport_slow_proto_transmit(bondport_ref p
, packet_buffer_ref buf
)
1754 struct ether_header
* eh_p
;
1757 /* packet_buffer_allocate leaves room for ethernet header */
1758 eh_p
= mtod(buf
, struct ether_header
*);
1759 bcopy(&slow_proto_multicast
, &eh_p
->ether_dhost
, sizeof(eh_p
->ether_dhost
));
1760 bcopy(&p
->po_saved_addr
, eh_p
->ether_shost
, sizeof(eh_p
->ether_shost
));
1761 eh_p
->ether_type
= htons(IEEE8023AD_SLOW_PROTO_ETHERTYPE
);
1762 error
= dlil_output(p
->po_ifp
, 0, buf
, NULL
, NULL
, 1);
1764 printf("bondport_slow_proto_transmit(%s) failed %d\n",
1765 bondport_get_name(p
), error
);
1771 bondport_timer_process_func(devtimer_ref timer
,
1772 devtimer_process_func_event event
)
1777 case devtimer_process_func_event_lock
:
1779 devtimer_retain(timer
);
1781 case devtimer_process_func_event_unlock
:
1782 if (devtimer_valid(timer
)) {
1783 /* as long as the devtimer is valid, we can look at arg0 */
1785 struct ifnet
* bond_ifp
= NULL
;
1787 p
= (bondport_ref
)devtimer_arg0(timer
);
1788 if (ifbond_selection(p
->po_bond
)) {
1789 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
1792 /* XXX need to take a reference on bond_ifp */
1793 bond_ifp
= p
->po_bond
->ifb_ifp
;
1795 devtimer_release(timer
);
1797 if (bond_ifp
!= NULL
) {
1798 interface_link_event(bond_ifp
, event_code
);
1802 /* timer is going away */
1803 devtimer_release(timer
);
1813 bondport_create(struct ifnet
* port_ifp
, lacp_port_priority priority
,
1814 int active
, int short_timeout
, int * ret_error
)
1817 bondport_ref p
= NULL
;
1818 lacp_actor_partner_state s
;
1821 p
= _MALLOC(sizeof(*p
), M_BOND
, M_WAITOK
);
1823 *ret_error
= ENOMEM
;
1826 bzero(p
, sizeof(*p
));
1827 multicast_list_init(&p
->po_multicast
);
1828 if ((u_long
)snprintf(p
->po_name
, sizeof(p
->po_name
), "%s%d",
1829 port_ifp
->if_name
, port_ifp
->if_unit
)
1830 >= sizeof(p
->po_name
)) {
1831 printf("if_bond: name too large\n");
1832 *ret_error
= EINVAL
;
1835 error
= siocgifdevmtu(port_ifp
, &p
->po_devmtu
);
1837 printf("if_bond: SIOCGIFDEVMTU %s failed, %d\n",
1838 bondport_get_name(p
), error
);
1841 /* remember the current interface MTU so it can be restored */
1842 p
->po_devmtu
.ifdm_current
= port_ifp
->if_mtu
;
1843 p
->po_ifp
= port_ifp
;
1844 p
->po_media_info
= interface_media_info(port_ifp
);
1845 p
->po_current_while_timer
= devtimer_create(bondport_timer_process_func
, p
);
1846 if (p
->po_current_while_timer
== NULL
) {
1847 *ret_error
= ENOMEM
;
1850 p
->po_periodic_timer
= devtimer_create(bondport_timer_process_func
, p
);
1851 if (p
->po_periodic_timer
== NULL
) {
1852 *ret_error
= ENOMEM
;
1855 p
->po_wait_while_timer
= devtimer_create(bondport_timer_process_func
, p
);
1856 if (p
->po_wait_while_timer
== NULL
) {
1857 *ret_error
= ENOMEM
;
1860 p
->po_transmit_timer
= devtimer_create(bondport_timer_process_func
, p
);
1861 if (p
->po_transmit_timer
== NULL
) {
1862 *ret_error
= ENOMEM
;
1865 p
->po_receive_state
= ReceiveState_none
;
1866 p
->po_mux_state
= MuxState_none
;
1867 p
->po_priority
= priority
;
1869 s
= lacp_actor_partner_state_set_aggregatable(s
);
1870 if (short_timeout
) {
1871 s
= lacp_actor_partner_state_set_short_timeout(s
);
1874 s
= lacp_actor_partner_state_set_active_lacp(s
);
1876 p
->po_actor_state
= s
;
1885 bondport_start(bondport_ref p
)
1887 bondport_receive_machine(p
, LAEventStart
, NULL
);
1888 bondport_mux_machine(p
, LAEventStart
, NULL
);
1889 bondport_periodic_transmit_machine(p
, LAEventStart
, NULL
);
1890 bondport_transmit_machine(p
, LAEventStart
, NULL
);
1895 * Function: bondport_invalidate_timers
1897 * Invalidate all of the timers for the bondport.
1900 bondport_invalidate_timers(bondport_ref p
)
1902 devtimer_invalidate(p
->po_current_while_timer
);
1903 devtimer_invalidate(p
->po_periodic_timer
);
1904 devtimer_invalidate(p
->po_wait_while_timer
);
1905 devtimer_invalidate(p
->po_transmit_timer
);
1909 bondport_free(bondport_ref p
)
1911 multicast_list_remove(&p
->po_multicast
);
1912 devtimer_release(p
->po_current_while_timer
);
1913 devtimer_release(p
->po_periodic_timer
);
1914 devtimer_release(p
->po_wait_while_timer
);
1915 devtimer_release(p
->po_transmit_timer
);
1920 #define BOND_ADD_PROGRESS_IN_LIST 0x1
1921 #define BOND_ADD_PROGRESS_PROTO_ATTACHED 0x2
1922 #define BOND_ADD_PROGRESS_LLADDR_SET 0x4
1923 #define BOND_ADD_PROGRESS_MTU_SET 0x8
1925 static __inline__
int
1926 bond_device_mtu(struct ifnet
* ifp
, ifbond_ref ifb
)
1928 return (((int)ifp
->if_mtu
> ifb
->ifb_altmtu
)
1929 ? (int)ifp
->if_mtu
: ifb
->ifb_altmtu
);
1933 bond_add_interface(struct ifnet
* ifp
, struct ifnet
* port_ifp
)
1939 struct sockaddr_dl
* ifb_sdl
;
1940 bondport_ref
* new_array
= NULL
;
1941 bondport_ref
* old_array
= NULL
;
1943 struct sockaddr_dl
* port_sdl
;
1946 /* pre-allocate space for new port */
1947 p
= bondport_create(port_ifp
, 0x8000, 1, 0, &error
);
1952 ifb
= (ifbond_ref
)ifp
->if_private
;
1953 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
1956 return ((ifb
== NULL
? EOPNOTSUPP
: EBUSY
));
1959 /* make sure this interface can handle our current MTU */
1960 devmtu
= bond_device_mtu(ifp
, ifb
);
1962 && (devmtu
> p
->po_devmtu
.ifdm_max
|| devmtu
< p
->po_devmtu
.ifdm_min
)) {
1964 printf("if_bond: interface %s doesn't support mtu %d",
1965 bondport_get_name(p
), devmtu
);
1970 /* make sure ifb doesn't get de-allocated while we wait */
1973 /* wait for other add or remove to complete */
1974 ifbond_wait(ifb
, "bond_add_interface");
1976 if (ifbond_flags_if_detaching(ifb
)) {
1977 /* someone destroyed the bond while we were waiting */
1981 if (bond_lookup_port(port_ifp
) != NULL
) {
1982 /* port is already part of a bond */
1986 ifnet_lock_exclusive(port_ifp
);
1987 if ((port_ifp
->if_eflags
& (IFEF_VLAN
| IFEF_BOND
)) != 0) {
1988 /* interface already has VLAN's, or is part of bond */
1989 ifnet_lock_done(port_ifp
);
1994 /* mark the interface busy */
1995 port_ifp
->if_eflags
|= IFEF_BOND
;
1996 ifnet_lock_done(port_ifp
);
1998 port_sdl
= ifp_get_sdl(port_ifp
);
1999 ifb_sdl
= ifp_get_sdl(ifp
);
2001 if (TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
2002 ifp
->if_hwassist
= port_ifp
->if_hwassist
;
2003 ifp
->if_flags
|= IFF_RUNNING
;
2004 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2005 /* first port added to bond determines bond's ethernet address */
2006 ether_addr_copy(LLADDR(ifb_sdl
), LLADDR(port_sdl
));
2007 ifb_sdl
->sdl_type
= IFT_ETHER
;
2008 ifb_sdl
->sdl_alen
= ETHER_ADDR_LEN
;
2011 if (ifp
->if_hwassist
!= port_ifp
->if_hwassist
) {
2012 printf("bond_add_interface(%s, %s) "
2013 "hwassist values don't match 0x%x != 0x%x\n",
2014 ifb
->ifb_name
, bondport_get_name(p
),
2015 ifp
->if_hwassist
, port_ifp
->if_hwassist
);
2018 * if the bond has VLAN's, we can't simply change the hwassist
2019 * field behind its back: this needs work
2021 ifp
->if_hwassist
= 0;
2026 /* remember the port's ethernet address so it can be restored */
2027 ether_addr_copy(&p
->po_saved_addr
, LLADDR(port_sdl
));
2029 /* add it to the list of ports */
2030 TAILQ_INSERT_TAIL(&ifb
->ifb_port_list
, p
, po_port_list
);
2031 ifb
->ifb_port_count
++;
2033 /* set the default MTU */
2034 if (ifp
->if_mtu
== 0) {
2035 ifp
->if_mtu
= ETHERMTU
;
2038 progress
|= BOND_ADD_PROGRESS_IN_LIST
;
2040 /* allocate a larger distributing array */
2041 new_array
= (bondport_ref
*)
2042 _MALLOC(sizeof(*new_array
) * ifb
->ifb_port_count
, M_BOND
, M_WAITOK
);
2043 if (new_array
== NULL
) {
2048 /* attach our BOND "protocol" to the interface */
2049 error
= bond_attach_protocol(port_ifp
);
2053 progress
|= BOND_ADD_PROGRESS_PROTO_ATTACHED
;
2055 /* set the interface MTU */
2056 devmtu
= bond_device_mtu(ifp
, ifb
);
2057 error
= siocsifmtu(port_ifp
, devmtu
);
2059 printf("bond_add_interface(%s, %s):"
2060 " SIOCSIFMTU %d failed %d\n",
2061 ifb
->ifb_name
, bondport_get_name(p
), devmtu
, error
);
2064 progress
|= BOND_ADD_PROGRESS_MTU_SET
;
2066 /* program the port with our multicast addresses */
2067 error
= multicast_list_program(&p
->po_multicast
, ifp
, port_ifp
);
2069 printf("bond_add_interface(%s, %s):"
2070 " multicast_list_program failed %d\n",
2071 ifb
->ifb_name
, bondport_get_name(p
), error
);
2075 /* mark the interface up */
2076 ifnet_set_flags(port_ifp
, IFF_UP
, IFF_UP
);
2078 error
= dlil_ioctl(0, port_ifp
, SIOCSIFFLAGS
, (caddr_t
)NULL
);
2080 printf("bond_add_interface(%s, %s): SIOCSIFFLAGS failed %d\n",
2081 ifb
->ifb_name
, bondport_get_name(p
), error
);
2085 /* re-program the port's ethernet address */
2086 error
= if_siflladdr(port_ifp
,
2087 (const struct ether_addr
*)LLADDR(ifb_sdl
));
2089 /* port doesn't support setting the link address */
2090 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2091 ifb
->ifb_name
, bondport_get_name(p
), error
);
2094 progress
|= BOND_ADD_PROGRESS_LLADDR_SET
;
2098 /* no failures past this point */
2101 /* copy the contents of the existing distributing array */
2102 if (ifb
->ifb_distributing_count
) {
2103 bcopy(ifb
->ifb_distributing_array
, new_array
,
2104 sizeof(*new_array
) * ifb
->ifb_distributing_count
);
2106 old_array
= ifb
->ifb_distributing_array
;
2107 ifb
->ifb_distributing_array
= new_array
;
2109 /* clear the busy state, and wakeup anyone waiting */
2110 ifbond_signal(ifb
, "bond_add_interface");
2113 /* check if we need to generate a link status event */
2114 if (ifbond_selection(ifb
)) {
2115 event_code
= (ifb
->ifb_active_lag
== NULL
)
2120 if (event_code
!= 0) {
2121 interface_link_event(ifp
, event_code
);
2123 if (old_array
!= NULL
) {
2124 FREE(old_array
, M_BOND
);
2129 bond_assert_lock_not_held();
2131 if (new_array
!= NULL
) {
2132 FREE(new_array
, M_BOND
);
2134 if ((progress
& BOND_ADD_PROGRESS_LLADDR_SET
) != 0) {
2137 error1
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2139 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2140 ifb
->ifb_name
, bondport_get_name(p
), error1
);
2143 if ((progress
& BOND_ADD_PROGRESS_PROTO_ATTACHED
) != 0) {
2144 (void)bond_detach_protocol(port_ifp
);
2146 if ((progress
& BOND_ADD_PROGRESS_MTU_SET
) != 0) {
2149 error1
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
2151 printf("bond_add_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2152 ifb
->ifb_name
, bondport_get_name(p
), p
->po_devmtu
.ifdm_current
,
2157 if ((progress
& BOND_ADD_PROGRESS_IN_LIST
) != 0) {
2158 TAILQ_REMOVE(&ifb
->ifb_port_list
, p
, po_port_list
);
2159 ifb
->ifb_port_count
--;
2161 ifnet_lock_exclusive(port_ifp
);
2162 port_ifp
->if_eflags
&= ~IFEF_BOND
;
2163 ifnet_lock_done(port_ifp
);
2164 if (TAILQ_EMPTY(&ifb
->ifb_port_list
)) {
2165 ifb
->ifb_altmtu
= 0;
2167 ifp
->if_hwassist
= 0;
2168 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2169 bzero(LLADDR(ifb_sdl
), ETHER_ADDR_LEN
);
2170 ifb_sdl
->sdl_type
= IFT_IEEE8023ADLAG
;
2171 ifb_sdl
->sdl_alen
= 0;
2176 ifbond_release(ifb
);
2177 ifbond_signal(ifb
, "bond_add_interface");
2184 bond_remove_interface(ifbond_ref ifb
, struct ifnet
* port_ifp
)
2189 bondport_ref head_port
;
2190 struct sockaddr_dl
* ifb_sdl
;
2192 int new_link_address
= 0;
2194 lacp_actor_partner_state s
;
2196 bond_assert_lock_held();
2199 ifbond_wait(ifb
, "bond_remove_interface");
2201 p
= ifbond_lookup_port(ifb
, port_ifp
);
2204 /* it got removed by another thread */
2208 /* de-select it and remove it from the lists */
2209 bondport_disable_distributing(p
);
2210 bondport_set_selected(p
, SelectedState_UNSELECTED
);
2211 active_lag
= bondport_remove_from_LAG(p
);
2212 TAILQ_REMOVE(&ifb
->ifb_port_list
, p
, po_port_list
);
2213 ifb
->ifb_port_count
--;
2215 /* invalidate timers here while holding the bond_lock */
2216 bondport_invalidate_timers(p
);
2218 /* announce that we're Individual now */
2219 s
= p
->po_actor_state
;
2220 s
= lacp_actor_partner_state_set_individual(s
);
2221 s
= lacp_actor_partner_state_set_not_collecting(s
);
2222 s
= lacp_actor_partner_state_set_not_distributing(s
);
2223 s
= lacp_actor_partner_state_set_out_of_sync(s
);
2224 p
->po_actor_state
= s
;
2225 bondport_flags_set_ntt(p
);
2228 ifb_sdl
= ifp_get_sdl(ifp
);
2229 head_port
= TAILQ_FIRST(&ifb
->ifb_port_list
);
2230 if (head_port
== NULL
) {
2231 ifp
->if_flags
&= ~IFF_RUNNING
;
2232 if (ifbond_flags_lladdr(ifb
) == FALSE
) {
2233 ifb_sdl
->sdl_type
= IFT_IEEE8023ADLAG
;
2234 ifb_sdl
->sdl_alen
= 0;
2235 bzero(LLADDR(ifb_sdl
), ETHER_ADDR_LEN
);
2237 ifp
->if_hwassist
= 0;
2239 ifb
->ifb_altmtu
= 0;
2240 } else if (ifbond_flags_lladdr(ifb
) == FALSE
2241 && bcmp(&p
->po_saved_addr
, LLADDR(ifb_sdl
),
2242 ETHER_ADDR_LEN
) == 0) {
2243 /* this port gave the bond its ethernet address, switch to new one */
2244 ether_addr_copy(LLADDR(ifb_sdl
), &head_port
->po_saved_addr
);
2245 ifb_sdl
->sdl_type
= IFT_ETHER
;
2246 ifb_sdl
->sdl_alen
= ETHER_ADDR_LEN
;
2247 new_link_address
= 1;
2249 /* check if we need to generate a link status event */
2250 if (ifbond_selection(ifb
) || active_lag
) {
2251 event_code
= (ifb
->ifb_active_lag
== NULL
)
2257 bondport_transmit_machine(p
, LAEventStart
, (void *)1);
2259 if (new_link_address
) {
2260 struct ifnet
* scan_ifp
;
2261 bondport_ref scan_port
;
2263 /* ifbond_wait() allows port list traversal without holding the lock */
2265 /* re-program each port with the new link address */
2266 TAILQ_FOREACH(scan_port
, &ifb
->ifb_port_list
, po_port_list
) {
2267 scan_ifp
= scan_port
->po_ifp
;
2269 error
= if_siflladdr(scan_ifp
,
2270 (const struct ether_addr
*) LLADDR(ifb_sdl
));
2272 printf("bond_remove_interface(%s, %s): "
2273 "if_siflladdr (%s) failed %d\n",
2274 ifb
->ifb_name
, bondport_get_name(p
),
2275 bondport_get_name(scan_port
), error
);
2280 /* restore the port's ethernet address */
2281 error
= if_siflladdr(port_ifp
, &p
->po_saved_addr
);
2283 printf("bond_remove_interface(%s, %s): if_siflladdr failed %d\n",
2284 ifb
->ifb_name
, bondport_get_name(p
), error
);
2287 /* restore the port's MTU */
2288 error
= siocsifmtu(port_ifp
, p
->po_devmtu
.ifdm_current
);
2290 printf("bond_remove_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2291 ifb
->ifb_name
, bondport_get_name(p
),
2292 p
->po_devmtu
.ifdm_current
, error
);
2295 /* remove the bond "protocol" */
2296 bond_detach_protocol(port_ifp
);
2298 /* generate link event */
2299 if (event_code
!= 0) {
2300 interface_link_event(ifp
, event_code
);
2304 ifbond_release(ifb
);
2306 ifnet_lock_exclusive(port_ifp
);
2307 port_ifp
->if_eflags
&= ~IFEF_BOND
;
2308 ifnet_lock_done(port_ifp
);
2311 ifbond_signal(ifb
, "bond_remove_interface");
2312 ifbond_release(ifb
); /* a second release for the second reference */
2317 bond_get_status(ifbond_ref ifb
, struct if_bond_req
* ibr_p
, user_addr_t datap
)
2322 struct if_bond_status_req
* ibsr
;
2323 struct if_bond_status ibs
;
2326 ibsr
= &(ibr_p
->ibr_ibru
.ibru_status
);
2327 if (ibsr
->ibsr_version
!= IF_BOND_STATUS_REQ_VERSION
) {
2330 ibsr
->ibsr_key
= ifb
->ifb_key
;
2331 ibsr
->ibsr_total
= ifb
->ifb_port_count
;
2332 dst
= proc_is64bit(current_proc())
2333 ? ibsr
->ibsr_ibsru
.ibsru_buffer64
2334 : CAST_USER_ADDR_T(ibsr
->ibsr_ibsru
.ibsru_buffer32
);
2335 if (dst
== USER_ADDR_NULL
) {
2336 /* just want to know how many there are */
2339 if (ibsr
->ibsr_count
< 0) {
2342 count
= (ifb
->ifb_port_count
< ibsr
->ibsr_count
)
2343 ? ifb
->ifb_port_count
: ibsr
->ibsr_count
;
2344 TAILQ_FOREACH(port
, &ifb
->ifb_port_list
, po_port_list
) {
2345 struct if_bond_partner_state
* ibps_p
;
2346 partner_state_ref ps
;
2351 bzero(&ibs
, sizeof(ibs
));
2352 strncpy(ibs
.ibs_if_name
, port
->po_name
, sizeof(ibs
.ibs_if_name
));
2353 ibs
.ibs_port_priority
= port
->po_priority
;
2354 ibs
.ibs_state
= port
->po_actor_state
;
2355 ibs
.ibs_selected_state
= port
->po_selected
;
2356 ps
= &port
->po_partner_state
;
2357 ibps_p
= &ibs
.ibs_partner_state
;
2358 ibps_p
->ibps_system
= ps
->ps_lag_info
.li_system
;
2359 ibps_p
->ibps_system_priority
= ps
->ps_lag_info
.li_system_priority
;
2360 ibps_p
->ibps_key
= ps
->ps_lag_info
.li_key
;
2361 ibps_p
->ibps_port
= ps
->ps_port
;
2362 ibps_p
->ibps_port_priority
= ps
->ps_port_priority
;
2363 ibps_p
->ibps_state
= ps
->ps_state
;
2364 error
= copyout(&ibs
, dst
, sizeof(ibs
));
2374 error
= copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2377 (void)copyout(ibr_p
, datap
, sizeof(*ibr_p
));
2383 bond_set_promisc(__unused
struct ifnet
*ifp
)
2387 ifbond_ref ifb
= ifp
->if_private
;
2390 if ((ifp
->if_flags
& IFF_PROMISC
) != 0) {
2391 if ((ifb
->ifb_flags
& IFBF_PROMISC
) == 0) {
2392 error
= ifnet_set_promiscuous(ifb
->ifb_p
, 1);
2394 ifb
->ifb_flags
|= IFBF_PROMISC
;
2397 if ((ifb
->ifb_flags
& IFBF_PROMISC
) != 0) {
2398 error
= ifnet_set_promiscuous(ifb
->ifb_p
, 0);
2400 ifb
->ifb_flags
&= ~IFBF_PROMISC
;
2408 bond_get_mtu_values(ifbond_ref ifb
, int * ret_min
, int * ret_max
)
2414 if (TAILQ_FIRST(&ifb
->ifb_port_list
) != NULL
) {
2415 mtu_min
= IF_MINMTU
;
2417 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2418 struct ifdevmtu
* devmtu_p
= &p
->po_devmtu
;
2420 if (devmtu_p
->ifdm_min
> mtu_min
) {
2421 mtu_min
= devmtu_p
->ifdm_min
;
2423 if (mtu_max
== 0 || devmtu_p
->ifdm_max
< mtu_max
) {
2424 mtu_max
= devmtu_p
->ifdm_max
;
2433 bond_set_mtu_on_ports(ifbond_ref ifb
, int mtu
)
2438 TAILQ_FOREACH(p
, &ifb
->ifb_port_list
, po_port_list
) {
2439 error
= siocsifmtu(p
->po_ifp
, mtu
);
2441 printf("if_bond(%s): SIOCSIFMTU %s failed, %d\n",
2442 ifb
->ifb_name
, bondport_get_name(p
), error
);
2450 bond_set_mtu(struct ifnet
* ifp
, int mtu
, int isdevmtu
)
2460 ifb
= (ifbond_ref
)ifp
->if_private
;
2461 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2462 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2466 ifbond_wait(ifb
, "bond_set_mtu");
2469 if (ifp
->if_private
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2473 bond_get_mtu_values(ifb
, &mtu_min
, &mtu_max
);
2474 if (mtu
> mtu_max
) {
2478 if (mtu
< mtu_min
&& (isdevmtu
== 0 || mtu
!= 0)) {
2479 /* allow SIOCSIFALTMTU to set the mtu to 0 */
2484 new_max
= (mtu
> (int)ifp
->if_mtu
) ? mtu
: (int)ifp
->if_mtu
;
2487 new_max
= (mtu
> ifb
->ifb_altmtu
) ? mtu
: ifb
->ifb_altmtu
;
2489 old_max
= ((int)ifp
->if_mtu
> ifb
->ifb_altmtu
)
2490 ? (int)ifp
->if_mtu
: ifb
->ifb_altmtu
;
2491 if (new_max
!= old_max
) {
2492 /* we can safely walk the list of port without the lock held */
2494 error
= bond_set_mtu_on_ports(ifb
, new_max
);
2496 /* try our best to back out of it */
2497 (void)bond_set_mtu_on_ports(ifb
, old_max
);
2503 ifb
->ifb_altmtu
= mtu
;
2511 ifbond_signal(ifb
, "bond_set_mtu");
2512 ifbond_release(ifb
);
2520 bond_ioctl(struct ifnet
*ifp
, u_int32_t cmd
, void * data
)
2523 struct if_bond_req ibr
;
2524 struct ifaddr
* ifa
;
2527 struct ifmediareq64
*ifmr
;
2528 struct ifnet
* port_ifp
= NULL
;
2529 user_addr_t user_addr
;
2531 if (ifp
->if_type
!= IFT_IEEE8023ADLAG
) {
2532 return (EOPNOTSUPP
);
2534 ifr
= (struct ifreq
*)data
;
2535 ifa
= (struct ifaddr
*)data
;
2539 ifnet_set_flags(ifp
, IFF_UP
, IFF_UP
);
2542 case SIOCGIFMEDIA64
:
2545 ifb
= (ifbond_ref
)ifp
->if_private
;
2546 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2548 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2550 ifmr
= (struct ifmediareq64
*)data
;
2551 ifmr
->ifm_current
= IFM_ETHER
;
2553 ifmr
->ifm_status
= IFM_AVALID
;
2554 ifmr
->ifm_active
= IFM_ETHER
;
2555 ifmr
->ifm_count
= 1;
2556 if (ifb
->ifb_active_lag
!= NULL
) {
2557 ifmr
->ifm_active
= ifb
->ifb_active_lag
->lag_active_media
;
2558 ifmr
->ifm_status
|= IFM_ACTIVE
;
2561 user_addr
= (cmd
== SIOCGIFMEDIA64
)
2562 ? ifmr
->ifm_ifmu
.ifmu_ulist64
2563 : CAST_USER_ADDR_T(ifmr
->ifm_ifmu
.ifmu_ulist32
);
2564 if (user_addr
!= USER_ADDR_NULL
) {
2565 error
= copyout(&ifmr
->ifm_current
,
2572 /* XXX send the SIFMEDIA to all children? Or force autoselect? */
2578 ifb
= (ifbond_ref
)ifp
->if_private
;
2579 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2581 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2584 ifr
->ifr_devmtu
.ifdm_current
= bond_device_mtu(ifp
, ifb
);
2585 bond_get_mtu_values(ifb
, &ifr
->ifr_devmtu
.ifdm_min
,
2586 &ifr
->ifr_devmtu
.ifdm_max
);
2592 ifb
= (ifbond_ref
)ifp
->if_private
;
2593 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2595 error
= (ifb
== NULL
) ? EOPNOTSUPP
: EBUSY
;
2598 ifr
->ifr_mtu
= ifb
->ifb_altmtu
;
2603 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 1);
2607 error
= bond_set_mtu(ifp
, ifr
->ifr_mtu
, 0);
2611 user_addr
= proc_is64bit(current_proc())
2612 ? ifr
->ifr_data64
: CAST_USER_ADDR_T(ifr
->ifr_data
);
2613 error
= copyin(user_addr
, &ibr
, sizeof(ibr
));
2617 switch (ibr
.ibr_op
) {
2618 case IF_BOND_OP_ADD_INTERFACE
:
2619 case IF_BOND_OP_REMOVE_INTERFACE
:
2620 /* XXX ifunit() needs to return a reference on the ifp */
2621 port_ifp
= ifunit(ibr
.ibr_ibru
.ibru_if_name
);
2622 if (port_ifp
== NULL
) {
2626 if (port_ifp
->if_type
!= IFT_ETHER
) {
2627 error
= EPROTONOSUPPORT
;
2631 case IF_BOND_OP_SET_VERBOSE
:
2640 switch (ibr
.ibr_op
) {
2641 case IF_BOND_OP_ADD_INTERFACE
:
2642 error
= bond_add_interface(ifp
, port_ifp
);
2644 case IF_BOND_OP_REMOVE_INTERFACE
:
2646 ifb
= (ifbond_ref
)ifp
->if_private
;
2647 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2649 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2651 error
= bond_remove_interface(ifb
, port_ifp
);
2654 case IF_BOND_OP_SET_VERBOSE
:
2656 if (g_bond
== NULL
) {
2661 g_bond
->verbose
= ibr
.ibr_ibru
.ibru_int_val
;
2668 user_addr
= proc_is64bit(current_proc())
2669 ? ifr
->ifr_data64
: CAST_USER_ADDR_T(ifr
->ifr_data
);
2670 error
= copyin(user_addr
, &ibr
, sizeof(ibr
));
2674 switch (ibr
.ibr_op
) {
2675 case IF_BOND_OP_GET_STATUS
:
2685 ifb
= (ifbond_ref
)ifp
->if_private
;
2686 if (ifb
== NULL
|| ifbond_flags_if_detaching(ifb
)) {
2688 return (ifb
== NULL
? EOPNOTSUPP
: EBUSY
);
2690 switch (ibr
.ibr_op
) {
2691 case IF_BOND_OP_GET_STATUS
:
2692 error
= bond_get_status(ifb
, &ibr
, user_addr
);
2703 /* enable/disable promiscuous mode */
2705 error
= bond_set_promisc(ifp
);
2711 error
= bond_setmulti(ifp
);
2720 bond_if_free(struct ifnet
* ifp
)
2728 ifb
= (ifbond_ref
)ifp
->if_private
;
2733 ifp
->if_private
= NULL
;
2734 ifbond_release(ifb
);
2736 dlil_if_release(ifp
);
2741 bond_event(struct ifnet
* port_ifp
, struct kev_msg
* event
)
2743 struct ifnet
* bond_ifp
= NULL
;
2746 struct media_info media_info
;
2748 if (event
->vendor_code
!= KEV_VENDOR_APPLE
2749 || event
->kev_class
!= KEV_NETWORK_CLASS
2750 || event
->kev_subclass
!= KEV_DL_SUBCLASS
) {
2753 switch (event
->event_code
) {
2754 case KEV_DL_IF_DETACHING
:
2756 case KEV_DL_LINK_OFF
:
2757 case KEV_DL_LINK_ON
:
2758 media_info
= interface_media_info(port_ifp
);
2764 p
= bond_lookup_port(port_ifp
);
2769 switch (event
->event_code
) {
2770 case KEV_DL_IF_DETACHING
:
2771 bond_remove_interface(p
->po_bond
, p
->po_ifp
);
2773 case KEV_DL_LINK_OFF
:
2774 case KEV_DL_LINK_ON
:
2775 p
->po_media_info
= media_info
;
2776 if (p
->po_enabled
) {
2777 bondport_link_status_changed(p
);
2781 /* generate a link-event */
2782 if (ifbond_selection(p
->po_bond
)) {
2783 event_code
= (p
->po_bond
->ifb_active_lag
== NULL
)
2786 /* XXX need to take a reference on bond_ifp */
2787 bond_ifp
= p
->po_bond
->ifb_ifp
;
2790 if (bond_ifp
!= NULL
) {
2791 interface_link_event(bond_ifp
, event_code
);
2797 interface_link_event(struct ifnet
* ifp
, u_long event_code
)
2800 struct kern_event_msg header
;
2802 char if_name
[IFNAMSIZ
];
2805 event
.header
.total_size
= sizeof(event
);
2806 event
.header
.vendor_code
= KEV_VENDOR_APPLE
;
2807 event
.header
.kev_class
= KEV_NETWORK_CLASS
;
2808 event
.header
.kev_subclass
= KEV_DL_SUBCLASS
;
2809 event
.header
.event_code
= event_code
;
2810 event
.header
.event_data
[0] = ifp
->if_family
;
2811 event
.unit
= (u_long
) ifp
->if_unit
;
2812 strncpy(event
.if_name
, ifp
->if_name
, IFNAMSIZ
);
2813 dlil_event(ifp
, &event
.header
);
2818 * Function: bond_attach_protocol
2820 * Attach a DLIL protocol to the interface.
2822 * The ethernet demux special cases to always return PF_BOND if the
2823 * interface is bonded. That means we receive all traffic from that
2824 * interface without passing any of the traffic to any other attached
2828 bond_attach_protocol(struct ifnet
*ifp
)
2831 struct dlil_proto_reg_str reg
;
2833 bzero(®
, sizeof(reg
));
2834 TAILQ_INIT(®
.demux_desc_head
);
2835 reg
.interface_family
= ifp
->if_family
;
2836 reg
.unit_number
= ifp
->if_unit
;
2837 reg
.input
= bond_input
;
2838 reg
.event
= bond_event
;
2839 reg
.protocol_family
= PF_BOND
;
2841 error
= dlil_attach_protocol(®
);
2843 printf("bond over %s%d: dlil_attach_protocol failed, %d\n",
2844 ifp
->if_name
, ifp
->if_unit
, error
);
2850 * Function: bond_detach_protocol
2852 * Detach our DLIL protocol from an interface
2855 bond_detach_protocol(struct ifnet
*ifp
)
2859 error
= dlil_detach_protocol(ifp
, PF_BOND
);
2861 printf("bond over %s%d: dlil_detach_protocol failed, %d\n",
2862 ifp
->if_name
, ifp
->if_unit
, error
);
2868 * DLIL interface family functions
2870 extern int ether_add_if(struct ifnet
*ifp
);
2871 extern int ether_del_if(struct ifnet
*ifp
);
2872 extern int ether_init_if(struct ifnet
*ifp
);
2873 extern int ether_add_proto_old(struct ifnet
*ifp
, u_long protocol_family
,
2874 struct ddesc_head_str
*desc_head
);
2876 extern int ether_attach_inet(struct ifnet
*ifp
, u_long protocol_family
);
2877 extern int ether_detach_inet(struct ifnet
*ifp
, u_long protocol_family
);
2878 extern int ether_attach_inet6(struct ifnet
*ifp
, u_long protocol_family
);
2879 extern int ether_detach_inet6(struct ifnet
*ifp
, u_long protocol_family
);
2881 __private_extern__
int
2882 bond_family_init(void)
2885 struct dlil_ifmod_reg_str ifmod_reg
;
2887 bzero(&ifmod_reg
, sizeof(ifmod_reg
));
2888 ifmod_reg
.add_if
= ether_add_if
;
2889 ifmod_reg
.del_if
= ether_del_if
;
2890 ifmod_reg
.init_if
= NULL
;
2891 ifmod_reg
.add_proto
= ether_add_proto_old
;
2892 ifmod_reg
.del_proto
= ether_del_proto
;
2893 ifmod_reg
.ifmod_ioctl
= ether_ioctl
;
2894 ifmod_reg
.shutdown
= NULL
;
2896 if (dlil_reg_if_modules(APPLE_IF_FAM_BOND
, &ifmod_reg
)) {
2897 printf("WARNING: bond_family_init -- "
2898 "Can't register if family modules\n");
2903 error
= dlil_reg_proto_module(PF_INET
, APPLE_IF_FAM_BOND
,
2907 printf("bond: dlil_reg_proto_module failed for AF_INET6 error=%d\n",
2912 error
= dlil_reg_proto_module(PF_INET6
, APPLE_IF_FAM_BOND
,
2914 ether_detach_inet6
);
2916 printf("bond: dlil_reg_proto_module failed for AF_INET6 error=%d\n",
2920 bond_clone_attach();
2932 ** LACP ifbond_list routines
2935 ifbond_list_find_moved_port(bondport_ref rx_port
,
2936 const lacp_actor_partner_tlv_ref atlv
)
2940 partner_state_ref ps
;
2943 TAILQ_FOREACH(bond
, &g_bond
->ifbond_list
, ifb_bond_list
) {
2944 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
2947 /* no point in comparing against ourselves */
2950 if (p
->po_receive_state
!= ReceiveState_PORT_DISABLED
) {
2951 /* it's not clear that we should be checking this */
2954 ps
= &p
->po_partner_state
;
2955 if (lacp_actor_partner_state_defaulted(ps
->ps_state
)) {
2958 ps_li
= &ps
->ps_lag_info
;
2959 if (ps
->ps_port
== lacp_actor_partner_tlv_get_port(atlv
)
2960 && bcmp(&ps_li
->li_system
, atlv
->lap_system
,
2961 sizeof(ps_li
->li_system
)) == 0) {
2962 if (g_bond
->verbose
) {
2963 timestamp_printf("System " EA_FORMAT
2964 " Port 0x%x moved from %s to %s\n",
2965 EA_LIST(&ps_li
->li_system
), ps
->ps_port
,
2966 bondport_get_name(p
),
2967 bondport_get_name(rx_port
));
2977 ** LACP ifbond, LAG routines
2981 ifbond_selection(ifbond_ref bond
)
2983 int all_ports_ready
= 0;
2984 int active_media
= 0;
2986 int lag_changed
= 0;
2990 lag
= ifbond_find_best_LAG(bond
, &active_media
);
2991 if (lag
!= bond
->ifb_active_lag
) {
2992 if (bond
->ifb_active_lag
!= NULL
) {
2993 ifbond_deactivate_LAG(bond
, bond
->ifb_active_lag
);
2994 bond
->ifb_active_lag
= NULL
;
2996 bond
->ifb_active_lag
= lag
;
2998 ifbond_activate_LAG(bond
, lag
, active_media
);
3002 else if (lag
!= NULL
) {
3003 if (lag
->lag_active_media
!= active_media
) {
3004 if (g_bond
->verbose
) {
3005 timestamp_printf("LAG PORT SPEED CHANGED from %d to %d\n",
3006 link_speed(lag
->lag_active_media
),
3007 link_speed(active_media
));
3009 ifbond_deactivate_LAG(bond
, lag
);
3010 ifbond_activate_LAG(bond
, lag
, active_media
);
3015 port_speed
= link_speed(active_media
);
3016 all_ports_ready
= ifbond_all_ports_ready(bond
);
3018 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3019 if (lag
!= NULL
&& p
->po_lag
== lag
3020 && media_speed(&p
->po_media_info
) == port_speed
3021 && (p
->po_mux_state
== MuxState_DETACHED
3022 || p
->po_selected
== SelectedState_SELECTED
3023 || p
->po_selected
== SelectedState_STANDBY
)
3024 && bondport_aggregatable(p
)) {
3025 if (bond
->ifb_max_active
> 0) {
3026 if (lag
->lag_selected_port_count
< bond
->ifb_max_active
) {
3027 if (p
->po_selected
== SelectedState_STANDBY
3028 || p
->po_selected
== SelectedState_UNSELECTED
) {
3029 bondport_set_selected(p
, SelectedState_SELECTED
);
3032 else if (p
->po_selected
== SelectedState_UNSELECTED
) {
3033 bondport_set_selected(p
, SelectedState_STANDBY
);
3037 bondport_set_selected(p
, SelectedState_SELECTED
);
3040 if (bondport_flags_selected_changed(p
)) {
3041 bondport_flags_clear_selected_changed(p
);
3042 bondport_mux_machine(p
, LAEventSelectedChange
, NULL
);
3045 && bondport_flags_ready(p
)
3046 && p
->po_mux_state
== MuxState_WAITING
) {
3047 bondport_mux_machine(p
, LAEventReady
, NULL
);
3049 bondport_transmit_machine(p
, LAEventStart
, NULL
);
3051 return (lag_changed
);
3055 ifbond_find_best_LAG(ifbond_ref bond
, int * active_media
)
3057 int best_active
= 0;
3058 LAG_ref best_lag
= NULL
;
3063 if (bond
->ifb_active_lag
!= NULL
) {
3064 best_lag
= bond
->ifb_active_lag
;
3065 best_count
= LAG_get_aggregatable_port_count(best_lag
, &best_active
);
3066 if (bond
->ifb_max_active
> 0
3067 && best_count
> bond
->ifb_max_active
) {
3068 best_count
= bond
->ifb_max_active
;
3070 best_speed
= link_speed(best_active
);
3072 TAILQ_FOREACH(lag
, &bond
->ifb_lag_list
, lag_list
) {
3077 if (lag
== bond
->ifb_active_lag
) {
3078 /* we've already computed it */
3081 count
= LAG_get_aggregatable_port_count(lag
, &active
);
3085 if (bond
->ifb_max_active
> 0
3086 && count
> bond
->ifb_max_active
) {
3087 /* if there's a limit, don't count extra links */
3088 count
= bond
->ifb_max_active
;
3090 speed
= link_speed(active
);
3091 if ((count
* speed
) > (best_count
* best_speed
)) {
3094 best_active
= active
;
3098 if (best_count
== 0) {
3101 *active_media
= best_active
;
3106 ifbond_deactivate_LAG(__unused ifbond_ref bond
, LAG_ref lag
)
3110 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3111 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3117 ifbond_activate_LAG(ifbond_ref bond
, LAG_ref lag
, int active_media
)
3122 if (bond
->ifb_max_active
> 0) {
3123 need
= bond
->ifb_max_active
;
3125 lag
->lag_active_media
= active_media
;
3126 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3127 if (bondport_aggregatable(p
) == 0) {
3128 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3130 else if (media_speed(&p
->po_media_info
) != link_speed(active_media
)) {
3131 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3133 else if (p
->po_mux_state
== MuxState_DETACHED
) {
3134 if (bond
->ifb_max_active
> 0) {
3136 bondport_set_selected(p
, SelectedState_SELECTED
);
3140 bondport_set_selected(p
, SelectedState_STANDBY
);
3144 bondport_set_selected(p
, SelectedState_SELECTED
);
3148 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3156 ifbond_set_max_active(ifbond_ref bond
, int max_active
)
3158 LAG_ref lag
= bond
->ifb_active_lag
;
3160 bond
->ifb_max_active
= max_active
;
3161 if (bond
->ifb_max_active
<= 0 || lag
== NULL
) {
3164 if (lag
->lag_selected_port_count
> bond
->ifb_max_active
) {
3168 remove_count
= lag
->lag_selected_port_count
- bond
->ifb_max_active
;
3169 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3170 if (p
->po_selected
== SelectedState_SELECTED
) {
3171 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3173 if (remove_count
== 0) {
3184 ifbond_all_ports_ready(ifbond_ref bond
)
3189 if (bond
->ifb_active_lag
== NULL
) {
3192 TAILQ_FOREACH(p
, &bond
->ifb_active_lag
->lag_port_list
, po_lag_port_list
) {
3193 if (p
->po_mux_state
== MuxState_WAITING
3194 && p
->po_selected
== SelectedState_SELECTED
) {
3195 if (bondport_flags_ready(p
) == 0) {
3199 /* note that there was at least one ready port */
3206 ifbond_all_ports_attached(ifbond_ref bond
, bondport_ref this_port
)
3210 TAILQ_FOREACH(p
, &bond
->ifb_port_list
, po_port_list
) {
3211 if (this_port
== p
) {
3214 if (bondport_flags_mux_attached(p
) == 0) {
3222 ifbond_get_LAG_matching_port(ifbond_ref bond
, bondport_ref p
)
3226 TAILQ_FOREACH(lag
, &bond
->ifb_lag_list
, lag_list
) {
3227 if (bcmp(&lag
->lag_info
, &p
->po_partner_state
.ps_lag_info
,
3228 sizeof(lag
->lag_info
)) == 0) {
3236 LAG_get_aggregatable_port_count(LAG_ref lag
, int * active_media
)
3246 TAILQ_FOREACH(p
, &lag
->lag_port_list
, po_lag_port_list
) {
3247 if (bondport_aggregatable(p
)) {
3250 this_speed
= media_speed(&p
->po_media_info
);
3251 if (this_speed
== 0) {
3254 if (this_speed
> speed
) {
3255 active
= p
->po_media_info
.mi_active
;
3259 else if (this_speed
== speed
) {
3264 *active_media
= active
;
3270 ** LACP bondport routines
3273 bondport_link_status_changed(bondport_ref p
)
3275 ifbond_ref bond
= p
->po_bond
;
3277 if (g_bond
->verbose
) {
3278 if (media_active(&p
->po_media_info
)) {
3279 timestamp_printf("[%s] Link UP %d Mbit/s %s duplex\n",
3280 bondport_get_name(p
),
3281 media_speed(&p
->po_media_info
),
3282 media_full_duplex(&p
->po_media_info
)
3286 timestamp_printf("[%s] Link DOWN\n", bondport_get_name(p
));
3289 if (media_active(&p
->po_media_info
)
3290 && bond
->ifb_active_lag
!= NULL
3291 && p
->po_lag
== bond
->ifb_active_lag
3292 && p
->po_selected
!= SelectedState_UNSELECTED
) {
3293 if (media_speed(&p
->po_media_info
) != p
->po_lag
->lag_active_media
) {
3294 if (g_bond
->verbose
) {
3295 timestamp_printf("[%s] Port speed %d differs from LAG %d\n",
3296 bondport_get_name(p
),
3297 media_speed(&p
->po_media_info
),
3298 link_speed(p
->po_lag
->lag_active_media
));
3300 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3303 bondport_receive_machine(p
, LAEventMediaChange
, NULL
);
3304 bondport_mux_machine(p
, LAEventMediaChange
, NULL
);
3305 bondport_periodic_transmit_machine(p
, LAEventMediaChange
, NULL
);
3311 bondport_aggregatable(bondport_ref p
)
3313 partner_state_ref ps
= &p
->po_partner_state
;
3315 if (lacp_actor_partner_state_aggregatable(p
->po_actor_state
) == 0
3316 || lacp_actor_partner_state_aggregatable(ps
->ps_state
) == 0) {
3317 /* we and/or our partner are individual */
3320 if (p
->po_lag
== NULL
) {
3323 switch (p
->po_receive_state
) {
3325 if (g_bond
->verbose
) {
3326 timestamp_printf("[%s] Port is not selectable\n",
3327 bondport_get_name(p
));
3330 case ReceiveState_CURRENT
:
3331 case ReceiveState_EXPIRED
:
3338 bondport_matches_LAG(bondport_ref p
, LAG_ref lag
)
3340 LAG_info_ref lag_li
;
3341 partner_state_ref ps
;
3344 ps
= &p
->po_partner_state
;
3345 ps_li
= &ps
->ps_lag_info
;
3346 lag_li
= &lag
->lag_info
;
3347 if (ps_li
->li_system_priority
== lag_li
->li_system_priority
3348 && ps_li
->li_key
== lag_li
->li_key
3349 && (bcmp(&ps_li
->li_system
, &lag_li
->li_system
,
3350 sizeof(lag_li
->li_system
))
3358 bondport_remove_from_LAG(bondport_ref p
)
3361 ifbond_ref bond
= p
->po_bond
;
3362 LAG_ref lag
= p
->po_lag
;
3367 TAILQ_REMOVE(&lag
->lag_port_list
, p
, po_lag_port_list
);
3368 if (g_bond
->verbose
) {
3369 timestamp_printf("[%s] Removed from LAG (0x%04x," EA_FORMAT
3371 bondport_get_name(p
),
3372 lag
->lag_info
.li_system_priority
,
3373 EA_LIST(&lag
->lag_info
.li_system
),
3374 lag
->lag_info
.li_key
);
3377 lag
->lag_port_count
--;
3378 if (lag
->lag_port_count
> 0) {
3379 return (bond
->ifb_active_lag
== lag
);
3381 if (g_bond
->verbose
) {
3382 timestamp_printf("Key 0x%04x: LAG Released (%04x," EA_FORMAT
3385 lag
->lag_info
.li_system_priority
,
3386 EA_LIST(&lag
->lag_info
.li_system
),
3387 lag
->lag_info
.li_key
);
3389 TAILQ_REMOVE(&bond
->ifb_lag_list
, lag
, lag_list
);
3390 if (bond
->ifb_active_lag
== lag
) {
3391 bond
->ifb_active_lag
= NULL
;
3395 return (active_lag
);
3399 bondport_add_to_LAG(bondport_ref p
, LAG_ref lag
)
3401 TAILQ_INSERT_TAIL(&lag
->lag_port_list
, p
, po_lag_port_list
);
3403 lag
->lag_port_count
++;
3404 if (g_bond
->verbose
) {
3405 timestamp_printf("[%s] Added to LAG (0x%04x," EA_FORMAT
"0x%04x)\n",
3406 bondport_get_name(p
),
3407 lag
->lag_info
.li_system_priority
,
3408 EA_LIST(&lag
->lag_info
.li_system
),
3409 lag
->lag_info
.li_key
);
3415 bondport_assign_to_LAG(bondport_ref p
)
3417 ifbond_ref bond
= p
->po_bond
;
3420 if (lacp_actor_partner_state_defaulted(p
->po_actor_state
)) {
3421 bondport_remove_from_LAG(p
);
3426 if (bondport_matches_LAG(p
, lag
)) {
3430 bondport_remove_from_LAG(p
);
3432 lag
= ifbond_get_LAG_matching_port(bond
, p
);
3434 bondport_add_to_LAG(p
, lag
);
3437 lag
= (LAG_ref
)_MALLOC(sizeof(*lag
), M_BOND
, M_WAITOK
);
3438 TAILQ_INIT(&lag
->lag_port_list
);
3439 lag
->lag_port_count
= 0;
3440 lag
->lag_selected_port_count
= 0;
3441 lag
->lag_info
= p
->po_partner_state
.ps_lag_info
;
3442 TAILQ_INSERT_TAIL(&bond
->ifb_lag_list
, lag
, lag_list
);
3443 if (g_bond
->verbose
) {
3444 timestamp_printf("Key 0x%04x: LAG Created (0x%04x," EA_FORMAT
3447 lag
->lag_info
.li_system_priority
,
3448 EA_LIST(&lag
->lag_info
.li_system
),
3449 lag
->lag_info
.li_key
);
3451 bondport_add_to_LAG(p
, lag
);
3456 bondport_receive_lacpdu(bondport_ref p
, lacpdu_ref in_lacpdu_p
)
3458 bondport_ref moved_port
;
3461 = ifbond_list_find_moved_port(p
, (const lacp_actor_partner_tlv_ref
)
3462 &in_lacpdu_p
->la_actor_tlv
);
3463 if (moved_port
!= NULL
) {
3464 bondport_receive_machine(moved_port
, LAEventPortMoved
, NULL
);
3466 bondport_receive_machine(p
, LAEventPacket
, in_lacpdu_p
);
3467 bondport_mux_machine(p
, LAEventPacket
, in_lacpdu_p
);
3468 bondport_periodic_transmit_machine(p
, LAEventPacket
, in_lacpdu_p
);
3473 bondport_set_selected(bondport_ref p
, SelectedState s
)
3475 if (s
!= p
->po_selected
) {
3476 ifbond_ref bond
= p
->po_bond
;
3477 LAG_ref lag
= p
->po_lag
;
3479 bondport_flags_set_selected_changed(p
);
3480 if (lag
!= NULL
&& bond
->ifb_active_lag
== lag
) {
3481 if (p
->po_selected
== SelectedState_SELECTED
) {
3482 lag
->lag_selected_port_count
--;
3484 else if (s
== SelectedState_SELECTED
) {
3485 lag
->lag_selected_port_count
++;
3487 if (g_bond
->verbose
) {
3488 timestamp_printf("[%s] SetSelected: %s (was %s)\n",
3489 bondport_get_name(p
),
3490 SelectedStateString(s
),
3491 SelectedStateString(p
->po_selected
));
3504 bondport_UpdateDefaultSelected(bondport_ref p
)
3506 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3511 bondport_RecordDefault(bondport_ref p
)
3513 bzero(&p
->po_partner_state
, sizeof(p
->po_partner_state
));
3515 = lacp_actor_partner_state_set_defaulted(p
->po_actor_state
);
3516 bondport_assign_to_LAG(p
);
3521 bondport_UpdateSelected(bondport_ref p
, lacpdu_ref lacpdu_p
)
3523 lacp_actor_partner_tlv_ref actor
;
3524 partner_state_ref ps
;
3527 /* compare the PDU's Actor information to our Partner state */
3528 actor
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_actor_tlv
;
3529 ps
= &p
->po_partner_state
;
3530 ps_li
= &ps
->ps_lag_info
;
3531 if (lacp_actor_partner_tlv_get_port(actor
) != ps
->ps_port
3532 || (lacp_actor_partner_tlv_get_port_priority(actor
)
3533 != ps
->ps_port_priority
)
3534 || bcmp(actor
->lap_system
, &ps_li
->li_system
, sizeof(ps_li
->li_system
))
3535 || (lacp_actor_partner_tlv_get_system_priority(actor
)
3536 != ps_li
->li_system_priority
)
3537 || (lacp_actor_partner_tlv_get_key(actor
) != ps_li
->li_key
)
3538 || (lacp_actor_partner_state_aggregatable(actor
->lap_state
)
3539 != lacp_actor_partner_state_aggregatable(ps
->ps_state
))) {
3540 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3541 if (g_bond
->verbose
) {
3542 timestamp_printf("[%s] updateSelected UNSELECTED\n",
3543 bondport_get_name(p
));
3550 bondport_RecordPDU(bondport_ref p
, lacpdu_ref lacpdu_p
)
3552 lacp_actor_partner_tlv_ref actor
;
3553 ifbond_ref bond
= p
->po_bond
;
3554 int lacp_maintain
= 0;
3555 partner_state_ref ps
;
3556 lacp_actor_partner_tlv_ref partner
;
3559 /* copy the PDU's Actor information into our Partner state */
3560 actor
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_actor_tlv
;
3561 ps
= &p
->po_partner_state
;
3562 ps_li
= &ps
->ps_lag_info
;
3563 ps
->ps_port
= lacp_actor_partner_tlv_get_port(actor
);
3564 ps
->ps_port_priority
= lacp_actor_partner_tlv_get_port_priority(actor
);
3565 ps_li
->li_system
= *((lacp_system_ref
)actor
->lap_system
);
3566 ps_li
->li_system_priority
3567 = lacp_actor_partner_tlv_get_system_priority(actor
);
3568 ps_li
->li_key
= lacp_actor_partner_tlv_get_key(actor
);
3569 ps
->ps_state
= lacp_actor_partner_state_set_out_of_sync(actor
->lap_state
);
3571 = lacp_actor_partner_state_set_not_defaulted(p
->po_actor_state
);
3573 /* compare the PDU's Partner information to our own information */
3574 partner
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_partner_tlv
;
3576 if (lacp_actor_partner_state_active_lacp(ps
->ps_state
)
3577 || (lacp_actor_partner_state_active_lacp(p
->po_actor_state
)
3578 && lacp_actor_partner_state_active_lacp(partner
->lap_state
))) {
3579 if (g_bond
->verbose
) {
3580 timestamp_printf("[%s] recordPDU: LACP will maintain\n",
3581 bondport_get_name(p
));
3585 if ((lacp_actor_partner_tlv_get_port(partner
)
3586 == bondport_get_index(p
))
3587 && lacp_actor_partner_tlv_get_port_priority(partner
) == p
->po_priority
3588 && bcmp(partner
->lap_system
, &g_bond
->system
,
3589 sizeof(g_bond
->system
)) == 0
3590 && (lacp_actor_partner_tlv_get_system_priority(partner
)
3591 == g_bond
->system_priority
)
3592 && lacp_actor_partner_tlv_get_key(partner
) == bond
->ifb_key
3593 && (lacp_actor_partner_state_aggregatable(partner
->lap_state
)
3594 == lacp_actor_partner_state_aggregatable(p
->po_actor_state
))
3595 && lacp_actor_partner_state_in_sync(actor
->lap_state
)
3597 ps
->ps_state
= lacp_actor_partner_state_set_in_sync(ps
->ps_state
);
3598 if (g_bond
->verbose
) {
3599 timestamp_printf("[%s] recordPDU: LACP partner in sync\n",
3600 bondport_get_name(p
));
3603 else if (lacp_actor_partner_state_aggregatable(actor
->lap_state
) == 0
3604 && lacp_actor_partner_state_in_sync(actor
->lap_state
)
3606 ps
->ps_state
= lacp_actor_partner_state_set_in_sync(ps
->ps_state
);
3607 if (g_bond
->verbose
) {
3608 timestamp_printf("[%s] recordPDU: LACP partner in sync (ind)\n",
3609 bondport_get_name(p
));
3612 bondport_assign_to_LAG(p
);
3616 static __inline__ lacp_actor_partner_state
3617 updateNTTBits(lacp_actor_partner_state s
)
3619 return (s
& (LACP_ACTOR_PARTNER_STATE_LACP_ACTIVITY
3620 | LACP_ACTOR_PARTNER_STATE_LACP_TIMEOUT
3621 | LACP_ACTOR_PARTNER_STATE_AGGREGATION
3622 | LACP_ACTOR_PARTNER_STATE_SYNCHRONIZATION
));
3626 bondport_UpdateNTT(bondport_ref p
, lacpdu_ref lacpdu_p
)
3628 ifbond_ref bond
= p
->po_bond
;
3629 lacp_actor_partner_tlv_ref partner
;
3631 /* compare the PDU's Actor information to our Partner state */
3632 partner
= (lacp_actor_partner_tlv_ref
)lacpdu_p
->la_partner_tlv
;
3633 if ((lacp_actor_partner_tlv_get_port(partner
) != bondport_get_index(p
))
3634 || lacp_actor_partner_tlv_get_port_priority(partner
) != p
->po_priority
3635 || bcmp(partner
->lap_system
, &g_bond
->system
, sizeof(g_bond
->system
))
3636 || (lacp_actor_partner_tlv_get_system_priority(partner
)
3637 != g_bond
->system_priority
)
3638 || lacp_actor_partner_tlv_get_key(partner
) != bond
->ifb_key
3639 || (updateNTTBits(partner
->lap_state
)
3640 != updateNTTBits(p
->po_actor_state
))) {
3641 bondport_flags_set_ntt(p
);
3642 if (g_bond
->verbose
) {
3643 timestamp_printf("[%s] updateNTT: Need To Transmit\n",
3644 bondport_get_name(p
));
3651 bondport_AttachMuxToAggregator(bondport_ref p
)
3653 if (bondport_flags_mux_attached(p
) == 0) {
3654 if (g_bond
->verbose
) {
3655 timestamp_printf("[%s] Attached Mux To Aggregator\n",
3656 bondport_get_name(p
));
3658 bondport_flags_set_mux_attached(p
);
3664 bondport_DetachMuxFromAggregator(bondport_ref p
)
3666 if (bondport_flags_mux_attached(p
)) {
3667 if (g_bond
->verbose
) {
3668 timestamp_printf("[%s] Detached Mux From Aggregator\n",
3669 bondport_get_name(p
));
3671 bondport_flags_clear_mux_attached(p
);
3677 bondport_enable_distributing(bondport_ref p
)
3679 if (bondport_flags_distributing(p
) == 0) {
3680 ifbond_ref bond
= p
->po_bond
;
3682 bond
->ifb_distributing_array
[bond
->ifb_distributing_count
++] = p
;
3683 if (g_bond
->verbose
) {
3684 timestamp_printf("[%s] Distribution Enabled\n",
3685 bondport_get_name(p
));
3687 bondport_flags_set_distributing(p
);
3693 bondport_disable_distributing(bondport_ref p
)
3695 if (bondport_flags_distributing(p
)) {
3696 bondport_ref
* array
;
3702 array
= bond
->ifb_distributing_array
;
3703 count
= bond
->ifb_distributing_count
;
3704 for (i
= 0; i
< count
; i
++) {
3705 if (array
[i
] == p
) {
3708 for (j
= i
; j
< (count
- 1); j
++) {
3709 array
[j
] = array
[j
+ 1];
3714 bond
->ifb_distributing_count
--;
3715 if (g_bond
->verbose
) {
3716 timestamp_printf("[%s] Distribution Disabled\n",
3717 bondport_get_name(p
));
3719 bondport_flags_clear_distributing(p
);
3725 ** Receive machine functions
3728 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
3731 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
3734 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
3737 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
3740 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
3743 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
3747 bondport_receive_machine_event(bondport_ref p
, LAEvent event
,
3750 switch (p
->po_receive_state
) {
3751 case ReceiveState_none
:
3752 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
3754 case ReceiveState_INITIALIZE
:
3755 bondport_receive_machine_initialize(p
, event
, event_data
);
3757 case ReceiveState_PORT_DISABLED
:
3758 bondport_receive_machine_port_disabled(p
, event
, event_data
);
3760 case ReceiveState_EXPIRED
:
3761 bondport_receive_machine_expired(p
, event
, event_data
);
3763 case ReceiveState_LACP_DISABLED
:
3764 bondport_receive_machine_lacp_disabled(p
, event
, event_data
);
3766 case ReceiveState_DEFAULTED
:
3767 bondport_receive_machine_defaulted(p
, event
, event_data
);
3769 case ReceiveState_CURRENT
:
3770 bondport_receive_machine_current(p
, event
, event_data
);
3779 bondport_receive_machine(bondport_ref p
, LAEvent event
,
3784 if (p
->po_receive_state
!= ReceiveState_LACP_DISABLED
) {
3785 bondport_receive_machine_current(p
, event
, event_data
);
3788 case LAEventMediaChange
:
3789 if (media_active(&p
->po_media_info
)) {
3790 switch (p
->po_receive_state
) {
3791 case ReceiveState_PORT_DISABLED
:
3792 case ReceiveState_LACP_DISABLED
:
3793 bondport_receive_machine_port_disabled(p
, LAEventMediaChange
, NULL
);
3800 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
3804 bondport_receive_machine_event(p
, event
, event_data
);
3811 bondport_receive_machine_initialize(bondport_ref p
, LAEvent event
,
3812 __unused
void * event_data
)
3816 devtimer_cancel(p
->po_current_while_timer
);
3817 if (g_bond
->verbose
) {
3818 timestamp_printf("[%s] Receive INITIALIZE\n",
3819 bondport_get_name(p
));
3821 p
->po_receive_state
= ReceiveState_INITIALIZE
;
3822 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3823 bondport_RecordDefault(p
);
3825 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
3826 bondport_receive_machine_port_disabled(p
, LAEventStart
, NULL
);
3835 bondport_receive_machine_port_disabled(bondport_ref p
, LAEvent event
,
3836 __unused
void * event_data
)
3838 partner_state_ref ps
;
3842 devtimer_cancel(p
->po_current_while_timer
);
3843 if (g_bond
->verbose
) {
3844 timestamp_printf("[%s] Receive PORT_DISABLED\n",
3845 bondport_get_name(p
));
3847 p
->po_receive_state
= ReceiveState_PORT_DISABLED
;
3848 ps
= &p
->po_partner_state
;
3849 ps
->ps_state
= lacp_actor_partner_state_set_out_of_sync(ps
->ps_state
);
3851 case LAEventMediaChange
:
3852 if (media_active(&p
->po_media_info
)) {
3853 if (media_full_duplex(&p
->po_media_info
)) {
3854 bondport_receive_machine_expired(p
, LAEventStart
, NULL
);
3857 bondport_receive_machine_lacp_disabled(p
, LAEventStart
, NULL
);
3860 else if (p
->po_selected
== SelectedState_SELECTED
) {
3863 if (g_bond
->verbose
) {
3864 timestamp_printf("[%s] Receive PORT_DISABLED: "
3865 "link timer started\n",
3866 bondport_get_name(p
));
3870 devtimer_set_relative(p
->po_current_while_timer
, tv
,
3871 (devtimer_timeout_func
)
3872 bondport_receive_machine_port_disabled
,
3873 (void *)LAEventTimeout
, NULL
);
3875 else if (p
->po_selected
== SelectedState_STANDBY
) {
3876 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3879 case LAEventTimeout
:
3880 if (p
->po_selected
== SelectedState_SELECTED
) {
3881 if (g_bond
->verbose
) {
3882 timestamp_printf("[%s] Receive PORT_DISABLED: "
3883 "link timer completed, marking UNSELECTED\n",
3884 bondport_get_name(p
));
3886 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3889 case LAEventPortMoved
:
3890 bondport_receive_machine_initialize(p
, LAEventStart
, NULL
);
3899 bondport_receive_machine_expired(bondport_ref p
, LAEvent event
,
3900 __unused
void * event_data
)
3902 lacp_actor_partner_state s
;
3907 devtimer_cancel(p
->po_current_while_timer
);
3908 if (g_bond
->verbose
) {
3909 timestamp_printf("[%s] Receive EXPIRED\n",
3910 bondport_get_name(p
));
3912 p
->po_receive_state
= ReceiveState_EXPIRED
;
3913 s
= p
->po_partner_state
.ps_state
;
3914 s
= lacp_actor_partner_state_set_out_of_sync(s
);
3915 s
= lacp_actor_partner_state_set_short_timeout(s
);
3916 p
->po_partner_state
.ps_state
= s
;
3918 = lacp_actor_partner_state_set_expired(p
->po_actor_state
);
3919 /* start current_while timer */
3920 tv
.tv_sec
= LACP_SHORT_TIMEOUT_TIME
;
3922 devtimer_set_relative(p
->po_current_while_timer
, tv
,
3923 (devtimer_timeout_func
)
3924 bondport_receive_machine_expired
,
3925 (void *)LAEventTimeout
, NULL
);
3928 case LAEventTimeout
:
3929 bondport_receive_machine_defaulted(p
, LAEventStart
, NULL
);
3938 bondport_receive_machine_lacp_disabled(bondport_ref p
, LAEvent event
,
3939 __unused
void * event_data
)
3941 partner_state_ref ps
;
3944 devtimer_cancel(p
->po_current_while_timer
);
3945 if (g_bond
->verbose
) {
3946 timestamp_printf("[%s] Receive LACP_DISABLED\n",
3947 bondport_get_name(p
));
3949 p
->po_receive_state
= ReceiveState_LACP_DISABLED
;
3950 bondport_set_selected(p
, SelectedState_UNSELECTED
);
3951 bondport_RecordDefault(p
);
3952 ps
= &p
->po_partner_state
;
3953 ps
->ps_state
= lacp_actor_partner_state_set_individual(ps
->ps_state
);
3955 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
3964 bondport_receive_machine_defaulted(bondport_ref p
, LAEvent event
,
3965 __unused
void * event_data
)
3969 devtimer_cancel(p
->po_current_while_timer
);
3970 if (g_bond
->verbose
) {
3971 timestamp_printf("[%s] Receive DEFAULTED\n",
3972 bondport_get_name(p
));
3974 p
->po_receive_state
= ReceiveState_DEFAULTED
;
3975 bondport_UpdateDefaultSelected(p
);
3976 bondport_RecordDefault(p
);
3978 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
3987 bondport_receive_machine_current(bondport_ref p
, LAEvent event
,
3990 partner_state_ref ps
;
3995 devtimer_cancel(p
->po_current_while_timer
);
3996 if (g_bond
->verbose
) {
3997 timestamp_printf("[%s] Receive CURRENT\n",
3998 bondport_get_name(p
));
4000 p
->po_receive_state
= ReceiveState_CURRENT
;
4001 bondport_UpdateSelected(p
, event_data
);
4002 bondport_UpdateNTT(p
, event_data
);
4003 bondport_RecordPDU(p
, event_data
);
4005 = lacp_actor_partner_state_set_not_expired(p
->po_actor_state
);
4006 bondport_assign_to_LAG(p
);
4007 /* start current_while timer */
4008 ps
= &p
->po_partner_state
;
4009 if (lacp_actor_partner_state_short_timeout(ps
->ps_state
)) {
4010 tv
.tv_sec
= LACP_SHORT_TIMEOUT_TIME
;
4013 tv
.tv_sec
= LACP_LONG_TIMEOUT_TIME
;
4016 devtimer_set_relative(p
->po_current_while_timer
, tv
,
4017 (devtimer_timeout_func
)
4018 bondport_receive_machine_current
,
4019 (void *)LAEventTimeout
, NULL
);
4021 case LAEventTimeout
:
4022 bondport_receive_machine_expired(p
, LAEventStart
, NULL
);
4031 ** Periodic Transmission machine
4035 bondport_periodic_transmit_machine(bondport_ref p
, LAEvent event
,
4036 __unused
void * event_data
)
4039 partner_state_ref ps
;
4044 if (g_bond
->verbose
) {
4045 timestamp_printf("[%s] periodic_transmit Start\n",
4046 bondport_get_name(p
));
4049 case LAEventMediaChange
:
4050 devtimer_cancel(p
->po_periodic_timer
);
4051 p
->po_periodic_interval
= 0;
4052 if (media_active(&p
->po_media_info
) == 0
4053 || media_full_duplex(&p
->po_media_info
) == 0) {
4057 /* Neither Partner nor Actor are LACP Active, no periodic tx */
4058 ps
= &p
->po_partner_state
;
4059 if (lacp_actor_partner_state_active_lacp(p
->po_actor_state
) == 0
4060 && (lacp_actor_partner_state_active_lacp(ps
->ps_state
)
4062 devtimer_cancel(p
->po_periodic_timer
);
4063 p
->po_periodic_interval
= 0;
4066 if (lacp_actor_partner_state_short_timeout(ps
->ps_state
)) {
4067 interval
= LACP_FAST_PERIODIC_TIME
;
4070 interval
= LACP_SLOW_PERIODIC_TIME
;
4072 if (p
->po_periodic_interval
!= interval
) {
4073 if (interval
== LACP_FAST_PERIODIC_TIME
4074 && p
->po_periodic_interval
== LACP_SLOW_PERIODIC_TIME
) {
4075 if (g_bond
->verbose
) {
4076 timestamp_printf("[%s] periodic_transmit:"
4077 " Need To Transmit\n",
4078 bondport_get_name(p
));
4080 bondport_flags_set_ntt(p
);
4082 p
->po_periodic_interval
= interval
;
4084 tv
.tv_sec
= interval
;
4085 devtimer_set_relative(p
->po_periodic_timer
, tv
,
4086 (devtimer_timeout_func
)
4087 bondport_periodic_transmit_machine
,
4088 (void *)LAEventTimeout
, NULL
);
4089 if (g_bond
->verbose
) {
4090 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4091 bondport_get_name(p
),
4092 p
->po_periodic_interval
);
4096 case LAEventTimeout
:
4097 bondport_flags_set_ntt(p
);
4098 tv
.tv_sec
= p
->po_periodic_interval
;
4100 devtimer_set_relative(p
->po_periodic_timer
, tv
, (devtimer_timeout_func
)
4101 bondport_periodic_transmit_machine
,
4102 (void *)LAEventTimeout
, NULL
);
4103 if (g_bond
->verbose
> 1) {
4104 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4105 bondport_get_name(p
), p
->po_periodic_interval
);
4118 bondport_can_transmit(bondport_ref p
, int32_t current_secs
,
4121 if (p
->po_last_transmit_secs
!= current_secs
) {
4122 p
->po_last_transmit_secs
= current_secs
;
4123 p
->po_n_transmit
= 0;
4125 if (p
->po_n_transmit
< LACP_PACKET_RATE
) {
4129 if (next_secs
!= NULL
) {
4130 *next_secs
= current_secs
+ 1;
4136 bondport_transmit_machine(bondport_ref p
, LAEvent event
,
4139 lacp_actor_partner_tlv_ref aptlv
;
4140 lacp_collector_tlv_ref ctlv
;
4141 struct timeval next_tick_time
= {0, 0};
4142 lacpdu_ref out_lacpdu_p
;
4143 packet_buffer_ref pkt
;
4144 partner_state_ref ps
;
4148 case LAEventTimeout
:
4150 if (p
->po_periodic_interval
== 0 || bondport_flags_ntt(p
) == 0) {
4153 if (event_data
!= NULL
) {
4154 /* we're going away, transmit the packet no matter what */
4156 else if (bondport_can_transmit(p
, devtimer_current_secs(),
4157 &next_tick_time
.tv_sec
) == 0) {
4158 if (devtimer_enabled(p
->po_transmit_timer
)) {
4159 if (g_bond
->verbose
> 0) {
4160 timestamp_printf("[%s] Transmit Timer Already Set\n",
4161 bondport_get_name(p
));
4165 devtimer_set_absolute(p
->po_transmit_timer
, next_tick_time
,
4166 (devtimer_timeout_func
)
4167 bondport_transmit_machine
,
4168 (void *)LAEventTimeout
, NULL
);
4169 if (g_bond
->verbose
> 0) {
4170 timestamp_printf("[%s] Transmit Timer Deadline %d secs\n",
4171 bondport_get_name(p
),
4172 next_tick_time
.tv_sec
);
4177 if (g_bond
->verbose
> 0) {
4178 if (event
== LAEventTimeout
) {
4179 timestamp_printf("[%s] Transmit Timer Complete\n",
4180 bondport_get_name(p
));
4183 pkt
= packet_buffer_allocate(sizeof(*out_lacpdu_p
));
4185 printf("[%s] Transmit: failed to allocate packet buffer\n",
4186 bondport_get_name(p
));
4189 out_lacpdu_p
= (lacpdu_ref
)packet_buffer_byteptr(pkt
);
4190 bzero(out_lacpdu_p
, sizeof(*out_lacpdu_p
));
4191 out_lacpdu_p
->la_subtype
= IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP
;
4192 out_lacpdu_p
->la_version
= LACPDU_VERSION_1
;
4195 aptlv
= (lacp_actor_partner_tlv_ref
)out_lacpdu_p
->la_actor_tlv
;
4196 aptlv
->lap_tlv_type
= LACPDU_TLV_TYPE_ACTOR
;
4197 aptlv
->lap_length
= LACPDU_ACTOR_TLV_LENGTH
;
4198 *((lacp_system_ref
)aptlv
->lap_system
) = g_bond
->system
;
4199 lacp_actor_partner_tlv_set_system_priority(aptlv
,
4200 g_bond
->system_priority
);
4201 lacp_actor_partner_tlv_set_port_priority(aptlv
, p
->po_priority
);
4202 lacp_actor_partner_tlv_set_port(aptlv
, bondport_get_index(p
));
4203 lacp_actor_partner_tlv_set_key(aptlv
, p
->po_bond
->ifb_key
);
4204 aptlv
->lap_state
= p
->po_actor_state
;
4207 aptlv
= (lacp_actor_partner_tlv_ref
)out_lacpdu_p
->la_partner_tlv
;
4208 aptlv
->lap_tlv_type
= LACPDU_TLV_TYPE_PARTNER
;
4209 aptlv
->lap_length
= LACPDU_PARTNER_TLV_LENGTH
;
4210 ps
= &p
->po_partner_state
;
4211 ps_li
= &ps
->ps_lag_info
;
4212 lacp_actor_partner_tlv_set_port(aptlv
, ps
->ps_port
);
4213 lacp_actor_partner_tlv_set_port_priority(aptlv
, ps
->ps_port_priority
);
4214 *((lacp_system_ref
)aptlv
->lap_system
) = ps_li
->li_system
;
4215 lacp_actor_partner_tlv_set_system_priority(aptlv
,
4216 ps_li
->li_system_priority
);
4217 lacp_actor_partner_tlv_set_key(aptlv
, ps_li
->li_key
);
4218 aptlv
->lap_state
= ps
->ps_state
;
4221 ctlv
= (lacp_collector_tlv_ref
)out_lacpdu_p
->la_collector_tlv
;
4222 ctlv
->lac_tlv_type
= LACPDU_TLV_TYPE_COLLECTOR
;
4223 ctlv
->lac_length
= LACPDU_COLLECTOR_TLV_LENGTH
;
4225 bondport_slow_proto_transmit(p
, pkt
);
4226 bondport_flags_clear_ntt(p
);
4227 if (g_bond
->verbose
> 0) {
4228 timestamp_printf("[%s] Transmit Packet %d\n",
4229 bondport_get_name(p
), p
->po_n_transmit
);
4239 ** Mux machine functions
4243 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4246 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4249 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4253 bondport_mux_machine_collecting_distributing(bondport_ref p
, LAEvent event
,
4257 bondport_mux_machine(bondport_ref p
, LAEvent event
, void * event_data
)
4259 switch (p
->po_mux_state
) {
4261 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4263 case MuxState_DETACHED
:
4264 bondport_mux_machine_detached(p
, event
, event_data
);
4266 case MuxState_WAITING
:
4267 bondport_mux_machine_waiting(p
, event
, event_data
);
4269 case MuxState_ATTACHED
:
4270 bondport_mux_machine_attached(p
, event
, event_data
);
4272 case MuxState_COLLECTING_DISTRIBUTING
:
4273 bondport_mux_machine_collecting_distributing(p
, event
, event_data
);
4282 bondport_mux_machine_detached(bondport_ref p
, LAEvent event
,
4283 __unused
void * event_data
)
4285 lacp_actor_partner_state s
;
4289 devtimer_cancel(p
->po_wait_while_timer
);
4290 if (g_bond
->verbose
) {
4291 timestamp_printf("[%s] Mux DETACHED\n",
4292 bondport_get_name(p
));
4294 p
->po_mux_state
= MuxState_DETACHED
;
4295 bondport_flags_clear_ready(p
);
4296 bondport_DetachMuxFromAggregator(p
);
4297 bondport_disable_distributing(p
);
4298 s
= p
->po_actor_state
;
4299 s
= lacp_actor_partner_state_set_out_of_sync(s
);
4300 s
= lacp_actor_partner_state_set_not_collecting(s
);
4301 s
= lacp_actor_partner_state_set_not_distributing(s
);
4302 p
->po_actor_state
= s
;
4303 bondport_flags_set_ntt(p
);
4305 case LAEventSelectedChange
:
4307 case LAEventMediaChange
:
4308 if (p
->po_selected
== SelectedState_SELECTED
4309 || p
->po_selected
== SelectedState_STANDBY
) {
4310 bondport_mux_machine_waiting(p
, LAEventStart
, NULL
);
4320 bondport_mux_machine_waiting(bondport_ref p
, LAEvent event
,
4321 __unused
void * event_data
)
4327 devtimer_cancel(p
->po_wait_while_timer
);
4328 if (g_bond
->verbose
) {
4329 timestamp_printf("[%s] Mux WAITING\n",
4330 bondport_get_name(p
));
4332 p
->po_mux_state
= MuxState_WAITING
;
4335 case LAEventSelectedChange
:
4336 if (p
->po_selected
== SelectedState_UNSELECTED
) {
4337 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4340 if (p
->po_selected
== SelectedState_STANDBY
) {
4341 devtimer_cancel(p
->po_wait_while_timer
);
4342 /* wait until state changes to SELECTED */
4343 if (g_bond
->verbose
) {
4344 timestamp_printf("[%s] Mux WAITING: Standby\n",
4345 bondport_get_name(p
));
4349 if (bondport_flags_ready(p
)) {
4350 if (g_bond
->verbose
) {
4351 timestamp_printf("[%s] Mux WAITING: Port is already ready\n",
4352 bondport_get_name(p
));
4356 if (devtimer_enabled(p
->po_wait_while_timer
)) {
4357 if (g_bond
->verbose
) {
4358 timestamp_printf("[%s] Mux WAITING: Timer already set\n",
4359 bondport_get_name(p
));
4363 if (ifbond_all_ports_attached(p
->po_bond
, p
)) {
4364 devtimer_cancel(p
->po_wait_while_timer
);
4365 if (g_bond
->verbose
) {
4366 timestamp_printf("[%s] Mux WAITING: No waiting\n",
4367 bondport_get_name(p
));
4369 bondport_flags_set_ready(p
);
4372 if (g_bond
->verbose
) {
4373 timestamp_printf("[%s] Mux WAITING: 2 seconds\n",
4374 bondport_get_name(p
));
4376 tv
.tv_sec
= LACP_AGGREGATE_WAIT_TIME
;
4378 devtimer_set_relative(p
->po_wait_while_timer
, tv
,
4379 (devtimer_timeout_func
)
4380 bondport_mux_machine_waiting
,
4381 (void *)LAEventTimeout
, NULL
);
4383 case LAEventTimeout
:
4384 if (g_bond
->verbose
) {
4385 timestamp_printf("[%s] Mux WAITING: Ready\n",
4386 bondport_get_name(p
));
4388 bondport_flags_set_ready(p
);
4392 if (bondport_flags_ready(p
)){
4393 if (g_bond
->verbose
) {
4394 timestamp_printf("[%s] Mux WAITING: All Ports Ready\n",
4395 bondport_get_name(p
));
4397 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);
4406 bondport_mux_machine_attached(bondport_ref p
, LAEvent event
,
4407 __unused
void * event_data
)
4409 lacp_actor_partner_state s
;
4413 devtimer_cancel(p
->po_wait_while_timer
);
4414 if (g_bond
->verbose
) {
4415 timestamp_printf("[%s] Mux ATTACHED\n",
4416 bondport_get_name(p
));
4418 p
->po_mux_state
= MuxState_ATTACHED
;
4419 bondport_AttachMuxToAggregator(p
);
4420 s
= p
->po_actor_state
;
4421 s
= lacp_actor_partner_state_set_in_sync(s
);
4422 s
= lacp_actor_partner_state_set_not_collecting(s
);
4423 s
= lacp_actor_partner_state_set_not_distributing(s
);
4424 bondport_disable_distributing(p
);
4425 p
->po_actor_state
= s
;
4426 bondport_flags_set_ntt(p
);
4429 switch (p
->po_selected
) {
4430 case SelectedState_SELECTED
:
4431 s
= p
->po_partner_state
.ps_state
;
4432 if (lacp_actor_partner_state_in_sync(s
)) {
4433 bondport_mux_machine_collecting_distributing(p
, LAEventStart
,
4438 bondport_mux_machine_detached(p
, LAEventStart
, NULL
);
4447 bondport_mux_machine_collecting_distributing(bondport_ref p
,
4449 __unused
void * event_data
)
4451 lacp_actor_partner_state s
;
4455 devtimer_cancel(p
->po_wait_while_timer
);
4456 if (g_bond
->verbose
) {
4457 timestamp_printf("[%s] Mux COLLECTING_DISTRIBUTING\n",
4458 bondport_get_name(p
));
4460 p
->po_mux_state
= MuxState_COLLECTING_DISTRIBUTING
;
4461 bondport_enable_distributing(p
);
4462 s
= p
->po_actor_state
;
4463 s
= lacp_actor_partner_state_set_collecting(s
);
4464 s
= lacp_actor_partner_state_set_distributing(s
);
4465 p
->po_actor_state
= s
;
4466 bondport_flags_set_ntt(p
);
4469 s
= p
->po_partner_state
.ps_state
;
4470 if (lacp_actor_partner_state_in_sync(s
) == 0) {
4471 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);
4474 switch (p
->po_selected
) {
4475 case SelectedState_UNSELECTED
:
4476 case SelectedState_STANDBY
:
4477 bondport_mux_machine_attached(p
, LAEventStart
, NULL
);