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