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