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