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