]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/if_bond.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / net / if_bond.c
CommitLineData
91447636 1/*
d1ecb069 2 * Copyright (c) 2004-2010 Apple Computer, Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
91447636 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636
A
27 */
28
29/*
30 * if_bond.c
31 * - bond/failover interface
32 * - implements IEEE 802.3ad Link Aggregation
33 */
34
35/*
36 * Modification History:
37 *
38 * April 29, 2004 Dieter Siegmund (dieter@apple.com)
39 * - created
40 */
41
42#include <sys/param.h>
43#include <sys/kernel.h>
44#include <sys/malloc.h>
45#include <sys/mbuf.h>
46#include <sys/queue.h>
47#include <sys/socket.h>
48#include <sys/sockio.h>
49#include <sys/sysctl.h>
50#include <sys/systm.h>
51#include <sys/kern_event.h>
52
53#include <net/bpf.h>
54#include <net/ethernet.h>
55#include <net/if.h>
56#include <net/kpi_interface.h>
57#include <net/if_arp.h>
58#include <net/if_dl.h>
59#include <net/if_ether.h>
60#include <net/if_types.h>
61#include <net/if_bond_var.h>
62#include <net/ieee8023ad.h>
63#include <net/lacp.h>
64#include <net/dlil.h>
65#include <sys/time.h>
66#include <net/devtimer.h>
67#include <net/if_vlan_var.h>
2d21ac55 68#include <net/kpi_protocol.h>
91447636
A
69
70#include <kern/locks.h>
71#include <libkern/OSAtomic.h>
72
73#include <netinet/in.h>
74#include <netinet/if_ether.h>
75#include <netinet/in_systm.h>
76#include <netinet/ip.h>
77#include <netinet/ip6.h>
78
79#include <net/if_media.h>
80#include <net/multicast_list.h>
81
2d21ac55 82extern void dlil_input_packet_list(struct ifnet *, struct mbuf *);
91447636
A
83
84static struct ether_addr slow_proto_multicast = {
85 IEEE8023AD_SLOW_PROTO_MULTICAST
86};
87
88#define BOND_MAXUNIT 128
89#define BONDNAME "bond"
90#define M_BOND M_DEVBUF
91
92#define EA_FORMAT "%x:%x:%x:%x:%x:%x"
93#define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)])
94#define EA_LIST(ea) EA_CH(ea,0),EA_CH(ea,1),EA_CH(ea,2),EA_CH(ea,3),EA_CH(ea,4),EA_CH(ea,5)
95
96#define timestamp_printf printf
97
98/**
99 ** bond locks
100 **/
101static __inline__ lck_grp_t *
102my_lck_grp_alloc_init(const char * grp_name)
103{
104 lck_grp_t * grp;
105 lck_grp_attr_t * grp_attrs;
106
107 grp_attrs = lck_grp_attr_alloc_init();
91447636
A
108 grp = lck_grp_alloc_init(grp_name, grp_attrs);
109 lck_grp_attr_free(grp_attrs);
110 return (grp);
111}
112
113static __inline__ lck_mtx_t *
114my_lck_mtx_alloc_init(lck_grp_t * lck_grp)
115{
116 lck_attr_t * lck_attrs;
117 lck_mtx_t * lck_mtx;
118
119 lck_attrs = lck_attr_alloc_init();
91447636
A
120 lck_mtx = lck_mtx_alloc_init(lck_grp, lck_attrs);
121 lck_attr_free(lck_attrs);
122 return (lck_mtx);
123}
124
125static lck_mtx_t * bond_lck_mtx;
126
127static __inline__ void
128bond_lock_init(void)
129{
130 lck_grp_t * bond_lck_grp;
131
132 bond_lck_grp = my_lck_grp_alloc_init("if_bond");
133 bond_lck_mtx = my_lck_mtx_alloc_init(bond_lck_grp);
134}
135
136static __inline__ void
137bond_assert_lock_held(void)
138{
139 lck_mtx_assert(bond_lck_mtx, LCK_MTX_ASSERT_OWNED);
140 return;
141}
142
143static __inline__ void
144bond_assert_lock_not_held(void)
145{
146 lck_mtx_assert(bond_lck_mtx, LCK_MTX_ASSERT_NOTOWNED);
147 return;
148}
149
150static __inline__ void
151bond_lock(void)
152{
153 lck_mtx_lock(bond_lck_mtx);
154 return;
155}
156
157static __inline__ void
158bond_unlock(void)
159{
160 lck_mtx_unlock(bond_lck_mtx);
161 return;
162}
163
164/**
165 ** bond structures, types
166 **/
167
168struct LAG_info_s {
169 lacp_system li_system;
170 lacp_system_priority li_system_priority;
171 lacp_key li_key;
172};
173typedef struct LAG_info_s LAG_info, * LAG_info_ref;
174
175struct bondport_s;
176TAILQ_HEAD(port_list, bondport_s);
177struct ifbond_s;
178TAILQ_HEAD(ifbond_list, ifbond_s);
179struct LAG_s;
180TAILQ_HEAD(lag_list, LAG_s);
181
182typedef struct ifbond_s ifbond, * ifbond_ref;
183typedef struct bondport_s bondport, * bondport_ref;
184
185struct LAG_s {
186 TAILQ_ENTRY(LAG_s) lag_list;
187 struct port_list lag_port_list;
188 short lag_port_count;
189 short lag_selected_port_count;
190 int lag_active_media;
191 LAG_info lag_info;
192};
193typedef struct LAG_s LAG, * LAG_ref;
194
195typedef struct partner_state_s {
196 LAG_info ps_lag_info;
197 lacp_port ps_port;
198 lacp_port_priority ps_port_priority;
199 lacp_actor_partner_state ps_state;
200} partner_state, * partner_state_ref;
201
202struct ifbond_s {
203 TAILQ_ENTRY(ifbond_s) ifb_bond_list;
204 int ifb_flags;
2d21ac55 205 SInt32 ifb_retain_count;
91447636
A
206 char ifb_name[IFNAMSIZ];
207 struct ifnet * ifb_ifp;
208 bpf_packet_func ifb_bpf_input;
209 bpf_packet_func ifb_bpf_output;
210 int ifb_altmtu;
211 struct port_list ifb_port_list;
212 short ifb_port_count;
213 struct lag_list ifb_lag_list;
214 lacp_key ifb_key;
215 short ifb_max_active; /* 0 == unlimited */
216 LAG_ref ifb_active_lag;
217 struct ifmultiaddr * ifb_ifma_slow_proto;
218 bondport_ref * ifb_distributing_array;
219 int ifb_distributing_count;
2d21ac55
A
220 int ifb_last_link_event;
221 int ifb_mode; /* LACP, STATIC */
91447636
A
222};
223
224struct media_info {
225 int mi_active;
226 int mi_status;
227};
228
229enum {
230 ReceiveState_none = 0,
231 ReceiveState_INITIALIZE = 1,
232 ReceiveState_PORT_DISABLED = 2,
233 ReceiveState_EXPIRED = 3,
234 ReceiveState_LACP_DISABLED = 4,
235 ReceiveState_DEFAULTED = 5,
236 ReceiveState_CURRENT = 6,
237};
238
239typedef u_char ReceiveState;
240
241enum {
242 SelectedState_UNSELECTED = IF_BOND_STATUS_SELECTED_STATE_UNSELECTED,
243 SelectedState_SELECTED = IF_BOND_STATUS_SELECTED_STATE_SELECTED,
244 SelectedState_STANDBY = IF_BOND_STATUS_SELECTED_STATE_STANDBY
245};
246typedef u_char SelectedState;
247
248static __inline__ const char *
249SelectedStateString(SelectedState s)
250{
251 static const char * names[] = { "UNSELECTED", "SELECTED", "STANDBY" };
252
253 if (s <= SelectedState_STANDBY) {
254 return (names[s]);
255 }
256 return ("<unknown>");
257}
258
259enum {
260 MuxState_none = 0,
261 MuxState_DETACHED = 1,
262 MuxState_WAITING = 2,
263 MuxState_ATTACHED = 3,
264 MuxState_COLLECTING_DISTRIBUTING = 4,
265};
266
267typedef u_char MuxState;
268
269struct bondport_s {
270 TAILQ_ENTRY(bondport_s) po_port_list;
271 ifbond_ref po_bond;
272 struct multicast_list po_multicast;
273 struct ifnet * po_ifp;
274 struct ether_addr po_saved_addr;
275 int po_enabled;
276 char po_name[IFNAMSIZ];
277 struct ifdevmtu po_devmtu;
278
279 /* LACP */
280 TAILQ_ENTRY(bondport_s) po_lag_port_list;
281 devtimer_ref po_current_while_timer;
282 devtimer_ref po_periodic_timer;
283 devtimer_ref po_wait_while_timer;
284 devtimer_ref po_transmit_timer;
285 partner_state po_partner_state;
286 lacp_port_priority po_priority;
287 lacp_actor_partner_state po_actor_state;
288 u_char po_flags;
289 u_char po_periodic_interval;
290 u_char po_n_transmit;
291 ReceiveState po_receive_state;
292 MuxState po_mux_state;
293 SelectedState po_selected;
294 int32_t po_last_transmit_secs;
295 struct media_info po_media_info;
296 LAG_ref po_lag;
297};
298
299#define IFBF_PROMISC 0x1 /* promiscuous mode */
300#define IFBF_IF_DETACHING 0x2 /* interface is detaching */
301#define IFBF_LLADDR 0x4 /* specific link address requested */
302#define IFBF_CHANGE_IN_PROGRESS 0x8 /* interface add/remove in progress */
303
304static int bond_get_status(ifbond_ref ifb, struct if_bond_req * ibr_p,
305 user_addr_t datap);
306
307static __inline__ int
308ifbond_flags_promisc(ifbond_ref ifb)
309{
310 return ((ifb->ifb_flags & IFBF_PROMISC) != 0);
311}
312
313static __inline__ void
314ifbond_flags_set_promisc(ifbond_ref ifb)
315{
316 ifb->ifb_flags |= IFBF_PROMISC;
317 return;
318}
319
320static __inline__ void
321ifbond_flags_clear_promisc(ifbond_ref ifb)
322{
323 ifb->ifb_flags &= ~IFBF_PROMISC;
324 return;
325}
326
327static __inline__ int
328ifbond_flags_if_detaching(ifbond_ref ifb)
329{
330 return ((ifb->ifb_flags & IFBF_IF_DETACHING) != 0);
331}
332
333static __inline__ void
334ifbond_flags_set_if_detaching(ifbond_ref ifb)
335{
336 ifb->ifb_flags |= IFBF_IF_DETACHING;
337 return;
338}
339
340static __inline__ int
341ifbond_flags_lladdr(ifbond_ref ifb)
342{
343 return ((ifb->ifb_flags & IFBF_LLADDR) != 0);
344}
345
346static __inline__ void
347ifbond_flags_set_lladdr(ifbond_ref ifb)
348{
349 ifb->ifb_flags |= IFBF_LLADDR;
350 return;
351}
352
353static __inline__ void
354ifbond_flags_clear_lladdr(ifbond_ref ifb)
355{
356 ifb->ifb_flags &= ~IFBF_LLADDR;
357 return;
358}
359
360static __inline__ int
361ifbond_flags_change_in_progress(ifbond_ref ifb)
362{
363 return ((ifb->ifb_flags & IFBF_CHANGE_IN_PROGRESS) != 0);
364}
365
366static __inline__ void
367ifbond_flags_set_change_in_progress(ifbond_ref ifb)
368{
369 ifb->ifb_flags |= IFBF_CHANGE_IN_PROGRESS;
370 return;
371}
372
373static __inline__ void
374ifbond_flags_clear_change_in_progress(ifbond_ref ifb)
375{
376 ifb->ifb_flags &= ~IFBF_CHANGE_IN_PROGRESS;
377 return;
378}
379
380/*
381 * bondport_ref->po_flags bits
382 */
383#define BONDPORT_FLAGS_NTT 0x01
384#define BONDPORT_FLAGS_READY 0x02
385#define BONDPORT_FLAGS_SELECTED_CHANGED 0x04
386#define BONDPORT_FLAGS_MUX_ATTACHED 0x08
387#define BONDPORT_FLAGS_DISTRIBUTING 0x10
388#define BONDPORT_FLAGS_UNUSED2 0x20
389#define BONDPORT_FLAGS_UNUSED3 0x40
390#define BONDPORT_FLAGS_UNUSED4 0x80
391
392static __inline__ void
393bondport_flags_set_ntt(bondport_ref p)
394{
395 p->po_flags |= BONDPORT_FLAGS_NTT;
396 return;
397}
398
399static __inline__ void
400bondport_flags_clear_ntt(bondport_ref p)
401{
402 p->po_flags &= ~BONDPORT_FLAGS_NTT;
403 return;
404}
405
406static __inline__ int
407bondport_flags_ntt(bondport_ref p)
408{
409 return ((p->po_flags & BONDPORT_FLAGS_NTT) != 0);
410}
411
412static __inline__ void
413bondport_flags_set_ready(bondport_ref p)
414{
415 p->po_flags |= BONDPORT_FLAGS_READY;
416 return;
417}
418
419static __inline__ void
420bondport_flags_clear_ready(bondport_ref p)
421{
422 p->po_flags &= ~BONDPORT_FLAGS_READY;
423 return;
424}
425
426static __inline__ int
427bondport_flags_ready(bondport_ref p)
428{
429 return ((p->po_flags & BONDPORT_FLAGS_READY) != 0);
430}
431
432static __inline__ void
433bondport_flags_set_selected_changed(bondport_ref p)
434{
435 p->po_flags |= BONDPORT_FLAGS_SELECTED_CHANGED;
436 return;
437}
438
439static __inline__ void
440bondport_flags_clear_selected_changed(bondport_ref p)
441{
442 p->po_flags &= ~BONDPORT_FLAGS_SELECTED_CHANGED;
443 return;
444}
445
446static __inline__ int
447bondport_flags_selected_changed(bondport_ref p)
448{
449 return ((p->po_flags & BONDPORT_FLAGS_SELECTED_CHANGED) != 0);
450}
451
452static __inline__ void
453bondport_flags_set_mux_attached(bondport_ref p)
454{
455 p->po_flags |= BONDPORT_FLAGS_MUX_ATTACHED;
456 return;
457}
458
459static __inline__ void
460bondport_flags_clear_mux_attached(bondport_ref p)
461{
462 p->po_flags &= ~BONDPORT_FLAGS_MUX_ATTACHED;
463 return;
464}
465
466static __inline__ int
467bondport_flags_mux_attached(bondport_ref p)
468{
469 return ((p->po_flags & BONDPORT_FLAGS_MUX_ATTACHED) != 0);
470}
471
472static __inline__ void
473bondport_flags_set_distributing(bondport_ref p)
474{
475 p->po_flags |= BONDPORT_FLAGS_DISTRIBUTING;
476 return;
477}
478
479static __inline__ void
480bondport_flags_clear_distributing(bondport_ref p)
481{
482 p->po_flags &= ~BONDPORT_FLAGS_DISTRIBUTING;
483 return;
484}
485
486static __inline__ int
487bondport_flags_distributing(bondport_ref p)
488{
489 return ((p->po_flags & BONDPORT_FLAGS_DISTRIBUTING) != 0);
490}
491
492typedef struct bond_globals_s {
493 struct ifbond_list ifbond_list;
494 lacp_system system;
495 lacp_system_priority system_priority;
496 int verbose;
497} * bond_globals_ref;
498
499static bond_globals_ref g_bond;
500
501/**
502 ** packet_buffer routines
503 ** - thin wrapper for mbuf
504 **/
505
506typedef struct mbuf * packet_buffer_ref;
507
508static packet_buffer_ref
509packet_buffer_allocate(int length)
510{
511 packet_buffer_ref m;
512 int size;
513
514 /* leave room for ethernet header */
515 size = length + sizeof(struct ether_header);
516 if (size > (int)MHLEN) {
517 /* XXX doesn't handle large payloads */
b0d623f7 518 printf("bond: packet_buffer_allocate size %d > max %u\n", size, MHLEN);
91447636
A
519 return (NULL);
520 }
521 m = m_gethdr(M_WAITOK, MT_DATA);
522 if (m == NULL) {
523 return (NULL);
524 }
525 m->m_len = size;
526 m->m_pkthdr.len = size;
527 return (m);
528}
529
530static void *
531packet_buffer_byteptr(packet_buffer_ref buf)
532{
533 return (buf->m_data + sizeof(struct ether_header));
534}
535
536typedef enum {
537 LAEventStart,
538 LAEventTimeout,
539 LAEventPacket,
540 LAEventMediaChange,
541 LAEventSelectedChange,
542 LAEventPortMoved,
543 LAEventReady
544} LAEvent;
545
546/**
547 ** Receive machine
548 **/
549static void
550bondport_receive_machine(bondport_ref p, LAEvent event,
551 void * event_data);
552/**
553 ** Periodic Transmission machine
554 **/
555static void
556bondport_periodic_transmit_machine(bondport_ref p, LAEvent event,
557 void * event_data);
558
559/**
560 ** Transmit machine
561 **/
2d21ac55
A
562#define TRANSMIT_MACHINE_TX_IMMEDIATE ((void *)1)
563
91447636
A
564static void
565bondport_transmit_machine(bondport_ref p, LAEvent event,
566 void * event_data);
567
568/**
569 ** Mux machine
570 **/
571static void
572bondport_mux_machine(bondport_ref p, LAEvent event,
573 void * event_data);
574
575/**
576 ** bond, LAG
577 **/
578static void
579ifbond_activate_LAG(ifbond_ref bond, LAG_ref lag, int active_media);
580
581static void
582ifbond_deactivate_LAG(ifbond_ref bond, LAG_ref lag);
583
584static int
585ifbond_all_ports_ready(ifbond_ref bond);
586
587static LAG_ref
588ifbond_find_best_LAG(ifbond_ref bond, int * active_media);
589
590static int
591LAG_get_aggregatable_port_count(LAG_ref lag, int * active_media);
592
593static int
594ifbond_selection(ifbond_ref bond);
595
596
597/**
598 ** bondport
599 **/
600
601static void
602bondport_receive_lacpdu(bondport_ref p, lacpdu_ref in_lacpdu_p);
603
604static void
605bondport_slow_proto_transmit(bondport_ref p, packet_buffer_ref buf);
606
607static bondport_ref
608bondport_create(struct ifnet * port_ifp, lacp_port_priority priority,
609 int active, int short_timeout, int * error);
610static void
611bondport_start(bondport_ref p);
612
613static void
614bondport_free(bondport_ref p);
615
616static int
617bondport_aggregatable(bondport_ref p);
618
619static int
620bondport_remove_from_LAG(bondport_ref p);
621
622static void
623bondport_set_selected(bondport_ref p, SelectedState s);
624
625static int
626bondport_matches_LAG(bondport_ref p, LAG_ref lag);
627
628static void
629bondport_link_status_changed(bondport_ref p);
630
631static void
632bondport_enable_distributing(bondport_ref p);
633
634static void
635bondport_disable_distributing(bondport_ref p);
636
637static __inline__ int
638bondport_collecting(bondport_ref p)
639{
2d21ac55
A
640 if (p->po_bond->ifb_mode == IF_BOND_MODE_LACP) {
641 return (lacp_actor_partner_state_collecting(p->po_actor_state));
642 }
643 return (TRUE);
91447636
A
644}
645
646/**
647 ** bond interface/dlil specific routines
648 **/
d1ecb069
A
649static int bond_clone_create(struct if_clone *, u_int32_t, void *);
650static int bond_clone_destroy(struct ifnet *);
2d21ac55
A
651static int bond_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t m,
652 char *frame_header);
91447636 653static int bond_output(struct ifnet *ifp, struct mbuf *m);
b0d623f7 654static int bond_ioctl(struct ifnet *ifp, u_long cmd, void * addr);
91447636
A
655static int bond_set_bpf_tap(struct ifnet * ifp, bpf_tap_mode mode,
656 bpf_packet_func func);
657static int bond_attach_protocol(struct ifnet *ifp);
658static int bond_detach_protocol(struct ifnet *ifp);
659static int bond_setmulti(struct ifnet *ifp);
660static int bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp);
661static int bond_remove_interface(ifbond_ref ifb, struct ifnet * port_ifp);
662static void bond_if_free(struct ifnet * ifp);
663
664static struct if_clone bond_cloner = IF_CLONE_INITIALIZER(BONDNAME,
665 bond_clone_create,
666 bond_clone_destroy,
667 0,
668 BOND_MAXUNIT);
b0d623f7 669static void interface_link_event(struct ifnet * ifp, u_int32_t event_code);
91447636
A
670
671static int
672siocsifmtu(struct ifnet * ifp, int mtu)
673{
674 struct ifreq ifr;
675
676 bzero(&ifr, sizeof(ifr));
677 ifr.ifr_mtu = mtu;
2d21ac55 678 return (ifnet_ioctl(ifp, 0, SIOCSIFMTU, &ifr));
91447636
A
679}
680
681static int
682siocgifdevmtu(struct ifnet * ifp, struct ifdevmtu * ifdm_p)
683{
684 struct ifreq ifr;
685 int error;
686
687 bzero(&ifr, sizeof(ifr));
2d21ac55 688 error = ifnet_ioctl(ifp, 0, SIOCGIFDEVMTU, &ifr);
91447636
A
689 if (error == 0) {
690 *ifdm_p = ifr.ifr_devmtu;
691 }
692 return (error);
693}
694
695static __inline__ void
696ether_addr_copy(void * dest, const void * source)
697{
698 bcopy(source, dest, ETHER_ADDR_LEN);
699 return;
700}
701
702static __inline__ void
703ifbond_retain(ifbond_ref ifb)
704{
705 OSIncrementAtomic(&ifb->ifb_retain_count);
706}
707
708static __inline__ void
709ifbond_release(ifbond_ref ifb)
710{
711 UInt32 old_retain_count;
712
713 old_retain_count = OSDecrementAtomic(&ifb->ifb_retain_count);
714 switch (old_retain_count) {
715 case 0:
716 panic("ifbond_release: retain count is 0\n");
717 break;
718 case 1:
719 if (g_bond->verbose) {
720 printf("ifbond_release(%s)\n", ifb->ifb_name);
721 }
722 if (ifb->ifb_ifma_slow_proto != NULL) {
723 if (g_bond->verbose) {
724 printf("ifbond_release(%s) removing multicast\n",
725 ifb->ifb_name);
726 }
727 (void)if_delmultiaddr(ifb->ifb_ifma_slow_proto, 0);
728 ifma_release(ifb->ifb_ifma_slow_proto);
729 }
730 if (ifb->ifb_distributing_array != NULL) {
731 FREE(ifb->ifb_distributing_array, M_BOND);
732 }
733 FREE(ifb, M_BOND);
734 break;
735 default:
736 break;
737 }
738 return;
739}
740
741/*
742 * Function: ifbond_wait
743 * Purpose:
744 * Allows a single thread to gain exclusive access to the ifbond
745 * data structure. Some operations take a long time to complete,
746 * and some have side-effects that we can't predict. Holding the
747 * bond_lock() across such operations is not possible.
748 *
749 * For example:
750 * 1) The SIOCSIFLLADDR ioctl takes a long time (several seconds) to
751 * complete. Simply holding the bond_lock() would freeze all other
752 * data structure accesses during that time.
753 * 2) When we attach our protocol to the interface, a dlil event is
754 * generated and invokes our bond_event() function. bond_event()
755 * needs to take the bond_lock(), but we're already holding it, so
756 * we're deadlocked against ourselves.
757 * Notes:
758 * Before calling, you must be holding the bond_lock and have taken
759 * a reference on the ifbond_ref.
760 */
761static void
762ifbond_wait(ifbond_ref ifb, const char * msg)
763{
764 int waited = 0;
765
766 /* other add/remove in progress */
767 while (ifbond_flags_change_in_progress(ifb)) {
768 if (g_bond->verbose) {
769 printf("%s: %s msleep\n", ifb->ifb_name, msg);
770 }
771 waited = 1;
772 (void)msleep(ifb, bond_lck_mtx, PZERO, msg, 0);
773 }
774 /* prevent other bond list remove/add from taking place */
775 ifbond_flags_set_change_in_progress(ifb);
776 if (g_bond->verbose && waited) {
777 printf("%s: %s woke up\n", ifb->ifb_name, msg);
778 }
779 return;
780}
781
782/*
783 * Function: ifbond_signal
784 * Purpose:
785 * Allows the thread that previously invoked ifbond_wait() to
786 * give up exclusive access to the ifbond data structure, and wake up
787 * any other threads waiting to access
788 * Notes:
789 * Before calling, you must be holding the bond_lock and have taken
790 * a reference on the ifbond_ref.
791 */
792static void
793ifbond_signal(ifbond_ref ifb, const char * msg)
794{
795 ifbond_flags_clear_change_in_progress(ifb);
796 wakeup((caddr_t)ifb);
797 if (g_bond->verbose) {
798 printf("%s: %s wakeup\n", ifb->ifb_name, msg);
799 }
800 return;
801}
802
803/**
804 ** Media information
805 **/
806
807static int
808link_speed(int active)
809{
810 switch (IFM_SUBTYPE(active)) {
811 case IFM_10_T:
812 case IFM_10_2:
813 case IFM_10_5:
814 case IFM_10_STP:
815 case IFM_10_FL:
816 return (10);
817 case IFM_100_TX:
818 case IFM_100_FX:
819 case IFM_100_T4:
820 case IFM_100_VG:
821 case IFM_100_T2:
822 return (100);
823 case IFM_1000_SX:
824 case IFM_1000_LX:
825 case IFM_1000_CX:
826 case IFM_1000_TX:
827 return (1000);
828 case IFM_HPNA_1:
829 return (0);
830 default:
831 /* assume that new defined types are going to be at least 10GigE */
832 case IFM_10G_SR:
833 case IFM_10G_LR:
834 return (10000);
835 }
836}
837
838static __inline__ int
839media_active(const struct media_info * mi)
840{
841 if ((mi->mi_status & IFM_AVALID) == 0) {
842 return (1);
843 }
844 return ((mi->mi_status & IFM_ACTIVE) != 0);
845}
846
847static __inline__ int
848media_full_duplex(const struct media_info * mi)
849{
850 return ((mi->mi_active & IFM_FDX) != 0);
851}
852
853static __inline__ int
854media_speed(const struct media_info * mi)
855{
856 return (link_speed(mi->mi_active));
857}
858
859static struct media_info
860interface_media_info(struct ifnet * ifp)
861{
862 struct ifmediareq ifmr;
863 struct media_info mi;
864
865 bzero(&mi, sizeof(mi));
866 bzero(&ifmr, sizeof(ifmr));
2d21ac55 867 if (ifnet_ioctl(ifp, 0, SIOCGIFMEDIA, &ifmr) == 0) {
91447636
A
868 if (ifmr.ifm_count != 0) {
869 mi.mi_status = ifmr.ifm_status;
870 mi.mi_active = ifmr.ifm_active;
871 }
872 }
873 return (mi);
874}
875
91447636
A
876static int
877if_siflladdr(struct ifnet * ifp, const struct ether_addr * ea_p)
878{
879 struct ifreq ifr;
880
881 /*
882 * XXX setting the sa_len to ETHER_ADDR_LEN is wrong, but the driver
883 * currently expects it that way
884 */
885 ifr.ifr_addr.sa_family = AF_UNSPEC;
886 ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
887 ether_addr_copy(ifr.ifr_addr.sa_data, ea_p);
888#if 0
2d21ac55
A
889 snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", ifnet_name(ifp),
890 ifnet_unit(ifp));
b0d623f7 891#endif
2d21ac55 892 return (ifnet_ioctl(ifp, 0, SIOCSIFLLADDR, &ifr));
91447636
A
893}
894
895/**
896 ** bond_globals
897 **/
898static bond_globals_ref
899bond_globals_create(lacp_system_priority sys_pri,
900 lacp_system_ref sys)
901{
902 bond_globals_ref b;
903
904 b = _MALLOC(sizeof(*b), M_BOND, M_WAITOK);
905 if (b == NULL) {
906 return (NULL);
907 }
908 bzero(b, sizeof(*b));
909 TAILQ_INIT(&b->ifbond_list);
910 b->system = *sys;
911 b->system_priority = sys_pri;
912#if 0
913 b->verbose = 1;
b0d623f7 914#endif
91447636
A
915 return (b);
916}
917
918static int
919bond_globals_init(void)
920{
921 bond_globals_ref b;
922 int i;
923 struct ifnet * ifp;
924
925 bond_assert_lock_not_held();
926
927 if (g_bond != NULL) {
928 return (0);
929 }
930
931 /*
932 * use en0's ethernet address as the system identifier, and if it's not
933 * there, use en1 .. en3
934 */
935 ifp = NULL;
936 for (i = 0; i < 4; i++) {
937 char ifname[IFNAMSIZ+1];
938 snprintf(ifname, sizeof(ifname), "en%d", i);
939 /* XXX ifunit() needs to return a reference on the ifp */
940 ifp = ifunit(ifname);
941 if (ifp != NULL) {
942 break;
943 }
944 }
945 b = NULL;
946 if (ifp != NULL) {
2d21ac55 947 b = bond_globals_create(0x8000, (lacp_system_ref)ifnet_lladdr(ifp));
91447636
A
948 }
949 bond_lock();
950 if (g_bond != NULL) {
951 bond_unlock();
952 _FREE(b, M_BOND);
953 return (0);
954 }
955 g_bond = b;
956 bond_unlock();
957 if (ifp == NULL) {
958 return (ENXIO);
959 }
960 if (b == NULL) {
961 return (ENOMEM);
962 }
963 return (0);
964}
965
966static void
967bond_bpf_vlan(struct ifnet * ifp, struct mbuf * m,
968 const struct ether_header * eh_p,
969 u_int16_t vlan_tag, bpf_packet_func func)
970{
971 struct ether_vlan_header * vlh_p;
972 struct mbuf * vl_m;
973
974 vl_m = m_get(M_DONTWAIT, MT_DATA);
975 if (vl_m == NULL) {
976 return;
977 }
978 /* populate a new mbuf containing the vlan ethernet header */
979 vl_m->m_len = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
980 vlh_p = mtod(vl_m, struct ether_vlan_header *);
981 bcopy(eh_p, vlh_p, offsetof(struct ether_header, ether_type));
982 vlh_p->evl_encap_proto = htons(ETHERTYPE_VLAN);
983 vlh_p->evl_tag = htons(vlan_tag);
984 vlh_p->evl_proto = eh_p->ether_type;
985 vl_m->m_next = m;
986 (*func)(ifp, vl_m);
987 vl_m->m_next = NULL;
988 m_free(vl_m);
989 return;
990}
991
992static __inline__ void
993bond_bpf_output(struct ifnet * ifp, struct mbuf * m,
994 bpf_packet_func func)
995{
996 if (func != NULL) {
997 if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
998 const struct ether_header * eh_p;
999 eh_p = mtod(m, const struct ether_header *);
1000 m->m_data += ETHER_HDR_LEN;
1001 m->m_len -= ETHER_HDR_LEN;
1002 bond_bpf_vlan(ifp, m, eh_p, m->m_pkthdr.vlan_tag, func);
1003 m->m_data -= ETHER_HDR_LEN;
1004 m->m_len += ETHER_HDR_LEN;
1005 } else {
1006 (*func)(ifp, m);
1007 }
1008 }
1009 return;
1010}
1011
1012static __inline__ void
1013bond_bpf_input(ifnet_t ifp, mbuf_t m, const struct ether_header * eh_p,
1014 bpf_packet_func func)
1015{
1016 if (func != NULL) {
1017 if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
1018 bond_bpf_vlan(ifp, m, eh_p, m->m_pkthdr.vlan_tag, func);
1019 } else {
1020 /* restore the header */
1021 m->m_data -= ETHER_HDR_LEN;
1022 m->m_len += ETHER_HDR_LEN;
1023 (*func)(ifp, m);
1024 m->m_data += ETHER_HDR_LEN;
1025 m->m_len -= ETHER_HDR_LEN;
1026 }
1027 }
1028 return;
1029}
1030
1031/*
1032 * Function: bond_setmulti
1033 * Purpose:
1034 * Enable multicast reception on "our" interface by enabling multicasts on
1035 * each of the member ports.
1036 */
1037static int
1038bond_setmulti(struct ifnet * ifp)
1039{
1040 ifbond_ref ifb;
1041 int error;
1042 int result = 0;
1043 bondport_ref p;
1044
1045 bond_lock();
2d21ac55 1046 ifb = ifnet_softc(ifp);
91447636
A
1047 if (ifb == NULL || ifbond_flags_if_detaching(ifb)
1048 || TAILQ_EMPTY(&ifb->ifb_port_list)) {
1049 bond_unlock();
1050 return (0);
1051 }
1052 ifbond_retain(ifb);
1053 ifbond_wait(ifb, "bond_setmulti");
1054
1055 if (ifbond_flags_if_detaching(ifb)) {
1056 /* someone destroyed the bond while we were waiting */
1057 result = EBUSY;
1058 goto signal_done;
1059 }
1060 bond_unlock();
1061
1062 /* ifbond_wait() let's us safely walk the list without holding the lock */
1063 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
1064 struct ifnet * port_ifp = p->po_ifp;
1065
1066 error = multicast_list_program(&p->po_multicast,
1067 ifp, port_ifp);
1068 if (error != 0) {
1069 printf("bond_setmulti(%s): "
1070 "multicast_list_program(%s%d) failed, %d\n",
2d21ac55
A
1071 ifb->ifb_name, ifnet_name(port_ifp),
1072 ifnet_unit(port_ifp), error);
91447636
A
1073 result = error;
1074 }
1075 }
1076 bond_lock();
1077 signal_done:
91447636
A
1078 ifbond_signal(ifb, "bond_setmulti");
1079 bond_unlock();
2d21ac55 1080 ifbond_release(ifb);
91447636
A
1081 return (result);
1082}
1083
b0d623f7 1084static int
91447636
A
1085bond_clone_attach(void)
1086{
b0d623f7
A
1087 int error;
1088
1089 if ((error = if_clone_attach(&bond_cloner)) != 0)
1090 return error;
91447636 1091 bond_lock_init();
b0d623f7 1092 return 0;
91447636
A
1093}
1094
1095static int
1096ifbond_add_slow_proto_multicast(ifbond_ref ifb)
1097{
1098 int error;
1099 struct ifmultiaddr * ifma = NULL;
1100 struct sockaddr_dl sdl;
1101
1102 bond_assert_lock_not_held();
1103
1104 bzero(&sdl, sizeof(sdl));
1105 sdl.sdl_len = sizeof(sdl);
1106 sdl.sdl_family = AF_LINK;
1107 sdl.sdl_type = IFT_ETHER;
1108 sdl.sdl_nlen = 0;
1109 sdl.sdl_alen = sizeof(slow_proto_multicast);
1110 bcopy(&slow_proto_multicast, sdl.sdl_data, sizeof(slow_proto_multicast));
1111 error = if_addmulti(ifb->ifb_ifp, (struct sockaddr *)&sdl,
1112 &ifma);
1113 if (error == 0) {
1114 ifb->ifb_ifma_slow_proto = ifma;
1115 }
1116 return (error);
1117}
1118
1119static int
d1ecb069 1120bond_clone_create(struct if_clone * ifc, u_int32_t unit, __unused void *params)
91447636 1121{
2d21ac55
A
1122 int error;
1123 ifbond_ref ifb;
1124 ifnet_t ifp;
1125 struct ifnet_init_params bond_init;
1126
1127 error = bond_globals_init();
1128 if (error != 0) {
1129 return (error);
1130 }
1131
1132 ifb = _MALLOC(sizeof(ifbond), M_BOND, M_WAITOK);
1133 if (ifb == NULL) {
1134 return (ENOMEM);
1135 }
1136 bzero(ifb, sizeof(*ifb));
1137
1138 ifbond_retain(ifb);
1139 TAILQ_INIT(&ifb->ifb_port_list);
1140 TAILQ_INIT(&ifb->ifb_lag_list);
1141 ifb->ifb_key = unit + 1;
1142
1143 /* use the interface name as the unique id for ifp recycle */
b0d623f7 1144 if ((u_int32_t)snprintf(ifb->ifb_name, sizeof(ifb->ifb_name), "%s%d",
2d21ac55
A
1145 ifc->ifc_name, unit) >= sizeof(ifb->ifb_name)) {
1146 ifbond_release(ifb);
1147 return (EINVAL);
1148 }
1149
1150 bzero(&bond_init, sizeof(bond_init));
1151 bond_init.uniqueid = ifb->ifb_name;
1152 bond_init.uniqueid_len = strlen(ifb->ifb_name);
1153 bond_init.name = ifc->ifc_name;
1154 bond_init.unit = unit;
1155 bond_init.family = IFNET_FAMILY_BOND;
1156 bond_init.type = IFT_IEEE8023ADLAG;
1157 bond_init.output = bond_output;
1158 bond_init.demux = ether_demux;
1159 bond_init.add_proto = ether_add_proto;
1160 bond_init.del_proto = ether_del_proto;
1161 bond_init.check_multi = ether_check_multi;
1162 bond_init.framer = ether_frameout;
1163 bond_init.ioctl = bond_ioctl;
1164 bond_init.set_bpf_tap = bond_set_bpf_tap;
1165 bond_init.detach = bond_if_free;
1166 bond_init.broadcast_addr = etherbroadcastaddr;
1167 bond_init.broadcast_len = ETHER_ADDR_LEN;
1168 bond_init.softc = ifb;
1169 error = ifnet_allocate(&bond_init, &ifp);
1170
1171 if (error) {
1172 ifbond_release(ifb);
1173 return (error);
1174 }
1175
1176 ifb->ifb_ifp = ifp;
1177 ifnet_set_offload(ifp, 0);
1178 ifnet_set_addrlen(ifp, ETHER_ADDR_LEN); /* XXX ethernet specific */
1179 ifnet_set_flags(ifp, IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX, 0xffff);
1180 ifnet_set_baudrate(ifp, 0);
1181 ifnet_set_mtu(ifp, 0);
1182
1183 error = ifnet_attach(ifp, NULL);
1184 if (error != 0) {
1185 ifnet_release(ifp);
1186 ifbond_release(ifb);
1187 return (error);
1188 }
1189 error = ifbond_add_slow_proto_multicast(ifb);
1190 if (error != 0) {
1191 printf("bond_clone_create(%s): "
1192 "failed to add slow_proto multicast, %d\n",
1193 ifb->ifb_name, error);
1194 }
1195
1196 /* attach as ethernet */
1197 bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
1198
1199 bond_lock();
1200 TAILQ_INSERT_HEAD(&g_bond->ifbond_list, ifb, ifb_bond_list);
1201 bond_unlock();
1202
1203 return (0);
91447636
A
1204}
1205
1206static void
1207bond_remove_all_interfaces(ifbond_ref ifb)
1208{
1209 bondport_ref p;
1210
1211 bond_assert_lock_held();
1212
1213 /*
1214 * do this in reverse order to avoid re-programming the mac address
1215 * as each head interface is removed
1216 */
1217 while ((p = TAILQ_LAST(&ifb->ifb_port_list, port_list)) != NULL) {
1218 bond_remove_interface(ifb, p->po_ifp);
1219 }
1220 return;
1221}
1222
1223static void
1224bond_remove(ifbond_ref ifb)
1225{
1226 bond_assert_lock_held();
1227 ifbond_flags_set_if_detaching(ifb);
1228 TAILQ_REMOVE(&g_bond->ifbond_list, ifb, ifb_bond_list);
1229 bond_remove_all_interfaces(ifb);
1230 return;
1231}
1232
1233static void
1234bond_if_detach(struct ifnet * ifp)
1235{
1236 int error;
1237
2d21ac55 1238 error = ifnet_detach(ifp);
91447636 1239 if (error) {
2d21ac55
A
1240 printf("bond_if_detach %s%d: ifnet_detach failed, %d\n",
1241 ifnet_name(ifp), ifnet_unit(ifp), error);
91447636 1242 }
2d21ac55 1243
91447636
A
1244 return;
1245}
1246
d1ecb069 1247static int
91447636
A
1248bond_clone_destroy(struct ifnet * ifp)
1249{
1250 ifbond_ref ifb;
1251
1252 bond_lock();
2d21ac55
A
1253 ifb = ifnet_softc(ifp);
1254 if (ifb == NULL || ifnet_type(ifp) != IFT_IEEE8023ADLAG) {
91447636 1255 bond_unlock();
d1ecb069 1256 return 0;
91447636
A
1257 }
1258 if (ifbond_flags_if_detaching(ifb)) {
1259 bond_unlock();
d1ecb069 1260 return 0;
91447636
A
1261 }
1262 bond_remove(ifb);
1263 bond_unlock();
1264 bond_if_detach(ifp);
d1ecb069 1265 return 0;
91447636
A
1266}
1267
1268static int
1269bond_set_bpf_tap(struct ifnet * ifp, bpf_tap_mode mode, bpf_packet_func func)
1270{
1271 ifbond_ref ifb;
1272
1273 bond_lock();
2d21ac55 1274 ifb = ifnet_softc(ifp);
91447636
A
1275 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
1276 bond_unlock();
1277 return (ENODEV);
1278 }
1279 switch (mode) {
1280 case BPF_TAP_DISABLE:
1281 ifb->ifb_bpf_input = ifb->ifb_bpf_output = NULL;
1282 break;
1283
1284 case BPF_TAP_INPUT:
1285 ifb->ifb_bpf_input = func;
1286 break;
1287
1288 case BPF_TAP_OUTPUT:
1289 ifb->ifb_bpf_output = func;
1290 break;
1291
1292 case BPF_TAP_INPUT_OUTPUT:
1293 ifb->ifb_bpf_input = ifb->ifb_bpf_output = func;
1294 break;
1295 default:
1296 break;
1297 }
1298 bond_unlock();
1299 return 0;
1300}
1301
1302static uint32_t
1303ether_header_hash(struct ether_header * eh_p)
1304{
1305 uint32_t h;
1306
1307 /* get 32-bits from destination ether and ether type */
1308 h = (*((uint16_t *)&eh_p->ether_dhost[4]) << 16)
1309 | eh_p->ether_type;
1310 h ^= *((uint32_t *)&eh_p->ether_dhost[0]);
1311 return (h);
1312}
1313
1314static struct mbuf *
b0d623f7 1315S_mbuf_skip_to_offset(struct mbuf * m, int32_t * offset)
91447636
A
1316{
1317 int len;
1318
1319 len = m->m_len;
1320 while (*offset >= len) {
1321 *offset -= len;
1322 m = m->m_next;
1323 if (m == NULL) {
1324 break;
1325 }
1326 len = m->m_len;
1327 }
1328 return (m);
1329}
1330
1331#if BYTE_ORDER == BIG_ENDIAN
1332static __inline__ uint32_t
1333make_uint32(u_char c0, u_char c1, u_char c2, u_char c3)
1334{
1335 return (((uint32_t)c0 << 24) | ((uint32_t)c1 << 16)
1336 | ((uint32_t)c2 << 8) | (uint32_t)c3);
1337}
1338#else /* BYTE_ORDER == LITTLE_ENDIAN */
1339static __inline__ uint32_t
1340make_uint32(u_char c0, u_char c1, u_char c2, u_char c3)
1341{
1342 return (((uint32_t)c3 << 24) | ((uint32_t)c2 << 16)
1343 | ((uint32_t)c1 << 8) | (uint32_t)c0);
1344}
1345#endif /* BYTE_ORDER == LITTLE_ENDIAN */
1346
1347static int
b0d623f7 1348S_mbuf_copy_uint32(struct mbuf * m, int32_t offset, uint32_t * val)
91447636
A
1349{
1350 struct mbuf * current;
1351 u_char * current_data;
1352 struct mbuf * next;
1353 u_char * next_data;
1354 int space_current;
1355
1356 current = S_mbuf_skip_to_offset(m, &offset);
1357 if (current == NULL) {
1358 return (1);
1359 }
1360 current_data = mtod(current, u_char *) + offset;
1361 space_current = current->m_len - offset;
1362 if (space_current >= (int)sizeof(uint32_t)) {
1363 *val = *((uint32_t *)current_data);
1364 return (0);
1365 }
1366 next = current->m_next;
1367 if (next == NULL || (next->m_len + space_current) < (int)sizeof(uint32_t)) {
1368 return (1);
1369 }
1370 next_data = mtod(next, u_char *);
1371 switch (space_current) {
1372 case 1:
1373 *val = make_uint32(current_data[0], next_data[0],
1374 next_data[1], next_data[2]);
1375 break;
1376 case 2:
1377 *val = make_uint32(current_data[0], current_data[1],
1378 next_data[0], next_data[1]);
1379 break;
1380 default:
1381 *val = make_uint32(current_data[0], current_data[1],
1382 current_data[2], next_data[0]);
1383 break;
1384 }
1385 return (0);
1386}
1387
1388#define IP_SRC_OFFSET (offsetof(struct ip, ip_src) - offsetof(struct ip, ip_p))
1389#define IP_DST_OFFSET (offsetof(struct ip, ip_dst) - offsetof(struct ip, ip_p))
1390
1391static uint32_t
1392ip_header_hash(struct mbuf * m)
1393{
1394 u_char * data;
1395 struct in_addr ip_dst;
1396 struct in_addr ip_src;
1397 u_char ip_p;
b0d623f7 1398 int32_t offset;
91447636
A
1399 struct mbuf * orig_m = m;
1400
1401 /* find the IP protocol field relative to the start of the packet */
1402 offset = offsetof(struct ip, ip_p) + sizeof(struct ether_header);
1403 m = S_mbuf_skip_to_offset(m, &offset);
1404 if (m == NULL || m->m_len < 1) {
1405 goto bad_ip_packet;
1406 }
1407 data = mtod(m, u_char *) + offset;
1408 ip_p = *data;
1409
1410 /* find the IP src relative to the IP protocol */
1411 if ((m->m_len - offset)
1412 >= (int)(IP_SRC_OFFSET + sizeof(struct in_addr) * 2)) {
1413 /* this should be the normal case */
1414 ip_src = *(struct in_addr *)(data + IP_SRC_OFFSET);
1415 ip_dst = *(struct in_addr *)(data + IP_DST_OFFSET);
1416 }
1417 else {
1418 if (S_mbuf_copy_uint32(m, offset + IP_SRC_OFFSET,
1419 (uint32_t *)&ip_src.s_addr)) {
1420 goto bad_ip_packet;
1421 }
1422 if (S_mbuf_copy_uint32(m, offset + IP_DST_OFFSET,
1423 (uint32_t *)&ip_dst.s_addr)) {
1424 goto bad_ip_packet;
1425 }
1426 }
1427 return (ntohl(ip_dst.s_addr) ^ ntohl(ip_src.s_addr) ^ ((uint32_t)ip_p));
1428
1429 bad_ip_packet:
1430 return (ether_header_hash(mtod(orig_m, struct ether_header *)));
1431}
1432
1433#define IP6_ADDRS_LEN (sizeof(struct in6_addr) * 2)
1434static uint32_t
1435ipv6_header_hash(struct mbuf * m)
1436{
1437 u_char * data;
1438 int i;
b0d623f7 1439 int32_t offset;
91447636
A
1440 struct mbuf * orig_m = m;
1441 uint32_t * scan;
1442 uint32_t val;
1443
1444 /* find the IP protocol field relative to the start of the packet */
1445 offset = offsetof(struct ip6_hdr, ip6_src) + sizeof(struct ether_header);
1446 m = S_mbuf_skip_to_offset(m, &offset);
1447 if (m == NULL) {
1448 goto bad_ipv6_packet;
1449 }
1450 data = mtod(m, u_char *) + offset;
1451 val = 0;
1452 if ((m->m_len - offset) >= (int)IP6_ADDRS_LEN) {
1453 /* this should be the normal case */
1454 for (i = 0, scan = (uint32_t *)data;
1455 i < (int)(IP6_ADDRS_LEN / sizeof(uint32_t));
1456 i++, scan++) {
1457 val ^= *scan;
1458 }
1459 }
1460 else {
1461 for (i = 0; i < (int)(IP6_ADDRS_LEN / sizeof(uint32_t)); i++) {
1462 uint32_t tmp;
1463 if (S_mbuf_copy_uint32(m, offset + i * sizeof(uint32_t),
1464 (uint32_t *)&tmp)) {
1465 goto bad_ipv6_packet;
1466 }
1467 val ^= tmp;
1468 }
1469 }
1470 return (ntohl(val));
1471
1472 bad_ipv6_packet:
1473 return (ether_header_hash(mtod(orig_m, struct ether_header *)));
1474}
1475
1476static int
1477bond_output(struct ifnet * ifp, struct mbuf * m)
1478{
1479 bpf_packet_func bpf_func;
1480 uint32_t h;
1481 ifbond_ref ifb;
1482 struct ifnet * port_ifp = NULL;
1483
1484 if (m == 0) {
1485 return (0);
1486 }
1487 if ((m->m_flags & M_PKTHDR) == 0) {
1488 m_freem(m);
1489 return (0);
1490 }
1491 if (m->m_pkthdr.socket_id != 0) {
1492 h = m->m_pkthdr.socket_id;
1493 }
1494 else {
1495 struct ether_header * eh_p;
1496
1497 eh_p = mtod(m, struct ether_header *);
1498 switch (ntohs(eh_p->ether_type)) {
1499 case ETHERTYPE_IP:
1500 h = ip_header_hash(m);
1501 break;
1502 case ETHERTYPE_IPV6:
1503 h = ipv6_header_hash(m);
1504 break;
1505 default:
1506 h = ether_header_hash(eh_p);
1507 break;
1508 }
1509 }
1510 bond_lock();
2d21ac55 1511 ifb = ifnet_softc(ifp);
91447636
A
1512 if (ifb == NULL || ifbond_flags_if_detaching(ifb)
1513 || ifb->ifb_distributing_count == 0) {
1514 goto done;
1515 }
1516 h %= ifb->ifb_distributing_count;
1517 port_ifp = ifb->ifb_distributing_array[h]->po_ifp;
1518 bpf_func = ifb->ifb_bpf_output;
1519 bond_unlock();
1520
1521 if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
1522 (void)ifnet_stat_increment_out(ifp, 1,
1523 m->m_pkthdr.len + ETHER_VLAN_ENCAP_LEN,
1524 0);
1525 } else {
1526 (void)ifnet_stat_increment_out(ifp, 1, m->m_pkthdr.len, 0);
1527 }
1528 bond_bpf_output(ifp, m, bpf_func);
1529
2d21ac55 1530 return (ifnet_output_raw(port_ifp, PF_BOND, m));
91447636
A
1531
1532 done:
1533 bond_unlock();
1534 m_freem(m);
1535 return (0);
1536}
1537
1538static bondport_ref
1539ifbond_lookup_port(ifbond_ref ifb, struct ifnet * port_ifp)
1540{
1541 bondport_ref p;
1542 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
1543 if (p->po_ifp == port_ifp) {
1544 return (p);
1545 }
1546 }
1547 return (NULL);
1548}
1549
1550static bondport_ref
1551bond_lookup_port(struct ifnet * port_ifp)
1552{
1553 ifbond_ref ifb;
1554 bondport_ref port;
1555
1556 TAILQ_FOREACH(ifb, &g_bond->ifbond_list, ifb_bond_list) {
1557 port = ifbond_lookup_port(ifb, port_ifp);
1558 if (port != NULL) {
1559 return (port);
1560 }
1561 }
1562 return (NULL);
1563}
1564
1565static void
1566bond_receive_lacpdu(struct mbuf * m, struct ifnet * port_ifp)
1567{
1568 struct ifnet * bond_ifp = NULL;
2d21ac55 1569 ifbond_ref ifb;
91447636
A
1570 int event_code = 0;
1571 bondport_ref p;
1572
1573 bond_lock();
2d21ac55 1574 if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) {
91447636
A
1575 goto done;
1576 }
1577 p = bond_lookup_port(port_ifp);
1578 if (p == NULL) {
1579 goto done;
1580 }
1581 if (p->po_enabled == 0) {
1582 goto done;
1583 }
2d21ac55
A
1584 ifb = p->po_bond;
1585 if (ifb->ifb_mode != IF_BOND_MODE_LACP) {
1586 goto done;
1587 }
91447636 1588 bondport_receive_lacpdu(p, (lacpdu_ref)m->m_data);
2d21ac55
A
1589 if (ifbond_selection(ifb)) {
1590 event_code = (ifb->ifb_active_lag == NULL)
91447636
A
1591 ? KEV_DL_LINK_OFF
1592 : KEV_DL_LINK_ON;
1593 /* XXX need to take a reference on bond_ifp */
2d21ac55
A
1594 bond_ifp = ifb->ifb_ifp;
1595 ifb->ifb_last_link_event = event_code;
1596 }
1597 else {
1598 event_code = (ifb->ifb_active_lag == NULL)
1599 ? KEV_DL_LINK_OFF
1600 : KEV_DL_LINK_ON;
1601 if (event_code != ifb->ifb_last_link_event) {
1602 if (g_bond->verbose) {
1603 timestamp_printf("%s: (receive) generating LINK event\n",
1604 ifb->ifb_name);
1605 }
1606 bond_ifp = ifb->ifb_ifp;
1607 ifb->ifb_last_link_event = event_code;
1608 }
91447636
A
1609 }
1610
1611 done:
1612 bond_unlock();
1613 if (bond_ifp != NULL) {
1614 interface_link_event(bond_ifp, event_code);
1615 }
1616 m_freem(m);
1617 return;
1618}
1619
1620static void
1621bond_receive_la_marker_pdu(struct mbuf * m, struct ifnet * port_ifp)
1622{
1623 la_marker_pdu_ref marker_p;
1624 bondport_ref p;
1625
1626 marker_p = (la_marker_pdu_ref)(m->m_data + ETHER_HDR_LEN);
1627 if (marker_p->lm_marker_tlv_type != LA_MARKER_TLV_TYPE_MARKER) {
1628 goto failed;
1629 }
1630 bond_lock();
2d21ac55 1631 if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) {
91447636
A
1632 bond_unlock();
1633 goto failed;
1634 }
1635 p = bond_lookup_port(port_ifp);
2d21ac55
A
1636 if (p == NULL || p->po_enabled == 0
1637 || p->po_bond->ifb_mode != IF_BOND_MODE_LACP) {
91447636
A
1638 bond_unlock();
1639 goto failed;
1640 }
1641 /* echo back the same packet as a marker response */
1642 marker_p->lm_marker_tlv_type = LA_MARKER_TLV_TYPE_MARKER_RESPONSE;
1643 bondport_slow_proto_transmit(p, (packet_buffer_ref)m);
1644 bond_unlock();
1645 return;
1646
1647 failed:
1648 m_freem(m);
1649 return;
1650}
1651
1652static int
2d21ac55
A
1653bond_input(ifnet_t port_ifp, __unused protocol_family_t protocol, mbuf_t m,
1654 char * frame_header)
91447636
A
1655{
1656 bpf_packet_func bpf_func;
1657 const struct ether_header * eh_p;
1658 ifbond_ref ifb;
1659 struct ifnet * ifp;
1660 bondport_ref p;
1661
1662 eh_p = (const struct ether_header *)frame_header;
1663 if ((m->m_flags & M_MCAST) != 0
1664 && bcmp(eh_p->ether_dhost, &slow_proto_multicast,
1665 sizeof(eh_p->ether_dhost)) == 0
1666 && ntohs(eh_p->ether_type) == IEEE8023AD_SLOW_PROTO_ETHERTYPE) {
1667 u_char subtype = *mtod(m, u_char *);
1668
1669 if (subtype == IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP) {
1670 if (m->m_pkthdr.len < (int)offsetof(lacpdu, la_reserved)) {
1671 m_freem(m);
1672 return (0);
1673 }
1674 /* send to lacp */
1675 if (m->m_len < (int)offsetof(lacpdu, la_reserved)) {
1676 m = m_pullup(m, offsetof(lacpdu, la_reserved));
1677 if (m == NULL) {
1678 return (0);
1679 }
1680 }
1681 bond_receive_lacpdu(m, port_ifp);
1682 return (0);
1683 }
1684 else if (subtype == IEEE8023AD_SLOW_PROTO_SUBTYPE_LA_MARKER_PROTOCOL) {
1685 int min_size;
1686
1687 /* restore the ethernet header pointer in the mbuf */
1688 m->m_pkthdr.len += ETHER_HDR_LEN;
1689 m->m_data -= ETHER_HDR_LEN;
1690 m->m_len += ETHER_HDR_LEN;
1691 min_size = ETHER_HDR_LEN + offsetof(la_marker_pdu, lm_reserved);
1692 if (m->m_pkthdr.len < min_size) {
1693 m_freem(m);
1694 return (0);
1695 }
1696 /* send to lacp */
1697 if (m->m_len < min_size) {
1698 m = m_pullup(m, min_size);
1699 if (m == NULL) {
1700 return (0);
1701 }
1702 }
1703 /* send to marker responder */
1704 bond_receive_la_marker_pdu(m, port_ifp);
1705 return (0);
1706 }
1707 else if (subtype == 0
1708 || subtype > IEEE8023AD_SLOW_PROTO_SUBTYPE_RESERVED_END) {
1709 /* invalid subtype, discard the frame */
1710 m_freem(m);
1711 return (0);
1712 }
1713 }
1714 bond_lock();
2d21ac55 1715 if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) {
91447636
A
1716 goto done;
1717 }
1718 p = bond_lookup_port(port_ifp);
1719 if (p == NULL || bondport_collecting(p) == 0) {
1720 goto done;
1721 }
1722
1723 /* make the packet appear as if it arrived on the bonded interface */
1724 ifb = p->po_bond;
1725 ifp = ifb->ifb_ifp;
1726 bpf_func = ifb->ifb_bpf_input;
1727 bond_unlock();
1728
1729 if (m->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) {
1730 (void)ifnet_stat_increment_in(ifp, 1,
1731 (m->m_pkthdr.len + ETHER_HDR_LEN
1732 + ETHER_VLAN_ENCAP_LEN), 0);
1733 }
1734 else {
1735 (void)ifnet_stat_increment_in(ifp, 1,
1736 (m->m_pkthdr.len + ETHER_HDR_LEN), 0);
1737 }
1738 m->m_pkthdr.rcvif = ifp;
1739 bond_bpf_input(ifp, m, eh_p, bpf_func);
2d21ac55
A
1740 m->m_pkthdr.header = frame_header;
1741 dlil_input_packet_list(ifp, m);
91447636
A
1742 return 0;
1743
1744 done:
1745 bond_unlock();
1746 m_freem(m);
1747 return (0);
1748}
1749
1750static __inline__ const char *
1751bondport_get_name(bondport_ref p)
1752{
1753 return (p->po_name);
1754}
1755
1756static __inline__ int
1757bondport_get_index(bondport_ref p)
1758{
2d21ac55 1759 return (ifnet_index(p->po_ifp));
91447636
A
1760}
1761
1762static void
1763bondport_slow_proto_transmit(bondport_ref p, packet_buffer_ref buf)
1764{
1765 struct ether_header * eh_p;
1766 int error;
1767
1768 /* packet_buffer_allocate leaves room for ethernet header */
1769 eh_p = mtod(buf, struct ether_header *);
1770 bcopy(&slow_proto_multicast, &eh_p->ether_dhost, sizeof(eh_p->ether_dhost));
1771 bcopy(&p->po_saved_addr, eh_p->ether_shost, sizeof(eh_p->ether_shost));
1772 eh_p->ether_type = htons(IEEE8023AD_SLOW_PROTO_ETHERTYPE);
2d21ac55 1773 error = ifnet_output_raw(p->po_ifp, PF_BOND, buf);
91447636
A
1774 if (error != 0) {
1775 printf("bondport_slow_proto_transmit(%s) failed %d\n",
1776 bondport_get_name(p), error);
1777 }
1778 return;
1779}
1780
1781static void
1782bondport_timer_process_func(devtimer_ref timer,
1783 devtimer_process_func_event event)
1784{
1785 bondport_ref p;
1786
1787 switch (event) {
1788 case devtimer_process_func_event_lock:
1789 bond_lock();
1790 devtimer_retain(timer);
1791 break;
1792 case devtimer_process_func_event_unlock:
1793 if (devtimer_valid(timer)) {
1794 /* as long as the devtimer is valid, we can look at arg0 */
1795 int event_code = 0;
1796 struct ifnet * bond_ifp = NULL;
1797
1798 p = (bondport_ref)devtimer_arg0(timer);
1799 if (ifbond_selection(p->po_bond)) {
1800 event_code = (p->po_bond->ifb_active_lag == NULL)
1801 ? KEV_DL_LINK_OFF
1802 : KEV_DL_LINK_ON;
1803 /* XXX need to take a reference on bond_ifp */
1804 bond_ifp = p->po_bond->ifb_ifp;
2d21ac55
A
1805 p->po_bond->ifb_last_link_event = event_code;
1806 }
1807 else {
1808 event_code = (p->po_bond->ifb_active_lag == NULL)
1809 ? KEV_DL_LINK_OFF
1810 : KEV_DL_LINK_ON;
1811 if (event_code != p->po_bond->ifb_last_link_event) {
1812 if (g_bond->verbose) {
1813 timestamp_printf("%s: (timer) generating LINK event\n",
1814 p->po_bond->ifb_name);
1815 }
1816 bond_ifp = p->po_bond->ifb_ifp;
1817 p->po_bond->ifb_last_link_event = event_code;
1818 }
91447636
A
1819 }
1820 devtimer_release(timer);
1821 bond_unlock();
1822 if (bond_ifp != NULL) {
1823 interface_link_event(bond_ifp, event_code);
1824 }
1825 }
1826 else {
1827 /* timer is going away */
1828 devtimer_release(timer);
1829 bond_unlock();
1830 }
1831 break;
1832 default:
1833 break;
1834 }
1835}
1836
1837static bondport_ref
1838bondport_create(struct ifnet * port_ifp, lacp_port_priority priority,
1839 int active, int short_timeout, int * ret_error)
1840{
1841 int error = 0;
1842 bondport_ref p = NULL;
1843 lacp_actor_partner_state s;
1844
1845 *ret_error = 0;
1846 p = _MALLOC(sizeof(*p), M_BOND, M_WAITOK);
1847 if (p == NULL) {
1848 *ret_error = ENOMEM;
1849 return (NULL);
1850 }
1851 bzero(p, sizeof(*p));
1852 multicast_list_init(&p->po_multicast);
b0d623f7 1853 if ((u_int32_t)snprintf(p->po_name, sizeof(p->po_name), "%s%d",
2d21ac55 1854 ifnet_name(port_ifp), ifnet_unit(port_ifp))
91447636
A
1855 >= sizeof(p->po_name)) {
1856 printf("if_bond: name too large\n");
1857 *ret_error = EINVAL;
1858 goto failed;
1859 }
1860 error = siocgifdevmtu(port_ifp, &p->po_devmtu);
1861 if (error != 0) {
1862 printf("if_bond: SIOCGIFDEVMTU %s failed, %d\n",
1863 bondport_get_name(p), error);
1864 goto failed;
1865 }
1866 /* remember the current interface MTU so it can be restored */
2d21ac55 1867 p->po_devmtu.ifdm_current = ifnet_mtu(port_ifp);
91447636
A
1868 p->po_ifp = port_ifp;
1869 p->po_media_info = interface_media_info(port_ifp);
1870 p->po_current_while_timer = devtimer_create(bondport_timer_process_func, p);
1871 if (p->po_current_while_timer == NULL) {
1872 *ret_error = ENOMEM;
1873 goto failed;
1874 }
1875 p->po_periodic_timer = devtimer_create(bondport_timer_process_func, p);
1876 if (p->po_periodic_timer == NULL) {
1877 *ret_error = ENOMEM;
1878 goto failed;
1879 }
1880 p->po_wait_while_timer = devtimer_create(bondport_timer_process_func, p);
1881 if (p->po_wait_while_timer == NULL) {
1882 *ret_error = ENOMEM;
1883 goto failed;
1884 }
1885 p->po_transmit_timer = devtimer_create(bondport_timer_process_func, p);
1886 if (p->po_transmit_timer == NULL) {
1887 *ret_error = ENOMEM;
1888 goto failed;
1889 }
1890 p->po_receive_state = ReceiveState_none;
1891 p->po_mux_state = MuxState_none;
1892 p->po_priority = priority;
1893 s = 0;
1894 s = lacp_actor_partner_state_set_aggregatable(s);
1895 if (short_timeout) {
1896 s = lacp_actor_partner_state_set_short_timeout(s);
1897 }
1898 if (active) {
1899 s = lacp_actor_partner_state_set_active_lacp(s);
1900 }
1901 p->po_actor_state = s;
1902 return (p);
1903
1904 failed:
1905 bondport_free(p);
1906 return (NULL);
1907}
1908
1909static void
1910bondport_start(bondport_ref p)
1911{
1912 bondport_receive_machine(p, LAEventStart, NULL);
1913 bondport_mux_machine(p, LAEventStart, NULL);
1914 bondport_periodic_transmit_machine(p, LAEventStart, NULL);
1915 bondport_transmit_machine(p, LAEventStart, NULL);
1916 return;
1917}
1918
1919/*
1920 * Function: bondport_invalidate_timers
1921 * Purpose:
1922 * Invalidate all of the timers for the bondport.
1923 */
1924static void
1925bondport_invalidate_timers(bondport_ref p)
1926{
1927 devtimer_invalidate(p->po_current_while_timer);
1928 devtimer_invalidate(p->po_periodic_timer);
1929 devtimer_invalidate(p->po_wait_while_timer);
1930 devtimer_invalidate(p->po_transmit_timer);
1931}
1932
2d21ac55
A
1933/*
1934 * Function: bondport_cancel_timers
1935 * Purpose:
1936 * Cancel all of the timers for the bondport.
1937 */
1938static void
1939bondport_cancel_timers(bondport_ref p)
1940{
1941 devtimer_cancel(p->po_current_while_timer);
1942 devtimer_cancel(p->po_periodic_timer);
1943 devtimer_cancel(p->po_wait_while_timer);
1944 devtimer_cancel(p->po_transmit_timer);
1945}
1946
91447636
A
1947static void
1948bondport_free(bondport_ref p)
1949{
1950 multicast_list_remove(&p->po_multicast);
1951 devtimer_release(p->po_current_while_timer);
1952 devtimer_release(p->po_periodic_timer);
1953 devtimer_release(p->po_wait_while_timer);
1954 devtimer_release(p->po_transmit_timer);
1955 FREE(p, M_BOND);
1956 return;
1957}
1958
1959#define BOND_ADD_PROGRESS_IN_LIST 0x1
1960#define BOND_ADD_PROGRESS_PROTO_ATTACHED 0x2
1961#define BOND_ADD_PROGRESS_LLADDR_SET 0x4
1962#define BOND_ADD_PROGRESS_MTU_SET 0x8
1963
1964static __inline__ int
1965bond_device_mtu(struct ifnet * ifp, ifbond_ref ifb)
1966{
2d21ac55
A
1967 return (((int)ifnet_mtu(ifp) > ifb->ifb_altmtu)
1968 ? (int)ifnet_mtu(ifp) : ifb->ifb_altmtu);
91447636
A
1969}
1970
1971static int
1972bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp)
1973{
1974 int devmtu;
1975 int error = 0;
1976 int event_code = 0;
2d21ac55 1977 int first = FALSE;
91447636 1978 ifbond_ref ifb;
91447636
A
1979 bondport_ref * new_array = NULL;
1980 bondport_ref * old_array = NULL;
1981 bondport_ref p;
91447636
A
1982 int progress = 0;
1983
1984 /* pre-allocate space for new port */
1985 p = bondport_create(port_ifp, 0x8000, 1, 0, &error);
1986 if (p == NULL) {
1987 return (error);
1988 }
1989 bond_lock();
2d21ac55 1990 ifb = (ifbond_ref)ifnet_softc(ifp);
91447636
A
1991 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
1992 bond_unlock();
1993 bondport_free(p);
1994 return ((ifb == NULL ? EOPNOTSUPP : EBUSY));
1995 }
1996
1997 /* make sure this interface can handle our current MTU */
1998 devmtu = bond_device_mtu(ifp, ifb);
1999 if (devmtu != 0
2000 && (devmtu > p->po_devmtu.ifdm_max || devmtu < p->po_devmtu.ifdm_min)) {
2001 bond_unlock();
2002 printf("if_bond: interface %s doesn't support mtu %d",
2003 bondport_get_name(p), devmtu);
2004 bondport_free(p);
2005 return (EINVAL);
2006 }
2007
2008 /* make sure ifb doesn't get de-allocated while we wait */
2009 ifbond_retain(ifb);
2010
2011 /* wait for other add or remove to complete */
2012 ifbond_wait(ifb, "bond_add_interface");
2013
2014 if (ifbond_flags_if_detaching(ifb)) {
2015 /* someone destroyed the bond while we were waiting */
2016 error = EBUSY;
2017 goto signal_done;
2018 }
2019 if (bond_lookup_port(port_ifp) != NULL) {
2020 /* port is already part of a bond */
2021 error = EBUSY;
2022 goto signal_done;
2023 }
2024 ifnet_lock_exclusive(port_ifp);
2d21ac55 2025 if ((ifnet_eflags(port_ifp) & (IFEF_VLAN | IFEF_BOND)) != 0) {
91447636
A
2026 /* interface already has VLAN's, or is part of bond */
2027 ifnet_lock_done(port_ifp);
2028 error = EBUSY;
2029 goto signal_done;
2030 }
2031
2032 /* mark the interface busy */
2d21ac55 2033 /* can't use ifnet_set_eflags because that takes the lock */
91447636
A
2034 port_ifp->if_eflags |= IFEF_BOND;
2035 ifnet_lock_done(port_ifp);
2036
91447636 2037 if (TAILQ_EMPTY(&ifb->ifb_port_list)) {
2d21ac55
A
2038 ifnet_set_offload(ifp, ifnet_offload(port_ifp));
2039 ifnet_set_flags(ifp, IFF_RUNNING, IFF_RUNNING);
91447636 2040 if (ifbond_flags_lladdr(ifb) == FALSE) {
2d21ac55 2041 first = TRUE;
91447636
A
2042 }
2043 } else {
2d21ac55
A
2044 ifnet_offload_t ifp_offload;
2045 ifnet_offload_t port_ifp_offload;
2046
2047 ifp_offload = ifnet_offload(ifp);
2048 port_ifp_offload = ifnet_offload(port_ifp);
2049 if (ifp_offload != port_ifp_offload) {
2050 ifnet_offload_t offload;
2051
2052 offload = ifp_offload & port_ifp_offload;
91447636 2053 printf("bond_add_interface(%s, %s) "
2d21ac55 2054 "hwassist values don't match 0x%x != 0x%x, using 0x%x instead\n",
91447636 2055 ifb->ifb_name, bondport_get_name(p),
2d21ac55 2056 ifp_offload, port_ifp_offload, offload);
91447636
A
2057 /*
2058 * XXX
2059 * if the bond has VLAN's, we can't simply change the hwassist
2060 * field behind its back: this needs work
2061 */
2d21ac55 2062 ifnet_set_offload(ifp, offload);
91447636
A
2063 }
2064 }
2065 p->po_bond = ifb;
2066
2067 /* remember the port's ethernet address so it can be restored */
2d21ac55 2068 ether_addr_copy(&p->po_saved_addr, ifnet_lladdr(port_ifp));
91447636
A
2069
2070 /* add it to the list of ports */
2071 TAILQ_INSERT_TAIL(&ifb->ifb_port_list, p, po_port_list);
2072 ifb->ifb_port_count++;
2073
2074 /* set the default MTU */
2d21ac55
A
2075 if (ifnet_mtu(ifp) == 0) {
2076 ifnet_set_mtu(ifp, ETHERMTU);
91447636
A
2077 }
2078 bond_unlock();
2d21ac55
A
2079
2080
2081 /* first port added to bond determines bond's ethernet address */
2082 if (first) {
2083 ifnet_set_lladdr_and_type(ifp, ifnet_lladdr(port_ifp), ETHER_ADDR_LEN,
2084 IFT_ETHER);
2085 }
2086
91447636
A
2087 progress |= BOND_ADD_PROGRESS_IN_LIST;
2088
2089 /* allocate a larger distributing array */
2090 new_array = (bondport_ref *)
2091 _MALLOC(sizeof(*new_array) * ifb->ifb_port_count, M_BOND, M_WAITOK);
2092 if (new_array == NULL) {
2093 error = ENOMEM;
2094 goto failed;
2095 }
2096
2097 /* attach our BOND "protocol" to the interface */
2098 error = bond_attach_protocol(port_ifp);
2099 if (error) {
2100 goto failed;
2101 }
2102 progress |= BOND_ADD_PROGRESS_PROTO_ATTACHED;
2103
2104 /* set the interface MTU */
2105 devmtu = bond_device_mtu(ifp, ifb);
2106 error = siocsifmtu(port_ifp, devmtu);
2107 if (error != 0) {
2108 printf("bond_add_interface(%s, %s):"
2109 " SIOCSIFMTU %d failed %d\n",
2110 ifb->ifb_name, bondport_get_name(p), devmtu, error);
2111 goto failed;
2112 }
2113 progress |= BOND_ADD_PROGRESS_MTU_SET;
2114
2115 /* program the port with our multicast addresses */
2116 error = multicast_list_program(&p->po_multicast, ifp, port_ifp);
2117 if (error) {
2118 printf("bond_add_interface(%s, %s):"
2119 " multicast_list_program failed %d\n",
2120 ifb->ifb_name, bondport_get_name(p), error);
2121 goto failed;
2122 }
2123
2124 /* mark the interface up */
2d21ac55 2125 ifnet_set_flags(port_ifp, IFF_UP, IFF_UP);
91447636 2126
2d21ac55 2127 error = ifnet_ioctl(port_ifp, 0, SIOCSIFFLAGS, NULL);
91447636
A
2128 if (error != 0) {
2129 printf("bond_add_interface(%s, %s): SIOCSIFFLAGS failed %d\n",
2130 ifb->ifb_name, bondport_get_name(p), error);
2131 goto failed;
2132 }
2133
2134 /* re-program the port's ethernet address */
2135 error = if_siflladdr(port_ifp,
2d21ac55 2136 (const struct ether_addr *)ifnet_lladdr(ifp));
91447636
A
2137 if (error != 0) {
2138 /* port doesn't support setting the link address */
2139 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2140 ifb->ifb_name, bondport_get_name(p), error);
2141 goto failed;
2142 }
2143 progress |= BOND_ADD_PROGRESS_LLADDR_SET;
2144
2145 bond_lock();
2146
2147 /* no failures past this point */
2148 p->po_enabled = 1;
2149
2150 /* copy the contents of the existing distributing array */
2151 if (ifb->ifb_distributing_count) {
2152 bcopy(ifb->ifb_distributing_array, new_array,
2153 sizeof(*new_array) * ifb->ifb_distributing_count);
2154 }
2155 old_array = ifb->ifb_distributing_array;
2156 ifb->ifb_distributing_array = new_array;
2157
2d21ac55
A
2158 if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2159 bondport_start(p);
91447636 2160
2d21ac55
A
2161 /* check if we need to generate a link status event */
2162 if (ifbond_selection(ifb)) {
2163 event_code = (ifb->ifb_active_lag == NULL)
2164 ? KEV_DL_LINK_OFF
2165 : KEV_DL_LINK_ON;
2166 ifb->ifb_last_link_event = event_code;
2167 }
2168 }
2169 else {
2170 /* are we adding the first distributing interface? */
2171 if (media_active(&p->po_media_info)) {
2172 if (ifb->ifb_distributing_count == 0) {
2173 ifb->ifb_last_link_event = event_code = KEV_DL_LINK_ON;
2174 }
2175 bondport_enable_distributing(p);
2176 }
2177 else {
2178 bondport_disable_distributing(p);
2179 }
91447636 2180 }
2d21ac55
A
2181 /* clear the busy state, and wakeup anyone waiting */
2182 ifbond_signal(ifb, "bond_add_interface");
91447636
A
2183 bond_unlock();
2184 if (event_code != 0) {
2185 interface_link_event(ifp, event_code);
2186 }
2187 if (old_array != NULL) {
2188 FREE(old_array, M_BOND);
2189 }
2190 return 0;
2191
2192 failed:
2193 bond_assert_lock_not_held();
2194
2d21ac55
A
2195 /* if this was the first port to be added, clear our address */
2196 if (first) {
2197 ifnet_set_lladdr_and_type(ifp, NULL, 0, IFT_IEEE8023ADLAG);
2198 }
2199
91447636
A
2200 if (new_array != NULL) {
2201 FREE(new_array, M_BOND);
2202 }
2203 if ((progress & BOND_ADD_PROGRESS_LLADDR_SET) != 0) {
2204 int error1;
2205
2206 error1 = if_siflladdr(port_ifp, &p->po_saved_addr);
2207 if (error1 != 0) {
2208 printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n",
2209 ifb->ifb_name, bondport_get_name(p), error1);
2210 }
2211 }
2212 if ((progress & BOND_ADD_PROGRESS_PROTO_ATTACHED) != 0) {
2213 (void)bond_detach_protocol(port_ifp);
2214 }
2215 if ((progress & BOND_ADD_PROGRESS_MTU_SET) != 0) {
2216 int error1;
2217
2218 error1 = siocsifmtu(port_ifp, p->po_devmtu.ifdm_current);
2219 if (error1 != 0) {
2220 printf("bond_add_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2d21ac55
A
2221 ifb->ifb_name, bondport_get_name(p),
2222 p->po_devmtu.ifdm_current, error1);
91447636
A
2223 }
2224 }
2225 bond_lock();
2226 if ((progress & BOND_ADD_PROGRESS_IN_LIST) != 0) {
2227 TAILQ_REMOVE(&ifb->ifb_port_list, p, po_port_list);
2228 ifb->ifb_port_count--;
2229 }
2d21ac55 2230 ifnet_set_eflags(ifp, 0, IFEF_BOND);
91447636
A
2231 if (TAILQ_EMPTY(&ifb->ifb_port_list)) {
2232 ifb->ifb_altmtu = 0;
2d21ac55
A
2233 ifnet_set_mtu(ifp, 0);
2234 ifnet_set_offload(ifp, 0);
91447636
A
2235 }
2236
2237 signal_done:
91447636
A
2238 ifbond_signal(ifb, "bond_add_interface");
2239 bond_unlock();
2d21ac55 2240 ifbond_release(ifb);
91447636
A
2241 bondport_free(p);
2242 return (error);
2243}
2244
2245static int
2246bond_remove_interface(ifbond_ref ifb, struct ifnet * port_ifp)
2247{
2248 int active_lag = 0;
2249 int error = 0;
2250 int event_code = 0;
2251 bondport_ref head_port;
91447636 2252 struct ifnet * ifp;
2d21ac55
A
2253 int last = FALSE;
2254 int new_link_address = FALSE;
91447636
A
2255 bondport_ref p;
2256 lacp_actor_partner_state s;
2d21ac55 2257 int was_distributing;
91447636
A
2258
2259 bond_assert_lock_held();
2260
2261 ifbond_retain(ifb);
2262 ifbond_wait(ifb, "bond_remove_interface");
2263
2264 p = ifbond_lookup_port(ifb, port_ifp);
2265 if (p == NULL) {
2266 error = ENXIO;
2267 /* it got removed by another thread */
2268 goto signal_done;
2269 }
2270
2271 /* de-select it and remove it from the lists */
2d21ac55 2272 was_distributing = bondport_flags_distributing(p);
91447636 2273 bondport_disable_distributing(p);
2d21ac55
A
2274 if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2275 bondport_set_selected(p, SelectedState_UNSELECTED);
2276 active_lag = bondport_remove_from_LAG(p);
2277 /* invalidate timers here while holding the bond_lock */
2278 bondport_invalidate_timers(p);
2279
2280 /* announce that we're Individual now */
2281 s = p->po_actor_state;
2282 s = lacp_actor_partner_state_set_individual(s);
2283 s = lacp_actor_partner_state_set_not_collecting(s);
2284 s = lacp_actor_partner_state_set_not_distributing(s);
2285 s = lacp_actor_partner_state_set_out_of_sync(s);
2286 p->po_actor_state = s;
2287 bondport_flags_set_ntt(p);
2288 }
2289
91447636
A
2290 TAILQ_REMOVE(&ifb->ifb_port_list, p, po_port_list);
2291 ifb->ifb_port_count--;
2292
91447636 2293 ifp = ifb->ifb_ifp;
91447636
A
2294 head_port = TAILQ_FIRST(&ifb->ifb_port_list);
2295 if (head_port == NULL) {
2d21ac55 2296 ifnet_set_flags(ifp, 0, IFF_RUNNING);
91447636 2297 if (ifbond_flags_lladdr(ifb) == FALSE) {
2d21ac55 2298 last = TRUE;
91447636 2299 }
2d21ac55
A
2300 ifnet_set_offload(ifp, 0);
2301 ifnet_set_mtu(ifp, 0);
91447636
A
2302 ifb->ifb_altmtu = 0;
2303 } else if (ifbond_flags_lladdr(ifb) == FALSE
2d21ac55 2304 && bcmp(&p->po_saved_addr, ifnet_lladdr(ifp),
91447636 2305 ETHER_ADDR_LEN) == 0) {
2d21ac55 2306 new_link_address = TRUE;
91447636
A
2307 }
2308 /* check if we need to generate a link status event */
2d21ac55
A
2309 if (ifb->ifb_mode == IF_BOND_MODE_LACP ) {
2310 if (ifbond_selection(ifb) || active_lag) {
2311 event_code = (ifb->ifb_active_lag == NULL)
2312 ? KEV_DL_LINK_OFF
2313 : KEV_DL_LINK_ON;
2314 ifb->ifb_last_link_event = event_code;
2315 }
2316 bondport_transmit_machine(p, LAEventStart,
2317 TRANSMIT_MACHINE_TX_IMMEDIATE);
2318 }
2319 else {
2320 /* are we removing the last distributing interface? */
2321 if (was_distributing && ifb->ifb_distributing_count == 0) {
2322 ifb->ifb_last_link_event = event_code = KEV_DL_LINK_OFF;
2323 }
91447636 2324 }
91447636 2325
2d21ac55 2326 bond_unlock();
91447636 2327
2d21ac55
A
2328 if (last) {
2329 ifnet_set_lladdr_and_type(ifp, NULL, 0, IFT_IEEE8023ADLAG);
2330 }
2331 else if (new_link_address) {
91447636
A
2332 struct ifnet * scan_ifp;
2333 bondport_ref scan_port;
2334
2335 /* ifbond_wait() allows port list traversal without holding the lock */
2336
2d21ac55
A
2337 /* this port gave the bond its ethernet address, switch to new one */
2338 ifnet_set_lladdr_and_type(ifp,
2339 &head_port->po_saved_addr, ETHER_ADDR_LEN,
2340 IFT_ETHER);
2341
91447636
A
2342 /* re-program each port with the new link address */
2343 TAILQ_FOREACH(scan_port, &ifb->ifb_port_list, po_port_list) {
2344 scan_ifp = scan_port->po_ifp;
2345
2346 error = if_siflladdr(scan_ifp,
2d21ac55 2347 (const struct ether_addr *) ifnet_lladdr(ifp));
91447636
A
2348 if (error != 0) {
2349 printf("bond_remove_interface(%s, %s): "
2350 "if_siflladdr (%s) failed %d\n",
2351 ifb->ifb_name, bondport_get_name(p),
2352 bondport_get_name(scan_port), error);
2353 }
2354 }
2355 }
2356
2357 /* restore the port's ethernet address */
2358 error = if_siflladdr(port_ifp, &p->po_saved_addr);
2359 if (error != 0) {
2360 printf("bond_remove_interface(%s, %s): if_siflladdr failed %d\n",
2361 ifb->ifb_name, bondport_get_name(p), error);
2362 }
2363
2364 /* restore the port's MTU */
2365 error = siocsifmtu(port_ifp, p->po_devmtu.ifdm_current);
2366 if (error != 0) {
2367 printf("bond_remove_interface(%s, %s): SIOCSIFMTU %d failed %d\n",
2368 ifb->ifb_name, bondport_get_name(p),
2369 p->po_devmtu.ifdm_current, error);
2370 }
2371
2372 /* remove the bond "protocol" */
2373 bond_detach_protocol(port_ifp);
2374
2375 /* generate link event */
2376 if (event_code != 0) {
2377 interface_link_event(ifp, event_code);
2378 }
2379
2380 bond_lock();
91447636 2381 bondport_free(p);
2d21ac55
A
2382 ifnet_set_eflags(port_ifp, 0, IFEF_BOND);
2383 /* release this bondport's reference to the ifbond */
2384 ifbond_release(ifb);
91447636
A
2385
2386 signal_done:
2387 ifbond_signal(ifb, "bond_remove_interface");
2d21ac55
A
2388 ifbond_release(ifb);
2389 return (error);
2390}
2391
2392static void
2393bond_set_lacp_mode(ifbond_ref ifb)
2394{
2395 bondport_ref p;
2396
2397 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2398 bondport_disable_distributing(p);
2399 bondport_start(p);
2400 }
2401 return;
2402}
2403
2404static void
2405bond_set_static_mode(ifbond_ref ifb)
2406{
2407 bondport_ref p;
2408 lacp_actor_partner_state s;
2409
2410 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2411 bondport_disable_distributing(p);
2412 bondport_set_selected(p, SelectedState_UNSELECTED);
2413 (void)bondport_remove_from_LAG(p);
2414 bondport_cancel_timers(p);
2415
2416 /* announce that we're Individual now */
2417 s = p->po_actor_state;
2418 s = lacp_actor_partner_state_set_individual(s);
2419 s = lacp_actor_partner_state_set_not_collecting(s);
2420 s = lacp_actor_partner_state_set_not_distributing(s);
2421 s = lacp_actor_partner_state_set_out_of_sync(s);
2422 p->po_actor_state = s;
2423 bondport_flags_set_ntt(p);
2424 bondport_transmit_machine(p, LAEventStart,
2425 TRANSMIT_MACHINE_TX_IMMEDIATE);
2426 /* clear state */
2427 p->po_actor_state = 0;
2428 bzero(&p->po_partner_state, sizeof(p->po_partner_state));
2429
2430 if (media_active(&p->po_media_info)) {
2431 bondport_enable_distributing(p);
2432 }
2433 else {
2434 bondport_disable_distributing(p);
2435 }
2436 }
2437 return;
2438}
2439
2440static int
2441bond_set_mode(struct ifnet * ifp, int mode)
2442{
2443 int error = 0;
2444 int event_code = 0;
2445 ifbond_ref ifb;
2446
2447 bond_lock();
2448 ifb = (ifbond_ref)ifnet_softc(ifp);
2449 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2450 bond_unlock();
2451 return ((ifb == NULL) ? EOPNOTSUPP : EBUSY);
2452 }
2453 if (ifb->ifb_mode == mode) {
2454 bond_unlock();
2455 return (0);
2456 }
2457
2458 ifbond_retain(ifb);
2459 ifbond_wait(ifb, "bond_set_mode");
2460
2461 /* verify (again) that the mode is actually different */
2462 if (ifb->ifb_mode == mode) {
2463 /* nothing to do */
2464 goto signal_done;
2465 }
2466
2467 ifb->ifb_mode = mode;
2468 if (mode == IF_BOND_MODE_LACP) {
2469 bond_set_lacp_mode(ifb);
2470
2471 /* check if we need to generate a link status event */
2472 if (ifbond_selection(ifb)) {
2473 event_code = (ifb->ifb_active_lag == NULL)
2474 ? KEV_DL_LINK_OFF
2475 : KEV_DL_LINK_ON;
2476 }
2477 } else {
2478 bond_set_static_mode(ifb);
2479 event_code = (ifb->ifb_distributing_count == 0)
2480 ? KEV_DL_LINK_OFF
2481 : KEV_DL_LINK_ON;
2482 }
2483 ifb->ifb_last_link_event = event_code;
2484
2485 signal_done:
2486 ifbond_signal(ifb, "bond_set_mode");
2487 bond_unlock();
2488 ifbond_release(ifb);
2489
2490 if (event_code != 0) {
2491 interface_link_event(ifp, event_code);
2492 }
91447636
A
2493 return (error);
2494}
2495
2496static int
2497bond_get_status(ifbond_ref ifb, struct if_bond_req * ibr_p, user_addr_t datap)
2498{
2499 int count;
2500 user_addr_t dst;
2501 int error = 0;
2502 struct if_bond_status_req * ibsr;
2503 struct if_bond_status ibs;
2504 bondport_ref port;
2505
2506 ibsr = &(ibr_p->ibr_ibru.ibru_status);
2507 if (ibsr->ibsr_version != IF_BOND_STATUS_REQ_VERSION) {
2508 return (EINVAL);
2509 }
2510 ibsr->ibsr_key = ifb->ifb_key;
2d21ac55 2511 ibsr->ibsr_mode = ifb->ifb_mode;
91447636
A
2512 ibsr->ibsr_total = ifb->ifb_port_count;
2513 dst = proc_is64bit(current_proc())
2514 ? ibsr->ibsr_ibsru.ibsru_buffer64
2d21ac55 2515 : CAST_USER_ADDR_T(ibsr->ibsr_ibsru.ibsru_buffer);
91447636
A
2516 if (dst == USER_ADDR_NULL) {
2517 /* just want to know how many there are */
2518 goto done;
2519 }
2520 if (ibsr->ibsr_count < 0) {
2521 return (EINVAL);
2522 }
2523 count = (ifb->ifb_port_count < ibsr->ibsr_count)
2524 ? ifb->ifb_port_count : ibsr->ibsr_count;
2525 TAILQ_FOREACH(port, &ifb->ifb_port_list, po_port_list) {
2526 struct if_bond_partner_state * ibps_p;
2527 partner_state_ref ps;
2528
2529 if (count == 0) {
2530 break;
2531 }
2532 bzero(&ibs, sizeof(ibs));
2533 strncpy(ibs.ibs_if_name, port->po_name, sizeof(ibs.ibs_if_name));
2534 ibs.ibs_port_priority = port->po_priority;
2d21ac55
A
2535 if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2536 ibs.ibs_state = port->po_actor_state;
2537 ibs.ibs_selected_state = port->po_selected;
2538 ps = &port->po_partner_state;
2539 ibps_p = &ibs.ibs_partner_state;
2540 ibps_p->ibps_system = ps->ps_lag_info.li_system;
2541 ibps_p->ibps_system_priority = ps->ps_lag_info.li_system_priority;
2542 ibps_p->ibps_key = ps->ps_lag_info.li_key;
2543 ibps_p->ibps_port = ps->ps_port;
2544 ibps_p->ibps_port_priority = ps->ps_port_priority;
2545 ibps_p->ibps_state = ps->ps_state;
2546 }
2547 else {
2548 /* fake the selected information */
2549 ibs.ibs_selected_state = bondport_flags_distributing(port)
2550 ? SelectedState_SELECTED : SelectedState_UNSELECTED;
2551 }
91447636
A
2552 error = copyout(&ibs, dst, sizeof(ibs));
2553 if (error != 0) {
2554 break;
2555 }
2556 dst += sizeof(ibs);
2557 count--;
2558 }
2559
2560 done:
2561 if (error == 0) {
2562 error = copyout(ibr_p, datap, sizeof(*ibr_p));
2563 }
2564 else {
2565 (void)copyout(ibr_p, datap, sizeof(*ibr_p));
2566 }
2567 return (error);
2568}
2569
2570static int
2571bond_set_promisc(__unused struct ifnet *ifp)
2572{
2573 int error = 0;
2574#if 0
2d21ac55 2575 ifbond_ref ifb = ifnet_softc(ifp);
91447636
A
2576
2577
2d21ac55 2578 if ((ifnet_flags(ifp) & IFF_PROMISC) != 0) {
91447636
A
2579 if ((ifb->ifb_flags & IFBF_PROMISC) == 0) {
2580 error = ifnet_set_promiscuous(ifb->ifb_p, 1);
2581 if (error == 0)
2582 ifb->ifb_flags |= IFBF_PROMISC;
2583 }
2584 } else {
2585 if ((ifb->ifb_flags & IFBF_PROMISC) != 0) {
2586 error = ifnet_set_promiscuous(ifb->ifb_p, 0);
2587 if (error == 0)
2588 ifb->ifb_flags &= ~IFBF_PROMISC;
2589 }
2590 }
b0d623f7 2591#endif
91447636
A
2592 return (error);
2593}
2594
2595static void
2596bond_get_mtu_values(ifbond_ref ifb, int * ret_min, int * ret_max)
2597{
2598 int mtu_min = 0;
2599 int mtu_max = 0;
2600 bondport_ref p;
2601
2602 if (TAILQ_FIRST(&ifb->ifb_port_list) != NULL) {
2603 mtu_min = IF_MINMTU;
2604 }
2605 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2606 struct ifdevmtu * devmtu_p = &p->po_devmtu;
2607
2608 if (devmtu_p->ifdm_min > mtu_min) {
2609 mtu_min = devmtu_p->ifdm_min;
2610 }
2611 if (mtu_max == 0 || devmtu_p->ifdm_max < mtu_max) {
2612 mtu_max = devmtu_p->ifdm_max;
2613 }
2614 }
2615 *ret_min = mtu_min;
2616 *ret_max = mtu_max;
2617 return;
2618}
2619
2620static int
2621bond_set_mtu_on_ports(ifbond_ref ifb, int mtu)
2622{
2623 int error = 0;
2624 bondport_ref p;
2625
2626 TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) {
2627 error = siocsifmtu(p->po_ifp, mtu);
2628 if (error != 0) {
2629 printf("if_bond(%s): SIOCSIFMTU %s failed, %d\n",
2630 ifb->ifb_name, bondport_get_name(p), error);
2631 break;
2632 }
2633 }
2634 return (error);
2635}
2636
2637static int
2638bond_set_mtu(struct ifnet * ifp, int mtu, int isdevmtu)
2639{
2640 int error = 0;
2641 ifbond_ref ifb;
2642 int mtu_min;
2643 int mtu_max;
2644 int new_max;
2645 int old_max;
2646
2647 bond_lock();
2d21ac55 2648 ifb = (ifbond_ref)ifnet_softc(ifp);
91447636
A
2649 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2650 error = (ifb == NULL) ? EOPNOTSUPP : EBUSY;
2651 goto done;
2652 }
2653 ifbond_retain(ifb);
2654 ifbond_wait(ifb, "bond_set_mtu");
2655
2656 /* check again */
2d21ac55 2657 if (ifnet_softc(ifp) == NULL || ifbond_flags_if_detaching(ifb)) {
91447636
A
2658 error = EBUSY;
2659 goto signal_done;
2660 }
2661 bond_get_mtu_values(ifb, &mtu_min, &mtu_max);
2662 if (mtu > mtu_max) {
2663 error = EINVAL;
2664 goto signal_done;
2665 }
2666 if (mtu < mtu_min && (isdevmtu == 0 || mtu != 0)) {
2667 /* allow SIOCSIFALTMTU to set the mtu to 0 */
2668 error = EINVAL;
2669 goto signal_done;
2670 }
2671 if (isdevmtu) {
2d21ac55 2672 new_max = (mtu > (int)ifnet_mtu(ifp)) ? mtu : (int)ifnet_mtu(ifp);
91447636
A
2673 }
2674 else {
2675 new_max = (mtu > ifb->ifb_altmtu) ? mtu : ifb->ifb_altmtu;
2676 }
2d21ac55
A
2677 old_max = ((int)ifnet_mtu(ifp) > ifb->ifb_altmtu)
2678 ? (int)ifnet_mtu(ifp) : ifb->ifb_altmtu;
91447636
A
2679 if (new_max != old_max) {
2680 /* we can safely walk the list of port without the lock held */
2681 bond_unlock();
2682 error = bond_set_mtu_on_ports(ifb, new_max);
2683 if (error != 0) {
2684 /* try our best to back out of it */
2685 (void)bond_set_mtu_on_ports(ifb, old_max);
2686 }
2687 bond_lock();
2688 }
2689 if (error == 0) {
2690 if (isdevmtu) {
2691 ifb->ifb_altmtu = mtu;
2692 }
2693 else {
2d21ac55 2694 ifnet_set_mtu(ifp, mtu);
91447636
A
2695 }
2696 }
2697
2698 signal_done:
2699 ifbond_signal(ifb, "bond_set_mtu");
2700 ifbond_release(ifb);
2701
2702 done:
2703 bond_unlock();
2704 return (error);
2705}
2706
2707static int
b0d623f7 2708bond_ioctl(struct ifnet *ifp, u_long cmd, void * data)
91447636
A
2709{
2710 int error = 0;
2711 struct if_bond_req ibr;
2712 struct ifaddr * ifa;
2713 ifbond_ref ifb;
2714 struct ifreq * ifr;
b0d623f7 2715 struct ifmediareq *ifmr;
91447636
A
2716 struct ifnet * port_ifp = NULL;
2717 user_addr_t user_addr;
2718
2d21ac55 2719 if (ifnet_type(ifp) != IFT_IEEE8023ADLAG) {
91447636
A
2720 return (EOPNOTSUPP);
2721 }
2722 ifr = (struct ifreq *)data;
2723 ifa = (struct ifaddr *)data;
2724
2725 switch (cmd) {
2726 case SIOCSIFADDR:
2727 ifnet_set_flags(ifp, IFF_UP, IFF_UP);
2728 break;
2729
b0d623f7 2730 case SIOCGIFMEDIA32:
91447636 2731 case SIOCGIFMEDIA64:
91447636 2732 bond_lock();
2d21ac55 2733 ifb = (ifbond_ref)ifnet_softc(ifp);
91447636
A
2734 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2735 bond_unlock();
2736 return (ifb == NULL ? EOPNOTSUPP : EBUSY);
2737 }
b0d623f7 2738 ifmr = (struct ifmediareq *)data;
91447636
A
2739 ifmr->ifm_current = IFM_ETHER;
2740 ifmr->ifm_mask = 0;
2741 ifmr->ifm_status = IFM_AVALID;
2742 ifmr->ifm_active = IFM_ETHER;
2743 ifmr->ifm_count = 1;
2d21ac55
A
2744 if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2745 if (ifb->ifb_active_lag != NULL) {
2746 ifmr->ifm_active = ifb->ifb_active_lag->lag_active_media;
2747 ifmr->ifm_status |= IFM_ACTIVE;
2748 }
2749 }
2750 else if (ifb->ifb_distributing_count > 0) {
2751 ifmr->ifm_active
2752 = ifb->ifb_distributing_array[0]->po_media_info.mi_active;
91447636
A
2753 ifmr->ifm_status |= IFM_ACTIVE;
2754 }
2755 bond_unlock();
b0d623f7
A
2756 user_addr = (cmd == SIOCGIFMEDIA64) ?
2757 ((struct ifmediareq64 *)ifmr)->ifmu_ulist :
2758 CAST_USER_ADDR_T(((struct ifmediareq32 *)ifmr)->ifmu_ulist);
91447636
A
2759 if (user_addr != USER_ADDR_NULL) {
2760 error = copyout(&ifmr->ifm_current,
2761 user_addr,
2762 sizeof(int));
2763 }
2764 break;
2765
2766 case SIOCSIFMEDIA:
2767 /* XXX send the SIFMEDIA to all children? Or force autoselect? */
2768 error = EINVAL;
2769 break;
2770
2771 case SIOCGIFDEVMTU:
2772 bond_lock();
2d21ac55 2773 ifb = (ifbond_ref)ifnet_softc(ifp);
91447636
A
2774 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2775 bond_unlock();
2776 error = (ifb == NULL) ? EOPNOTSUPP : EBUSY;
2777 break;
2778 }
2779 ifr->ifr_devmtu.ifdm_current = bond_device_mtu(ifp, ifb);
2780 bond_get_mtu_values(ifb, &ifr->ifr_devmtu.ifdm_min,
2781 &ifr->ifr_devmtu.ifdm_max);
2782 bond_unlock();
2783 break;
2784
2785 case SIOCGIFALTMTU:
2786 bond_lock();
2d21ac55 2787 ifb = (ifbond_ref)ifnet_softc(ifp);
91447636
A
2788 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2789 bond_unlock();
2790 error = (ifb == NULL) ? EOPNOTSUPP : EBUSY;
2791 break;
2792 }
2793 ifr->ifr_mtu = ifb->ifb_altmtu;
2794 bond_unlock();
2795 break;
2796
2797 case SIOCSIFALTMTU:
2798 error = bond_set_mtu(ifp, ifr->ifr_mtu, 1);
2799 break;
2800
2801 case SIOCSIFMTU:
2802 error = bond_set_mtu(ifp, ifr->ifr_mtu, 0);
2803 break;
2804
2805 case SIOCSIFBOND:
2806 user_addr = proc_is64bit(current_proc())
2807 ? ifr->ifr_data64 : CAST_USER_ADDR_T(ifr->ifr_data);
2808 error = copyin(user_addr, &ibr, sizeof(ibr));
2809 if (error) {
2810 break;
2811 }
2812 switch (ibr.ibr_op) {
2813 case IF_BOND_OP_ADD_INTERFACE:
2814 case IF_BOND_OP_REMOVE_INTERFACE:
2815 /* XXX ifunit() needs to return a reference on the ifp */
2816 port_ifp = ifunit(ibr.ibr_ibru.ibru_if_name);
2817 if (port_ifp == NULL) {
2818 error = ENXIO;
2819 break;
2820 }
2d21ac55 2821 if (ifnet_type(port_ifp) != IFT_ETHER) {
91447636
A
2822 error = EPROTONOSUPPORT;
2823 break;
2824 }
2825 break;
2826 case IF_BOND_OP_SET_VERBOSE:
2d21ac55 2827 case IF_BOND_OP_SET_MODE:
91447636
A
2828 break;
2829 default:
2830 error = EOPNOTSUPP;
2831 break;
2832 }
2833 if (error != 0) {
2834 break;
2835 }
2836 switch (ibr.ibr_op) {
2837 case IF_BOND_OP_ADD_INTERFACE:
2838 error = bond_add_interface(ifp, port_ifp);
2839 break;
2840 case IF_BOND_OP_REMOVE_INTERFACE:
2841 bond_lock();
2d21ac55 2842 ifb = (ifbond_ref)ifnet_softc(ifp);
91447636
A
2843 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2844 bond_unlock();
2845 return (ifb == NULL ? EOPNOTSUPP : EBUSY);
2846 }
2847 error = bond_remove_interface(ifb, port_ifp);
2848 bond_unlock();
2849 break;
2850 case IF_BOND_OP_SET_VERBOSE:
2851 bond_lock();
2852 if (g_bond == NULL) {
2853 bond_unlock();
2854 error = ENXIO;
2855 break;
2856 }
2857 g_bond->verbose = ibr.ibr_ibru.ibru_int_val;
2858 bond_unlock();
2859 break;
2d21ac55
A
2860 case IF_BOND_OP_SET_MODE:
2861 switch (ibr.ibr_ibru.ibru_int_val) {
2862 case IF_BOND_MODE_LACP:
2863 case IF_BOND_MODE_STATIC:
2864 break;
2865 default:
2866 error = EINVAL;
2867 break;
2868 }
2869 if (error != 0) {
2870 break;
2871 }
2872 error = bond_set_mode(ifp, ibr.ibr_ibru.ibru_int_val);
2873 break;
91447636 2874 }
2d21ac55 2875 break; /* SIOCSIFBOND */
91447636
A
2876
2877 case SIOCGIFBOND:
2878 user_addr = proc_is64bit(current_proc())
2879 ? ifr->ifr_data64 : CAST_USER_ADDR_T(ifr->ifr_data);
2880 error = copyin(user_addr, &ibr, sizeof(ibr));
2881 if (error) {
2882 break;
2883 }
2884 switch (ibr.ibr_op) {
2885 case IF_BOND_OP_GET_STATUS:
2886 break;
2887 default:
2888 error = EOPNOTSUPP;
2889 break;
2890 }
2891 if (error != 0) {
2892 break;
2893 }
2894 bond_lock();
2d21ac55 2895 ifb = (ifbond_ref)ifnet_softc(ifp);
91447636
A
2896 if (ifb == NULL || ifbond_flags_if_detaching(ifb)) {
2897 bond_unlock();
2898 return (ifb == NULL ? EOPNOTSUPP : EBUSY);
2899 }
2900 switch (ibr.ibr_op) {
2901 case IF_BOND_OP_GET_STATUS:
2902 error = bond_get_status(ifb, &ibr, user_addr);
2903 break;
2904 }
2905 bond_unlock();
2d21ac55 2906 break; /* SIOCGIFBOND */
91447636
A
2907
2908 case SIOCSIFLLADDR:
2909 error = EOPNOTSUPP;
2910 break;
2911
2912 case SIOCSIFFLAGS:
2913 /* enable/disable promiscuous mode */
2914 bond_lock();
2915 error = bond_set_promisc(ifp);
2916 bond_unlock();
2917 break;
2918
2919 case SIOCADDMULTI:
2920 case SIOCDELMULTI:
2921 error = bond_setmulti(ifp);
2922 break;
2923 default:
2924 error = EOPNOTSUPP;
2925 }
2926 return error;
2927}
2928
2929static void
2930bond_if_free(struct ifnet * ifp)
2931{
2932 ifbond_ref ifb;
2933
2934 if (ifp == NULL) {
2935 return;
2936 }
2937 bond_lock();
2d21ac55 2938 ifb = (ifbond_ref)ifnet_softc(ifp);
91447636
A
2939 if (ifb == NULL) {
2940 bond_unlock();
2941 return;
2942 }
91447636
A
2943 ifbond_release(ifb);
2944 bond_unlock();
2d21ac55 2945 ifnet_release(ifp);
91447636
A
2946 return;
2947}
2948
2949static void
2d21ac55
A
2950bond_event(struct ifnet * port_ifp, __unused protocol_family_t protocol,
2951 const struct kev_msg * event)
91447636
A
2952{
2953 struct ifnet * bond_ifp = NULL;
2954 int event_code = 0;
2d21ac55
A
2955 ifbond_ref ifb;
2956 int old_distributing_count;
91447636 2957 bondport_ref p;
2d21ac55 2958 struct media_info media_info = { 0, 0};
91447636
A
2959
2960 if (event->vendor_code != KEV_VENDOR_APPLE
2961 || event->kev_class != KEV_NETWORK_CLASS
2962 || event->kev_subclass != KEV_DL_SUBCLASS) {
2963 return;
2964 }
2965 switch (event->event_code) {
2966 case KEV_DL_IF_DETACHING:
2967 break;
2968 case KEV_DL_LINK_OFF:
2969 case KEV_DL_LINK_ON:
2970 media_info = interface_media_info(port_ifp);
2971 break;
2972 default:
2973 return;
2974 }
2975 bond_lock();
2976 p = bond_lookup_port(port_ifp);
2977 if (p == NULL) {
2978 bond_unlock();
2979 return;
2980 }
2d21ac55
A
2981 ifb = p->po_bond;
2982 old_distributing_count = ifb->ifb_distributing_count;
91447636
A
2983 switch (event->event_code) {
2984 case KEV_DL_IF_DETACHING:
2d21ac55 2985 bond_remove_interface(ifb, p->po_ifp);
91447636
A
2986 break;
2987 case KEV_DL_LINK_OFF:
2988 case KEV_DL_LINK_ON:
2989 p->po_media_info = media_info;
2990 if (p->po_enabled) {
2991 bondport_link_status_changed(p);
2992 }
2993 break;
2994 }
2995 /* generate a link-event */
2d21ac55
A
2996 if (ifb->ifb_mode == IF_BOND_MODE_LACP) {
2997 if (ifbond_selection(ifb)) {
2998 event_code = (ifb->ifb_active_lag == NULL)
2999 ? KEV_DL_LINK_OFF
3000 : KEV_DL_LINK_ON;
3001 /* XXX need to take a reference on bond_ifp */
3002 bond_ifp = ifb->ifb_ifp;
3003 ifb->ifb_last_link_event = event_code;
3004 }
3005 else {
3006 event_code = (ifb->ifb_active_lag == NULL)
3007 ? KEV_DL_LINK_OFF
3008 : KEV_DL_LINK_ON;
3009 if (event_code != ifb->ifb_last_link_event) {
3010 if (g_bond->verbose) {
3011 timestamp_printf("%s: (event) generating LINK event\n",
3012 ifb->ifb_name);
3013 }
3014 bond_ifp = ifb->ifb_ifp;
3015 ifb->ifb_last_link_event = event_code;
3016 }
3017 }
91447636 3018 }
2d21ac55
A
3019 else {
3020 /*
3021 * if the distributing array membership changed from 0 <-> !0
3022 * generate a link event
3023 */
3024 if (old_distributing_count == 0
3025 && ifb->ifb_distributing_count != 0) {
3026 event_code = KEV_DL_LINK_ON;
3027 }
3028 else if (old_distributing_count != 0
3029 && ifb->ifb_distributing_count == 0) {
3030 event_code = KEV_DL_LINK_OFF;
3031 }
3032 if (event_code != 0 && event_code != ifb->ifb_last_link_event) {
3033 bond_ifp = ifb->ifb_ifp;
3034 ifb->ifb_last_link_event = event_code;
3035 }
3036 }
3037
91447636
A
3038 bond_unlock();
3039 if (bond_ifp != NULL) {
3040 interface_link_event(bond_ifp, event_code);
3041 }
3042 return;
3043}
3044
3045static void
b0d623f7 3046interface_link_event(struct ifnet * ifp, u_int32_t event_code)
91447636
A
3047{
3048 struct {
3049 struct kern_event_msg header;
b0d623f7 3050 u_int32_t unit;
91447636
A
3051 char if_name[IFNAMSIZ];
3052 } event;
3053
3054 event.header.total_size = sizeof(event);
3055 event.header.vendor_code = KEV_VENDOR_APPLE;
3056 event.header.kev_class = KEV_NETWORK_CLASS;
3057 event.header.kev_subclass = KEV_DL_SUBCLASS;
3058 event.header.event_code = event_code;
2d21ac55 3059 event.header.event_data[0] = ifnet_family(ifp);
b0d623f7 3060 event.unit = (u_int32_t) ifnet_unit(ifp);
2d21ac55
A
3061 strncpy(event.if_name, ifnet_name(ifp), IFNAMSIZ);
3062 ifnet_event(ifp, &event.header);
91447636
A
3063 return;
3064}
3065
3066/*
3067 * Function: bond_attach_protocol
3068 * Purpose:
3069 * Attach a DLIL protocol to the interface.
3070 *
3071 * The ethernet demux special cases to always return PF_BOND if the
3072 * interface is bonded. That means we receive all traffic from that
3073 * interface without passing any of the traffic to any other attached
3074 * protocol.
3075 */
3076static int
3077bond_attach_protocol(struct ifnet *ifp)
3078{
2d21ac55
A
3079 int error;
3080 struct ifnet_attach_proto_param reg;
91447636
A
3081
3082 bzero(&reg, sizeof(reg));
91447636
A
3083 reg.input = bond_input;
3084 reg.event = bond_event;
91447636 3085
2d21ac55 3086 error = ifnet_attach_protocol(ifp, PF_BOND, &reg);
91447636 3087 if (error) {
2d21ac55
A
3088 printf("bond over %s%d: ifnet_attach_protocol failed, %d\n",
3089 ifnet_name(ifp), ifnet_unit(ifp), error);
91447636
A
3090 }
3091 return (error);
3092}
3093
3094/*
3095 * Function: bond_detach_protocol
3096 * Purpose:
3097 * Detach our DLIL protocol from an interface
3098 */
3099static int
3100bond_detach_protocol(struct ifnet *ifp)
3101{
3102 int error;
3103
2d21ac55 3104 error = ifnet_detach_protocol(ifp, PF_BOND);
91447636 3105 if (error) {
2d21ac55
A
3106 printf("bond over %s%d: ifnet_detach_protocol failed, %d\n",
3107 ifnet_name(ifp), ifnet_unit(ifp), error);
91447636
A
3108 }
3109 return (error);
3110}
3111
3112/*
3113 * DLIL interface family functions
3114 */
2d21ac55
A
3115extern int ether_attach_inet(ifnet_t ifp, protocol_family_t protocol_family);
3116extern void ether_detach_inet(ifnet_t ifp, protocol_family_t protocol_family);
3117extern int ether_attach_inet6(ifnet_t ifp, protocol_family_t protocol_family);
3118extern void ether_detach_inet6(ifnet_t ifp, protocol_family_t protocol_family);
3119extern int ether_attach_at(ifnet_t ifp, protocol_family_t protocol_family);
3120extern void ether_detach_at(ifnet_t ifp, protocol_family_t protocol_family);
91447636
A
3121
3122__private_extern__ int
3123bond_family_init(void)
3124{
3125 int error=0;
91447636 3126
2d21ac55 3127 error = proto_register_plumber(PF_INET, APPLE_IF_FAM_BOND,
91447636
A
3128 ether_attach_inet,
3129 ether_detach_inet);
3130 if (error != 0) {
2d21ac55 3131 printf("bond: proto_register_plumber failed for AF_INET error=%d\n",
91447636
A
3132 error);
3133 goto done;
3134 }
2d21ac55
A
3135#if INET6
3136 error = proto_register_plumber(PF_INET6, APPLE_IF_FAM_BOND,
91447636
A
3137 ether_attach_inet6,
3138 ether_detach_inet6);
3139 if (error != 0) {
2d21ac55
A
3140 printf("bond: proto_register_plumber failed for AF_INET6 error=%d\n",
3141 error);
3142 goto done;
3143 }
3144#endif
b0d623f7 3145#if NETAT
2d21ac55
A
3146 error = proto_register_plumber(PF_APPLETALK, APPLE_IF_FAM_BOND,
3147 ether_attach_at,
3148 ether_detach_at);
3149 if (error != 0) {
3150 printf("bond: proto_register_plumber failed for AppleTalk error=%d\n",
91447636
A
3151 error);
3152 goto done;
3153 }
b0d623f7
A
3154#endif
3155 error = bond_clone_attach();
3156 if (error != 0) {
3157 printf("bond: proto_register_plumber failed bond_clone_attach error=%d\n",
3158 error);
3159 goto done;
3160 }
91447636
A
3161
3162 done:
3163 return (error);
3164}
3165/**
3166 **
3167 ** LACP routines:
3168 **
3169 **/
3170
3171/**
3172 ** LACP ifbond_list routines
3173 **/
3174static bondport_ref
3175ifbond_list_find_moved_port(bondport_ref rx_port,
3176 const lacp_actor_partner_tlv_ref atlv)
3177{
3178 ifbond_ref bond;
3179 bondport_ref p;
3180 partner_state_ref ps;
3181 LAG_info_ref ps_li;
3182
3183 TAILQ_FOREACH(bond, &g_bond->ifbond_list, ifb_bond_list) {
3184 TAILQ_FOREACH(p, &bond->ifb_port_list, po_port_list) {
3185
3186 if (rx_port == p) {
3187 /* no point in comparing against ourselves */
3188 continue;
3189 }
3190 if (p->po_receive_state != ReceiveState_PORT_DISABLED) {
3191 /* it's not clear that we should be checking this */
3192 continue;
3193 }
3194 ps = &p->po_partner_state;
3195 if (lacp_actor_partner_state_defaulted(ps->ps_state)) {
3196 continue;
3197 }
3198 ps_li = &ps->ps_lag_info;
3199 if (ps->ps_port == lacp_actor_partner_tlv_get_port(atlv)
3200 && bcmp(&ps_li->li_system, atlv->lap_system,
3201 sizeof(ps_li->li_system)) == 0) {
3202 if (g_bond->verbose) {
3203 timestamp_printf("System " EA_FORMAT
3204 " Port 0x%x moved from %s to %s\n",
3205 EA_LIST(&ps_li->li_system), ps->ps_port,
3206 bondport_get_name(p),
3207 bondport_get_name(rx_port));
3208 }
3209 return (p);
3210 }
3211 }
3212 }
3213 return (NULL);
3214}
3215
3216/**
3217 ** LACP ifbond, LAG routines
3218 **/
3219
3220static int
3221ifbond_selection(ifbond_ref bond)
3222{
3223 int all_ports_ready = 0;
3224 int active_media = 0;
3225 LAG_ref lag = NULL;
3226 int lag_changed = 0;
3227 bondport_ref p;
3228 int port_speed = 0;
3229
3230 lag = ifbond_find_best_LAG(bond, &active_media);
3231 if (lag != bond->ifb_active_lag) {
3232 if (bond->ifb_active_lag != NULL) {
3233 ifbond_deactivate_LAG(bond, bond->ifb_active_lag);
3234 bond->ifb_active_lag = NULL;
3235 }
3236 bond->ifb_active_lag = lag;
3237 if (lag != NULL) {
3238 ifbond_activate_LAG(bond, lag, active_media);
3239 }
3240 lag_changed = 1;
3241 }
3242 else if (lag != NULL) {
3243 if (lag->lag_active_media != active_media) {
3244 if (g_bond->verbose) {
3245 timestamp_printf("LAG PORT SPEED CHANGED from %d to %d\n",
3246 link_speed(lag->lag_active_media),
3247 link_speed(active_media));
3248 }
3249 ifbond_deactivate_LAG(bond, lag);
3250 ifbond_activate_LAG(bond, lag, active_media);
3251 lag_changed = 1;
3252 }
3253 }
3254 if (lag != NULL) {
3255 port_speed = link_speed(active_media);
3256 all_ports_ready = ifbond_all_ports_ready(bond);
3257 }
3258 TAILQ_FOREACH(p, &bond->ifb_port_list, po_port_list) {
3259 if (lag != NULL && p->po_lag == lag
3260 && media_speed(&p->po_media_info) == port_speed
3261 && (p->po_mux_state == MuxState_DETACHED
3262 || p->po_selected == SelectedState_SELECTED
3263 || p->po_selected == SelectedState_STANDBY)
3264 && bondport_aggregatable(p)) {
3265 if (bond->ifb_max_active > 0) {
3266 if (lag->lag_selected_port_count < bond->ifb_max_active) {
3267 if (p->po_selected == SelectedState_STANDBY
3268 || p->po_selected == SelectedState_UNSELECTED) {
3269 bondport_set_selected(p, SelectedState_SELECTED);
3270 }
3271 }
3272 else if (p->po_selected == SelectedState_UNSELECTED) {
3273 bondport_set_selected(p, SelectedState_STANDBY);
3274 }
3275 }
3276 else {
3277 bondport_set_selected(p, SelectedState_SELECTED);
3278 }
3279 }
3280 if (bondport_flags_selected_changed(p)) {
3281 bondport_flags_clear_selected_changed(p);
3282 bondport_mux_machine(p, LAEventSelectedChange, NULL);
3283 }
3284 if (all_ports_ready
3285 && bondport_flags_ready(p)
3286 && p->po_mux_state == MuxState_WAITING) {
3287 bondport_mux_machine(p, LAEventReady, NULL);
3288 }
3289 bondport_transmit_machine(p, LAEventStart, NULL);
3290 }
3291 return (lag_changed);
3292}
3293
3294static LAG_ref
3295ifbond_find_best_LAG(ifbond_ref bond, int * active_media)
3296{
3297 int best_active = 0;
3298 LAG_ref best_lag = NULL;
3299 int best_count = 0;
3300 int best_speed = 0;
3301 LAG_ref lag;
3302
3303 if (bond->ifb_active_lag != NULL) {
3304 best_lag = bond->ifb_active_lag;
3305 best_count = LAG_get_aggregatable_port_count(best_lag, &best_active);
3306 if (bond->ifb_max_active > 0
3307 && best_count > bond->ifb_max_active) {
3308 best_count = bond->ifb_max_active;
3309 }
3310 best_speed = link_speed(best_active);
3311 }
3312 TAILQ_FOREACH(lag, &bond->ifb_lag_list, lag_list) {
3313 int active;
3314 int count;
3315 int speed;
3316
3317 if (lag == bond->ifb_active_lag) {
3318 /* we've already computed it */
3319 continue;
3320 }
3321 count = LAG_get_aggregatable_port_count(lag, &active);
3322 if (count == 0) {
3323 continue;
3324 }
3325 if (bond->ifb_max_active > 0
3326 && count > bond->ifb_max_active) {
3327 /* if there's a limit, don't count extra links */
3328 count = bond->ifb_max_active;
3329 }
3330 speed = link_speed(active);
3331 if ((count * speed) > (best_count * best_speed)) {
3332 best_count = count;
3333 best_speed = speed;
3334 best_active = active;
3335 best_lag = lag;
3336 }
3337 }
3338 if (best_count == 0) {
3339 return (NULL);
3340 }
3341 *active_media = best_active;
3342 return (best_lag);
3343}
3344
3345static void
3346ifbond_deactivate_LAG(__unused ifbond_ref bond, LAG_ref lag)
3347{
3348 bondport_ref p;
3349
3350 TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3351 bondport_set_selected(p, SelectedState_UNSELECTED);
3352 }
3353 return;
3354}
3355
3356static void
3357ifbond_activate_LAG(ifbond_ref bond, LAG_ref lag, int active_media)
3358{
3359 int need = 0;
3360 bondport_ref p;
3361
3362 if (bond->ifb_max_active > 0) {
3363 need = bond->ifb_max_active;
3364 }
3365 lag->lag_active_media = active_media;
3366 TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3367 if (bondport_aggregatable(p) == 0) {
3368 bondport_set_selected(p, SelectedState_UNSELECTED);
3369 }
3370 else if (media_speed(&p->po_media_info) != link_speed(active_media)) {
3371 bondport_set_selected(p, SelectedState_UNSELECTED);
3372 }
3373 else if (p->po_mux_state == MuxState_DETACHED) {
3374 if (bond->ifb_max_active > 0) {
3375 if (need > 0) {
3376 bondport_set_selected(p, SelectedState_SELECTED);
3377 need--;
3378 }
3379 else {
3380 bondport_set_selected(p, SelectedState_STANDBY);
3381 }
3382 }
3383 else {
3384 bondport_set_selected(p, SelectedState_SELECTED);
3385 }
3386 }
3387 else {
3388 bondport_set_selected(p, SelectedState_UNSELECTED);
3389 }
3390 }
3391 return;
3392}
3393
3394#if 0
3395static void
3396ifbond_set_max_active(ifbond_ref bond, int max_active)
3397{
3398 LAG_ref lag = bond->ifb_active_lag;
3399
3400 bond->ifb_max_active = max_active;
3401 if (bond->ifb_max_active <= 0 || lag == NULL) {
3402 return;
3403 }
3404 if (lag->lag_selected_port_count > bond->ifb_max_active) {
3405 bondport_ref p;
3406 int remove_count;
3407
3408 remove_count = lag->lag_selected_port_count - bond->ifb_max_active;
3409 TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3410 if (p->po_selected == SelectedState_SELECTED) {
3411 bondport_set_selected(p, SelectedState_UNSELECTED);
3412 remove_count--;
3413 if (remove_count == 0) {
3414 break;
3415 }
3416 }
3417 }
3418 }
3419 return;
3420}
b0d623f7 3421#endif
91447636
A
3422
3423static int
3424ifbond_all_ports_ready(ifbond_ref bond)
3425{
3426 int ready = 0;
3427 bondport_ref p;
3428
3429 if (bond->ifb_active_lag == NULL) {
3430 return (0);
3431 }
3432 TAILQ_FOREACH(p, &bond->ifb_active_lag->lag_port_list, po_lag_port_list) {
3433 if (p->po_mux_state == MuxState_WAITING
3434 && p->po_selected == SelectedState_SELECTED) {
3435 if (bondport_flags_ready(p) == 0) {
3436 return (0);
3437 }
3438 }
3439 /* note that there was at least one ready port */
3440 ready = 1;
3441 }
3442 return (ready);
3443}
3444
3445static int
3446ifbond_all_ports_attached(ifbond_ref bond, bondport_ref this_port)
3447{
3448 bondport_ref p;
3449
3450 TAILQ_FOREACH(p, &bond->ifb_port_list, po_port_list) {
3451 if (this_port == p) {
3452 continue;
3453 }
3454 if (bondport_flags_mux_attached(p) == 0) {
3455 return (0);
3456 }
3457 }
3458 return (1);
3459}
3460
3461static LAG_ref
3462ifbond_get_LAG_matching_port(ifbond_ref bond, bondport_ref p)
3463{
3464 LAG_ref lag;
3465
3466 TAILQ_FOREACH(lag, &bond->ifb_lag_list, lag_list) {
3467 if (bcmp(&lag->lag_info, &p->po_partner_state.ps_lag_info,
3468 sizeof(lag->lag_info)) == 0) {
3469 return (lag);
3470 }
3471 }
3472 return (NULL);
3473}
3474
3475static int
3476LAG_get_aggregatable_port_count(LAG_ref lag, int * active_media)
3477{
3478 int active;
3479 int count;
3480 bondport_ref p;
3481 int speed;
3482
3483 active = 0;
3484 count = 0;
3485 speed = 0;
3486 TAILQ_FOREACH(p, &lag->lag_port_list, po_lag_port_list) {
3487 if (bondport_aggregatable(p)) {
3488 int this_speed;
3489
3490 this_speed = media_speed(&p->po_media_info);
3491 if (this_speed == 0) {
3492 continue;
3493 }
3494 if (this_speed > speed) {
3495 active = p->po_media_info.mi_active;
3496 speed = this_speed;
3497 count = 1;
3498 }
3499 else if (this_speed == speed) {
3500 count++;
3501 }
3502 }
3503 }
3504 *active_media = active;
3505 return (count);
3506}
3507
3508
3509/**
3510 ** LACP bondport routines
3511 **/
3512static void
3513bondport_link_status_changed(bondport_ref p)
3514{
3515 ifbond_ref bond = p->po_bond;
3516
3517 if (g_bond->verbose) {
3518 if (media_active(&p->po_media_info)) {
3519 timestamp_printf("[%s] Link UP %d Mbit/s %s duplex\n",
3520 bondport_get_name(p),
3521 media_speed(&p->po_media_info),
3522 media_full_duplex(&p->po_media_info)
3523 ? "full" : "half");
3524 }
3525 else {
3526 timestamp_printf("[%s] Link DOWN\n", bondport_get_name(p));
3527 }
3528 }
2d21ac55
A
3529 if (bond->ifb_mode == IF_BOND_MODE_LACP) {
3530 if (media_active(&p->po_media_info)
3531 && bond->ifb_active_lag != NULL
3532 && p->po_lag == bond->ifb_active_lag
3533 && p->po_selected != SelectedState_UNSELECTED) {
3534 if (media_speed(&p->po_media_info) != p->po_lag->lag_active_media) {
3535 if (g_bond->verbose) {
3536 timestamp_printf("[%s] Port speed %d differs from LAG %d\n",
3537 bondport_get_name(p),
3538 media_speed(&p->po_media_info),
3539 link_speed(p->po_lag->lag_active_media));
3540 }
3541 bondport_set_selected(p, SelectedState_UNSELECTED);
91447636 3542 }
2d21ac55
A
3543 }
3544 bondport_receive_machine(p, LAEventMediaChange, NULL);
3545 bondport_mux_machine(p, LAEventMediaChange, NULL);
3546 bondport_periodic_transmit_machine(p, LAEventMediaChange, NULL);
3547 }
3548 else {
3549 if (media_active(&p->po_media_info)) {
3550 bondport_enable_distributing(p);
3551 }
3552 else {
3553 bondport_disable_distributing(p);
91447636
A
3554 }
3555 }
91447636
A
3556 return;
3557}
3558
3559static int
3560bondport_aggregatable(bondport_ref p)
3561{
3562 partner_state_ref ps = &p->po_partner_state;
3563
3564 if (lacp_actor_partner_state_aggregatable(p->po_actor_state) == 0
3565 || lacp_actor_partner_state_aggregatable(ps->ps_state) == 0) {
3566 /* we and/or our partner are individual */
3567 return (0);
3568 }
3569 if (p->po_lag == NULL) {
3570 return (0);
3571 }
3572 switch (p->po_receive_state) {
3573 default:
3574 if (g_bond->verbose) {
3575 timestamp_printf("[%s] Port is not selectable\n",
3576 bondport_get_name(p));
3577 }
3578 return (0);
3579 case ReceiveState_CURRENT:
3580 case ReceiveState_EXPIRED:
3581 break;
3582 }
3583 return (1);
3584}
3585
3586static int
3587bondport_matches_LAG(bondport_ref p, LAG_ref lag)
3588{
3589 LAG_info_ref lag_li;
3590 partner_state_ref ps;
3591 LAG_info_ref ps_li;
3592
3593 ps = &p->po_partner_state;
3594 ps_li = &ps->ps_lag_info;
3595 lag_li = &lag->lag_info;
3596 if (ps_li->li_system_priority == lag_li->li_system_priority
3597 && ps_li->li_key == lag_li->li_key
3598 && (bcmp(&ps_li->li_system, &lag_li->li_system,
3599 sizeof(lag_li->li_system))
3600 == 0)) {
3601 return (1);
3602 }
3603 return (0);
3604}
3605
3606static int
3607bondport_remove_from_LAG(bondport_ref p)
3608{
3609 int active_lag = 0;
3610 ifbond_ref bond = p->po_bond;
3611 LAG_ref lag = p->po_lag;
3612
3613 if (lag == NULL) {
3614 return (0);
3615 }
3616 TAILQ_REMOVE(&lag->lag_port_list, p, po_lag_port_list);
3617 if (g_bond->verbose) {
3618 timestamp_printf("[%s] Removed from LAG (0x%04x," EA_FORMAT
3619 ",0x%04x)\n",
3620 bondport_get_name(p),
3621 lag->lag_info.li_system_priority,
3622 EA_LIST(&lag->lag_info.li_system),
3623 lag->lag_info.li_key);
3624 }
3625 p->po_lag = NULL;
3626 lag->lag_port_count--;
3627 if (lag->lag_port_count > 0) {
3628 return (bond->ifb_active_lag == lag);
3629 }
3630 if (g_bond->verbose) {
3631 timestamp_printf("Key 0x%04x: LAG Released (%04x," EA_FORMAT
3632 ",0x%04x)\n",
3633 bond->ifb_key,
3634 lag->lag_info.li_system_priority,
3635 EA_LIST(&lag->lag_info.li_system),
3636 lag->lag_info.li_key);
3637 }
3638 TAILQ_REMOVE(&bond->ifb_lag_list, lag, lag_list);
3639 if (bond->ifb_active_lag == lag) {
3640 bond->ifb_active_lag = NULL;
3641 active_lag = 1;
3642 }
3643 FREE(lag, M_BOND);
3644 return (active_lag);
3645}
3646
3647static void
3648bondport_add_to_LAG(bondport_ref p, LAG_ref lag)
3649{
3650 TAILQ_INSERT_TAIL(&lag->lag_port_list, p, po_lag_port_list);
3651 p->po_lag = lag;
3652 lag->lag_port_count++;
3653 if (g_bond->verbose) {
3654 timestamp_printf("[%s] Added to LAG (0x%04x," EA_FORMAT "0x%04x)\n",
3655 bondport_get_name(p),
3656 lag->lag_info.li_system_priority,
3657 EA_LIST(&lag->lag_info.li_system),
3658 lag->lag_info.li_key);
3659 }
3660 return;
3661}
3662
3663static void
3664bondport_assign_to_LAG(bondport_ref p)
3665{
3666 ifbond_ref bond = p->po_bond;
3667 LAG_ref lag;
3668
3669 if (lacp_actor_partner_state_defaulted(p->po_actor_state)) {
3670 bondport_remove_from_LAG(p);
3671 return;
3672 }
3673 lag = p->po_lag;
3674 if (lag != NULL) {
3675 if (bondport_matches_LAG(p, lag)) {
3676 /* still OK */
3677 return;
3678 }
3679 bondport_remove_from_LAG(p);
3680 }
3681 lag = ifbond_get_LAG_matching_port(bond, p);
3682 if (lag != NULL) {
3683 bondport_add_to_LAG(p, lag);
3684 return;
3685 }
3686 lag = (LAG_ref)_MALLOC(sizeof(*lag), M_BOND, M_WAITOK);
3687 TAILQ_INIT(&lag->lag_port_list);
3688 lag->lag_port_count = 0;
3689 lag->lag_selected_port_count = 0;
3690 lag->lag_info = p->po_partner_state.ps_lag_info;
3691 TAILQ_INSERT_TAIL(&bond->ifb_lag_list, lag, lag_list);
3692 if (g_bond->verbose) {
3693 timestamp_printf("Key 0x%04x: LAG Created (0x%04x," EA_FORMAT
3694 ",0x%04x)\n",
3695 bond->ifb_key,
3696 lag->lag_info.li_system_priority,
3697 EA_LIST(&lag->lag_info.li_system),
3698 lag->lag_info.li_key);
3699 }
3700 bondport_add_to_LAG(p, lag);
3701 return;
3702}
3703
3704static void
3705bondport_receive_lacpdu(bondport_ref p, lacpdu_ref in_lacpdu_p)
3706{
3707 bondport_ref moved_port;
3708
3709 moved_port
3710 = ifbond_list_find_moved_port(p, (const lacp_actor_partner_tlv_ref)
3711 &in_lacpdu_p->la_actor_tlv);
3712 if (moved_port != NULL) {
3713 bondport_receive_machine(moved_port, LAEventPortMoved, NULL);
3714 }
3715 bondport_receive_machine(p, LAEventPacket, in_lacpdu_p);
3716 bondport_mux_machine(p, LAEventPacket, in_lacpdu_p);
3717 bondport_periodic_transmit_machine(p, LAEventPacket, in_lacpdu_p);
3718 return;
3719}
3720
3721static void
3722bondport_set_selected(bondport_ref p, SelectedState s)
3723{
3724 if (s != p->po_selected) {
3725 ifbond_ref bond = p->po_bond;
3726 LAG_ref lag = p->po_lag;
3727
3728 bondport_flags_set_selected_changed(p);
3729 if (lag != NULL && bond->ifb_active_lag == lag) {
3730 if (p->po_selected == SelectedState_SELECTED) {
3731 lag->lag_selected_port_count--;
3732 }
3733 else if (s == SelectedState_SELECTED) {
3734 lag->lag_selected_port_count++;
3735 }
3736 if (g_bond->verbose) {
3737 timestamp_printf("[%s] SetSelected: %s (was %s)\n",
3738 bondport_get_name(p),
3739 SelectedStateString(s),
3740 SelectedStateString(p->po_selected));
3741 }
3742 }
3743 }
3744 p->po_selected = s;
3745 return;
3746}
3747
3748/**
3749 ** Receive machine
3750 **/
3751
3752static void
3753bondport_UpdateDefaultSelected(bondport_ref p)
3754{
3755 bondport_set_selected(p, SelectedState_UNSELECTED);
3756 return;
3757}
3758
3759static void
3760bondport_RecordDefault(bondport_ref p)
3761{
3762 bzero(&p->po_partner_state, sizeof(p->po_partner_state));
3763 p->po_actor_state
3764 = lacp_actor_partner_state_set_defaulted(p->po_actor_state);
3765 bondport_assign_to_LAG(p);
3766 return;
3767}
3768
3769static void
3770bondport_UpdateSelected(bondport_ref p, lacpdu_ref lacpdu_p)
3771{
3772 lacp_actor_partner_tlv_ref actor;
3773 partner_state_ref ps;
3774 LAG_info_ref ps_li;
3775
3776 /* compare the PDU's Actor information to our Partner state */
3777 actor = (lacp_actor_partner_tlv_ref)lacpdu_p->la_actor_tlv;
3778 ps = &p->po_partner_state;
3779 ps_li = &ps->ps_lag_info;
3780 if (lacp_actor_partner_tlv_get_port(actor) != ps->ps_port
3781 || (lacp_actor_partner_tlv_get_port_priority(actor)
3782 != ps->ps_port_priority)
3783 || bcmp(actor->lap_system, &ps_li->li_system, sizeof(ps_li->li_system))
3784 || (lacp_actor_partner_tlv_get_system_priority(actor)
3785 != ps_li->li_system_priority)
3786 || (lacp_actor_partner_tlv_get_key(actor) != ps_li->li_key)
3787 || (lacp_actor_partner_state_aggregatable(actor->lap_state)
3788 != lacp_actor_partner_state_aggregatable(ps->ps_state))) {
3789 bondport_set_selected(p, SelectedState_UNSELECTED);
3790 if (g_bond->verbose) {
3791 timestamp_printf("[%s] updateSelected UNSELECTED\n",
3792 bondport_get_name(p));
3793 }
3794 }
3795 return;
3796}
3797
3798static void
3799bondport_RecordPDU(bondport_ref p, lacpdu_ref lacpdu_p)
3800{
3801 lacp_actor_partner_tlv_ref actor;
3802 ifbond_ref bond = p->po_bond;
3803 int lacp_maintain = 0;
3804 partner_state_ref ps;
3805 lacp_actor_partner_tlv_ref partner;
3806 LAG_info_ref ps_li;
3807
3808 /* copy the PDU's Actor information into our Partner state */
3809 actor = (lacp_actor_partner_tlv_ref)lacpdu_p->la_actor_tlv;
3810 ps = &p->po_partner_state;
3811 ps_li = &ps->ps_lag_info;
3812 ps->ps_port = lacp_actor_partner_tlv_get_port(actor);
3813 ps->ps_port_priority = lacp_actor_partner_tlv_get_port_priority(actor);
3814 ps_li->li_system = *((lacp_system_ref)actor->lap_system);
3815 ps_li->li_system_priority
3816 = lacp_actor_partner_tlv_get_system_priority(actor);
3817 ps_li->li_key = lacp_actor_partner_tlv_get_key(actor);
3818 ps->ps_state = lacp_actor_partner_state_set_out_of_sync(actor->lap_state);
3819 p->po_actor_state
3820 = lacp_actor_partner_state_set_not_defaulted(p->po_actor_state);
3821
3822 /* compare the PDU's Partner information to our own information */
3823 partner = (lacp_actor_partner_tlv_ref)lacpdu_p->la_partner_tlv;
3824
3825 if (lacp_actor_partner_state_active_lacp(ps->ps_state)
3826 || (lacp_actor_partner_state_active_lacp(p->po_actor_state)
3827 && lacp_actor_partner_state_active_lacp(partner->lap_state))) {
3828 if (g_bond->verbose) {
3829 timestamp_printf("[%s] recordPDU: LACP will maintain\n",
3830 bondport_get_name(p));
3831 }
3832 lacp_maintain = 1;
3833 }
3834 if ((lacp_actor_partner_tlv_get_port(partner)
3835 == bondport_get_index(p))
3836 && lacp_actor_partner_tlv_get_port_priority(partner) == p->po_priority
3837 && bcmp(partner->lap_system, &g_bond->system,
3838 sizeof(g_bond->system)) == 0
3839 && (lacp_actor_partner_tlv_get_system_priority(partner)
3840 == g_bond->system_priority)
3841 && lacp_actor_partner_tlv_get_key(partner) == bond->ifb_key
3842 && (lacp_actor_partner_state_aggregatable(partner->lap_state)
3843 == lacp_actor_partner_state_aggregatable(p->po_actor_state))
3844 && lacp_actor_partner_state_in_sync(actor->lap_state)
3845 && lacp_maintain) {
3846 ps->ps_state = lacp_actor_partner_state_set_in_sync(ps->ps_state);
3847 if (g_bond->verbose) {
3848 timestamp_printf("[%s] recordPDU: LACP partner in sync\n",
3849 bondport_get_name(p));
3850 }
3851 }
3852 else if (lacp_actor_partner_state_aggregatable(actor->lap_state) == 0
3853 && lacp_actor_partner_state_in_sync(actor->lap_state)
3854 && lacp_maintain) {
3855 ps->ps_state = lacp_actor_partner_state_set_in_sync(ps->ps_state);
3856 if (g_bond->verbose) {
3857 timestamp_printf("[%s] recordPDU: LACP partner in sync (ind)\n",
3858 bondport_get_name(p));
3859 }
3860 }
3861 bondport_assign_to_LAG(p);
3862 return;
3863}
3864
3865static __inline__ lacp_actor_partner_state
3866updateNTTBits(lacp_actor_partner_state s)
3867{
3868 return (s & (LACP_ACTOR_PARTNER_STATE_LACP_ACTIVITY
3869 | LACP_ACTOR_PARTNER_STATE_LACP_TIMEOUT
3870 | LACP_ACTOR_PARTNER_STATE_AGGREGATION
3871 | LACP_ACTOR_PARTNER_STATE_SYNCHRONIZATION));
3872}
3873
3874static void
3875bondport_UpdateNTT(bondport_ref p, lacpdu_ref lacpdu_p)
3876{
3877 ifbond_ref bond = p->po_bond;
3878 lacp_actor_partner_tlv_ref partner;
3879
3880 /* compare the PDU's Actor information to our Partner state */
3881 partner = (lacp_actor_partner_tlv_ref)lacpdu_p->la_partner_tlv;
3882 if ((lacp_actor_partner_tlv_get_port(partner) != bondport_get_index(p))
3883 || lacp_actor_partner_tlv_get_port_priority(partner) != p->po_priority
3884 || bcmp(partner->lap_system, &g_bond->system, sizeof(g_bond->system))
3885 || (lacp_actor_partner_tlv_get_system_priority(partner)
3886 != g_bond->system_priority)
3887 || lacp_actor_partner_tlv_get_key(partner) != bond->ifb_key
3888 || (updateNTTBits(partner->lap_state)
3889 != updateNTTBits(p->po_actor_state))) {
3890 bondport_flags_set_ntt(p);
3891 if (g_bond->verbose) {
3892 timestamp_printf("[%s] updateNTT: Need To Transmit\n",
3893 bondport_get_name(p));
3894 }
3895 }
3896 return;
3897}
3898
3899static void
3900bondport_AttachMuxToAggregator(bondport_ref p)
3901{
3902 if (bondport_flags_mux_attached(p) == 0) {
3903 if (g_bond->verbose) {
3904 timestamp_printf("[%s] Attached Mux To Aggregator\n",
3905 bondport_get_name(p));
3906 }
3907 bondport_flags_set_mux_attached(p);
3908 }
3909 return;
3910}
3911
3912static void
3913bondport_DetachMuxFromAggregator(bondport_ref p)
3914{
3915 if (bondport_flags_mux_attached(p)) {
3916 if (g_bond->verbose) {
3917 timestamp_printf("[%s] Detached Mux From Aggregator\n",
3918 bondport_get_name(p));
3919 }
3920 bondport_flags_clear_mux_attached(p);
3921 }
3922 return;
3923}
3924
3925static void
3926bondport_enable_distributing(bondport_ref p)
3927{
3928 if (bondport_flags_distributing(p) == 0) {
3929 ifbond_ref bond = p->po_bond;
3930
3931 bond->ifb_distributing_array[bond->ifb_distributing_count++] = p;
3932 if (g_bond->verbose) {
3933 timestamp_printf("[%s] Distribution Enabled\n",
3934 bondport_get_name(p));
3935 }
3936 bondport_flags_set_distributing(p);
3937 }
3938 return;
3939}
3940
3941static void
3942bondport_disable_distributing(bondport_ref p)
3943{
3944 if (bondport_flags_distributing(p)) {
3945 bondport_ref * array;
3946 ifbond_ref bond;
3947 int count;
3948 int i;
3949
3950 bond = p->po_bond;
3951 array = bond->ifb_distributing_array;
3952 count = bond->ifb_distributing_count;
3953 for (i = 0; i < count; i++) {
3954 if (array[i] == p) {
3955 int j;
3956
3957 for (j = i; j < (count - 1); j++) {
3958 array[j] = array[j + 1];
3959 }
3960 break;
3961 }
3962 }
3963 bond->ifb_distributing_count--;
3964 if (g_bond->verbose) {
3965 timestamp_printf("[%s] Distribution Disabled\n",
3966 bondport_get_name(p));
3967 }
3968 bondport_flags_clear_distributing(p);
3969 }
3970 return;
3971}
3972
3973/**
3974 ** Receive machine functions
3975 **/
3976static void
3977bondport_receive_machine_initialize(bondport_ref p, LAEvent event,
3978 void * event_data);
3979static void
3980bondport_receive_machine_port_disabled(bondport_ref p, LAEvent event,
3981 void * event_data);
3982static void
3983bondport_receive_machine_expired(bondport_ref p, LAEvent event,
3984 void * event_data);
3985static void
3986bondport_receive_machine_lacp_disabled(bondport_ref p, LAEvent event,
3987 void * event_data);
3988static void
3989bondport_receive_machine_defaulted(bondport_ref p, LAEvent event,
3990 void * event_data);
3991static void
3992bondport_receive_machine_current(bondport_ref p, LAEvent event,
3993 void * event_data);
3994
3995static void
3996bondport_receive_machine_event(bondport_ref p, LAEvent event,
3997 void * event_data)
3998{
3999 switch (p->po_receive_state) {
4000 case ReceiveState_none:
4001 bondport_receive_machine_initialize(p, LAEventStart, NULL);
4002 break;
4003 case ReceiveState_INITIALIZE:
4004 bondport_receive_machine_initialize(p, event, event_data);
4005 break;
4006 case ReceiveState_PORT_DISABLED:
4007 bondport_receive_machine_port_disabled(p, event, event_data);
4008 break;
4009 case ReceiveState_EXPIRED:
4010 bondport_receive_machine_expired(p, event, event_data);
4011 break;
4012 case ReceiveState_LACP_DISABLED:
4013 bondport_receive_machine_lacp_disabled(p, event, event_data);
4014 break;
4015 case ReceiveState_DEFAULTED:
4016 bondport_receive_machine_defaulted(p, event, event_data);
4017 break;
4018 case ReceiveState_CURRENT:
4019 bondport_receive_machine_current(p, event, event_data);
4020 break;
4021 default:
4022 break;
4023 }
4024 return;
4025}
4026
4027static void
4028bondport_receive_machine(bondport_ref p, LAEvent event,
4029 void * event_data)
4030{
4031 switch (event) {
4032 case LAEventPacket:
4033 if (p->po_receive_state != ReceiveState_LACP_DISABLED) {
4034 bondport_receive_machine_current(p, event, event_data);
4035 }
4036 break;
4037 case LAEventMediaChange:
4038 if (media_active(&p->po_media_info)) {
4039 switch (p->po_receive_state) {
4040 case ReceiveState_PORT_DISABLED:
4041 case ReceiveState_LACP_DISABLED:
4042 bondport_receive_machine_port_disabled(p, LAEventMediaChange, NULL);
4043 break;
4044 default:
4045 break;
4046 }
4047 }
4048 else {
4049 bondport_receive_machine_port_disabled(p, LAEventStart, NULL);
4050 }
4051 break;
4052 default:
4053 bondport_receive_machine_event(p, event, event_data);
4054 break;
4055 }
4056 return;
4057}
4058
4059static void
4060bondport_receive_machine_initialize(bondport_ref p, LAEvent event,
4061 __unused void * event_data)
4062{
4063 switch (event) {
4064 case LAEventStart:
4065 devtimer_cancel(p->po_current_while_timer);
4066 if (g_bond->verbose) {
4067 timestamp_printf("[%s] Receive INITIALIZE\n",
4068 bondport_get_name(p));
4069 }
4070 p->po_receive_state = ReceiveState_INITIALIZE;
4071 bondport_set_selected(p, SelectedState_UNSELECTED);
4072 bondport_RecordDefault(p);
4073 p->po_actor_state
4074 = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4075 bondport_receive_machine_port_disabled(p, LAEventStart, NULL);
4076 break;
4077 default:
4078 break;
4079 }
4080 return;
4081}
4082
4083static void
4084bondport_receive_machine_port_disabled(bondport_ref p, LAEvent event,
4085 __unused void * event_data)
4086{
4087 partner_state_ref ps;
4088
4089 switch (event) {
4090 case LAEventStart:
4091 devtimer_cancel(p->po_current_while_timer);
4092 if (g_bond->verbose) {
4093 timestamp_printf("[%s] Receive PORT_DISABLED\n",
4094 bondport_get_name(p));
4095 }
4096 p->po_receive_state = ReceiveState_PORT_DISABLED;
4097 ps = &p->po_partner_state;
4098 ps->ps_state = lacp_actor_partner_state_set_out_of_sync(ps->ps_state);
4099 /* FALL THROUGH */
4100 case LAEventMediaChange:
4101 if (media_active(&p->po_media_info)) {
4102 if (media_full_duplex(&p->po_media_info)) {
4103 bondport_receive_machine_expired(p, LAEventStart, NULL);
4104 }
4105 else {
4106 bondport_receive_machine_lacp_disabled(p, LAEventStart, NULL);
4107 }
4108 }
4109 else if (p->po_selected == SelectedState_SELECTED) {
4110 struct timeval tv;
4111
4112 if (g_bond->verbose) {
4113 timestamp_printf("[%s] Receive PORT_DISABLED: "
4114 "link timer started\n",
4115 bondport_get_name(p));
4116 }
4117 tv.tv_sec = 1;
4118 tv.tv_usec = 0;
4119 devtimer_set_relative(p->po_current_while_timer, tv,
4120 (devtimer_timeout_func)
4121 bondport_receive_machine_port_disabled,
4122 (void *)LAEventTimeout, NULL);
4123 }
4124 else if (p->po_selected == SelectedState_STANDBY) {
4125 bondport_set_selected(p, SelectedState_UNSELECTED);
4126 }
4127 break;
4128 case LAEventTimeout:
4129 if (p->po_selected == SelectedState_SELECTED) {
4130 if (g_bond->verbose) {
4131 timestamp_printf("[%s] Receive PORT_DISABLED: "
4132 "link timer completed, marking UNSELECTED\n",
4133 bondport_get_name(p));
4134 }
4135 bondport_set_selected(p, SelectedState_UNSELECTED);
4136 }
4137 break;
4138 case LAEventPortMoved:
4139 bondport_receive_machine_initialize(p, LAEventStart, NULL);
4140 break;
4141 default:
4142 break;
4143 }
4144 return;
4145}
4146
4147static void
4148bondport_receive_machine_expired(bondport_ref p, LAEvent event,
4149 __unused void * event_data)
4150{
4151 lacp_actor_partner_state s;
4152 struct timeval tv;
4153
4154 switch (event) {
4155 case LAEventStart:
4156 devtimer_cancel(p->po_current_while_timer);
4157 if (g_bond->verbose) {
4158 timestamp_printf("[%s] Receive EXPIRED\n",
4159 bondport_get_name(p));
4160 }
4161 p->po_receive_state = ReceiveState_EXPIRED;
4162 s = p->po_partner_state.ps_state;
4163 s = lacp_actor_partner_state_set_out_of_sync(s);
4164 s = lacp_actor_partner_state_set_short_timeout(s);
4165 p->po_partner_state.ps_state = s;
4166 p->po_actor_state
4167 = lacp_actor_partner_state_set_expired(p->po_actor_state);
4168 /* start current_while timer */
4169 tv.tv_sec = LACP_SHORT_TIMEOUT_TIME;
4170 tv.tv_usec = 0;
4171 devtimer_set_relative(p->po_current_while_timer, tv,
4172 (devtimer_timeout_func)
4173 bondport_receive_machine_expired,
4174 (void *)LAEventTimeout, NULL);
4175
4176 break;
4177 case LAEventTimeout:
4178 bondport_receive_machine_defaulted(p, LAEventStart, NULL);
4179 break;
4180 default:
4181 break;
4182 }
4183 return;
4184}
4185
4186static void
4187bondport_receive_machine_lacp_disabled(bondport_ref p, LAEvent event,
4188 __unused void * event_data)
4189{
4190 partner_state_ref ps;
4191 switch (event) {
4192 case LAEventStart:
4193 devtimer_cancel(p->po_current_while_timer);
4194 if (g_bond->verbose) {
4195 timestamp_printf("[%s] Receive LACP_DISABLED\n",
4196 bondport_get_name(p));
4197 }
4198 p->po_receive_state = ReceiveState_LACP_DISABLED;
4199 bondport_set_selected(p, SelectedState_UNSELECTED);
4200 bondport_RecordDefault(p);
4201 ps = &p->po_partner_state;
4202 ps->ps_state = lacp_actor_partner_state_set_individual(ps->ps_state);
4203 p->po_actor_state
4204 = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4205 break;
4206 default:
4207 break;
4208 }
4209 return;
4210}
4211
4212static void
4213bondport_receive_machine_defaulted(bondport_ref p, LAEvent event,
4214 __unused void * event_data)
4215{
4216 switch (event) {
4217 case LAEventStart:
4218 devtimer_cancel(p->po_current_while_timer);
4219 if (g_bond->verbose) {
4220 timestamp_printf("[%s] Receive DEFAULTED\n",
4221 bondport_get_name(p));
4222 }
4223 p->po_receive_state = ReceiveState_DEFAULTED;
4224 bondport_UpdateDefaultSelected(p);
4225 bondport_RecordDefault(p);
4226 p->po_actor_state
4227 = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4228 break;
4229 default:
4230 break;
4231 }
4232 return;
4233}
4234
4235static void
4236bondport_receive_machine_current(bondport_ref p, LAEvent event,
4237 void * event_data)
4238{
4239 partner_state_ref ps;
4240 struct timeval tv;
4241
4242 switch (event) {
4243 case LAEventPacket:
4244 devtimer_cancel(p->po_current_while_timer);
4245 if (g_bond->verbose) {
4246 timestamp_printf("[%s] Receive CURRENT\n",
4247 bondport_get_name(p));
4248 }
4249 p->po_receive_state = ReceiveState_CURRENT;
4250 bondport_UpdateSelected(p, event_data);
4251 bondport_UpdateNTT(p, event_data);
4252 bondport_RecordPDU(p, event_data);
4253 p->po_actor_state
4254 = lacp_actor_partner_state_set_not_expired(p->po_actor_state);
4255 bondport_assign_to_LAG(p);
4256 /* start current_while timer */
4257 ps = &p->po_partner_state;
4258 if (lacp_actor_partner_state_short_timeout(ps->ps_state)) {
4259 tv.tv_sec = LACP_SHORT_TIMEOUT_TIME;
4260 }
4261 else {
4262 tv.tv_sec = LACP_LONG_TIMEOUT_TIME;
4263 }
4264 tv.tv_usec = 0;
4265 devtimer_set_relative(p->po_current_while_timer, tv,
4266 (devtimer_timeout_func)
4267 bondport_receive_machine_current,
4268 (void *)LAEventTimeout, NULL);
4269 break;
4270 case LAEventTimeout:
4271 bondport_receive_machine_expired(p, LAEventStart, NULL);
4272 break;
4273 default:
4274 break;
4275 }
4276 return;
4277}
4278
4279/**
4280 ** Periodic Transmission machine
4281 **/
4282
4283static void
4284bondport_periodic_transmit_machine(bondport_ref p, LAEvent event,
4285 __unused void * event_data)
4286{
4287 int interval;
4288 partner_state_ref ps;
4289 struct timeval tv;
4290
4291 switch (event) {
4292 case LAEventStart:
4293 if (g_bond->verbose) {
4294 timestamp_printf("[%s] periodic_transmit Start\n",
4295 bondport_get_name(p));
4296 }
4297 /* FALL THROUGH */
4298 case LAEventMediaChange:
4299 devtimer_cancel(p->po_periodic_timer);
4300 p->po_periodic_interval = 0;
4301 if (media_active(&p->po_media_info) == 0
4302 || media_full_duplex(&p->po_media_info) == 0) {
4303 break;
4304 }
4305 case LAEventPacket:
4306 /* Neither Partner nor Actor are LACP Active, no periodic tx */
4307 ps = &p->po_partner_state;
4308 if (lacp_actor_partner_state_active_lacp(p->po_actor_state) == 0
4309 && (lacp_actor_partner_state_active_lacp(ps->ps_state)
4310 == 0)) {
4311 devtimer_cancel(p->po_periodic_timer);
4312 p->po_periodic_interval = 0;
4313 break;
4314 }
4315 if (lacp_actor_partner_state_short_timeout(ps->ps_state)) {
4316 interval = LACP_FAST_PERIODIC_TIME;
4317 }
4318 else {
4319 interval = LACP_SLOW_PERIODIC_TIME;
4320 }
4321 if (p->po_periodic_interval != interval) {
4322 if (interval == LACP_FAST_PERIODIC_TIME
4323 && p->po_periodic_interval == LACP_SLOW_PERIODIC_TIME) {
4324 if (g_bond->verbose) {
4325 timestamp_printf("[%s] periodic_transmit:"
4326 " Need To Transmit\n",
4327 bondport_get_name(p));
4328 }
4329 bondport_flags_set_ntt(p);
4330 }
4331 p->po_periodic_interval = interval;
4332 tv.tv_usec = 0;
4333 tv.tv_sec = interval;
4334 devtimer_set_relative(p->po_periodic_timer, tv,
4335 (devtimer_timeout_func)
4336 bondport_periodic_transmit_machine,
4337 (void *)LAEventTimeout, NULL);
4338 if (g_bond->verbose) {
4339 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4340 bondport_get_name(p),
4341 p->po_periodic_interval);
4342 }
4343 }
4344 break;
4345 case LAEventTimeout:
4346 bondport_flags_set_ntt(p);
4347 tv.tv_sec = p->po_periodic_interval;
4348 tv.tv_usec = 0;
4349 devtimer_set_relative(p->po_periodic_timer, tv, (devtimer_timeout_func)
4350 bondport_periodic_transmit_machine,
4351 (void *)LAEventTimeout, NULL);
4352 if (g_bond->verbose > 1) {
4353 timestamp_printf("[%s] Periodic Transmission Timer: %d secs\n",
4354 bondport_get_name(p), p->po_periodic_interval);
4355 }
4356 break;
4357 default:
4358 break;
4359 }
4360 return;
4361}
4362
4363/**
4364 ** Transmit machine
4365 **/
4366static int
4367bondport_can_transmit(bondport_ref p, int32_t current_secs,
b0d623f7 4368 __darwin_time_t * next_secs)
91447636
A
4369{
4370 if (p->po_last_transmit_secs != current_secs) {
4371 p->po_last_transmit_secs = current_secs;
4372 p->po_n_transmit = 0;
4373 }
4374 if (p->po_n_transmit < LACP_PACKET_RATE) {
4375 p->po_n_transmit++;
4376 return (1);
4377 }
4378 if (next_secs != NULL) {
4379 *next_secs = current_secs + 1;
4380 }
4381 return (0);
4382}
4383
4384static void
4385bondport_transmit_machine(bondport_ref p, LAEvent event,
4386 void * event_data)
4387{
4388 lacp_actor_partner_tlv_ref aptlv;
4389 lacp_collector_tlv_ref ctlv;
4390 struct timeval next_tick_time = {0, 0};
4391 lacpdu_ref out_lacpdu_p;
4392 packet_buffer_ref pkt;
4393 partner_state_ref ps;
4394 LAG_info_ref ps_li;
4395
4396 switch (event) {
4397 case LAEventTimeout:
4398 case LAEventStart:
4399 if (p->po_periodic_interval == 0 || bondport_flags_ntt(p) == 0) {
4400 break;
4401 }
2d21ac55 4402 if (event_data == TRANSMIT_MACHINE_TX_IMMEDIATE) {
91447636
A
4403 /* we're going away, transmit the packet no matter what */
4404 }
4405 else if (bondport_can_transmit(p, devtimer_current_secs(),
4406 &next_tick_time.tv_sec) == 0) {
4407 if (devtimer_enabled(p->po_transmit_timer)) {
4408 if (g_bond->verbose > 0) {
4409 timestamp_printf("[%s] Transmit Timer Already Set\n",
4410 bondport_get_name(p));
4411 }
4412 }
4413 else {
4414 devtimer_set_absolute(p->po_transmit_timer, next_tick_time,
4415 (devtimer_timeout_func)
4416 bondport_transmit_machine,
4417 (void *)LAEventTimeout, NULL);
4418 if (g_bond->verbose > 0) {
4419 timestamp_printf("[%s] Transmit Timer Deadline %d secs\n",
4420 bondport_get_name(p),
2d21ac55 4421 (int)next_tick_time.tv_sec);
91447636
A
4422 }
4423 }
4424 break;
4425 }
4426 if (g_bond->verbose > 0) {
4427 if (event == LAEventTimeout) {
4428 timestamp_printf("[%s] Transmit Timer Complete\n",
4429 bondport_get_name(p));
4430 }
4431 }
4432 pkt = packet_buffer_allocate(sizeof(*out_lacpdu_p));
4433 if (pkt == NULL) {
4434 printf("[%s] Transmit: failed to allocate packet buffer\n",
4435 bondport_get_name(p));
4436 break;
4437 }
4438 out_lacpdu_p = (lacpdu_ref)packet_buffer_byteptr(pkt);
4439 bzero(out_lacpdu_p, sizeof(*out_lacpdu_p));
4440 out_lacpdu_p->la_subtype = IEEE8023AD_SLOW_PROTO_SUBTYPE_LACP;
4441 out_lacpdu_p->la_version = LACPDU_VERSION_1;
4442
4443 /* Actor */
4444 aptlv = (lacp_actor_partner_tlv_ref)out_lacpdu_p->la_actor_tlv;
4445 aptlv->lap_tlv_type = LACPDU_TLV_TYPE_ACTOR;
4446 aptlv->lap_length = LACPDU_ACTOR_TLV_LENGTH;
4447 *((lacp_system_ref)aptlv->lap_system) = g_bond->system;
4448 lacp_actor_partner_tlv_set_system_priority(aptlv,
4449 g_bond->system_priority);
4450 lacp_actor_partner_tlv_set_port_priority(aptlv, p->po_priority);
4451 lacp_actor_partner_tlv_set_port(aptlv, bondport_get_index(p));
4452 lacp_actor_partner_tlv_set_key(aptlv, p->po_bond->ifb_key);
4453 aptlv->lap_state = p->po_actor_state;
4454
4455 /* Partner */
4456 aptlv = (lacp_actor_partner_tlv_ref)out_lacpdu_p->la_partner_tlv;
4457 aptlv->lap_tlv_type = LACPDU_TLV_TYPE_PARTNER;
4458 aptlv->lap_length = LACPDU_PARTNER_TLV_LENGTH;
4459 ps = &p->po_partner_state;
4460 ps_li = &ps->ps_lag_info;
4461 lacp_actor_partner_tlv_set_port(aptlv, ps->ps_port);
4462 lacp_actor_partner_tlv_set_port_priority(aptlv, ps->ps_port_priority);
4463 *((lacp_system_ref)aptlv->lap_system) = ps_li->li_system;
4464 lacp_actor_partner_tlv_set_system_priority(aptlv,
4465 ps_li->li_system_priority);
4466 lacp_actor_partner_tlv_set_key(aptlv, ps_li->li_key);
4467 aptlv->lap_state = ps->ps_state;
4468
4469 /* Collector */
4470 ctlv = (lacp_collector_tlv_ref)out_lacpdu_p->la_collector_tlv;
4471 ctlv->lac_tlv_type = LACPDU_TLV_TYPE_COLLECTOR;
4472 ctlv->lac_length = LACPDU_COLLECTOR_TLV_LENGTH;
4473
4474 bondport_slow_proto_transmit(p, pkt);
4475 bondport_flags_clear_ntt(p);
4476 if (g_bond->verbose > 0) {
4477 timestamp_printf("[%s] Transmit Packet %d\n",
4478 bondport_get_name(p), p->po_n_transmit);
4479 }
4480 break;
4481 default:
4482 break;
4483 }
4484 return;
4485}
4486
4487/**
4488 ** Mux machine functions
4489 **/
4490
4491static void
4492bondport_mux_machine_detached(bondport_ref p, LAEvent event,
4493 void * event_data);
4494static void
4495bondport_mux_machine_waiting(bondport_ref p, LAEvent event,
4496 void * event_data);
4497static void
4498bondport_mux_machine_attached(bondport_ref p, LAEvent event,
4499 void * event_data);
4500
4501static void
4502bondport_mux_machine_collecting_distributing(bondport_ref p, LAEvent event,
4503 void * event_data);
4504
4505static void
4506bondport_mux_machine(bondport_ref p, LAEvent event, void * event_data)
4507{
4508 switch (p->po_mux_state) {
4509 case MuxState_none:
4510 bondport_mux_machine_detached(p, LAEventStart, NULL);
4511 break;
4512 case MuxState_DETACHED:
4513 bondport_mux_machine_detached(p, event, event_data);
4514 break;
4515 case MuxState_WAITING:
4516 bondport_mux_machine_waiting(p, event, event_data);
4517 break;
4518 case MuxState_ATTACHED:
4519 bondport_mux_machine_attached(p, event, event_data);
4520 break;
4521 case MuxState_COLLECTING_DISTRIBUTING:
4522 bondport_mux_machine_collecting_distributing(p, event, event_data);
4523 break;
4524 default:
4525 break;
4526 }
4527 return;
4528}
4529
4530static void
4531bondport_mux_machine_detached(bondport_ref p, LAEvent event,
4532 __unused void * event_data)
4533{
4534 lacp_actor_partner_state s;
4535
4536 switch (event) {
4537 case LAEventStart:
4538 devtimer_cancel(p->po_wait_while_timer);
4539 if (g_bond->verbose) {
4540 timestamp_printf("[%s] Mux DETACHED\n",
4541 bondport_get_name(p));
4542 }
4543 p->po_mux_state = MuxState_DETACHED;
4544 bondport_flags_clear_ready(p);
4545 bondport_DetachMuxFromAggregator(p);
4546 bondport_disable_distributing(p);
4547 s = p->po_actor_state;
4548 s = lacp_actor_partner_state_set_out_of_sync(s);
4549 s = lacp_actor_partner_state_set_not_collecting(s);
4550 s = lacp_actor_partner_state_set_not_distributing(s);
4551 p->po_actor_state = s;
4552 bondport_flags_set_ntt(p);
4553 break;
4554 case LAEventSelectedChange:
4555 case LAEventPacket:
4556 case LAEventMediaChange:
4557 if (p->po_selected == SelectedState_SELECTED
4558 || p->po_selected == SelectedState_STANDBY) {
4559 bondport_mux_machine_waiting(p, LAEventStart, NULL);
4560 }
4561 break;
4562 default:
4563 break;
4564 }
4565 return;
4566}
4567
4568static void
4569bondport_mux_machine_waiting(bondport_ref p, LAEvent event,
4570 __unused void * event_data)
4571{
4572 struct timeval tv;
4573
4574 switch (event) {
4575 case LAEventStart:
4576 devtimer_cancel(p->po_wait_while_timer);
4577 if (g_bond->verbose) {
4578 timestamp_printf("[%s] Mux WAITING\n",
4579 bondport_get_name(p));
4580 }
4581 p->po_mux_state = MuxState_WAITING;
4582 /* FALL THROUGH */
4583 default:
4584 case LAEventSelectedChange:
4585 if (p->po_selected == SelectedState_UNSELECTED) {
4586 bondport_mux_machine_detached(p, LAEventStart, NULL);
4587 break;
4588 }
4589 if (p->po_selected == SelectedState_STANDBY) {
4590 devtimer_cancel(p->po_wait_while_timer);
4591 /* wait until state changes to SELECTED */
4592 if (g_bond->verbose) {
4593 timestamp_printf("[%s] Mux WAITING: Standby\n",
4594 bondport_get_name(p));
4595 }
4596 break;
4597 }
4598 if (bondport_flags_ready(p)) {
4599 if (g_bond->verbose) {
4600 timestamp_printf("[%s] Mux WAITING: Port is already ready\n",
4601 bondport_get_name(p));
4602 }
4603 break;
4604 }
4605 if (devtimer_enabled(p->po_wait_while_timer)) {
4606 if (g_bond->verbose) {
4607 timestamp_printf("[%s] Mux WAITING: Timer already set\n",
4608 bondport_get_name(p));
4609 }
4610 break;
4611 }
4612 if (ifbond_all_ports_attached(p->po_bond, p)) {
4613 devtimer_cancel(p->po_wait_while_timer);
4614 if (g_bond->verbose) {
4615 timestamp_printf("[%s] Mux WAITING: No waiting\n",
4616 bondport_get_name(p));
4617 }
4618 bondport_flags_set_ready(p);
4619 goto no_waiting;
4620 }
4621 if (g_bond->verbose) {
4622 timestamp_printf("[%s] Mux WAITING: 2 seconds\n",
4623 bondport_get_name(p));
4624 }
4625 tv.tv_sec = LACP_AGGREGATE_WAIT_TIME;
4626 tv.tv_usec = 0;
4627 devtimer_set_relative(p->po_wait_while_timer, tv,
4628 (devtimer_timeout_func)
4629 bondport_mux_machine_waiting,
4630 (void *)LAEventTimeout, NULL);
4631 break;
4632 case LAEventTimeout:
4633 if (g_bond->verbose) {
4634 timestamp_printf("[%s] Mux WAITING: Ready\n",
4635 bondport_get_name(p));
4636 }
4637 bondport_flags_set_ready(p);
4638 break;
4639 case LAEventReady:
4640 no_waiting:
4641 if (bondport_flags_ready(p)){
4642 if (g_bond->verbose) {
4643 timestamp_printf("[%s] Mux WAITING: All Ports Ready\n",
4644 bondport_get_name(p));
4645 }
4646 bondport_mux_machine_attached(p, LAEventStart, NULL);
4647 break;
4648 }
4649 break;
4650 }
4651 return;
4652}
4653
4654static void
4655bondport_mux_machine_attached(bondport_ref p, LAEvent event,
4656 __unused void * event_data)
4657{
4658 lacp_actor_partner_state s;
4659
4660 switch (event) {
4661 case LAEventStart:
4662 devtimer_cancel(p->po_wait_while_timer);
4663 if (g_bond->verbose) {
4664 timestamp_printf("[%s] Mux ATTACHED\n",
4665 bondport_get_name(p));
4666 }
4667 p->po_mux_state = MuxState_ATTACHED;
4668 bondport_AttachMuxToAggregator(p);
4669 s = p->po_actor_state;
4670 s = lacp_actor_partner_state_set_in_sync(s);
4671 s = lacp_actor_partner_state_set_not_collecting(s);
4672 s = lacp_actor_partner_state_set_not_distributing(s);
4673 bondport_disable_distributing(p);
4674 p->po_actor_state = s;
4675 bondport_flags_set_ntt(p);
4676 /* FALL THROUGH */
4677 default:
4678 switch (p->po_selected) {
4679 case SelectedState_SELECTED:
4680 s = p->po_partner_state.ps_state;
4681 if (lacp_actor_partner_state_in_sync(s)) {
4682 bondport_mux_machine_collecting_distributing(p, LAEventStart,
4683 NULL);
4684 }
4685 break;
4686 default:
4687 bondport_mux_machine_detached(p, LAEventStart, NULL);
4688 break;
4689 }
4690 break;
4691 }
4692 return;
4693}
4694
4695static void
4696bondport_mux_machine_collecting_distributing(bondport_ref p,
4697 LAEvent event,
4698 __unused void * event_data)
4699{
4700 lacp_actor_partner_state s;
4701
4702 switch (event) {
4703 case LAEventStart:
4704 devtimer_cancel(p->po_wait_while_timer);
4705 if (g_bond->verbose) {
4706 timestamp_printf("[%s] Mux COLLECTING_DISTRIBUTING\n",
4707 bondport_get_name(p));
4708 }
4709 p->po_mux_state = MuxState_COLLECTING_DISTRIBUTING;
4710 bondport_enable_distributing(p);
4711 s = p->po_actor_state;
4712 s = lacp_actor_partner_state_set_collecting(s);
4713 s = lacp_actor_partner_state_set_distributing(s);
4714 p->po_actor_state = s;
4715 bondport_flags_set_ntt(p);
4716 /* FALL THROUGH */
4717 default:
4718 s = p->po_partner_state.ps_state;
4719 if (lacp_actor_partner_state_in_sync(s) == 0) {
4720 bondport_mux_machine_attached(p, LAEventStart, NULL);
4721 break;
4722 }
4723 switch (p->po_selected) {
4724 case SelectedState_UNSELECTED:
4725 case SelectedState_STANDBY:
4726 bondport_mux_machine_attached(p, LAEventStart, NULL);
4727 break;
4728 default:
4729 break;
4730 }
4731 break;
4732 }
4733 return;
4734}