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