Files
m241Neelima/components/ip_net2-6.9/ipnet2/src/ipnet_bond.c
T
2026-07-30 11:19:44 +05:30

1054 lines
32 KiB
C

/*
******************************************************************************
* 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 <Jonas.Rendel@windriver.com>
******************************************************************************
*/
/*
****************************************************************************
* 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 <ipcom_clib.h>
#include <ipcom_cstyle.h>
#include <ipcom_err.h>
#include <ipcom_hash.h>
#include <ipcom_type.h>
#include <ipcom_sock.h>
#ifndef IPNET_BOND_DEBUG
#include <ipcom_syslog.h>
#endif
#ifdef IPCOM_USE_FORWARDER
#include <ipcom_forwarder.h>
#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
****************************************************************************
*/