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