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