X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8f6c56a50524aa785f7e596d52dddfb331e18961..4d15aeb193b2c68f1d38666c317f8d3734f5f083:/bsd/net/if_bond.c diff --git a/bsd/net/if_bond.c b/bsd/net/if_bond.c index d5b5e3abd..34f6e03d4 100644 --- a/bsd/net/if_bond.c +++ b/bsd/net/if_bond.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2014 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -78,8 +79,6 @@ #include #include -extern int dlil_input_packet(struct ifnet *, struct mbuf *, char *); - static struct ether_addr slow_proto_multicast = { IEEE8023AD_SLOW_PROTO_MULTICAST }; @@ -104,8 +103,6 @@ my_lck_grp_alloc_init(const char * grp_name) lck_grp_attr_t * grp_attrs; grp_attrs = lck_grp_attr_alloc_init(); - lck_grp_attr_setdefault(grp_attrs); - lck_grp_attr_setdefault(grp_attrs); grp = lck_grp_alloc_init(grp_name, grp_attrs); lck_grp_attr_free(grp_attrs); return (grp); @@ -118,7 +115,6 @@ my_lck_mtx_alloc_init(lck_grp_t * lck_grp) lck_mtx_t * lck_mtx; lck_attrs = lck_attr_alloc_init(); - lck_attr_setdefault(lck_attrs); lck_mtx = lck_mtx_alloc_init(lck_grp, lck_attrs); lck_attr_free(lck_attrs); return (lck_mtx); @@ -204,7 +200,7 @@ typedef struct partner_state_s { struct ifbond_s { TAILQ_ENTRY(ifbond_s) ifb_bond_list; int ifb_flags; - UInt32 ifb_retain_count; + SInt32 ifb_retain_count; char ifb_name[IFNAMSIZ]; struct ifnet * ifb_ifp; bpf_packet_func ifb_bpf_input; @@ -219,6 +215,8 @@ struct ifbond_s { struct ifmultiaddr * ifb_ifma_slow_proto; bondport_ref * ifb_distributing_array; int ifb_distributing_count; + int ifb_last_link_event; + int ifb_mode; /* LACP, STATIC */ }; struct media_info { @@ -304,26 +302,6 @@ struct bondport_s { static int bond_get_status(ifbond_ref ifb, struct if_bond_req * ibr_p, user_addr_t datap); -static __inline__ int -ifbond_flags_promisc(ifbond_ref ifb) -{ - return ((ifb->ifb_flags & IFBF_PROMISC) != 0); -} - -static __inline__ void -ifbond_flags_set_promisc(ifbond_ref ifb) -{ - ifb->ifb_flags |= IFBF_PROMISC; - return; -} - -static __inline__ void -ifbond_flags_clear_promisc(ifbond_ref ifb) -{ - ifb->ifb_flags &= ~IFBF_PROMISC; - return; -} - static __inline__ int ifbond_flags_if_detaching(ifbond_ref ifb) { @@ -343,20 +321,6 @@ ifbond_flags_lladdr(ifbond_ref ifb) return ((ifb->ifb_flags & IFBF_LLADDR) != 0); } -static __inline__ void -ifbond_flags_set_lladdr(ifbond_ref ifb) -{ - ifb->ifb_flags |= IFBF_LLADDR; - return; -} - -static __inline__ void -ifbond_flags_clear_lladdr(ifbond_ref ifb) -{ - ifb->ifb_flags &= ~IFBF_LLADDR; - return; -} - static __inline__ int ifbond_flags_change_in_progress(ifbond_ref ifb) { @@ -514,11 +478,15 @@ packet_buffer_allocate(int length) /* leave room for ethernet header */ size = length + sizeof(struct ether_header); if (size > (int)MHLEN) { - /* XXX doesn't handle large payloads */ - printf("bond: packet_buffer_allocate size %d > max %d\n", size, MHLEN); - return (NULL); + if (size > (int)MCLBYTES) { + printf("bond: packet_buffer_allocate size %d > max %u\n", + size, MCLBYTES); + return (NULL); + } + m = m_getcl(M_WAITOK, MT_DATA, M_PKTHDR); + } else { + m = m_gethdr(M_WAITOK, MT_DATA); } - m = m_gethdr(M_WAITOK, MT_DATA); if (m == NULL) { return (NULL); } @@ -559,6 +527,8 @@ bondport_periodic_transmit_machine(bondport_ref p, LAEvent event, /** ** Transmit machine **/ +#define TRANSMIT_MACHINE_TX_IMMEDIATE ((void *)1) + static void bondport_transmit_machine(bondport_ref p, LAEvent event, void * event_data); @@ -635,18 +605,21 @@ bondport_disable_distributing(bondport_ref p); static __inline__ int bondport_collecting(bondport_ref p) { - return (lacp_actor_partner_state_collecting(p->po_actor_state)); + if (p->po_bond->ifb_mode == IF_BOND_MODE_LACP) { + return (lacp_actor_partner_state_collecting(p->po_actor_state)); + } + return (TRUE); } /** ** bond interface/dlil specific routines **/ -static int bond_clone_create(struct if_clone *, int); -static void bond_clone_destroy(struct ifnet *); -static int bond_input(struct mbuf *m, char *frame_header, struct ifnet *ifp, - u_long protocol_family, int sync_ok); +static int bond_clone_create(struct if_clone *, u_int32_t, void *); +static int bond_clone_destroy(struct ifnet *); +static int bond_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t m, + char *frame_header); static int bond_output(struct ifnet *ifp, struct mbuf *m); -static int bond_ioctl(struct ifnet *ifp, u_int32_t cmd, void * addr); +static int bond_ioctl(struct ifnet *ifp, u_long cmd, void * addr); static int bond_set_bpf_tap(struct ifnet * ifp, bpf_tap_mode mode, bpf_packet_func func); static int bond_attach_protocol(struct ifnet *ifp); @@ -661,7 +634,7 @@ static struct if_clone bond_cloner = IF_CLONE_INITIALIZER(BONDNAME, bond_clone_destroy, 0, BOND_MAXUNIT); -static void interface_link_event(struct ifnet * ifp, u_long event_code); +static void interface_link_event(struct ifnet * ifp, u_int32_t event_code); static int siocsifmtu(struct ifnet * ifp, int mtu) @@ -670,7 +643,7 @@ siocsifmtu(struct ifnet * ifp, int mtu) bzero(&ifr, sizeof(ifr)); ifr.ifr_mtu = mtu; - return (dlil_ioctl(0, ifp, SIOCSIFMTU, (caddr_t)&ifr)); + return (ifnet_ioctl(ifp, 0, SIOCSIFMTU, &ifr)); } static int @@ -680,7 +653,7 @@ siocgifdevmtu(struct ifnet * ifp, struct ifdevmtu * ifdm_p) int error; bzero(&ifr, sizeof(ifr)); - error = dlil_ioctl(0, ifp, SIOCGIFDEVMTU, (caddr_t)&ifr); + error = ifnet_ioctl(ifp, 0, SIOCGIFDEVMTU, &ifr); if (error == 0) { *ifdm_p = ifr.ifr_devmtu; } @@ -719,8 +692,9 @@ ifbond_release(ifbond_ref ifb) printf("ifbond_release(%s) removing multicast\n", ifb->ifb_name); } - (void)if_delmultiaddr(ifb->ifb_ifma_slow_proto, 0); - ifma_release(ifb->ifb_ifma_slow_proto); + (void) if_delmulti_anon(ifb->ifb_ifma_slow_proto->ifma_ifp, + ifb->ifb_ifma_slow_proto->ifma_addr); + IFMA_REMREF(ifb->ifb_ifma_slow_proto); } if (ifb->ifb_distributing_array != NULL) { FREE(ifb->ifb_distributing_array, M_BOND); @@ -827,6 +801,10 @@ link_speed(int active) case IFM_10G_SR: case IFM_10G_LR: return (10000); + case IFM_2500_T: + return (2500); + case IFM_5000_T: + return (5000); } } @@ -859,7 +837,7 @@ interface_media_info(struct ifnet * ifp) bzero(&mi, sizeof(mi)); bzero(&ifmr, sizeof(ifmr)); - if (dlil_ioctl(0, ifp, SIOCGIFMEDIA, (caddr_t)&ifmr) == 0) { + if (ifnet_ioctl(ifp, 0, SIOCGIFMEDIA, &ifmr) == 0) { if (ifmr.ifm_count != 0) { mi.mi_status = ifmr.ifm_status; mi.mi_active = ifmr.ifm_active; @@ -868,33 +846,6 @@ interface_media_info(struct ifnet * ifp) return (mi); } -/** - ** interface utility functions - **/ -static __inline__ struct ifaddr * -ifindex_get_ifaddr(int i) -{ - if (i > if_index || i == 0) { - return (NULL); - } - return (ifnet_addrs[i - 1]); -} - -static __inline__ struct ifaddr * -ifp_get_ifaddr(struct ifnet * ifp) -{ - return (ifindex_get_ifaddr(ifp->if_index)); -} - -static __inline__ struct sockaddr_dl * -ifp_get_sdl(struct ifnet * ifp) -{ - struct ifaddr * ifa; - - ifa = ifp_get_ifaddr(ifp); - return ((struct sockaddr_dl *)(ifa->ifa_addr)); -} - static int if_siflladdr(struct ifnet * ifp, const struct ether_addr * ea_p) { @@ -907,11 +858,7 @@ if_siflladdr(struct ifnet * ifp, const struct ether_addr * ea_p) ifr.ifr_addr.sa_family = AF_UNSPEC; ifr.ifr_addr.sa_len = ETHER_ADDR_LEN; ether_addr_copy(ifr.ifr_addr.sa_data, ea_p); -#if 0 - snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s%d", ifp->if_name, - ifp->if_unit); -#endif 0 - return (dlil_ioctl(0, ifp, SIOCSIFLLADDR, (caddr_t)&ifr)); + return (ifnet_ioctl(ifp, 0, SIOCSIFLLADDR, &ifr)); } /** @@ -923,17 +870,13 @@ bond_globals_create(lacp_system_priority sys_pri, { bond_globals_ref b; - b = _MALLOC(sizeof(*b), M_BOND, M_WAITOK); + b = _MALLOC(sizeof(*b), M_BOND, M_WAITOK | M_ZERO); if (b == NULL) { return (NULL); } - bzero(b, sizeof(*b)); TAILQ_INIT(&b->ifbond_list); b->system = *sys; b->system_priority = sys_pri; -#if 0 - b->verbose = 1; -#endif 0 return (b); } @@ -958,7 +901,6 @@ bond_globals_init(void) for (i = 0; i < 4; i++) { char ifname[IFNAMSIZ+1]; snprintf(ifname, sizeof(ifname), "en%d", i); - /* XXX ifunit() needs to return a reference on the ifp */ ifp = ifunit(ifname); if (ifp != NULL) { break; @@ -966,8 +908,7 @@ bond_globals_init(void) } b = NULL; if (ifp != NULL) { - b = bond_globals_create(0x8000, - (lacp_system_ref)LLADDR(ifp_get_sdl(ifp))); + b = bond_globals_create(0x8000, (lacp_system_ref)IF_LLADDR(ifp)); } bond_lock(); if (g_bond != NULL) { @@ -1066,7 +1007,7 @@ bond_setmulti(struct ifnet * ifp) bondport_ref p; bond_lock(); - ifb = ifp->if_private; + ifb = ifnet_softc(ifp); if (ifb == NULL || ifbond_flags_if_detaching(ifb) || TAILQ_EMPTY(&ifb->ifb_port_list)) { bond_unlock(); @@ -1091,25 +1032,28 @@ bond_setmulti(struct ifnet * ifp) if (error != 0) { printf("bond_setmulti(%s): " "multicast_list_program(%s%d) failed, %d\n", - ifb->ifb_name, port_ifp->if_name, - port_ifp->if_unit, error); + ifb->ifb_name, ifnet_name(port_ifp), + ifnet_unit(port_ifp), error); result = error; } } bond_lock(); signal_done: - ifbond_release(ifb); ifbond_signal(ifb, "bond_setmulti"); bond_unlock(); + ifbond_release(ifb); return (result); } -static void +static int bond_clone_attach(void) { - if_clone_attach(&bond_cloner); + int error; + + if ((error = if_clone_attach(&bond_cloner)) != 0) + return error; bond_lock_init(); - return; + return 0; } static int @@ -1128,8 +1072,7 @@ ifbond_add_slow_proto_multicast(ifbond_ref ifb) sdl.sdl_nlen = 0; sdl.sdl_alen = sizeof(slow_proto_multicast); bcopy(&slow_proto_multicast, sdl.sdl_data, sizeof(slow_proto_multicast)); - error = if_addmulti(ifb->ifb_ifp, (struct sockaddr *)&sdl, - &ifma); + error = if_addmulti_anon(ifb->ifb_ifp, (struct sockaddr *)&sdl, &ifma); if (error == 0) { ifb->ifb_ifma_slow_proto = ifma; } @@ -1137,84 +1080,92 @@ ifbond_add_slow_proto_multicast(ifbond_ref ifb) } static int -bond_clone_create(struct if_clone * ifc, int unit) +bond_clone_create(struct if_clone * ifc, u_int32_t unit, __unused void *params) { - int error; - ifbond_ref ifb; - struct ifnet * ifp; - - error = bond_globals_init(); - if (error != 0) { - return (error); - } - - ifb = _MALLOC(sizeof(ifbond), M_BOND, M_WAITOK); - if (ifb == NULL) { - return (ENOMEM); - } - bzero(ifb, sizeof(*ifb)); - - ifbond_retain(ifb); - TAILQ_INIT(&ifb->ifb_port_list); - TAILQ_INIT(&ifb->ifb_lag_list); - ifb->ifb_key = unit + 1; - - /* use the interface name as the unique id for ifp recycle */ - if ((u_long)snprintf(ifb->ifb_name, sizeof(ifb->ifb_name), "%s%d", - ifc->ifc_name, unit) >= sizeof(ifb->ifb_name)) { - ifbond_release(ifb); - return (EINVAL); - } - error = dlil_if_acquire(APPLE_IF_FAM_BOND, - ifb->ifb_name, - strlen(ifb->ifb_name), - &ifp); - if (error) { - ifbond_release(ifb); - return (error); - } - ifb->ifb_ifp = ifp; - ifp->if_name = ifc->ifc_name; - ifp->if_unit = unit; - ifp->if_family = APPLE_IF_FAM_BOND; - ifp->if_private = NULL; - ifp->if_ioctl = bond_ioctl; - ifp->if_set_bpf_tap = bond_set_bpf_tap; - ifp->if_free = bond_if_free; - ifp->if_output = bond_output; - ifp->if_hwassist = 0; - ifp->if_addrlen = ETHER_ADDR_LEN; - ifp->if_baudrate = 0; - ifp->if_type = IFT_IEEE8023ADLAG; - ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX; - ifp->if_mtu = 0; - - /* XXX ethernet specific */ - ifp->if_broadcast.length = ETHER_ADDR_LEN; - bcopy(etherbroadcastaddr, ifp->if_broadcast.u.buffer, ETHER_ADDR_LEN); - - error = dlil_if_attach(ifp); - if (error != 0) { - dlil_if_release(ifp); - ifbond_release(ifb); - return (error); - } - error = ifbond_add_slow_proto_multicast(ifb); - if (error != 0) { - printf("bond_clone_create(%s): " - "failed to add slow_proto multicast, %d\n", - ifb->ifb_name, error); - } - - /* attach as ethernet */ - bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); - - bond_lock(); - ifp->if_private = ifb; - TAILQ_INSERT_HEAD(&g_bond->ifbond_list, ifb, ifb_bond_list); - bond_unlock(); - - return (0); + int error; + ifbond_ref ifb; + ifnet_t ifp; + struct ifnet_init_eparams bond_init; + + error = bond_globals_init(); + if (error != 0) { + return (error); + } + + ifb = _MALLOC(sizeof(ifbond), M_BOND, M_WAITOK | M_ZERO); + if (ifb == NULL) { + return (ENOMEM); + } + + ifbond_retain(ifb); + TAILQ_INIT(&ifb->ifb_port_list); + TAILQ_INIT(&ifb->ifb_lag_list); + ifb->ifb_key = unit + 1; + + /* use the interface name as the unique id for ifp recycle */ + if ((u_int32_t)snprintf(ifb->ifb_name, sizeof(ifb->ifb_name), "%s%d", + ifc->ifc_name, unit) >= sizeof(ifb->ifb_name)) { + ifbond_release(ifb); + return (EINVAL); + } + + bzero(&bond_init, sizeof(bond_init)); + bond_init.ver = IFNET_INIT_CURRENT_VERSION; + bond_init.len = sizeof (bond_init); + bond_init.flags = IFNET_INIT_LEGACY; + bond_init.uniqueid = ifb->ifb_name; + bond_init.uniqueid_len = strlen(ifb->ifb_name); + bond_init.name = ifc->ifc_name; + bond_init.unit = unit; + bond_init.family = IFNET_FAMILY_BOND; + bond_init.type = IFT_IEEE8023ADLAG; + bond_init.output = bond_output; + bond_init.demux = ether_demux; + bond_init.add_proto = ether_add_proto; + bond_init.del_proto = ether_del_proto; + bond_init.check_multi = ether_check_multi; + bond_init.framer_extended = ether_frameout_extended; + bond_init.ioctl = bond_ioctl; + bond_init.set_bpf_tap = bond_set_bpf_tap; + bond_init.detach = bond_if_free; + bond_init.broadcast_addr = etherbroadcastaddr; + bond_init.broadcast_len = ETHER_ADDR_LEN; + bond_init.softc = ifb; + error = ifnet_allocate_extended(&bond_init, &ifp); + + if (error) { + ifbond_release(ifb); + return (error); + } + + ifb->ifb_ifp = ifp; + ifnet_set_offload(ifp, 0); + ifnet_set_addrlen(ifp, ETHER_ADDR_LEN); /* XXX ethernet specific */ + ifnet_set_flags(ifp, IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX, 0xffff); + ifnet_set_baudrate(ifp, 0); + ifnet_set_mtu(ifp, 0); + + error = ifnet_attach(ifp, NULL); + if (error != 0) { + ifnet_release(ifp); + ifbond_release(ifb); + return (error); + } + error = ifbond_add_slow_proto_multicast(ifb); + if (error != 0) { + printf("bond_clone_create(%s): " + "failed to add slow_proto multicast, %d\n", + ifb->ifb_name, error); + } + + /* attach as ethernet */ + bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header)); + + bond_lock(); + TAILQ_INSERT_HEAD(&g_bond->ifbond_list, ifb, ifb_bond_list); + bond_unlock(); + + return (0); } static void @@ -1249,36 +1200,34 @@ bond_if_detach(struct ifnet * ifp) { int error; - error = dlil_if_detach(ifp); - if (error != DLIL_WAIT_FOR_FREE) { - if (error) { - printf("bond_if_detach %s%d: dlil_if_detach failed, %d\n", - ifp->if_name, ifp->if_unit, error); - } - bond_if_free(ifp); + error = ifnet_detach(ifp); + if (error) { + printf("bond_if_detach %s%d: ifnet_detach failed, %d\n", + ifnet_name(ifp), ifnet_unit(ifp), error); } + return; } -static void +static int bond_clone_destroy(struct ifnet * ifp) { ifbond_ref ifb; bond_lock(); - ifb = ifp->if_private; - if (ifb == NULL || ifp->if_type != IFT_IEEE8023ADLAG) { + ifb = ifnet_softc(ifp); + if (ifb == NULL || ifnet_type(ifp) != IFT_IEEE8023ADLAG) { bond_unlock(); - return; + return 0; } if (ifbond_flags_if_detaching(ifb)) { bond_unlock(); - return; + return 0; } bond_remove(ifb); bond_unlock(); bond_if_detach(ifp); - return; + return 0; } static int @@ -1287,7 +1236,7 @@ bond_set_bpf_tap(struct ifnet * ifp, bpf_tap_mode mode, bpf_packet_func func) ifbond_ref ifb; bond_lock(); - ifb = ifp->if_private; + ifb = ifnet_softc(ifp); if (ifb == NULL || ifbond_flags_if_detaching(ifb)) { bond_unlock(); return (ENODEV); @@ -1328,7 +1277,7 @@ ether_header_hash(struct ether_header * eh_p) } static struct mbuf * -S_mbuf_skip_to_offset(struct mbuf * m, long * offset) +S_mbuf_skip_to_offset(struct mbuf * m, int32_t * offset) { int len; @@ -1361,7 +1310,7 @@ make_uint32(u_char c0, u_char c1, u_char c2, u_char c3) #endif /* BYTE_ORDER == LITTLE_ENDIAN */ static int -S_mbuf_copy_uint32(struct mbuf * m, long offset, uint32_t * val) +S_mbuf_copy_uint32(struct mbuf * m, int32_t offset, uint32_t * val) { struct mbuf * current; u_char * current_data; @@ -1411,7 +1360,7 @@ ip_header_hash(struct mbuf * m) struct in_addr ip_dst; struct in_addr ip_src; u_char ip_p; - long offset; + int32_t offset; struct mbuf * orig_m = m; /* find the IP protocol field relative to the start of the packet */ @@ -1452,7 +1401,7 @@ ipv6_header_hash(struct mbuf * m) { u_char * data; int i; - long offset; + int32_t offset; struct mbuf * orig_m = m; uint32_t * scan; uint32_t val; @@ -1496,6 +1445,8 @@ bond_output(struct ifnet * ifp, struct mbuf * m) uint32_t h; ifbond_ref ifb; struct ifnet * port_ifp = NULL; + int err; + struct flowadv adv = { FADV_SUCCESS }; if (m == 0) { return (0); @@ -1504,8 +1455,8 @@ bond_output(struct ifnet * ifp, struct mbuf * m) m_freem(m); return (0); } - if (m->m_pkthdr.socket_id != 0) { - h = m->m_pkthdr.socket_id; + if (m->m_pkthdr.pkt_flowid != 0) { + h = m->m_pkthdr.pkt_flowid; } else { struct ether_header * eh_p; @@ -1524,7 +1475,7 @@ bond_output(struct ifnet * ifp, struct mbuf * m) } } bond_lock(); - ifb = ifp->if_private; + ifb = ifnet_softc(ifp); if (ifb == NULL || ifbond_flags_if_detaching(ifb) || ifb->ifb_distributing_count == 0) { goto done; @@ -1543,7 +1494,17 @@ bond_output(struct ifnet * ifp, struct mbuf * m) } bond_bpf_output(ifp, m, bpf_func); - return (dlil_output(port_ifp, 0, m, NULL, NULL, 1)); + err = dlil_output(port_ifp, PF_BOND, m, NULL, NULL, 1, &adv); + + if (err == 0) { + if (adv.code == FADV_FLOW_CONTROLLED) { + err = EQFULL; + } else if (adv.code == FADV_SUSPENDED) { + err = EQSUSPENDED; + } + } + + return (err); done: bond_unlock(); @@ -1582,11 +1543,12 @@ static void bond_receive_lacpdu(struct mbuf * m, struct ifnet * port_ifp) { struct ifnet * bond_ifp = NULL; + ifbond_ref ifb; int event_code = 0; bondport_ref p; bond_lock(); - if ((port_ifp->if_eflags & IFEF_BOND) == 0) { + if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) { goto done; } p = bond_lookup_port(port_ifp); @@ -1596,13 +1558,31 @@ bond_receive_lacpdu(struct mbuf * m, struct ifnet * port_ifp) if (p->po_enabled == 0) { goto done; } + ifb = p->po_bond; + if (ifb->ifb_mode != IF_BOND_MODE_LACP) { + goto done; + } bondport_receive_lacpdu(p, (lacpdu_ref)m->m_data); - if (ifbond_selection(p->po_bond)) { - event_code = (p->po_bond->ifb_active_lag == NULL) + if (ifbond_selection(ifb)) { + event_code = (ifb->ifb_active_lag == NULL) ? KEV_DL_LINK_OFF : KEV_DL_LINK_ON; /* XXX need to take a reference on bond_ifp */ - bond_ifp = p->po_bond->ifb_ifp; + bond_ifp = ifb->ifb_ifp; + ifb->ifb_last_link_event = event_code; + } + else { + event_code = (ifb->ifb_active_lag == NULL) + ? KEV_DL_LINK_OFF + : KEV_DL_LINK_ON; + if (event_code != ifb->ifb_last_link_event) { + if (g_bond->verbose) { + timestamp_printf("%s: (receive) generating LINK event\n", + ifb->ifb_name); + } + bond_ifp = ifb->ifb_ifp; + ifb->ifb_last_link_event = event_code; + } } done: @@ -1625,12 +1605,13 @@ bond_receive_la_marker_pdu(struct mbuf * m, struct ifnet * port_ifp) goto failed; } bond_lock(); - if ((port_ifp->if_eflags & IFEF_BOND) == 0) { + if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) { bond_unlock(); goto failed; } p = bond_lookup_port(port_ifp); - if (p == NULL || p->po_enabled == 0) { + if (p == NULL || p->po_enabled == 0 + || p->po_bond->ifb_mode != IF_BOND_MODE_LACP) { bond_unlock(); goto failed; } @@ -1646,8 +1627,8 @@ bond_receive_la_marker_pdu(struct mbuf * m, struct ifnet * port_ifp) } static int -bond_input(struct mbuf * m, char * frame_header, struct ifnet * port_ifp, - __unused u_long protocol_family, __unused int sync_ok) +bond_input(ifnet_t port_ifp, __unused protocol_family_t protocol, mbuf_t m, + char * frame_header) { bpf_packet_func bpf_func; const struct ether_header * eh_p; @@ -1708,7 +1689,7 @@ bond_input(struct mbuf * m, char * frame_header, struct ifnet * port_ifp, } } bond_lock(); - if ((port_ifp->if_eflags & IFEF_BOND) == 0) { + if ((ifnet_eflags(port_ifp) & IFEF_BOND) == 0) { goto done; } p = bond_lookup_port(port_ifp); @@ -1733,7 +1714,8 @@ bond_input(struct mbuf * m, char * frame_header, struct ifnet * port_ifp, } m->m_pkthdr.rcvif = ifp; bond_bpf_input(ifp, m, eh_p, bpf_func); - dlil_input_packet(ifp, m, frame_header); + m->m_pkthdr.pkt_hdr = frame_header; + dlil_input_packet_list(ifp, m); return 0; done: @@ -1751,7 +1733,7 @@ bondport_get_name(bondport_ref p) static __inline__ int bondport_get_index(bondport_ref p) { - return (p->po_ifp->if_index); + return (ifnet_index(p->po_ifp)); } static void @@ -1765,7 +1747,7 @@ bondport_slow_proto_transmit(bondport_ref p, packet_buffer_ref buf) bcopy(&slow_proto_multicast, &eh_p->ether_dhost, sizeof(eh_p->ether_dhost)); bcopy(&p->po_saved_addr, eh_p->ether_shost, sizeof(eh_p->ether_shost)); eh_p->ether_type = htons(IEEE8023AD_SLOW_PROTO_ETHERTYPE); - error = dlil_output(p->po_ifp, 0, buf, NULL, NULL, 1); + error = ifnet_output_raw(p->po_ifp, PF_BOND, buf); if (error != 0) { printf("bondport_slow_proto_transmit(%s) failed %d\n", bondport_get_name(p), error); @@ -1797,6 +1779,20 @@ bondport_timer_process_func(devtimer_ref timer, : KEV_DL_LINK_ON; /* XXX need to take a reference on bond_ifp */ bond_ifp = p->po_bond->ifb_ifp; + p->po_bond->ifb_last_link_event = event_code; + } + else { + event_code = (p->po_bond->ifb_active_lag == NULL) + ? KEV_DL_LINK_OFF + : KEV_DL_LINK_ON; + if (event_code != p->po_bond->ifb_last_link_event) { + if (g_bond->verbose) { + timestamp_printf("%s: (timer) generating LINK event\n", + p->po_bond->ifb_name); + } + bond_ifp = p->po_bond->ifb_ifp; + p->po_bond->ifb_last_link_event = event_code; + } } devtimer_release(timer); bond_unlock(); @@ -1824,15 +1820,14 @@ bondport_create(struct ifnet * port_ifp, lacp_port_priority priority, lacp_actor_partner_state s; *ret_error = 0; - p = _MALLOC(sizeof(*p), M_BOND, M_WAITOK); + p = _MALLOC(sizeof(*p), M_BOND, M_WAITOK | M_ZERO); if (p == NULL) { *ret_error = ENOMEM; return (NULL); } - bzero(p, sizeof(*p)); multicast_list_init(&p->po_multicast); - if ((u_long)snprintf(p->po_name, sizeof(p->po_name), "%s%d", - port_ifp->if_name, port_ifp->if_unit) + if ((u_int32_t)snprintf(p->po_name, sizeof(p->po_name), "%s%d", + ifnet_name(port_ifp), ifnet_unit(port_ifp)) >= sizeof(p->po_name)) { printf("if_bond: name too large\n"); *ret_error = EINVAL; @@ -1845,7 +1840,7 @@ bondport_create(struct ifnet * port_ifp, lacp_port_priority priority, goto failed; } /* remember the current interface MTU so it can be restored */ - p->po_devmtu.ifdm_current = port_ifp->if_mtu; + p->po_devmtu.ifdm_current = ifnet_mtu(port_ifp); p->po_ifp = port_ifp; p->po_media_info = interface_media_info(port_ifp); p->po_current_while_timer = devtimer_create(bondport_timer_process_func, p); @@ -1911,6 +1906,20 @@ bondport_invalidate_timers(bondport_ref p) devtimer_invalidate(p->po_transmit_timer); } +/* + * Function: bondport_cancel_timers + * Purpose: + * Cancel all of the timers for the bondport. + */ +static void +bondport_cancel_timers(bondport_ref p) +{ + devtimer_cancel(p->po_current_while_timer); + devtimer_cancel(p->po_periodic_timer); + devtimer_cancel(p->po_wait_while_timer); + devtimer_cancel(p->po_transmit_timer); +} + static void bondport_free(bondport_ref p) { @@ -1931,8 +1940,8 @@ bondport_free(bondport_ref p) static __inline__ int bond_device_mtu(struct ifnet * ifp, ifbond_ref ifb) { - return (((int)ifp->if_mtu > ifb->ifb_altmtu) - ? (int)ifp->if_mtu : ifb->ifb_altmtu); + return (((int)ifnet_mtu(ifp) > ifb->ifb_altmtu) + ? (int)ifnet_mtu(ifp) : ifb->ifb_altmtu); } static int @@ -1941,12 +1950,11 @@ bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp) int devmtu; int error = 0; int event_code = 0; + int first = FALSE; ifbond_ref ifb; - struct sockaddr_dl * ifb_sdl; bondport_ref * new_array = NULL; bondport_ref * old_array = NULL; bondport_ref p; - struct sockaddr_dl * port_sdl; int progress = 0; /* pre-allocate space for new port */ @@ -1955,7 +1963,7 @@ bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp) return (error); } bond_lock(); - ifb = (ifbond_ref)ifp->if_private; + ifb = (ifbond_ref)ifnet_softc(ifp); if (ifb == NULL || ifbond_flags_if_detaching(ifb)) { bond_unlock(); bondport_free(p); @@ -1990,7 +1998,7 @@ bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp) goto signal_done; } ifnet_lock_exclusive(port_ifp); - if ((port_ifp->if_eflags & (IFEF_VLAN | IFEF_BOND)) != 0) { + if ((ifnet_eflags(port_ifp) & (IFEF_VLAN | IFEF_BOND)) != 0) { /* interface already has VLAN's, or is part of bond */ ifnet_lock_done(port_ifp); error = EBUSY; @@ -1998,49 +2006,60 @@ bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp) } /* mark the interface busy */ + /* can't use ifnet_set_eflags because that takes the lock */ port_ifp->if_eflags |= IFEF_BOND; ifnet_lock_done(port_ifp); - port_sdl = ifp_get_sdl(port_ifp); - ifb_sdl = ifp_get_sdl(ifp); - if (TAILQ_EMPTY(&ifb->ifb_port_list)) { - ifp->if_hwassist = port_ifp->if_hwassist; - ifp->if_flags |= IFF_RUNNING; + ifnet_set_offload(ifp, ifnet_offload(port_ifp)); + ifnet_set_flags(ifp, IFF_RUNNING, IFF_RUNNING); if (ifbond_flags_lladdr(ifb) == FALSE) { - /* first port added to bond determines bond's ethernet address */ - ether_addr_copy(LLADDR(ifb_sdl), LLADDR(port_sdl)); - ifb_sdl->sdl_type = IFT_ETHER; - ifb_sdl->sdl_alen = ETHER_ADDR_LEN; + first = TRUE; } } else { - if (ifp->if_hwassist != port_ifp->if_hwassist) { + ifnet_offload_t ifp_offload; + ifnet_offload_t port_ifp_offload; + + ifp_offload = ifnet_offload(ifp); + port_ifp_offload = ifnet_offload(port_ifp); + if (ifp_offload != port_ifp_offload) { + ifnet_offload_t offload; + + offload = ifp_offload & port_ifp_offload; printf("bond_add_interface(%s, %s) " - "hwassist values don't match 0x%x != 0x%x\n", + "hwassist values don't match 0x%x != 0x%x, using 0x%x instead\n", ifb->ifb_name, bondport_get_name(p), - ifp->if_hwassist, port_ifp->if_hwassist); + ifp_offload, port_ifp_offload, offload); /* * XXX * if the bond has VLAN's, we can't simply change the hwassist * field behind its back: this needs work */ - ifp->if_hwassist = 0; + ifnet_set_offload(ifp, offload); } } p->po_bond = ifb; /* remember the port's ethernet address so it can be restored */ - ether_addr_copy(&p->po_saved_addr, LLADDR(port_sdl)); + ether_addr_copy(&p->po_saved_addr, IF_LLADDR(port_ifp)); /* add it to the list of ports */ TAILQ_INSERT_TAIL(&ifb->ifb_port_list, p, po_port_list); ifb->ifb_port_count++; /* set the default MTU */ - if (ifp->if_mtu == 0) { - ifp->if_mtu = ETHERMTU; + if (ifnet_mtu(ifp) == 0) { + ifnet_set_mtu(ifp, ETHERMTU); } bond_unlock(); + + + /* first port added to bond determines bond's ethernet address */ + if (first) { + ifnet_set_lladdr_and_type(ifp, IF_LLADDR(port_ifp), ETHER_ADDR_LEN, + IFT_ETHER); + } + progress |= BOND_ADD_PROGRESS_IN_LIST; /* allocate a larger distributing array */ @@ -2079,9 +2098,9 @@ bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp) } /* mark the interface up */ - ifnet_set_flags(port_ifp, IFF_UP, IFF_UP); + ifnet_set_flags(port_ifp, IFF_UP, IFF_UP); - error = dlil_ioctl(0, port_ifp, SIOCSIFFLAGS, (caddr_t)NULL); + error = ifnet_ioctl(port_ifp, 0, SIOCSIFFLAGS, NULL); if (error != 0) { printf("bond_add_interface(%s, %s): SIOCSIFFLAGS failed %d\n", ifb->ifb_name, bondport_get_name(p), error); @@ -2090,7 +2109,7 @@ bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp) /* re-program the port's ethernet address */ error = if_siflladdr(port_ifp, - (const struct ether_addr *)LLADDR(ifb_sdl)); + (const struct ether_addr *)IF_LLADDR(ifp)); if (error != 0) { /* port doesn't support setting the link address */ printf("bond_add_interface(%s, %s): if_siflladdr failed %d\n", @@ -2112,16 +2131,31 @@ bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp) old_array = ifb->ifb_distributing_array; ifb->ifb_distributing_array = new_array; - /* clear the busy state, and wakeup anyone waiting */ - ifbond_signal(ifb, "bond_add_interface"); - bondport_start(p); + if (ifb->ifb_mode == IF_BOND_MODE_LACP) { + bondport_start(p); - /* check if we need to generate a link status event */ - if (ifbond_selection(ifb)) { - event_code = (ifb->ifb_active_lag == NULL) - ? KEV_DL_LINK_OFF - : KEV_DL_LINK_ON; + /* check if we need to generate a link status event */ + if (ifbond_selection(ifb)) { + event_code = (ifb->ifb_active_lag == NULL) + ? KEV_DL_LINK_OFF + : KEV_DL_LINK_ON; + ifb->ifb_last_link_event = event_code; + } + } + else { + /* are we adding the first distributing interface? */ + if (media_active(&p->po_media_info)) { + if (ifb->ifb_distributing_count == 0) { + ifb->ifb_last_link_event = event_code = KEV_DL_LINK_ON; + } + bondport_enable_distributing(p); + } + else { + bondport_disable_distributing(p); + } } + /* clear the busy state, and wakeup anyone waiting */ + ifbond_signal(ifb, "bond_add_interface"); bond_unlock(); if (event_code != 0) { interface_link_event(ifp, event_code); @@ -2134,6 +2168,11 @@ bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp) failed: bond_assert_lock_not_held(); + /* if this was the first port to be added, clear our address */ + if (first) { + ifnet_set_lladdr_and_type(ifp, NULL, 0, IFT_IEEE8023ADLAG); + } + if (new_array != NULL) { FREE(new_array, M_BOND); } @@ -2155,8 +2194,8 @@ bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp) error1 = siocsifmtu(port_ifp, p->po_devmtu.ifdm_current); if (error1 != 0) { printf("bond_add_interface(%s, %s): SIOCSIFMTU %d failed %d\n", - ifb->ifb_name, bondport_get_name(p), p->po_devmtu.ifdm_current, - error1); + ifb->ifb_name, bondport_get_name(p), + p->po_devmtu.ifdm_current, error1); } } bond_lock(); @@ -2164,24 +2203,17 @@ bond_add_interface(struct ifnet * ifp, struct ifnet * port_ifp) TAILQ_REMOVE(&ifb->ifb_port_list, p, po_port_list); ifb->ifb_port_count--; } - ifnet_lock_exclusive(port_ifp); - port_ifp->if_eflags &= ~IFEF_BOND; - ifnet_lock_done(port_ifp); + ifnet_set_eflags(ifp, 0, IFEF_BOND); if (TAILQ_EMPTY(&ifb->ifb_port_list)) { ifb->ifb_altmtu = 0; - ifp->if_mtu = 0; - ifp->if_hwassist = 0; - if (ifbond_flags_lladdr(ifb) == FALSE) { - bzero(LLADDR(ifb_sdl), ETHER_ADDR_LEN); - ifb_sdl->sdl_type = IFT_IEEE8023ADLAG; - ifb_sdl->sdl_alen = 0; - } + ifnet_set_mtu(ifp, 0); + ifnet_set_offload(ifp, 0); } signal_done: - ifbond_release(ifb); ifbond_signal(ifb, "bond_add_interface"); bond_unlock(); + ifbond_release(ifb); bondport_free(p); return (error); } @@ -2193,11 +2225,12 @@ bond_remove_interface(ifbond_ref ifb, struct ifnet * port_ifp) int error = 0; int event_code = 0; bondport_ref head_port; - struct sockaddr_dl * ifb_sdl; struct ifnet * ifp; - int new_link_address = 0; + int last = FALSE; + int new_link_address = FALSE; bondport_ref p; lacp_actor_partner_state s; + int was_distributing; bond_assert_lock_held(); @@ -2212,68 +2245,82 @@ bond_remove_interface(ifbond_ref ifb, struct ifnet * port_ifp) } /* de-select it and remove it from the lists */ + was_distributing = bondport_flags_distributing(p); bondport_disable_distributing(p); - bondport_set_selected(p, SelectedState_UNSELECTED); - active_lag = bondport_remove_from_LAG(p); - TAILQ_REMOVE(&ifb->ifb_port_list, p, po_port_list); - ifb->ifb_port_count--; + if (ifb->ifb_mode == IF_BOND_MODE_LACP) { + bondport_set_selected(p, SelectedState_UNSELECTED); + active_lag = bondport_remove_from_LAG(p); + /* invalidate timers here while holding the bond_lock */ + bondport_invalidate_timers(p); - /* invalidate timers here while holding the bond_lock */ - bondport_invalidate_timers(p); + /* announce that we're Individual now */ + s = p->po_actor_state; + s = lacp_actor_partner_state_set_individual(s); + s = lacp_actor_partner_state_set_not_collecting(s); + s = lacp_actor_partner_state_set_not_distributing(s); + s = lacp_actor_partner_state_set_out_of_sync(s); + p->po_actor_state = s; + bondport_flags_set_ntt(p); + } - /* announce that we're Individual now */ - s = p->po_actor_state; - s = lacp_actor_partner_state_set_individual(s); - s = lacp_actor_partner_state_set_not_collecting(s); - s = lacp_actor_partner_state_set_not_distributing(s); - s = lacp_actor_partner_state_set_out_of_sync(s); - p->po_actor_state = s; - bondport_flags_set_ntt(p); + TAILQ_REMOVE(&ifb->ifb_port_list, p, po_port_list); + ifb->ifb_port_count--; ifp = ifb->ifb_ifp; - ifb_sdl = ifp_get_sdl(ifp); head_port = TAILQ_FIRST(&ifb->ifb_port_list); if (head_port == NULL) { - ifp->if_flags &= ~IFF_RUNNING; + ifnet_set_flags(ifp, 0, IFF_RUNNING); if (ifbond_flags_lladdr(ifb) == FALSE) { - ifb_sdl->sdl_type = IFT_IEEE8023ADLAG; - ifb_sdl->sdl_alen = 0; - bzero(LLADDR(ifb_sdl), ETHER_ADDR_LEN); + last = TRUE; } - ifp->if_hwassist = 0; - ifp->if_mtu = 0; + ifnet_set_offload(ifp, 0); + ifnet_set_mtu(ifp, 0); ifb->ifb_altmtu = 0; } else if (ifbond_flags_lladdr(ifb) == FALSE - && bcmp(&p->po_saved_addr, LLADDR(ifb_sdl), + && bcmp(&p->po_saved_addr, IF_LLADDR(ifp), ETHER_ADDR_LEN) == 0) { - /* this port gave the bond its ethernet address, switch to new one */ - ether_addr_copy(LLADDR(ifb_sdl), &head_port->po_saved_addr); - ifb_sdl->sdl_type = IFT_ETHER; - ifb_sdl->sdl_alen = ETHER_ADDR_LEN; - new_link_address = 1; + new_link_address = TRUE; } /* check if we need to generate a link status event */ - if (ifbond_selection(ifb) || active_lag) { - event_code = (ifb->ifb_active_lag == NULL) - ? KEV_DL_LINK_OFF - : KEV_DL_LINK_ON; + if (ifb->ifb_mode == IF_BOND_MODE_LACP ) { + if (ifbond_selection(ifb) || active_lag) { + event_code = (ifb->ifb_active_lag == NULL) + ? KEV_DL_LINK_OFF + : KEV_DL_LINK_ON; + ifb->ifb_last_link_event = event_code; + } + bondport_transmit_machine(p, LAEventStart, + TRANSMIT_MACHINE_TX_IMMEDIATE); + } + else { + /* are we removing the last distributing interface? */ + if (was_distributing && ifb->ifb_distributing_count == 0) { + ifb->ifb_last_link_event = event_code = KEV_DL_LINK_OFF; + } } - bond_unlock(); - bondport_transmit_machine(p, LAEventStart, (void *)1); + bond_unlock(); - if (new_link_address) { + if (last) { + ifnet_set_lladdr_and_type(ifp, NULL, 0, IFT_IEEE8023ADLAG); + } + else if (new_link_address) { struct ifnet * scan_ifp; bondport_ref scan_port; /* ifbond_wait() allows port list traversal without holding the lock */ + /* this port gave the bond its ethernet address, switch to new one */ + ifnet_set_lladdr_and_type(ifp, + &head_port->po_saved_addr, ETHER_ADDR_LEN, + IFT_ETHER); + /* re-program each port with the new link address */ TAILQ_FOREACH(scan_port, &ifb->ifb_port_list, po_port_list) { scan_ifp = scan_port->po_ifp; error = if_siflladdr(scan_ifp, - (const struct ether_addr *) LLADDR(ifb_sdl)); + (const struct ether_addr *) IF_LLADDR(ifp)); if (error != 0) { printf("bond_remove_interface(%s, %s): " "if_siflladdr (%s) failed %d\n", @@ -2307,15 +2354,118 @@ bond_remove_interface(ifbond_ref ifb, struct ifnet * port_ifp) } bond_lock(); - ifbond_release(ifb); bondport_free(p); - ifnet_lock_exclusive(port_ifp); - port_ifp->if_eflags &= ~IFEF_BOND; - ifnet_lock_done(port_ifp); + ifnet_set_eflags(port_ifp, 0, IFEF_BOND); + /* release this bondport's reference to the ifbond */ + ifbond_release(ifb); signal_done: ifbond_signal(ifb, "bond_remove_interface"); - ifbond_release(ifb); /* a second release for the second reference */ + ifbond_release(ifb); + return (error); +} + +static void +bond_set_lacp_mode(ifbond_ref ifb) +{ + bondport_ref p; + + TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) { + bondport_disable_distributing(p); + bondport_start(p); + } + return; +} + +static void +bond_set_static_mode(ifbond_ref ifb) +{ + bondport_ref p; + lacp_actor_partner_state s; + + TAILQ_FOREACH(p, &ifb->ifb_port_list, po_port_list) { + bondport_disable_distributing(p); + bondport_set_selected(p, SelectedState_UNSELECTED); + (void)bondport_remove_from_LAG(p); + bondport_cancel_timers(p); + + /* announce that we're Individual now */ + s = p->po_actor_state; + s = lacp_actor_partner_state_set_individual(s); + s = lacp_actor_partner_state_set_not_collecting(s); + s = lacp_actor_partner_state_set_not_distributing(s); + s = lacp_actor_partner_state_set_out_of_sync(s); + p->po_actor_state = s; + bondport_flags_set_ntt(p); + bondport_transmit_machine(p, LAEventStart, + TRANSMIT_MACHINE_TX_IMMEDIATE); + /* clear state */ + p->po_actor_state = 0; + bzero(&p->po_partner_state, sizeof(p->po_partner_state)); + + if (media_active(&p->po_media_info)) { + bondport_enable_distributing(p); + } + else { + bondport_disable_distributing(p); + } + } + return; +} + +static int +bond_set_mode(struct ifnet * ifp, int mode) +{ + int error = 0; + int event_code = 0; + ifbond_ref ifb; + + bond_lock(); + ifb = (ifbond_ref)ifnet_softc(ifp); + if (ifb == NULL || ifbond_flags_if_detaching(ifb)) { + bond_unlock(); + return ((ifb == NULL) ? EOPNOTSUPP : EBUSY); + } + if (ifb->ifb_mode == mode) { + bond_unlock(); + return (0); + } + + ifbond_retain(ifb); + ifbond_wait(ifb, "bond_set_mode"); + + /* verify (again) that the mode is actually different */ + if (ifb->ifb_mode == mode) { + /* nothing to do */ + goto signal_done; + } + + ifb->ifb_mode = mode; + if (mode == IF_BOND_MODE_LACP) { + bond_set_lacp_mode(ifb); + + /* check if we need to generate a link status event */ + if (ifbond_selection(ifb)) { + event_code = (ifb->ifb_active_lag == NULL) + ? KEV_DL_LINK_OFF + : KEV_DL_LINK_ON; + } + } else { + bond_set_static_mode(ifb); + event_code = (ifb->ifb_distributing_count == 0) + ? KEV_DL_LINK_OFF + : KEV_DL_LINK_ON; + } + ifb->ifb_last_link_event = event_code; + + signal_done: + ifbond_signal(ifb, "bond_set_mode"); + bond_unlock(); + ifbond_release(ifb); + + if (event_code != 0) { + interface_link_event(ifp, event_code); + } return (error); } @@ -2334,10 +2484,11 @@ bond_get_status(ifbond_ref ifb, struct if_bond_req * ibr_p, user_addr_t datap) return (EINVAL); } ibsr->ibsr_key = ifb->ifb_key; + ibsr->ibsr_mode = ifb->ifb_mode; ibsr->ibsr_total = ifb->ifb_port_count; dst = proc_is64bit(current_proc()) ? ibsr->ibsr_ibsru.ibsru_buffer64 - : CAST_USER_ADDR_T(ibsr->ibsr_ibsru.ibsru_buffer32); + : CAST_USER_ADDR_T(ibsr->ibsr_ibsru.ibsru_buffer); if (dst == USER_ADDR_NULL) { /* just want to know how many there are */ goto done; @@ -2355,18 +2506,25 @@ bond_get_status(ifbond_ref ifb, struct if_bond_req * ibr_p, user_addr_t datap) break; } bzero(&ibs, sizeof(ibs)); - strncpy(ibs.ibs_if_name, port->po_name, sizeof(ibs.ibs_if_name)); + strlcpy(ibs.ibs_if_name, port->po_name, sizeof(ibs.ibs_if_name)); ibs.ibs_port_priority = port->po_priority; - ibs.ibs_state = port->po_actor_state; - ibs.ibs_selected_state = port->po_selected; - ps = &port->po_partner_state; - ibps_p = &ibs.ibs_partner_state; - ibps_p->ibps_system = ps->ps_lag_info.li_system; - ibps_p->ibps_system_priority = ps->ps_lag_info.li_system_priority; - ibps_p->ibps_key = ps->ps_lag_info.li_key; - ibps_p->ibps_port = ps->ps_port; - ibps_p->ibps_port_priority = ps->ps_port_priority; - ibps_p->ibps_state = ps->ps_state; + if (ifb->ifb_mode == IF_BOND_MODE_LACP) { + ibs.ibs_state = port->po_actor_state; + ibs.ibs_selected_state = port->po_selected; + ps = &port->po_partner_state; + ibps_p = &ibs.ibs_partner_state; + ibps_p->ibps_system = ps->ps_lag_info.li_system; + ibps_p->ibps_system_priority = ps->ps_lag_info.li_system_priority; + ibps_p->ibps_key = ps->ps_lag_info.li_key; + ibps_p->ibps_port = ps->ps_port; + ibps_p->ibps_port_priority = ps->ps_port_priority; + ibps_p->ibps_state = ps->ps_state; + } + else { + /* fake the selected information */ + ibs.ibs_selected_state = bondport_flags_distributing(port) + ? SelectedState_SELECTED : SelectedState_UNSELECTED; + } error = copyout(&ibs, dst, sizeof(ibs)); if (error != 0) { break; @@ -2389,24 +2547,6 @@ static int bond_set_promisc(__unused struct ifnet *ifp) { int error = 0; -#if 0 - ifbond_ref ifb = ifp->if_private; - - - if ((ifp->if_flags & IFF_PROMISC) != 0) { - if ((ifb->ifb_flags & IFBF_PROMISC) == 0) { - error = ifnet_set_promiscuous(ifb->ifb_p, 1); - if (error == 0) - ifb->ifb_flags |= IFBF_PROMISC; - } - } else { - if ((ifb->ifb_flags & IFBF_PROMISC) != 0) { - error = ifnet_set_promiscuous(ifb->ifb_p, 0); - if (error == 0) - ifb->ifb_flags &= ~IFBF_PROMISC; - } - } -#endif 0 return (error); } @@ -2463,7 +2603,7 @@ bond_set_mtu(struct ifnet * ifp, int mtu, int isdevmtu) int old_max; bond_lock(); - ifb = (ifbond_ref)ifp->if_private; + ifb = (ifbond_ref)ifnet_softc(ifp); if (ifb == NULL || ifbond_flags_if_detaching(ifb)) { error = (ifb == NULL) ? EOPNOTSUPP : EBUSY; goto done; @@ -2472,7 +2612,7 @@ bond_set_mtu(struct ifnet * ifp, int mtu, int isdevmtu) ifbond_wait(ifb, "bond_set_mtu"); /* check again */ - if (ifp->if_private == NULL || ifbond_flags_if_detaching(ifb)) { + if (ifnet_softc(ifp) == NULL || ifbond_flags_if_detaching(ifb)) { error = EBUSY; goto signal_done; } @@ -2487,13 +2627,13 @@ bond_set_mtu(struct ifnet * ifp, int mtu, int isdevmtu) goto signal_done; } if (isdevmtu) { - new_max = (mtu > (int)ifp->if_mtu) ? mtu : (int)ifp->if_mtu; + new_max = (mtu > (int)ifnet_mtu(ifp)) ? mtu : (int)ifnet_mtu(ifp); } else { new_max = (mtu > ifb->ifb_altmtu) ? mtu : ifb->ifb_altmtu; } - old_max = ((int)ifp->if_mtu > ifb->ifb_altmtu) - ? (int)ifp->if_mtu : ifb->ifb_altmtu; + old_max = ((int)ifnet_mtu(ifp) > ifb->ifb_altmtu) + ? (int)ifnet_mtu(ifp) : ifb->ifb_altmtu; if (new_max != old_max) { /* we can safely walk the list of port without the lock held */ bond_unlock(); @@ -2509,7 +2649,7 @@ bond_set_mtu(struct ifnet * ifp, int mtu, int isdevmtu) ifb->ifb_altmtu = mtu; } else { - ifp->if_mtu = mtu; + ifnet_set_mtu(ifp, mtu); } } @@ -2523,18 +2663,18 @@ bond_set_mtu(struct ifnet * ifp, int mtu, int isdevmtu) } static int -bond_ioctl(struct ifnet *ifp, u_int32_t cmd, void * data) +bond_ioctl(struct ifnet *ifp, u_long cmd, void * data) { int error = 0; struct if_bond_req ibr; struct ifaddr * ifa; ifbond_ref ifb; struct ifreq * ifr; - struct ifmediareq64 *ifmr; + struct ifmediareq *ifmr; struct ifnet * port_ifp = NULL; user_addr_t user_addr; - if (ifp->if_type != IFT_IEEE8023ADLAG) { + if (ifnet_type(ifp) != IFT_IEEE8023ADLAG) { return (EOPNOTSUPP); } ifr = (struct ifreq *)data; @@ -2545,28 +2685,35 @@ bond_ioctl(struct ifnet *ifp, u_int32_t cmd, void * data) ifnet_set_flags(ifp, IFF_UP, IFF_UP); break; + case SIOCGIFMEDIA32: case SIOCGIFMEDIA64: - case SIOCGIFMEDIA: bond_lock(); - ifb = (ifbond_ref)ifp->if_private; + ifb = (ifbond_ref)ifnet_softc(ifp); if (ifb == NULL || ifbond_flags_if_detaching(ifb)) { bond_unlock(); return (ifb == NULL ? EOPNOTSUPP : EBUSY); } - ifmr = (struct ifmediareq64 *)data; + ifmr = (struct ifmediareq *)data; ifmr->ifm_current = IFM_ETHER; ifmr->ifm_mask = 0; ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; ifmr->ifm_count = 1; - if (ifb->ifb_active_lag != NULL) { - ifmr->ifm_active = ifb->ifb_active_lag->lag_active_media; + if (ifb->ifb_mode == IF_BOND_MODE_LACP) { + if (ifb->ifb_active_lag != NULL) { + ifmr->ifm_active = ifb->ifb_active_lag->lag_active_media; + ifmr->ifm_status |= IFM_ACTIVE; + } + } + else if (ifb->ifb_distributing_count > 0) { + ifmr->ifm_active + = ifb->ifb_distributing_array[0]->po_media_info.mi_active; ifmr->ifm_status |= IFM_ACTIVE; } bond_unlock(); - user_addr = (cmd == SIOCGIFMEDIA64) - ? ifmr->ifm_ifmu.ifmu_ulist64 - : CAST_USER_ADDR_T(ifmr->ifm_ifmu.ifmu_ulist32); + user_addr = (cmd == SIOCGIFMEDIA64) ? + ((struct ifmediareq64 *)ifmr)->ifmu_ulist : + CAST_USER_ADDR_T(((struct ifmediareq32 *)ifmr)->ifmu_ulist); if (user_addr != USER_ADDR_NULL) { error = copyout(&ifmr->ifm_current, user_addr, @@ -2581,7 +2728,7 @@ bond_ioctl(struct ifnet *ifp, u_int32_t cmd, void * data) case SIOCGIFDEVMTU: bond_lock(); - ifb = (ifbond_ref)ifp->if_private; + ifb = (ifbond_ref)ifnet_softc(ifp); if (ifb == NULL || ifbond_flags_if_detaching(ifb)) { bond_unlock(); error = (ifb == NULL) ? EOPNOTSUPP : EBUSY; @@ -2595,7 +2742,7 @@ bond_ioctl(struct ifnet *ifp, u_int32_t cmd, void * data) case SIOCGIFALTMTU: bond_lock(); - ifb = (ifbond_ref)ifp->if_private; + ifb = (ifbond_ref)ifnet_softc(ifp); if (ifb == NULL || ifbond_flags_if_detaching(ifb)) { bond_unlock(); error = (ifb == NULL) ? EOPNOTSUPP : EBUSY; @@ -2623,18 +2770,18 @@ bond_ioctl(struct ifnet *ifp, u_int32_t cmd, void * data) switch (ibr.ibr_op) { case IF_BOND_OP_ADD_INTERFACE: case IF_BOND_OP_REMOVE_INTERFACE: - /* XXX ifunit() needs to return a reference on the ifp */ port_ifp = ifunit(ibr.ibr_ibru.ibru_if_name); if (port_ifp == NULL) { error = ENXIO; break; } - if (port_ifp->if_type != IFT_ETHER) { + if (ifnet_type(port_ifp) != IFT_ETHER) { error = EPROTONOSUPPORT; break; } break; case IF_BOND_OP_SET_VERBOSE: + case IF_BOND_OP_SET_MODE: break; default: error = EOPNOTSUPP; @@ -2649,7 +2796,7 @@ bond_ioctl(struct ifnet *ifp, u_int32_t cmd, void * data) break; case IF_BOND_OP_REMOVE_INTERFACE: bond_lock(); - ifb = (ifbond_ref)ifp->if_private; + ifb = (ifbond_ref)ifnet_softc(ifp); if (ifb == NULL || ifbond_flags_if_detaching(ifb)) { bond_unlock(); return (ifb == NULL ? EOPNOTSUPP : EBUSY); @@ -2667,8 +2814,22 @@ bond_ioctl(struct ifnet *ifp, u_int32_t cmd, void * data) g_bond->verbose = ibr.ibr_ibru.ibru_int_val; bond_unlock(); break; + case IF_BOND_OP_SET_MODE: + switch (ibr.ibr_ibru.ibru_int_val) { + case IF_BOND_MODE_LACP: + case IF_BOND_MODE_STATIC: + break; + default: + error = EINVAL; + break; + } + if (error != 0) { + break; + } + error = bond_set_mode(ifp, ibr.ibr_ibru.ibru_int_val); + break; } - break; + break; /* SIOCSIFBOND */ case SIOCGIFBOND: user_addr = proc_is64bit(current_proc()) @@ -2688,7 +2849,7 @@ bond_ioctl(struct ifnet *ifp, u_int32_t cmd, void * data) break; } bond_lock(); - ifb = (ifbond_ref)ifp->if_private; + ifb = (ifbond_ref)ifnet_softc(ifp); if (ifb == NULL || ifbond_flags_if_detaching(ifb)) { bond_unlock(); return (ifb == NULL ? EOPNOTSUPP : EBUSY); @@ -2699,7 +2860,7 @@ bond_ioctl(struct ifnet *ifp, u_int32_t cmd, void * data) break; } bond_unlock(); - break; + break; /* SIOCGIFBOND */ case SIOCSIFLLADDR: error = EOPNOTSUPP; @@ -2731,33 +2892,28 @@ bond_if_free(struct ifnet * ifp) return; } bond_lock(); - ifb = (ifbond_ref)ifp->if_private; + ifb = (ifbond_ref)ifnet_softc(ifp); if (ifb == NULL) { bond_unlock(); return; } - ifp->if_private = NULL; ifbond_release(ifb); bond_unlock(); - dlil_if_release(ifp); + ifnet_release(ifp); return; } static void -bond_event(struct ifnet * port_ifp, struct kev_msg * event) +bond_handle_event(struct ifnet * port_ifp, int event_code) { struct ifnet * bond_ifp = NULL; - int event_code = 0; + ifbond_ref ifb; + int old_distributing_count; bondport_ref p; - struct media_info media_info; + struct media_info media_info = { 0, 0}; - if (event->vendor_code != KEV_VENDOR_APPLE - || event->kev_class != KEV_NETWORK_CLASS - || event->kev_subclass != KEV_DL_SUBCLASS) { - return; - } - switch (event->event_code) { - case KEV_DL_IF_DETACHING: + switch (event_code) { + case KEV_DL_IF_DETACHED: break; case KEV_DL_LINK_OFF: case KEV_DL_LINK_ON: @@ -2772,9 +2928,11 @@ bond_event(struct ifnet * port_ifp, struct kev_msg * event) bond_unlock(); return; } - switch (event->event_code) { - case KEV_DL_IF_DETACHING: - bond_remove_interface(p->po_bond, p->po_ifp); + ifb = p->po_bond; + old_distributing_count = ifb->ifb_distributing_count; + switch (event_code) { + case KEV_DL_IF_DETACHED: + bond_remove_interface(ifb, p->po_ifp); break; case KEV_DL_LINK_OFF: case KEV_DL_LINK_ON: @@ -2785,13 +2943,48 @@ bond_event(struct ifnet * port_ifp, struct kev_msg * event) break; } /* generate a link-event */ - if (ifbond_selection(p->po_bond)) { - event_code = (p->po_bond->ifb_active_lag == NULL) - ? KEV_DL_LINK_OFF - : KEV_DL_LINK_ON; - /* XXX need to take a reference on bond_ifp */ - bond_ifp = p->po_bond->ifb_ifp; + if (ifb->ifb_mode == IF_BOND_MODE_LACP) { + if (ifbond_selection(ifb)) { + event_code = (ifb->ifb_active_lag == NULL) + ? KEV_DL_LINK_OFF + : KEV_DL_LINK_ON; + /* XXX need to take a reference on bond_ifp */ + bond_ifp = ifb->ifb_ifp; + ifb->ifb_last_link_event = event_code; + } + else { + event_code = (ifb->ifb_active_lag == NULL) + ? KEV_DL_LINK_OFF + : KEV_DL_LINK_ON; + if (event_code != ifb->ifb_last_link_event) { + if (g_bond->verbose) { + timestamp_printf("%s: (event) generating LINK event\n", + ifb->ifb_name); + } + bond_ifp = ifb->ifb_ifp; + ifb->ifb_last_link_event = event_code; + } + } + } + else { + /* + * if the distributing array membership changed from 0 <-> !0 + * generate a link event + */ + if (old_distributing_count == 0 + && ifb->ifb_distributing_count != 0) { + event_code = KEV_DL_LINK_ON; + } + else if (old_distributing_count != 0 + && ifb->ifb_distributing_count == 0) { + event_code = KEV_DL_LINK_OFF; + } + if (event_code != 0 && event_code != ifb->ifb_last_link_event) { + bond_ifp = ifb->ifb_ifp; + ifb->ifb_last_link_event = event_code; + } } + bond_unlock(); if (bond_ifp != NULL) { interface_link_event(bond_ifp, event_code); @@ -2800,23 +2993,55 @@ bond_event(struct ifnet * port_ifp, struct kev_msg * event) } static void -interface_link_event(struct ifnet * ifp, u_long event_code) +bond_event(struct ifnet * port_ifp, __unused protocol_family_t protocol, + const struct kev_msg * event) +{ + int event_code; + + if (event->vendor_code != KEV_VENDOR_APPLE + || event->kev_class != KEV_NETWORK_CLASS + || event->kev_subclass != KEV_DL_SUBCLASS) { + return; + } + event_code = event->event_code; + switch (event_code) { + case KEV_DL_LINK_OFF: + case KEV_DL_LINK_ON: + /* we only care about link status changes */ + bond_handle_event(port_ifp, event_code); + break; + default: + break; + } + return; +} + +static errno_t +bond_detached(ifnet_t port_ifp, __unused protocol_family_t protocol) +{ + bond_handle_event(port_ifp, KEV_DL_IF_DETACHED); + return (0); +} + +static void +interface_link_event(struct ifnet * ifp, u_int32_t event_code) { struct { struct kern_event_msg header; - u_long unit; + u_int32_t unit; char if_name[IFNAMSIZ]; } event; + bzero(&event, sizeof(event)); event.header.total_size = sizeof(event); event.header.vendor_code = KEV_VENDOR_APPLE; event.header.kev_class = KEV_NETWORK_CLASS; event.header.kev_subclass = KEV_DL_SUBCLASS; event.header.event_code = event_code; - event.header.event_data[0] = ifp->if_family; - event.unit = (u_long) ifp->if_unit; - strncpy(event.if_name, ifp->if_name, IFNAMSIZ); - dlil_event(ifp, &event.header); + event.header.event_data[0] = ifnet_family(ifp); + event.unit = (u_int32_t) ifnet_unit(ifp); + strlcpy(event.if_name, ifnet_name(ifp), IFNAMSIZ); + ifnet_event(ifp, &event.header); return; } @@ -2833,21 +3058,18 @@ interface_link_event(struct ifnet * ifp, u_long event_code) static int bond_attach_protocol(struct ifnet *ifp) { - int error; - struct dlil_proto_reg_str reg; + int error; + struct ifnet_attach_proto_param reg; bzero(®, sizeof(reg)); - TAILQ_INIT(®.demux_desc_head); - reg.interface_family = ifp->if_family; - reg.unit_number = ifp->if_unit; reg.input = bond_input; reg.event = bond_event; - reg.protocol_family = PF_BOND; + reg.detached = bond_detached; - error = dlil_attach_protocol(®); + error = ifnet_attach_protocol(ifp, PF_BOND, ®); if (error) { - printf("bond over %s%d: dlil_attach_protocol failed, %d\n", - ifp->if_name, ifp->if_unit, error); + printf("bond over %s%d: ifnet_attach_protocol failed, %d\n", + ifnet_name(ifp), ifnet_unit(ifp), error); } return (error); } @@ -2862,10 +3084,10 @@ bond_detach_protocol(struct ifnet *ifp) { int error; - error = dlil_detach_protocol(ifp, PF_BOND); + error = ifnet_detach_protocol(ifp, PF_BOND); if (error) { - printf("bond over %s%d: dlil_detach_protocol failed, %d\n", - ifp->if_name, ifp->if_unit, error); + printf("bond over %s%d: ifnet_detach_protocol failed, %d\n", + ifnet_name(ifp), ifnet_unit(ifp), error); } return (error); } @@ -2873,57 +3095,42 @@ bond_detach_protocol(struct ifnet *ifp) /* * DLIL interface family functions */ -extern int ether_add_if(struct ifnet *ifp); -extern int ether_del_if(struct ifnet *ifp); -extern int ether_init_if(struct ifnet *ifp); -extern int ether_add_proto_old(struct ifnet *ifp, u_long protocol_family, - struct ddesc_head_str *desc_head); - -extern int ether_attach_inet(struct ifnet *ifp, u_long protocol_family); -extern int ether_detach_inet(struct ifnet *ifp, u_long protocol_family); -extern int ether_attach_inet6(struct ifnet *ifp, u_long protocol_family); -extern int ether_detach_inet6(struct ifnet *ifp, u_long protocol_family); +extern int ether_attach_inet(ifnet_t ifp, protocol_family_t protocol_family); +extern void ether_detach_inet(ifnet_t ifp, protocol_family_t protocol_family); +extern int ether_attach_inet6(ifnet_t ifp, protocol_family_t protocol_family); +extern void ether_detach_inet6(ifnet_t ifp, protocol_family_t protocol_family); +extern int ether_attach_at(ifnet_t ifp, protocol_family_t protocol_family); +extern void ether_detach_at(ifnet_t ifp, protocol_family_t protocol_family); __private_extern__ int bond_family_init(void) { int error=0; - struct dlil_ifmod_reg_str ifmod_reg; - - bzero(&ifmod_reg, sizeof(ifmod_reg)); - ifmod_reg.add_if = ether_add_if; - ifmod_reg.del_if = ether_del_if; - ifmod_reg.init_if = NULL; - ifmod_reg.add_proto = ether_add_proto_old; - ifmod_reg.del_proto = ether_del_proto; - ifmod_reg.ifmod_ioctl = ether_ioctl; - ifmod_reg.shutdown = NULL; - - if (dlil_reg_if_modules(APPLE_IF_FAM_BOND, &ifmod_reg)) { - printf("WARNING: bond_family_init -- " - "Can't register if family modules\n"); - error = EIO; - goto done; - } - error = dlil_reg_proto_module(PF_INET, APPLE_IF_FAM_BOND, + error = proto_register_plumber(PF_INET, APPLE_IF_FAM_BOND, ether_attach_inet, ether_detach_inet); if (error != 0) { - printf("bond: dlil_reg_proto_module failed for AF_INET6 error=%d\n", + printf("bond: proto_register_plumber failed for AF_INET error=%d\n", error); goto done; } - - error = dlil_reg_proto_module(PF_INET6, APPLE_IF_FAM_BOND, +#if INET6 + error = proto_register_plumber(PF_INET6, APPLE_IF_FAM_BOND, ether_attach_inet6, ether_detach_inet6); if (error != 0) { - printf("bond: dlil_reg_proto_module failed for AF_INET6 error=%d\n", + printf("bond: proto_register_plumber failed for AF_INET6 error=%d\n", error); goto done; } - bond_clone_attach(); +#endif + error = bond_clone_attach(); + if (error != 0) { + printf("bond: proto_register_plumber failed bond_clone_attach error=%d\n", + error); + goto done; + } done: return (error); @@ -3184,7 +3391,7 @@ ifbond_set_max_active(ifbond_ref bond, int max_active) } return; } -#endif 0 +#endif static int ifbond_all_ports_ready(ifbond_ref bond) @@ -3292,24 +3499,33 @@ bondport_link_status_changed(bondport_ref p) timestamp_printf("[%s] Link DOWN\n", bondport_get_name(p)); } } - if (media_active(&p->po_media_info) - && bond->ifb_active_lag != NULL - && p->po_lag == bond->ifb_active_lag - && p->po_selected != SelectedState_UNSELECTED) { - if (media_speed(&p->po_media_info) != p->po_lag->lag_active_media) { - if (g_bond->verbose) { - timestamp_printf("[%s] Port speed %d differs from LAG %d\n", - bondport_get_name(p), - media_speed(&p->po_media_info), - link_speed(p->po_lag->lag_active_media)); + if (bond->ifb_mode == IF_BOND_MODE_LACP) { + if (media_active(&p->po_media_info) + && bond->ifb_active_lag != NULL + && p->po_lag == bond->ifb_active_lag + && p->po_selected != SelectedState_UNSELECTED) { + if (media_speed(&p->po_media_info) != p->po_lag->lag_active_media) { + if (g_bond->verbose) { + timestamp_printf("[%s] Port speed %d differs from LAG %d\n", + bondport_get_name(p), + media_speed(&p->po_media_info), + link_speed(p->po_lag->lag_active_media)); + } + bondport_set_selected(p, SelectedState_UNSELECTED); } - bondport_set_selected(p, SelectedState_UNSELECTED); + } + bondport_receive_machine(p, LAEventMediaChange, NULL); + bondport_mux_machine(p, LAEventMediaChange, NULL); + bondport_periodic_transmit_machine(p, LAEventMediaChange, NULL); + } + else { + if (media_active(&p->po_media_info)) { + bondport_enable_distributing(p); + } + else { + bondport_disable_distributing(p); } } - bondport_receive_machine(p, LAEventMediaChange, NULL); - bondport_mux_machine(p, LAEventMediaChange, NULL); - bondport_periodic_transmit_machine(p, LAEventMediaChange, NULL); - return; } @@ -4122,7 +4338,7 @@ bondport_periodic_transmit_machine(bondport_ref p, LAEvent event, **/ static int bondport_can_transmit(bondport_ref p, int32_t current_secs, - long * next_secs) + __darwin_time_t * next_secs) { if (p->po_last_transmit_secs != current_secs) { p->po_last_transmit_secs = current_secs; @@ -4156,7 +4372,7 @@ bondport_transmit_machine(bondport_ref p, LAEvent event, if (p->po_periodic_interval == 0 || bondport_flags_ntt(p) == 0) { break; } - if (event_data != NULL) { + if (event_data == TRANSMIT_MACHINE_TX_IMMEDIATE) { /* we're going away, transmit the packet no matter what */ } else if (bondport_can_transmit(p, devtimer_current_secs(), @@ -4175,7 +4391,7 @@ bondport_transmit_machine(bondport_ref p, LAEvent event, if (g_bond->verbose > 0) { timestamp_printf("[%s] Transmit Timer Deadline %d secs\n", bondport_get_name(p), - next_tick_time.tv_sec); + (int)next_tick_time.tv_sec); } } break;