/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipnet_bond.c,v $ $Revision: 1.3.10.2 $ * $Source: /home/interpeak/CVSRoot/ipnet2/src/ipnet_bond.c,v $ * $Author: hxie $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Jonas Rendel ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** * Processing of link aggregated frames (bonding device) */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifndef IPCOM_KERNEL #define IPCOM_KERNEL #endif #include "ipnet_config.h" /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #ifdef IPNET_USE_BOND /*#define IPNET_BOND_DEBUG */ /*#define IPNET_BOND_DEBUG2*/ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #ifndef IPNET_BOND_DEBUG #include #endif #ifdef IPCOM_USE_FORWARDER #include #endif #include "ipnet.h" #include "ipnet_h.h" #include "ipnet_eth.h" #ifdef IPCOM_USE_INET #include "ipnet_ip4.h" #endif #ifdef IPNET_USE_NETLINKSOCK #include "ipnet_netlink_h.h" #include "ipnet_rtnetlink_h.h" #endif /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* Transmit load balancing algorithms */ #define IPNET_BOND_XMIT_POLICY_LAYER2 0 #define IPNET_BOND_XMIT_POLICY_LAYER34 1 #define IPNET_BOND_XMIT_POLICY_LAYER23 2 #define IPNET_BOND_MASTER(bondif) ((Ipnet_bond_master*)bondif->eth->bond.priv) #ifdef IPNET_BOND_DEBUG #define IPCOM_LOG0(x,s) ipcom_printf(s IP_LF); #define IPCOM_LOG1(x,s,a1) ipcom_printf(s IP_LF,a1); #define IPCOM_LOG2(x,s,a1,a2) ipcom_printf(s IP_LF,a1,a2); #define IPCOM_LOG3(x,s,a1,a2,a3) ipcom_printf(s IP_LF,a1,a2,a3); #define IPCOM_LOG4(x,s,a1,a2,a3,a4) ipcom_printf(s IP_LF,a1,a2,a3,a4); #endif /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* *=========================================================================== * Ipnet_bond_slave *=========================================================================== */ typedef struct Ipnet_bond_slave_struct { Ipcom_list list; Ipnet_netif *netif; /* Slaves physical Ethernet interface */ Ip_u32 active_in_lag; /* Slave is active in link aggr. group */ } Ipnet_bond_slave; /* *=========================================================================== * Ipnet_bond_master *=========================================================================== */ typedef struct Ipnet_bond_master_struct { Ipcom_list slave_head; /* List of enslaved Ethernet interfaces */ int slave_count; /* Number of enslaved Ethernet interfaces */ int lag_count; /* Number of slaves active in link aggr. group */ int promisc_count; int (*xmit_policy)(Ipnet_netif *bondif, Ipcom_pkt *pkt); Ip_u8 policy; /* Identifier for xmit policy callback */ } Ipnet_bond_master; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_STATIC void ipnet_bond_netlink_notify_laginfo(Ipnet_netif *bondif, Ipnet_netif *slaveif, Ip_u32 lag_status); /* **************************************************************************** * 8 DATA **************************************************************************** */ IP_STATIC struct Ip_rtnl_link_ops bond_ops; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipnet_bond_xmit_policy_l2 *=========================================================================== * Description: Transmit policy algorithm based on hashing parts * of the packet layer 2 header. * * Parameters: bondif - The bond interface to operate on. * pkt - The packet to transmit. * Returns: 0 = success, < 0 = error code * */ IP_STATIC int ipnet_bond_xmit_policy_l2(Ipnet_netif *bondif, Ipcom_pkt *pkt) { Ipnet_pkt_eth *eth = (Ipnet_pkt_eth *)&pkt->data[pkt->start]; int cnt = IPNET_BOND_MASTER(bondif)->lag_count; if (cnt == 0) return -IP_ERRNO_ENODEV; return (eth->dst[5] ^ bondif->ipcom.link_addr[5]) % cnt; } /* *=========================================================================== * ipnet_bond_xmit_policy_l23 *=========================================================================== * Description: Transmit policy algorithm based on hashing parts * of the packet layer 2 and 3 headers. * * Parameters: bondif - The bond interface to operate on. * pkt - The packet to transmit. * Returns: 0 = success, < 0 = error code * */ IP_STATIC int ipnet_bond_xmit_policy_l23(Ipnet_netif *bondif, Ipcom_pkt *pkt) { #ifdef IPCOM_USE_INET Ipnet_pkt_ip *iph = (Ipnet_pkt_ip*)&pkt->data[pkt->ipstart]; Ipnet_pkt_eth *eth = (Ipnet_pkt_eth*)&pkt->data[pkt->start]; int cnt = IPNET_BOND_MASTER(bondif)->lag_count; if (cnt == 0) return -IP_ERRNO_ENODEV; if (eth->d.type == IPNET_ETHFRAME_IP) { return ((ip_ntohl(IPNET_IP4_GET_IPADDR(iph->src) ^ IPNET_IP4_GET_IPADDR(iph->dst)) & 0xffff) ^ (eth->dst[5] ^ bondif->ipcom.link_addr[5])) % cnt; } #endif return ipnet_bond_xmit_policy_l2(bondif, pkt); } /* *=========================================================================== * ipnet_bond_xmit_policy_l34 *=========================================================================== * Description: Transmit policy algorithm based on hashing parts * of the packet layer 3 and 4 headers. * * Parameters: bondif - The bond interface to operate on. * pkt - The packet to transmit. * Returns: 0 = success, < 0 = error code * */ IP_STATIC int ipnet_bond_xmit_policy_l34(Ipnet_netif *bondif, Ipcom_pkt *pkt) { #ifdef IPCOM_USE_INET Ipnet_pkt_ip *iph = (Ipnet_pkt_ip*)&pkt->data[pkt->ipstart]; Ip_u16 *tlh = (Ip_u16*)&pkt->data[pkt->tlstart]; Ipnet_pkt_eth *eth = (Ipnet_pkt_eth*)&pkt->data[pkt->start]; int cnt = IPNET_BOND_MASTER(bondif)->lag_count; int tl_hash = 0; if (cnt == 0) return -IP_ERRNO_ENODEV; if (eth->d.type == IPNET_ETHFRAME_IP) { if (!IPNET_ISFRAG(iph->off) && (iph->p == IP_IPPROTO_UDP || iph->p == IP_IPPROTO_TCP)) { tl_hash = ip_ntohs(*tlh ^ *(tlh + 1)); } return (tl_hash ^ (ip_ntohl(IPNET_IP4_GET_IPADDR(iph->src) ^ IPNET_IP4_GET_IPADDR(iph->dst)) & 0xffff)) % cnt; } #endif return ipnet_bond_xmit_policy_l2(bondif, pkt); } /* *=========================================================================== * ipnet_bond_set_xmit_policy *=========================================================================== * Description: Set transmit policy on a bond interface. * * Parameters: bondif - The bond interface to operate on. * policy - Policy identifier. * Returns: 0 = success, < 0 = error code * */ IP_STATIC int ipnet_bond_set_xmit_policy(Ipnet_netif *bondif, Ip_u8 policy) { char *str; int ret = 0; switch (policy) { case IPNET_BOND_XMIT_POLICY_LAYER2: str = "layer2"; IPNET_BOND_MASTER(bondif)->xmit_policy = ipnet_bond_xmit_policy_l2; break; case IPNET_BOND_XMIT_POLICY_LAYER34: str = "layer34"; IPNET_BOND_MASTER(bondif)->xmit_policy = ipnet_bond_xmit_policy_l34; break; case IPNET_BOND_XMIT_POLICY_LAYER23: str = "layer23"; IPNET_BOND_MASTER(bondif)->xmit_policy = ipnet_bond_xmit_policy_l23; break; default: str = "unknown"; ret = -IP_ERRNO_EINVAL; } IPCOM_LOG2(DEBUG,"%s: transmit policy set to %s.", bondif->ipcom.name, str); return ret; } /* *=========================================================================== * ipnet_bond_set_lag_membership *=========================================================================== * Description: Toggle memberhsip of the Link Aggregation Group for a certain * enslaved Ethernet device * * Parameters: bondif - The bond interface to operate on. * ifindex - Interface index to the slave. * enabled - 1=True,0=False * Returns: - * */ IP_STATIC void ipnet_bond_set_lag_membership(Ipnet_netif *bondif, Ip_u32 ifindex, Ip_u32 enabled) { Ipnet_bond_slave *slave = IP_NULL; for (slave = IPCOM_LIST_FIRST(&IPNET_BOND_MASTER(bondif)->slave_head); slave; slave = IPCOM_LIST_NEXT(&slave->list)) { if (slave->netif->ipcom.ifindex == ifindex) break; } if (slave != IP_NULL) { if (enabled && !slave->active_in_lag) IPNET_BOND_MASTER(bondif)->lag_count++; else if (!enabled && slave->active_in_lag) IPNET_BOND_MASTER(bondif)->lag_count--; slave->active_in_lag = enabled; #if defined(IPCOM_USE_FORWARDER) && !defined(IP_PORT_UNIX) ipcom_forwarder_route_cache_invalidate(); #endif ipnet_bond_netlink_notify_laginfo(bondif, slave->netif, enabled); IPCOM_LOG4(INFO,"%s: enslaved interface %s %s the LAG (%d members)", bondif->ipcom.name, slave->netif->ipcom.name, enabled == 0 ? "left" : "joined", IPNET_BOND_MASTER(bondif)->lag_count); } else { /* Should never happen */ IPCOM_LOG2(ERR,"%s: failed to toggle LAG membership. Has no slave with index %d", bondif->ipcom.name, ifindex); } } /* *=========================================================================== * ipnet_bond_if_destroy *=========================================================================== * Description: Destroys a bond interface. * * Parameters: bondif - The bond interface to operate on. * Returns: 0 = success, < 0 = error code * */ IP_STATIC int ipnet_bond_if_destroy(Ipnet_netif *bondif) { Ipnet_bond_slave *slave = IP_NULL; int ret = 0; if (IP_BIT_ISSET(bondif->ipcom.flags, IP_IFF_UP)) return -IP_ERRNO_EBUSY; IPCOM_LOG1(INFO,"%s removing bond interface", bondif->ipcom.name); for (slave = IPCOM_LIST_FIRST(&IPNET_BOND_MASTER(bondif)->slave_head); slave; slave = IPCOM_LIST_NEXT(&slave->list)) (void)ipnet_bond_if_release(slave->netif); ret = ipcom_if_detach(&bondif->ipcom); if (ret >= 0) { ipcom_free(IPNET_BOND_MASTER(bondif)); (void)ipcom_if_free(&bondif->ipcom); } return ret; } /* *=========================================================================== * ipnet_bond_drv_ioctl *=========================================================================== * Description: Driver level ioctl for bond interface. * Parameters: bondif - A bond interface. * command - The ioctl command. * data - Command specific data. * Returns: 0 = success, <0 = error code. * */ IP_STATIC int ipnet_bond_drv_ioctl(Ipnet_netif *bondif, Ip_u32 command, void *data) { Ipnet_bond_slave *slave = IP_NULL; int ret = 0; switch (command) { case IP_SIOCIFDESTROY: ret = ipnet_bond_if_destroy(bondif); break; case IP_SIOCXPROMISC: if (*(Ip_bool *)data) { IPNET_BOND_MASTER(bondif)->promisc_count++; IP_BIT_SET(bondif->ipcom.flags, IP_IFF_PROMISC); } else if (--IPNET_BOND_MASTER(bondif)->promisc_count == 0) IP_BIT_CLR(bondif->ipcom.flags, IP_IFF_PROMISC); /* fall through */ default: /* Execute ioctl on all enslaved devices */ for (slave = IPCOM_LIST_FIRST(&IPNET_BOND_MASTER(bondif)->slave_head); slave; slave = IPCOM_LIST_NEXT(&slave->list)) (void)slave->netif->ipcom.drv_ioctl(&slave->netif->ipcom, command, data); } return ret; } /* *=========================================================================== * ipnet_bond_drv_output *=========================================================================== * Description: Output function for bond interface. * Parameters: bondif - The bond interface to use to output the frame. * pkt - The frame to send. * Returns: 0 = success, <0 = error code. * */ IP_STATIC int ipnet_bond_drv_output(Ipnet_netif *bondif, Ipcom_pkt *pkt) { Ipnet_bond_slave *slave = IP_NULL; int xmit_slave_id; if (bondif->ipcom.link_tap) { Ipnet_pkt_eth *eth = (Ipnet_pkt_eth *)&pkt->data[pkt->start]; /* Let the tap handler copy the packet */ bondif->ipcom.link_tap(&bondif->ipcom, pkt, IP_PACKET_OUTGOING, eth->d.type, pkt->start, pkt->ipstart); } /* Select physical link to transmit on */ xmit_slave_id = IPNET_BOND_MASTER(bondif)->xmit_policy(bondif, pkt); for (slave = IPCOM_LIST_FIRST(&IPNET_BOND_MASTER(bondif)->slave_head); slave; slave = IPCOM_LIST_NEXT(&slave->list)) { if (slave->active_in_lag) xmit_slave_id--; if (xmit_slave_id < 0) break; } if (xmit_slave_id >= 0 || slave == IP_NULL) { IPCOM_LOG1(ERR,"%s: could not find a slave to transmit on.", bondif->ipcom.name); return -IP_ERRNO_ENODEV; } #ifdef IPNET_BOND_DEBUG2 IPCOM_LOG2(DEBUG,"%s transmitting on slave %s", bondif->ipcom.name, slave->netif->ipcom.name); #endif return slave->netif->ipcom.drv_output(&slave->netif->ipcom, pkt); } #ifdef IPNET_USE_NETLINKSOCK /* *=========================================================================== * ipnet_bond_netlink_changelink *=========================================================================== * Description: Netlink LINKINFO changelink handler for devices * of kind "bond". * * Parameters: bondif - bond interface. * tb - Netlink attributes. * data - Netlink LINKINFO attributes. * * Returns: 0 = success, <0 = error code. * */ IP_STATIC int ipnet_bond_netlink_changelink(Ipnet_netif *bondif, struct Ip_nlattr *tb[], struct Ip_nlattr *data[]) { (void)tb; IPCOM_LOG1(DEBUG,"netlink %s: changing bond parameters.", bondif->ipcom.name); if (data[IP_IFLA_BOND_XMIT_POLICY - 1]) { ipnet_bond_set_xmit_policy(bondif, *(Ip_u8*)IP_RTA_DATA(data[IP_IFLA_BOND_XMIT_POLICY - 1])); } if (data[IP_IFLA_BOND_LAG_MEMBER - 1]) { struct Ip_ifla_bond_lag lag; ipcom_memcpy(&lag, IP_RTA_DATA(data[IP_IFLA_BOND_LAG_MEMBER - 1]), sizeof(lag)); ipnet_bond_set_lag_membership(bondif, lag.ifindex, lag.enabled); } return 0; } /* *=========================================================================== * ipnet_bond_netlink_newlink *=========================================================================== * Description: Netlink LINKINFO newlink handler for devices * of kind "bond". * * Parameters: bondif - bond interface. * tb - Netlink attributes. * data - Netlink LINKINFO attributes. * * Returns: 0 = success, <0 = error code. * */ IP_STATIC int ipnet_bond_netlink_newlink(Ipnet_netif *bondif, struct Ip_nlattr *tb[], struct Ip_nlattr *data[]) { IPCOM_LOG1(DEBUG,"netlink %s: initializing new bond interface.", bondif->ipcom.name); /* Set the master flag */ IP_BIT_SET(bondif->ipcom.flags, IP_IFF_MASTER); /* Setup the bond driver callbacks */ bondif->ipcom.drv_ioctl = (Ipcom_drv_ioctl)ipnet_bond_drv_ioctl; bondif->ipcom.drv_output = (Ipcom_drv_output)ipnet_bond_drv_output; bondif->ipcom.arphrd_type = IP_ARPHRD_ETHER; #ifdef IPNET_USE_NETLINKSOCK bondif->rtnetlink_ops = &bond_ops; #endif /* Create the bonding master block */ bondif->eth->bond.priv = ipcom_calloc(1, sizeof(Ipnet_bond_master)); if (IPNET_BOND_MASTER(bondif) == IP_NULL) return -IP_ERRNO_ENOMEM; /* Setup default xmit policy */ ipnet_bond_set_xmit_policy(bondif, IPNET_BOND_XMIT_POLICY_LAYER2); (void)ipnet_bond_netlink_changelink(bondif, tb, data); ipcom_list_init(&IPNET_BOND_MASTER(bondif)->slave_head); return ipcom_if_attach(&bondif->ipcom); } /* *=========================================================================== * ipnet_bond_netlink_dellink *=========================================================================== * Description: Netlink LINKINFO dellink handler for devices * of kind "bond". * * Parameters: bondif - bond interface. * tb - Netlink attributes. * data - Netlink LINKINFO attributes. * * Returns: 0 = success, <0 = error code. * */ IP_STATIC void ipnet_bond_netlink_dellink(Ipnet_netif *bondif) { IPCOM_LOG1(DEBUG,"netlink %s: deleting interface.", bondif->ipcom.name); ipnet_bond_if_destroy(bondif); } /* *=========================================================================== * ipnet_bond_netlink_get_size *=========================================================================== * Description: Netlink LINKINFO getsize handler for devices * of kind "bond". * * Parameters: * * Returns: 0 = success, <0 = error code. * */ IP_STATIC Ip_size_t ipnet_bond_netlink_get_size(Ipnet_netif *bondif) { Ip_size_t tot = 0; (void)bondif; tot += IP_RTA_LENGTH(sizeof(Ip_u8)); /* IP_IFLA_BOND_XMIT_POLICY */ tot += IP_RTA_LENGTH(sizeof(struct Ip_ifla_bond_lag)); /* IP_IFLA_BOND_LAG_MEMBER */ return tot; } /* *=========================================================================== * ipnet_bond_netlink_fill_info *=========================================================================== * Description: Netlink LINKINFO fillinfo handler for devices * of kind "bond". * * Parameters: mem - area to dump LINKINFO attributes in. * * * Returns: 0 = success, <0 = error code. * */ IP_STATIC int ipnet_bond_netlink_fill_info(Ipnet_netlink_mem_t *mem, Ipnet_netif *bondif) { if (!ipnet_rtnetlink_rta_sz_put(mem, IP_IFLA_BOND_XMIT_POLICY, sizeof(Ip_u8), &IPNET_BOND_MASTER(bondif)->policy)) return -1; return 0; } /* *=========================================================================== * ipnet_bond_netlink_notify_laginfo *=========================================================================== * Description: Netlink notify function for bonded ethernet devices. * Transmits info about joining/leaving of link aggregation * groups via netlink. * * Parameters: mem - area to dump LINKINFO attributes in. * * * Returns: 0 = success, <0 = error code. * */ IP_STATIC void ipnet_bond_netlink_notify_laginfo(Ipnet_netif *bondif, Ipnet_netif *slaveif, Ip_u32 lag_status) { struct Ip_ifinfomsg *ifm; struct Ip_nlattr *linkinfo, *linkdata; struct Ip_nlmsghdr *nlh; struct Ip_ifla_bond_lag lag; Ipcom_pkt *pkt = IP_NULL; Ipnet_netlink_mem_t mem; Ip_size_t tot = 0; tot += IP_NLMSG_ALIGN(sizeof(struct Ip_ifinfomsg)); tot += IP_RTA_LENGTH(IP_IFNAMSIZ); /* IP_IFLA_IFNAME */ tot += IP_RTA_LENGTH(sizeof(Ip_u32)); /* IP_IFLA_VR */ tot += IP_NLMSG_LENGTH(sizeof(struct Ip_nlattr)); /* IP_IFLA_LINKINFO */ tot += IP_NLMSG_LENGTH(strlen(bond_ops.kind) + 1); /* IP_IFLA_INFO_KIND */ tot += bond_ops.get_size(bondif); if (!ipnet_netlink_pkt_alloc(&pkt, IP_NULL, IP_TRUE, &mem, tot)) return; /* Must explicitly switch to the correct VR here */ pkt->vr_index = mem.vr = bondif->vr_index; nlh = ipnet_netlink_nlmsg_sz_begin(&mem, 0, IP_RTM_NEWLINK, 0); if (nlh == IP_NULL) goto errout; /* Setup the IFINFO header */ ifm = ipnet_netlink_sz_put(&mem, IP_NULL, sizeof(*ifm)); if (!ifm) goto errout; ifm->ifi_family = IP_AF_UNSPEC; ifm->ifi_type = (Ip_u16)IPCOM_ARPHRD_TYPE(&bondif->ipcom); ifm->ifi_index = bondif->ipcom.ifindex; ifm->ifi_flags = bondif->ipcom.flags; ifm->ifi_change = 0; /* Add device name as attribute */ if (!ipnet_rtnetlink_rta_sz_put(&mem, IP_IFLA_IFNAME, ipcom_strlen(bondif->ipcom.name) + 1, bondif->ipcom.name)) goto errout; if (!ipnet_rtnetlink_rta_sz_put(&mem, IP_IFLA_VR, sizeof(Ip_u32), &bondif->vr_index)) goto errout; /* * Setup a link info area with data. Will be handled * directly by the bond driver in the NAE. */ linkinfo = ipnet_rtnetlink_rta_sz_nested_begin(&mem, IP_IFLA_LINKINFO); if (linkinfo == IP_NULL) goto errout; if (!ipnet_rtnetlink_rta_sz_put(&mem, IP_IFLA_INFO_KIND, ipcom_strlen(bond_ops.kind) + 1, bond_ops.kind)) goto errout; linkdata = ipnet_rtnetlink_rta_sz_nested_begin(&mem, IP_IFLA_INFO_DATA); if (linkdata == IP_NULL) goto errout; /* Add bond specific link info attributes */ lag.ifindex = slaveif->ipcom.ifindex; lag.enabled = lag_status; if (!ipnet_rtnetlink_rta_sz_put(&mem, IP_IFLA_BOND_LAG_MEMBER, sizeof(struct Ip_ifla_bond_lag), &lag)) goto errout; ipnet_rtnetlink_rta_sz_nested_end(&mem, linkdata); ipnet_rtnetlink_rta_sz_nested_end(&mem, linkinfo); pkt->end = ipnet_netlink_nlmsg_sz_end(&mem, nlh); /* We're done; do report this pkt */ ipnet_rtnetlink_broadcast(pkt, IP_RTNLGRP_LINK); return; errout: ip_assert(pkt != IP_NULL); ipcom_pkt_free(pkt); } IP_STATIC struct Ip_rtnl_link_ops bond_ops = { IP_NULL, "bond", IP_IFLA_BOND_MAX, IP_IFT_ETHER, IP_NULL, IP_NULL, ipnet_bond_netlink_newlink, ipnet_bond_netlink_changelink, ipnet_bond_netlink_dellink, ipnet_bond_netlink_get_size, ipnet_bond_netlink_fill_info, IP_NULL, IP_NULL, IP_NULL, }; #endif /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipnet_bond_get_tx_slave *=========================================================================== * Description: Get transmission slave device for a bond device. * Parameters: pkt - The packet to transmit * ipcomif - A Bonding network interface. * Returns: 0 = success, <0 = error code. * */ IP_GLOBAL Ipcom_netif* ipnet_bond_get_tx_slave(Ipcom_pkt *pkt, Ipcom_netif *ipcomif) { Ipnet_bond_slave *slave = IP_NULL; Ipnet_netif *bondif = (Ipnet_netif*)ipcomif; int xmit_slave_id; xmit_slave_id = IPNET_BOND_MASTER(bondif)->xmit_policy(bondif, pkt); if (xmit_slave_id < 0) return IP_NULL; for (slave = IPCOM_LIST_FIRST(&IPNET_BOND_MASTER(bondif)->slave_head); slave; slave = IPCOM_LIST_NEXT(&slave->list)) { if (slave->active_in_lag) xmit_slave_id--; if (xmit_slave_id < 0) break; } if (xmit_slave_id >= 0 || slave == IP_NULL) { IPCOM_LOG1(ERR,"%s: could not find a transmit slave.", bondif->ipcom.name); return IP_NULL; } #ifdef IPNET_BOND_DEBUG2 IPCOM_LOG2(DEBUG,"%s ipnet_bond_get_tx_slave :: selected slave %s", bondif->ipcom.name, slave->netif->ipcom.name); #endif return &slave->netif->ipcom; } /* *=========================================================================== * ipnet_bond_if_enslave *=========================================================================== * Description: Enslaves a physical interface to the specified master. * Ethernet interface. * Parameters: bondif - A Bonding network interface. * netif - An Ethernet interface. * Returns: 0 = success, <0 = error code. * */ IP_GLOBAL int ipnet_bond_if_enslave(Ipnet_netif *bondif, Ipnet_netif *netif) { Ipnet_bond_slave *slave; if (netif->ipcom.type != IP_IFT_ETHER) /* Currently only Ethernet devices can be used as slaves */ return -IP_ERRNO_EINVAL; if (IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_SLAVE)) /* Interface already enslaved */ return -IP_ERRNO_EEXIST; if (IP_BIT_ISFALSE(bondif->ipcom.flags, IP_IFF_MASTER) || IPNET_BOND_MASTER(bondif) == IP_NULL) /* Not a valid bonding interface */ return -IP_ERRNO_EINVAL; for (slave = IPCOM_LIST_FIRST(&IPNET_BOND_MASTER(bondif)->slave_head); slave; slave = IPCOM_LIST_NEXT(&slave->list)) { if (slave->netif == netif) /* Interface already exists in this aggregation */ return -IP_ERRNO_EEXIST; } /* Create new slave entry */ slave = ipcom_calloc(1,sizeof(Ipnet_bond_slave)); if (slave == IP_NULL) return -IP_ERRNO_ENOMEM; slave->netif = netif; slave->active_in_lag = IP_FALSE; IPNET_IF_LOCK(bondif); /* * Bump ref counter on slave. * Hold it until the slave is release */ IPNET_IF_LOCK(netif); netif->eth->bond.master = bondif; IP_BIT_SET(netif->ipcom.flags, IP_IFF_SLAVE); /* DO we need a spinlock here ???*/ ipcom_list_insert_last(&IPNET_BOND_MASTER(bondif)->slave_head, &slave->list); IPNET_BOND_MASTER(bondif)->slave_count++; IPNET_IF_UNLOCK(bondif); IPNET_NETLINKSOCK(ipnet_rtnetlink_link_change(netif)); IPCOM_LOG2(INFO,"%s enslaved interface %s", bondif->ipcom.name, netif->ipcom.name ); return 0; } /* *=========================================================================== * ipnet_bond_release *=========================================================================== * Description: Release a slave from the specified bond device * Ethernet interface. * Parameters: bondif - A bond device. * netif - An Ethernet device. * Returns: * */ IP_GLOBAL int ipnet_bond_if_release(Ipnet_netif *netif) { Ipnet_bond_slave *slave = IP_NULL; Ipnet_netif *bondif = netif->eth->bond.master; if (netif->ipcom.type != IP_IFT_ETHER) /* Currently only Ethernet devices can be used as slaves */ return -IP_ERRNO_EINVAL; if (IP_BIT_ISFALSE(netif->ipcom.flags, IP_IFF_SLAVE)) /* Interface is not enslaved */ return -IP_ERRNO_EINVAL; if (IP_BIT_ISFALSE(bondif->ipcom.flags, IP_IFF_MASTER) || bondif->eth->bond.priv == IP_NULL) /* Not a valid bonding interface */ return -IP_ERRNO_EINVAL; /* Find the interface in the aggregation */ for (slave = IPCOM_LIST_FIRST(&IPNET_BOND_MASTER(bondif)->slave_head); slave; slave = IPCOM_LIST_NEXT(&slave->list)) { if (slave->netif == netif) break; } if (slave == IP_NULL) { /* The interface does not belong to this bond interface */ IPCOM_LOG2(ERR,"%s failed to release interface %s.", bondif->ipcom.name, netif->ipcom.name ); return -IP_ERRNO_ENOTFOUND; } IPNET_IF_LOCK(bondif); netif->eth->bond.master = IP_NULL; IP_BIT_CLR(netif->ipcom.flags, IP_IFF_SLAVE); /* DO we need a spinlock here ???*/ ipnet_bond_set_lag_membership(bondif, netif->ipcom.ifindex, IP_FALSE); ipcom_list_remove(&slave->list); IPNET_BOND_MASTER(bondif)->slave_count--; ipcom_free(slave); IPNET_NETLINKSOCK(ipnet_rtnetlink_link_change(netif)); IPCOM_LOG2(INFO,"%s released interface %s", bondif->ipcom.name, netif->ipcom.name ); IPNET_IF_UNLOCK(netif); IPNET_IF_UNLOCK(bondif); return 0; } /* *=========================================================================== * ipnet_bond_get_master *=========================================================================== * Description: Returns the master device of this enslaved * Ethernet interface. * Parameters: netif - An Ethernet device. * Returns: A netif pointer to the master device. * */ IP_GLOBAL Ipnet_netif* ipnet_bond_get_master(Ipnet_netif *netif) { if (netif->ipcom.type == IP_IFT_ETHER && IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_SLAVE)) return netif->eth->bond.master; return IP_NULL; } #ifdef IPNET_USE_NETLINKSOCK IP_GLOBAL void ipnet_bond_rtnetlink_init(void) { ipnet_rtnetlink_register_ops(&bond_ops); } #endif /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ #endif /* IPNET_USE_BOND */ /* **************************************************************************** * END OF FILE **************************************************************************** */