1054 lines
32 KiB
C
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
|
|
****************************************************************************
|
|
*/
|
|
|