static u8 __get_duplex(struct port *port);
static inline void __initialize_port_locks(struct port *port);
//conversions
+static void __htons_lacpdu(struct lacpdu *lacpdu);
static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
// ================= main 802.3ad protocol functions ==================
static int ad_lacpdu_send(struct port *port);
-static int ad_marker_send(struct port *port, struct bond_marker *marker);
+static int ad_marker_send(struct port *port, struct marker *marker);
static void ad_mux_machine(struct port *port);
static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port);
static void ad_tx_machine(struct port *port);
static void ad_initialize_lacpdu(struct lacpdu *Lacpdu);
static void ad_enable_collecting_distributing(struct port *port);
static void ad_disable_collecting_distributing(struct port *port);
-static void ad_marker_info_received(struct bond_marker *marker_info, struct port *port);
-static void ad_marker_response_received(struct bond_marker *marker, struct port *port);
+static void ad_marker_info_received(struct marker *marker_info, struct port *port);
+static void ad_marker_response_received(struct marker *marker, struct port *port);
/////////////////////////////////////////////////////////////////////////////////
}
//conversions
+/**
+ * __htons_lacpdu - convert the contents of a LACPDU to network byte order
+ * @lacpdu: the speicifed lacpdu
+ *
+ * For each multi-byte field in the lacpdu, convert its content
+ */
+static void __htons_lacpdu(struct lacpdu *lacpdu)
+{
+ if (lacpdu) {
+ lacpdu->actor_system_priority = htons(lacpdu->actor_system_priority);
+ lacpdu->actor_key = htons(lacpdu->actor_key);
+ lacpdu->actor_port_priority = htons(lacpdu->actor_port_priority);
+ lacpdu->actor_port = htons(lacpdu->actor_port);
+ lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority);
+ lacpdu->partner_key = htons(lacpdu->partner_key);
+ lacpdu->partner_port_priority = htons(lacpdu->partner_port_priority);
+ lacpdu->partner_port = htons(lacpdu->partner_port);
+ lacpdu->collector_max_delay = htons(lacpdu->collector_max_delay);
+ }
+}
/**
* __ad_timer_to_ticks - convert a given timer type to AD module ticks
* lacpdu->actor_information_length initialized
*/
- lacpdu->actor_system_priority = htons(port->actor_system_priority);
+ lacpdu->actor_system_priority = port->actor_system_priority;
lacpdu->actor_system = port->actor_system;
- lacpdu->actor_key = htons(port->actor_oper_port_key);
- lacpdu->actor_port_priority = htons(port->actor_port_priority);
- lacpdu->actor_port = htons(port->actor_port_number);
+ lacpdu->actor_key = port->actor_oper_port_key;
+ lacpdu->actor_port_priority = port->actor_port_priority;
+ lacpdu->actor_port = port->actor_port_number;
lacpdu->actor_state = port->actor_oper_port_state;
/* lacpdu->reserved_3_1 initialized
* lacpdu->partner_information_length initialized
*/
- lacpdu->partner_system_priority = htons(port->partner_oper_system_priority);
+ lacpdu->partner_system_priority = port->partner_oper_system_priority;
lacpdu->partner_system = port->partner_oper_system;
- lacpdu->partner_key = htons(port->partner_oper_key);
- lacpdu->partner_port_priority = htons(port->partner_oper_port_priority);
- lacpdu->partner_port = htons(port->partner_oper_port_number);
+ lacpdu->partner_key = port->partner_oper_key;
+ lacpdu->partner_port_priority = port->partner_oper_port_priority;
+ lacpdu->partner_port = port->partner_oper_port_number;
lacpdu->partner_state = port->partner_oper_port_state;
/* lacpdu->reserved_3_2 initialized
* terminator_length initialized
* reserved_50[50] initialized
*/
+
+ /* Convert all non u8 parameters to Big Endian for transmit */
+ __htons_lacpdu(lacpdu);
}
//////////////////////////////////////////////////////////////////////////////////////
}
skb->dev = slave->dev;
- skb_reset_mac_header(skb);
- skb->nh.raw = skb->mac.raw + ETH_HLEN;
+ skb->mac.raw = skb->data;
+ skb->nh.raw = skb->data + ETH_HLEN;
skb->protocol = PKT_TYPE_LACPDU;
skb->priority = TC_PRIO_CONTROL;
* Returns: 0 on success
* < 0 on error
*/
-static int ad_marker_send(struct port *port, struct bond_marker *marker)
+static int ad_marker_send(struct port *port, struct marker *marker)
{
struct slave *slave = port->slave;
struct sk_buff *skb;
- struct bond_marker_header *marker_header;
- int length = sizeof(struct bond_marker_header);
+ struct marker_header *marker_header;
+ int length = sizeof(struct marker_header);
struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR;
skb = dev_alloc_skb(length + 16);
skb_reserve(skb, 16);
skb->dev = slave->dev;
- skb_reset_mac_header(skb);
- skb->nh.raw = skb->mac.raw + ETH_HLEN;
+ skb->mac.raw = skb->data;
+ skb->nh.raw = skb->data + ETH_HLEN;
skb->protocol = PKT_TYPE_LACPDU;
- marker_header = (struct bond_marker_header *)skb_put(skb, length);
+ marker_header = (struct marker_header *)skb_put(skb, length);
marker_header->ad_header.destination_address = lacpdu_multicast_address;
/* Note: source addres is set to be the member's PERMANENT address, because we use it
*/
static void ad_marker_info_send(struct port *port)
{
- struct bond_marker marker;
+ struct marker marker;
u16 index;
// fill the marker PDU with the appropriate values
* @port: the port we're looking at
*
*/
-static void ad_marker_info_received(struct bond_marker *marker_info,
- struct port *port)
+static void ad_marker_info_received(struct marker *marker_info,struct port *port)
{
- struct bond_marker marker;
+ struct marker marker;
// copy the received marker data to the response marker
//marker = *marker_info;
- memcpy(&marker, marker_info, sizeof(struct bond_marker));
+ memcpy(&marker, marker_info, sizeof(struct marker));
// change the marker subtype to marker response
marker.tlv_type=AD_MARKER_RESPONSE_SUBTYPE;
// send the marker response
* response for marker PDU's, in this stage, but only to respond to marker
* information.
*/
-static void ad_marker_response_received(struct bond_marker *marker,
- struct port *port)
+static void ad_marker_response_received(struct marker *marker, struct port *port)
{
marker=NULL; // just to satisfy the compiler
port=NULL; // just to satisfy the compiler
}
lacpdu->tlv_type_collector_info = 0x03;
lacpdu->collector_information_length= 0x10;
- lacpdu->collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY);
+ lacpdu->collector_max_delay = AD_COLLECTOR_MAX_DELAY;
for (index=0; index<=11; index++) {
lacpdu->reserved_12[index]=0;
}
* times out, and it selects an aggregator for the ports that are yet not
* related to any aggregator, and selects the active aggregator for a bond.
*/
-void bond_3ad_state_machine_handler(void *work_data)
+void bond_3ad_state_machine_handler(struct bonding *bond)
{
- struct bonding *bond = work_data;
struct port *port;
struct aggregator *aggregator;
}
re_arm:
- queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks);
+ mod_timer(&(BOND_AD_INFO(bond).ad_timer), jiffies + ad_delta_in_ticks);
out:
read_unlock(&bond->lock);
}
case AD_TYPE_MARKER:
// No need to convert fields to Little Endian since we don't use the marker's fields.
- switch (((struct bond_marker *)lacpdu)->tlv_type) {
+ switch (((struct marker *)lacpdu)->tlv_type) {
case AD_MARKER_INFORMATION_SUBTYPE:
dprintk("Received Marker Information on port %d\n", port->actor_port_number);
- ad_marker_info_received((struct bond_marker *)lacpdu, port);
+ ad_marker_info_received((struct marker *)lacpdu, port);
break;
case AD_MARKER_RESPONSE_SUBTYPE:
dprintk("Received Marker Response on port %d\n", port->actor_port_number);
- ad_marker_response_received((struct bond_marker *)lacpdu, port);
+ ad_marker_response_received((struct marker *)lacpdu, port);
break;
default:
}
/*
- * set link state for bonding master: if we have an active
+ * set link state for bonding master: if we have an active partnered
* aggregator, we're up, if not, we're down. Presumes that we cannot
* have an active aggregator if there are no slaves with link up.
*
- * This behavior complies with IEEE 802.3 section 43.3.9.
- *
* Called by bond_set_carrier(). Return zero if carrier state does not
* change, nonzero if it does.
*/
int bond_3ad_set_carrier(struct bonding *bond)
{
- if (__get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator))) {
+ struct aggregator *agg;
+
+ agg = __get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator));
+ if (agg && MAC_ADDRESS_COMPARE(&agg->partner_system, &null_mac_addr)) {
if (!netif_carrier_ok(bond->dev)) {
netif_carrier_on(bond->dev);
return 1;
typedef enum {
AD_MARKER_INFORMATION_SUBTYPE = 1, // marker imformation subtype
AD_MARKER_RESPONSE_SUBTYPE // marker response subtype
-} bond_marker_subtype_t;
+} marker_subtype_t;
// timers types(43.4.9 in the 802.3ad standard)
typedef enum {
typedef struct ad_header {
struct mac_addr destination_address;
struct mac_addr source_address;
- __be16 length_type;
+ u16 length_type;
} ad_header_t;
// Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard)
u8 version_number;
u8 tlv_type_actor_info; // = actor information(type/length/value)
u8 actor_information_length; // = 20
- __be16 actor_system_priority;
+ u16 actor_system_priority;
struct mac_addr actor_system;
- __be16 actor_key;
- __be16 actor_port_priority;
- __be16 actor_port;
+ u16 actor_key;
+ u16 actor_port_priority;
+ u16 actor_port;
u8 actor_state;
u8 reserved_3_1[3]; // = 0
u8 tlv_type_partner_info; // = partner information
u8 partner_information_length; // = 20
- __be16 partner_system_priority;
+ u16 partner_system_priority;
struct mac_addr partner_system;
- __be16 partner_key;
- __be16 partner_port_priority;
- __be16 partner_port;
+ u16 partner_key;
+ u16 partner_port_priority;
+ u16 partner_port;
u8 partner_state;
u8 reserved_3_2[3]; // = 0
u8 tlv_type_collector_info; // = collector information
u8 collector_information_length; // = 16
- __be16 collector_max_delay;
+ u16 collector_max_delay;
u8 reserved_12[12];
u8 tlv_type_terminator; // = terminator
u8 terminator_length; // = 0
} lacpdu_header_t;
// Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard)
-typedef struct bond_marker {
+typedef struct marker {
u8 subtype; // = 0x02 (marker PDU)
u8 version_number; // = 0x01
u8 tlv_type; // = 0x01 (marker information)
u8 tlv_type_terminator; // = 0x00
u8 terminator_length; // = 0x00
u8 reserved_90[90]; // = 0
-} bond_marker_t;
+} marker_t;
-typedef struct bond_marker_header {
+typedef struct marker_header {
struct ad_header ad_header;
- struct bond_marker marker;
-} bond_marker_header_t;
+ struct marker marker;
+} marker_header_t;
#pragma pack()
void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fast);
int bond_3ad_bind_slave(struct slave *slave);
void bond_3ad_unbind_slave(struct slave *slave);
-void bond_3ad_state_machine_handler(void *);
+void bond_3ad_state_machine_handler(struct bonding *bond);
void bond_3ad_adapter_speed_changed(struct slave *slave);
void bond_3ad_adapter_duplex_changed(struct slave *slave);
void bond_3ad_handle_link_change(struct slave *slave, char link);
struct learning_pkt {
u8 mac_dst[ETH_ALEN];
u8 mac_src[ETH_ALEN];
- __be16 type;
+ u16 type;
u8 padding[ETH_ZLEN - ETH_HLEN];
};
struct arp_pkt {
- __be16 hw_addr_space;
- __be16 prot_addr_space;
+ u16 hw_addr_space;
+ u16 prot_addr_space;
u8 hw_addr_len;
u8 prot_addr_len;
- __be16 op_code;
+ u16 op_code;
u8 mac_src[ETH_ALEN]; /* sender hardware address */
- __be32 ip_src; /* sender IP address */
+ u32 ip_src; /* sender IP address */
u8 mac_dst[ETH_ALEN]; /* target hardware address */
- __be32 ip_dst; /* target IP address */
+ u32 ip_dst; /* target IP address */
};
#pragma pack()
-static inline struct arp_pkt *arp_pkt(const struct sk_buff *skb)
-{
- return (struct arp_pkt *)skb_network_header(skb);
-}
-
/* Forward declaration */
static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]);
-static inline u8 _simple_hash(const u8 *hash_start, int hash_size)
+static inline u8 _simple_hash(u8 *hash_start, int hash_size)
{
int i;
u8 hash = 0;
static inline void _lock_tx_hashtbl(struct bonding *bond)
{
- spin_lock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
+ spin_lock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
}
static inline void _unlock_tx_hashtbl(struct bonding *bond)
{
- spin_unlock_bh(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
+ spin_unlock(&(BOND_ALB_INFO(bond).tx_hashtbl_lock));
}
/* Caller must hold tx_hashtbl lock */
/*********************** rlb specific functions ***************************/
static inline void _lock_rx_hashtbl(struct bonding *bond)
{
- spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+ spin_lock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
}
static inline void _unlock_rx_hashtbl(struct bonding *bond)
{
- spin_unlock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
+ spin_unlock(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
}
/* when an ARP REPLY is received from a client update its info
_unlock_rx_hashtbl(bond);
- write_lock_bh(&bond->curr_slave_lock);
+ write_lock(&bond->curr_slave_lock);
if (slave != bond->curr_active_slave) {
rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr);
}
- write_unlock_bh(&bond->curr_slave_lock);
+ write_unlock(&bond->curr_slave_lock);
}
static void rlb_update_client(struct rlb_client_info *client_info)
}
/* mark all clients using src_ip to be updated */
-static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip)
+static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct rlb_client_info *client_info;
static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bond)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
- struct arp_pkt *arp = arp_pkt(skb);
+ struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw;
struct slave *assigned_slave;
struct rlb_client_info *client_info;
u32 hash_index = 0;
*/
static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
{
- struct arp_pkt *arp = arp_pkt(skb);
+ struct arp_pkt *arp = (struct arp_pkt *)skb->nh.raw;
struct slave *tx_slave = NULL;
if (arp->op_code == __constant_htons(ARPOP_REPLY)) {
data = skb_put(skb, size);
memcpy(data, &pkt, size);
- skb_reset_mac_header(skb);
- skb->nh.raw = skb->mac.raw + ETH_HLEN;
+ skb->mac.raw = data;
+ skb->nh.raw = data + ETH_HLEN;
skb->protocol = pkt.type;
skb->priority = TC_PRIO_CONTROL;
skb->dev = slave->dev;
return 0;
}
-/*
- * Swap MAC addresses between two slaves.
- *
- * Called with RTNL held, and no other locks.
- *
- */
-
+/* Caller must hold bond lock for write or curr_slave_lock for write*/
static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct slave *slave2)
{
+ struct slave *disabled_slave = NULL;
u8 tmp_mac_addr[ETH_ALEN];
+ int slaves_state_differ;
+
+ slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2));
memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN);
alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled);
alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled);
-}
-
-/*
- * Send learning packets after MAC address swap.
- *
- * Called with RTNL and bond->lock held for read.
- */
-static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1,
- struct slave *slave2)
-{
- int slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2));
- struct slave *disabled_slave = NULL;
-
/* fasten the change in the switch */
if (SLAVE_IS_OK(slave1)) {
alb_send_learning_packets(slave1, slave1->dev->dev_addr);
}
if (found) {
- /* locking: needs RTNL and nothing else */
alb_swap_mac_addr(bond, slave, tmp_slave);
- alb_fasten_mac_swap(bond, slave, tmp_slave);
}
}
}
struct ethhdr *eth_data;
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct slave *tx_slave = NULL;
- static __be32 ip_bcast;
+ static const u32 ip_bcast = 0xffffffff;
int hash_size = 0;
int do_tx_balance = 1;
u32 hash_index = 0;
- const u8 *hash_start = NULL;
+ u8 *hash_start = NULL;
int res = 1;
- ip_bcast = htonl(0xffffffff);
- skb_reset_mac_header(skb);
+ skb->mac.raw = (unsigned char *)skb->data;
eth_data = eth_hdr(skb);
/* make sure that the curr_active_slave and the slaves list do
}
switch (ntohs(skb->protocol)) {
- case ETH_P_IP: {
- const struct iphdr *iph = ip_hdr(skb);
-
+ case ETH_P_IP:
if ((memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) ||
- (iph->daddr == ip_bcast) ||
- (iph->protocol == IPPROTO_IGMP)) {
+ (skb->nh.iph->daddr == ip_bcast) ||
+ (skb->nh.iph->protocol == IPPROTO_IGMP)) {
do_tx_balance = 0;
break;
}
- hash_start = (char *)&(iph->daddr);
- hash_size = sizeof(iph->daddr);
- }
+ hash_start = (char*)&(skb->nh.iph->daddr);
+ hash_size = sizeof(skb->nh.iph->daddr);
break;
case ETH_P_IPV6:
if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) {
break;
}
- hash_start = (char *)&(ipv6_hdr(skb)->daddr);
- hash_size = sizeof(ipv6_hdr(skb)->daddr);
+ hash_start = (char*)&(skb->nh.ipv6h->daddr);
+ hash_size = sizeof(skb->nh.ipv6h->daddr);
break;
case ETH_P_IPX:
- if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) {
+ if (ipx_hdr(skb)->ipx_checksum !=
+ __constant_htons(IPX_NO_CHECKSUM)) {
/* something is wrong with this packet */
do_tx_balance = 0;
break;
return 0;
}
-void bond_alb_monitor(void *work_data)
+void bond_alb_monitor(struct bonding *bond)
{
- struct bonding *bond = work_data;
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
struct slave *slave;
int i;
/* handle rlb stuff */
if (bond_info->rlb_enabled) {
+ /* the following code changes the promiscuity of the
+ * the curr_active_slave. It needs to be locked with a
+ * write lock to protect from other code that also
+ * sets the promiscuity.
+ */
+ write_lock_bh(&bond->curr_slave_lock);
+
if (bond_info->primary_is_promisc &&
(++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) {
- /*
- * dev_set_promiscuity requires rtnl and
- * nothing else.
- */
- read_unlock(&bond->lock);
- rtnl_lock();
-
bond_info->rlb_promisc_timeout_counter = 0;
/* If the primary was set to promiscuous mode
*/
dev_set_promiscuity(bond->curr_active_slave->dev, -1);
bond_info->primary_is_promisc = 0;
-
- rtnl_unlock();
- read_lock(&bond->lock);
}
+ write_unlock_bh(&bond->curr_slave_lock);
+
if (bond_info->rlb_rebalance) {
bond_info->rlb_rebalance = 0;
rlb_rebalance(bond);
}
re_arm:
- queue_delayed_work(bond->wq, &bond->alb_work, alb_delta_in_ticks);
+ mod_timer(&(bond_info->alb_timer), jiffies + alb_delta_in_ticks);
out:
read_unlock(&bond->lock);
}
/* caller must hold the bond lock for write since the mac addresses
* are compared and may be swapped.
*/
- read_lock(&bond->lock);
+ write_lock_bh(&bond->lock);
res = alb_handle_addr_collision_on_attach(bond, slave);
- read_unlock(&bond->lock);
+ write_unlock_bh(&bond->lock);
if (res) {
return res;
* Set the bond->curr_active_slave to @new_slave and handle
* mac address swapping and promiscuity changes as needed.
*
- * If new_slave is NULL, caller must hold curr_slave_lock or
- * bond->lock for write.
- *
- * If new_slave is not NULL, caller must hold RTNL, bond->lock for
- * read and curr_slave_lock for write. Processing here may sleep, so
- * no other locks may be held.
+ * Caller must hold bond curr_slave_lock for write (or bond lock for write)
*/
void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave)
{
struct slave *swap_slave;
int i;
- if (new_slave)
- ASSERT_RTNL();
-
if (bond->curr_active_slave == new_slave) {
return;
}
}
}
- /*
- * Arrange for swap_slave and new_slave to temporarily be
- * ignored so we can mess with their MAC addresses without
- * fear of interference from transmit activity.
- */
- if (swap_slave) {
- tlb_clear_slave(bond, swap_slave, 1);
- }
- tlb_clear_slave(bond, new_slave, 1);
-
- write_unlock_bh(&bond->curr_slave_lock);
- read_unlock(&bond->lock);
-
/* curr_active_slave must be set before calling alb_swap_mac_addr */
if (swap_slave) {
/* swap mac address */
/* set the new_slave to the bond mac address */
alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr,
bond->alb_info.rlb_enabled);
- }
-
- read_lock(&bond->lock);
-
- if (swap_slave) {
- alb_fasten_mac_swap(bond, swap_slave, new_slave);
- } else {
/* fasten bond mac on new current slave */
alb_send_learning_packets(new_slave, bond->dev->dev_addr);
}
-
- write_lock_bh(&bond->curr_slave_lock);
}
-/*
- * Called with RTNL
- */
int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
{
struct bonding *bond = bond_dev->priv;
}
}
- write_unlock_bh(&bond->curr_slave_lock);
- read_unlock(&bond->lock);
-
if (swap_slave) {
alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave);
- alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave);
} else {
alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr,
bond->alb_info.rlb_enabled);
}
}
- read_lock(&bond->lock);
- write_lock_bh(&bond->curr_slave_lock);
-
return 0;
}
* -------------------------------------------------------------------------
*/
struct rlb_client_info {
- __be32 ip_src; /* the server IP address */
- __be32 ip_dst; /* the client IP address */
+ u32 ip_src; /* the server IP address */
+ u32 ip_dst; /* the client IP address */
u8 mac_dst[ETH_ALEN]; /* the client MAC address */
u32 next; /* The next Hash table entry index */
u32 prev; /* The previous Hash table entry index */
void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char link);
void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave);
int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
-void bond_alb_monitor(void *);
+void bond_alb_monitor(struct bonding *bond);
int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr);
void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id);
#endif /* __BOND_ALB_H__ */
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/if_bonding.h>
-#include <linux/jiffies.h>
#include <net/route.h>
#include "bonding.h"
#include "bond_3ad.h"
static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
static char *arp_validate = NULL;
-static int fail_over_mac = 0;
struct bond_params bonding_defaults;
module_param(max_bonds, int, 0);
MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
module_param(arp_validate, charp, 0);
MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
-module_param(fail_over_mac, int, 0);
-MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. 0 of off (default), 1 for on.");
/*----------------------------- Global variables ----------------------------*/
#endif
extern struct rw_semaphore bonding_rwsem;
-static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
+static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
static int arp_ip_count = 0;
static int bond_mode = BOND_MODE_ROUNDROBIN;
static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2;
struct bond_parm_tbl xmit_hashtype_tbl[] = {
{ "layer2", BOND_XMIT_POLICY_LAYER2},
{ "layer3+4", BOND_XMIT_POLICY_LAYER34},
-{ "layer2+3", BOND_XMIT_POLICY_LAYER23},
{ NULL, -1},
};
/*-------------------------- Forward declarations ---------------------------*/
static void bond_send_gratuitous_arp(struct bonding *bond);
-static void bond_deinit(struct net_device *bond_dev);
/*---------------------------- General routines -----------------------------*/
-static const char *bond_mode_name(int mode)
+const char *bond_mode_name(int mode)
{
switch (mode) {
case BOND_MODE_ROUNDROBIN :
if (new_active) {
bond_set_slave_active_flags(new_active);
}
-
- /* when bonding does not set the slave MAC address, the bond MAC
- * address is the one of the active slave.
- */
- if (new_active && bond->params.fail_over_mac)
- memcpy(bond->dev->dev_addr, new_active->dev->dev_addr,
- new_active->dev->addr_len);
- if (bond->curr_active_slave &&
- test_bit(__LINK_STATE_LINKWATCH_PENDING,
- &bond->curr_active_slave->dev->state)) {
- dprintk("delaying gratuitous arp on %s\n",
- bond->curr_active_slave->dev->name);
- bond->send_grat_arp = 1;
- } else
- bond_send_gratuitous_arp(bond);
+ bond_send_gratuitous_arp(bond);
}
}
/*---------------------------------- IOCTL ----------------------------------*/
-static int bond_sethwaddr(struct net_device *bond_dev,
- struct net_device *slave_dev)
+int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev)
{
dprintk("bond_dev=%p\n", bond_dev);
dprintk("slave_dev=%p\n", slave_dev);
return 0;
}
-#define BOND_VLAN_FEATURES \
- (NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \
- NETIF_F_HW_VLAN_FILTER)
+#define BOND_INTERSECT_FEATURES \
+ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_TSO | NETIF_F_UFO)
/*
* Compute the common dev->feature set available to all slaves. Some
- * feature bits are managed elsewhere, so preserve those feature bits
- * on the master device.
+ * feature bits are managed elsewhere, so preserve feature bits set on
+ * master device that are not part of the examined set.
*/
static int bond_compute_features(struct bonding *bond)
{
+ unsigned long features = BOND_INTERSECT_FEATURES;
struct slave *slave;
struct net_device *bond_dev = bond->dev;
- unsigned long features = bond_dev->features;
unsigned short max_hard_header_len = ETH_HLEN;
int i;
- features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
- features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
- NETIF_F_GSO_MASK | NETIF_F_NO_CSUM;
-
bond_for_each_slave(bond, slave, i) {
- features = netdev_compute_features(features,
- slave->dev->features);
+ features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
if (slave->dev->hard_header_len > max_hard_header_len)
max_hard_header_len = slave->dev->hard_header_len;
}
- features |= (bond_dev->features & BOND_VLAN_FEATURES);
+ if ((features & NETIF_F_SG) &&
+ !(features & NETIF_F_ALL_CSUM))
+ features &= ~NETIF_F_SG;
+
+ /*
+ * features will include NETIF_F_TSO (NETIF_F_UFO) iff all
+ * slave devices support NETIF_F_TSO (NETIF_F_UFO), which
+ * implies that all slaves also support scatter-gather
+ * (NETIF_F_SG), which implies that features also includes
+ * NETIF_F_SG. So no need to check whether we have an
+ * illegal combination of NETIF_F_{TSO,UFO} and
+ * !NETIF_F_SG
+ */
+
+ features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES);
bond_dev->features = features;
bond_dev->hard_header_len = max_hard_header_len;
}
if (slave_dev->set_mac_address == NULL) {
- if (bond->slave_cnt == 0) {
- printk(KERN_WARNING DRV_NAME
- ": %s: Warning: The first slave device "
- "specified does not support setting the MAC "
- "address. Enabling the fail_over_mac option.",
- bond_dev->name);
- bond->params.fail_over_mac = 1;
- } else if (!bond->params.fail_over_mac) {
- printk(KERN_ERR DRV_NAME
- ": %s: Error: The slave device specified "
- "does not support setting the MAC address, "
- "but fail_over_mac is not enabled.\n"
- , bond_dev->name);
- res = -EOPNOTSUPP;
- goto err_undo_flags;
- }
+ printk(KERN_ERR DRV_NAME
+ ": %s: Error: The slave device you specified does "
+ "not support setting the MAC address. "
+ "Your kernel likely does not support slave "
+ "devices.\n", bond_dev->name);
+ res = -EOPNOTSUPP;
+ goto err_undo_flags;
}
if (slave_dev->get_stats == NULL) {
*/
memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN);
- if (!bond->params.fail_over_mac) {
- /*
- * Set slave to master's mac address. The application already
- * set the master's mac address to that of the first slave
- */
- memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
- addr.sa_family = slave_dev->type;
- res = dev_set_mac_address(slave_dev, &addr);
- if (res) {
- dprintk("Error %d calling set_mac_address\n", res);
- goto err_free;
- }
- }
-
- res = netdev_set_master(slave_dev, bond_dev);
+ /*
+ * Set slave to master's mac address. The application already
+ * set the master's mac address to that of the first slave
+ */
+ memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len);
+ addr.sa_family = slave_dev->type;
+ res = dev_set_mac_address(slave_dev, &addr);
if (res) {
- dprintk("Error %d calling netdev_set_master\n", res);
- goto err_close;
+ dprintk("Error %d calling set_mac_address\n", res);
+ goto err_free;
}
+
/* open the slave since the application closed it */
res = dev_open(slave_dev);
if (res) {
goto err_restore_mac;
}
+ res = netdev_set_master(slave_dev, bond_dev);
+ if (res) {
+ dprintk("Error %d calling netdev_set_master\n", res);
+ goto err_close;
+ }
+
new_slave->dev = slave_dev;
slave_dev->priv_flags |= IFF_BONDING;
case BOND_MODE_TLB:
case BOND_MODE_ALB:
new_slave->state = BOND_STATE_ACTIVE;
- bond_set_slave_inactive_flags(new_slave);
+ if ((!bond->curr_active_slave) &&
+ (new_slave->link != BOND_LINK_DOWN)) {
+ /* first slave or no active slave yet, and this link
+ * is OK, so make this interface the active one
+ */
+ bond_change_active_slave(bond, new_slave);
+ } else {
+ bond_set_slave_inactive_flags(new_slave);
+ }
break;
default:
dprintk("This slave is always active in trunk mode\n");
dev_close(slave_dev);
err_restore_mac:
- if (!bond->params.fail_over_mac) {
- memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
- }
+ memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN);
+ addr.sa_family = slave_dev->type;
+ dev_set_mac_address(slave_dev, &addr);
err_free:
kfree(new_slave);
bond_alb_deinit_slave(bond, slave);
}
- if (oldcurrent == slave) {
- /*
- * Note that we hold RTNL over this sequence, so there
- * is no concern that another slave add/remove event
- * will interfere.
- */
- write_unlock_bh(&bond->lock);
- read_lock(&bond->lock);
- write_lock_bh(&bond->curr_slave_lock);
-
+ if (oldcurrent == slave)
bond_select_active_slave(bond);
- write_unlock_bh(&bond->curr_slave_lock);
- read_unlock(&bond->lock);
- write_lock_bh(&bond->lock);
- }
-
if (bond->slave_cnt == 0) {
bond_set_carrier(bond);
/* close slave before restoring its mac address */
dev_close(slave_dev);
- if (!bond->params.fail_over_mac) {
- /* restore original ("permanent") mac address */
- memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
- }
+ /* restore original ("permanent") mac address */
+ memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+ addr.sa_family = slave_dev->type;
+ dev_set_mac_address(slave_dev, &addr);
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
IFF_SLAVE_INACTIVE | IFF_BONDING |
return 0; /* deletion OK */
}
-/*
-* Destroy a bonding device.
-* Must be under rtnl_lock when this function is called.
-*/
-void bond_destroy(struct bonding *bond)
-{
- bond_deinit(bond->dev);
- bond_destroy_sysfs_entry(bond);
- unregister_netdevice(bond->dev);
-}
-
-/*
-* First release a slave and than destroy the bond if no more slaves iare left.
-* Must be under rtnl_lock when this function is called.
-*/
-int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev)
-{
- struct bonding *bond = bond_dev->priv;
- int ret;
-
- ret = bond_release(bond_dev, slave_dev);
- if ((ret == 0) && (bond->slave_cnt == 0)) {
- printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n",
- bond_dev->name, bond_dev->name);
- bond_destroy(bond);
- }
- return ret;
-}
-
/*
* This function releases all slaves.
*/
/* close slave before restoring its mac address */
dev_close(slave_dev);
- if (!bond->params.fail_over_mac) {
- /* restore original ("permanent") mac address*/
- memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
- addr.sa_family = slave_dev->type;
- dev_set_mac_address(slave_dev, &addr);
- }
+ /* restore original ("permanent") mac address*/
+ memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN);
+ addr.sa_family = slave_dev->type;
+ dev_set_mac_address(slave_dev, &addr);
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
IFF_SLAVE_INACTIVE);
return -EINVAL;
}
- read_lock(&bond->lock);
+ write_lock_bh(&bond->lock);
- read_lock(&bond->curr_slave_lock);
old_active = bond->curr_active_slave;
- read_unlock(&bond->curr_slave_lock);
-
new_active = bond_get_slave_by_dev(bond, slave_dev);
/*
* Changing to the current active: do nothing; return success.
*/
if (new_active && (new_active == old_active)) {
- read_unlock(&bond->lock);
+ write_unlock_bh(&bond->lock);
return 0;
}
(old_active) &&
(new_active->link == BOND_LINK_UP) &&
IS_UP(new_active->dev)) {
- write_lock_bh(&bond->curr_slave_lock);
bond_change_active_slave(bond, new_active);
- write_unlock_bh(&bond->curr_slave_lock);
} else {
res = -EINVAL;
}
- read_unlock(&bond->lock);
+ write_unlock_bh(&bond->lock);
return res;
}
info->bond_mode = bond->params.mode;
info->miimon = bond->params.miimon;
- read_lock(&bond->lock);
+ read_lock_bh(&bond->lock);
info->num_slaves = bond->slave_cnt;
- read_unlock(&bond->lock);
+ read_unlock_bh(&bond->lock);
return 0;
}
return -ENODEV;
}
- read_lock(&bond->lock);
+ read_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i) {
if (i == (int)info->slave_id) {
}
}
- read_unlock(&bond->lock);
+ read_unlock_bh(&bond->lock);
if (found) {
strcpy(info->slave_name, slave->dev->name);
/*-------------------------------- Monitoring -------------------------------*/
-/*
- * if !have_locks, return nonzero if a failover is necessary. if
- * have_locks, do whatever failover activities are needed.
- *
- * This is to separate the inspection and failover steps for locking
- * purposes; failover requires rtnl, but acquiring it for every
- * inspection is undesirable, so a wrapper first does inspection, and
- * the acquires the necessary locks and calls again to perform
- * failover if needed. Since all locks are dropped, a complete
- * restart is needed between calls.
- */
-static int __bond_mii_monitor(struct bonding *bond, int have_locks)
+/* this function is called regularly to monitor each slave's link. */
+void bond_mii_monitor(struct net_device *bond_dev)
{
+ struct bonding *bond = bond_dev->priv;
struct slave *slave, *oldcurrent;
int do_failover = 0;
+ int delta_in_ticks;
int i;
- if (bond->slave_cnt == 0)
+ read_lock(&bond->lock);
+
+ delta_in_ticks = (bond->params.miimon * HZ) / 1000;
+
+ if (bond->kill_timers) {
goto out;
+ }
+
+ if (bond->slave_cnt == 0) {
+ goto re_arm;
+ }
/* we will try to read the link status of each of our slaves, and
* set their IFF_RUNNING flag appropriately. For each slave not
* program could monitor the link itself if needed.
*/
- if (bond->send_grat_arp) {
- if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING,
- &bond->curr_active_slave->dev->state))
- dprintk("Needs to send gratuitous arp but not yet\n");
- else {
- dprintk("sending delayed gratuitous arp on on %s\n",
- bond->curr_active_slave->dev->name);
- bond_send_gratuitous_arp(bond);
- bond->send_grat_arp = 0;
- }
- }
read_lock(&bond->curr_slave_lock);
oldcurrent = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock);
switch (slave->link) {
case BOND_LINK_UP: /* the link was up */
if (link_state == BMSR_LSTATUS) {
- if (!oldcurrent) {
- if (!have_locks)
- return 1;
- do_failover = 1;
- }
+ /* link stays up, nothing more to do */
break;
} else { /* link going down */
slave->link = BOND_LINK_FAIL;
": %s: link status down for %s "
"interface %s, disabling it in "
"%d ms.\n",
- bond->dev->name,
+ bond_dev->name,
IS_UP(slave_dev)
? ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
? ((slave == oldcurrent)
if (link_state != BMSR_LSTATUS) {
/* link stays down */
if (slave->delay <= 0) {
- if (!have_locks)
- return 1;
-
/* link down for too long time */
slave->link = BOND_LINK_DOWN;
": %s: link status definitely "
"down for interface %s, "
"disabling it\n",
- bond->dev->name,
+ bond_dev->name,
slave_dev->name);
/* notify ad that the link status has changed */
printk(KERN_INFO DRV_NAME
": %s: link status up again after %d "
"ms for interface %s.\n",
- bond->dev->name,
+ bond_dev->name,
(bond->params.downdelay - slave->delay) * bond->params.miimon,
slave_dev->name);
}
": %s: link status up for "
"interface %s, enabling it "
"in %d ms.\n",
- bond->dev->name,
+ bond_dev->name,
slave_dev->name,
bond->params.updelay * bond->params.miimon);
}
printk(KERN_INFO DRV_NAME
": %s: link status down again after %d "
"ms for interface %s.\n",
- bond->dev->name,
+ bond_dev->name,
(bond->params.updelay - slave->delay) * bond->params.miimon,
slave_dev->name);
} else {
/* link stays up */
if (slave->delay == 0) {
- if (!have_locks)
- return 1;
-
/* now the link has been up for long time enough */
slave->link = BOND_LINK_UP;
slave->jiffies = jiffies;
printk(KERN_INFO DRV_NAME
": %s: link status definitely "
"up for interface %s.\n",
- bond->dev->name,
+ bond_dev->name,
slave_dev->name);
/* notify ad that the link status has changed */
/* Should not happen */
printk(KERN_ERR DRV_NAME
": %s: Error: %s Illegal value (link=%d)\n",
- bond->dev->name,
+ bond_dev->name,
slave->dev->name,
slave->link);
goto out;
} /* end of for */
if (do_failover) {
- ASSERT_RTNL();
-
- write_lock_bh(&bond->curr_slave_lock);
+ write_lock(&bond->curr_slave_lock);
bond_select_active_slave(bond);
- write_unlock_bh(&bond->curr_slave_lock);
-
+ write_unlock(&bond->curr_slave_lock);
} else
bond_set_carrier(bond);
-out:
- return 0;
-}
-
-/*
- * bond_mii_monitor
- *
- * Really a wrapper that splits the mii monitor into two phases: an
- * inspection, then (if inspection indicates something needs to be
- * done) an acquisition of appropriate locks followed by another pass
- * to implement whatever link state changes are indicated.
- */
-void bond_mii_monitor(void *work_data)
-{
- struct bonding *bond = work_data;
- unsigned long delay;
-
- read_lock(&bond->lock);
- if (bond->kill_timers) {
- read_unlock(&bond->lock);
- return;
- }
- if (__bond_mii_monitor(bond, 0)) {
- read_unlock(&bond->lock);
- rtnl_lock();
- read_lock(&bond->lock);
- __bond_mii_monitor(bond, 1);
- rtnl_unlock();
+re_arm:
+ if (bond->params.miimon) {
+ mod_timer(&bond->mii_timer, jiffies + delta_in_ticks);
}
-
- delay = ((bond->params.miimon * HZ) / 1000) ? : 1;
+out:
read_unlock(&bond->lock);
- queue_delayed_work(bond->wq, &bond->mii_work, delay);
}
-static __be32 bond_glean_dev_ip(struct net_device *dev)
+
+static u32 bond_glean_dev_ip(struct net_device *dev)
{
struct in_device *idev;
struct in_ifaddr *ifa;
return 0;
}
-static int bond_has_this_ip(struct bonding *bond, __be32 ip)
+static int bond_has_this_ip(struct bonding *bond, u32 ip)
{
struct vlan_entry *vlan, *vlan_next;
* switches in VLAN mode (especially if ports are configured as
* "native" to a VLAN) might not pass non-tagged frames.
*/
-static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ip, __be32 src_ip, unsigned short vlan_id)
+static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, u32 src_ip, unsigned short vlan_id)
{
struct sk_buff *skb;
static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
{
int i, vlan_id, rv;
- __be32 *targets = bond->params.arp_targets;
+ u32 *targets = bond->params.arp_targets;
struct vlan_entry *vlan, *vlan_next;
struct net_device *vlan_dev;
struct flowi fl;
if (bond->master_ip) {
bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
- bond->master_ip, 0);
+ bond->master_ip, 0);
}
list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
}
}
-static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip)
+static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip)
{
int i;
- __be32 *targets = bond->params.arp_targets;
+ u32 *targets = bond->params.arp_targets;
targets = bond->params.arp_targets;
for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
struct slave *slave;
struct bonding *bond;
unsigned char *arp_ptr;
- __be32 sip, tip;
+ u32 sip, tip;
if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
goto out;
(2 * sizeof(u32)))))
goto out_unlock;
- arp = arp_hdr(skb);
+ arp = skb->nh.arph;
if (arp->ar_hln != dev->addr_len ||
skb->pkt_type == PACKET_OTHERHOST ||
skb->pkt_type == PACKET_LOOPBACK ||
* arp is transmitted to generate traffic. see activebackup_arp_monitor for
* arp monitoring in active backup mode.
*/
-void bond_loadbalance_arp_mon(void *work_data)
+void bond_loadbalance_arp_mon(struct net_device *bond_dev)
{
- struct bonding *bond = work_data;
+ struct bonding *bond = bond_dev->priv;
struct slave *slave, *oldcurrent;
int do_failover = 0;
int delta_in_ticks;
*/
bond_for_each_slave(bond, slave, i) {
if (slave->link != BOND_LINK_UP) {
- if (time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks) &&
- time_before_eq(jiffies, slave->dev->last_rx + delta_in_ticks)) {
+ if (((jiffies - slave->dev->trans_start) <= delta_in_ticks) &&
+ ((jiffies - slave->dev->last_rx) <= delta_in_ticks)) {
slave->link = BOND_LINK_UP;
slave->state = BOND_STATE_ACTIVE;
printk(KERN_INFO DRV_NAME
": %s: link status definitely "
"up for interface %s, ",
- bond->dev->name,
+ bond_dev->name,
slave->dev->name);
do_failover = 1;
} else {
printk(KERN_INFO DRV_NAME
": %s: interface %s is now up\n",
- bond->dev->name,
+ bond_dev->name,
slave->dev->name);
}
}
* when the source ip is 0, so don't take the link down
* if we don't know our ip yet
*/
- if (time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) ||
- (time_after_eq(jiffies, slave->dev->last_rx + 2*delta_in_ticks) &&
+ if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
+ (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
bond_has_ip(bond))) {
slave->link = BOND_LINK_DOWN;
printk(KERN_INFO DRV_NAME
": %s: interface %s is now down.\n",
- bond->dev->name,
+ bond_dev->name,
slave->dev->name);
if (slave == oldcurrent) {
}
if (do_failover) {
- rtnl_lock();
- write_lock_bh(&bond->curr_slave_lock);
+ write_lock(&bond->curr_slave_lock);
bond_select_active_slave(bond);
- write_unlock_bh(&bond->curr_slave_lock);
- rtnl_unlock();
-
+ write_unlock(&bond->curr_slave_lock);
}
re_arm:
- if (bond->params.arp_interval)
- queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
+ if (bond->params.arp_interval) {
+ mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
+ }
out:
read_unlock(&bond->lock);
}
* may have received.
* see loadbalance_arp_monitor for arp monitoring in load balancing mode
*/
-void bond_activebackup_arp_mon(void *work_data)
+void bond_activebackup_arp_mon(struct net_device *bond_dev)
{
- struct bonding *bond = work_data;
+ struct bonding *bond = bond_dev->priv;
struct slave *slave;
int delta_in_ticks;
int i;
*/
bond_for_each_slave(bond, slave, i) {
if (slave->link != BOND_LINK_UP) {
- if (time_before_eq(jiffies,
- slave_last_rx(bond, slave) + delta_in_ticks)) {
+ if ((jiffies - slave_last_rx(bond, slave)) <=
+ delta_in_ticks) {
slave->link = BOND_LINK_UP;
- rtnl_lock();
-
- write_lock_bh(&bond->curr_slave_lock);
+ write_lock(&bond->curr_slave_lock);
if ((!bond->curr_active_slave) &&
- time_before_eq(jiffies, slave->dev->trans_start + delta_in_ticks)) {
+ ((jiffies - slave->dev->trans_start) <= delta_in_ticks)) {
bond_change_active_slave(bond, slave);
bond->current_arp_slave = NULL;
} else if (bond->curr_active_slave != slave) {
printk(KERN_INFO DRV_NAME
": %s: %s is up and now the "
"active interface\n",
- bond->dev->name,
+ bond_dev->name,
slave->dev->name);
netif_carrier_on(bond->dev);
} else {
printk(KERN_INFO DRV_NAME
": %s: backup interface %s is "
"now up\n",
- bond->dev->name,
+ bond_dev->name,
slave->dev->name);
}
- write_unlock_bh(&bond->curr_slave_lock);
- rtnl_unlock();
+ write_unlock(&bond->curr_slave_lock);
}
} else {
read_lock(&bond->curr_slave_lock);
if ((slave != bond->curr_active_slave) &&
(!bond->current_arp_slave) &&
- (time_after_eq(jiffies, slave_last_rx(bond, slave) + 3*delta_in_ticks) &&
+ (((jiffies - slave_last_rx(bond, slave)) >= 3*delta_in_ticks) &&
bond_has_ip(bond))) {
/* a backup slave has gone down; three times
* the delta allows the current slave to be
printk(KERN_INFO DRV_NAME
": %s: backup interface %s is now down\n",
- bond->dev->name,
+ bond_dev->name,
slave->dev->name);
} else {
read_unlock(&bond->curr_slave_lock);
* before being taken out. if a primary is being used, check
* if it is up and needs to take over as the curr_active_slave
*/
- if ((time_after_eq(jiffies, slave->dev->trans_start + 2*delta_in_ticks) ||
- (time_after_eq(jiffies, slave_last_rx(bond, slave) + 2*delta_in_ticks) &&
- bond_has_ip(bond))) &&
- time_after_eq(jiffies, slave->jiffies + 2*delta_in_ticks)) {
+ if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
+ (((jiffies - slave_last_rx(bond, slave)) >= (2*delta_in_ticks)) &&
+ bond_has_ip(bond))) &&
+ ((jiffies - slave->jiffies) >= 2*delta_in_ticks)) {
slave->link = BOND_LINK_DOWN;
printk(KERN_INFO DRV_NAME
": %s: link status down for active interface "
"%s, disabling it\n",
- bond->dev->name,
+ bond_dev->name,
slave->dev->name);
- rtnl_lock();
- write_lock_bh(&bond->curr_slave_lock);
+ write_lock(&bond->curr_slave_lock);
bond_select_active_slave(bond);
slave = bond->curr_active_slave;
- write_unlock_bh(&bond->curr_slave_lock);
-
- rtnl_unlock();
+ write_unlock(&bond->curr_slave_lock);
bond->current_arp_slave = slave;
printk(KERN_INFO DRV_NAME
": %s: changing from interface %s to primary "
"interface %s\n",
- bond->dev->name,
+ bond_dev->name,
slave->dev->name,
bond->primary_slave->dev->name);
/* primary is up so switch to it */
- rtnl_lock();
- write_lock_bh(&bond->curr_slave_lock);
+ write_lock(&bond->curr_slave_lock);
bond_change_active_slave(bond, bond->primary_slave);
- write_unlock_bh(&bond->curr_slave_lock);
-
- rtnl_unlock();
+ write_unlock(&bond->curr_slave_lock);
slave = bond->primary_slave;
slave->jiffies = jiffies;
printk(KERN_INFO DRV_NAME
": %s: backup interface %s is "
"now down.\n",
- bond->dev->name,
+ bond_dev->name,
slave->dev->name);
}
}
re_arm:
if (bond->params.arp_interval) {
- queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
+ mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
}
out:
read_unlock(&bond->lock);
/* make sure the bond won't be taken away */
read_lock(&dev_base_lock);
- read_lock(&bond->lock);
+ read_lock_bh(&bond->lock);
if (*pos == 0) {
return SEQ_START_TOKEN;
{
struct bonding *bond = seq->private;
- read_unlock(&bond->lock);
+ read_unlock_bh(&bond->lock);
read_unlock(&dev_base_lock);
}
curr = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock);
- seq_printf(seq, "Bonding Mode: %s",
+ seq_printf(seq, "Bonding Mode: %s\n",
bond_mode_name(bond->params.mode));
- if (bond->params.mode == BOND_MODE_ACTIVEBACKUP &&
- bond->params.fail_over_mac)
- seq_printf(seq, " (fail_over_mac)");
-
- seq_printf(seq, "\n");
-
if (bond->params.mode == BOND_MODE_XOR ||
bond->params.mode == BOND_MODE_8023AD) {
seq_printf(seq, "Transmit Hash Policy: %s (%d)\n",
* ... Or is it this?
*/
break;
- case NETDEV_GOING_DOWN:
- dprintk("slave %s is going down\n", slave_dev->name);
- if (bond->setup_by_slave)
- bond_release_and_destroy(bond_dev, slave_dev);
- break;
case NETDEV_CHANGEMTU:
/*
* TODO: Should slaves be allowed to
/*---------------------------- Hashing Policies -----------------------------*/
/*
- * Hash for the output device based upon layer 2 and layer 3 data. If
- * the packet is not IP mimic bond_xmit_hash_policy_l2()
- */
-static int bond_xmit_hash_policy_l23(struct sk_buff *skb,
- struct net_device *bond_dev, int count)
-{
- struct ethhdr *data = (struct ethhdr *)skb->data;
- struct iphdr *iph = ip_hdr(skb);
-
- if (skb->protocol == __constant_htons(ETH_P_IP)) {
- return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^
- (data->h_dest[5] ^ bond_dev->dev_addr[5])) % count;
- }
-
- return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count;
-}
-
-/*
- * Hash for the output device based upon layer 3 and layer 4 data. If
+ * Hash for the the output device based upon layer 3 and layer 4 data. If
* the packet is a frag or not TCP or UDP, just use layer 3 data. If it is
* altogether not IP, mimic bond_xmit_hash_policy_l2()
*/
struct net_device *bond_dev, int count)
{
struct ethhdr *data = (struct ethhdr *)skb->data;
- struct iphdr *iph = ip_hdr(skb);
- __be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl);
+ struct iphdr *iph = skb->nh.iph;
+ u16 *layer4hdr = (u16 *)((u32 *)iph + iph->ihl);
int layer4_xor = 0;
if (skb->protocol == __constant_htons(ETH_P_IP)) {
if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) &&
(iph->protocol == IPPROTO_TCP ||
iph->protocol == IPPROTO_UDP)) {
- layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1)));
+ layer4_xor = htons((*layer4hdr ^ *(layer4hdr + 1)));
}
return (layer4_xor ^
((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count;
static int bond_open(struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
+ struct timer_list *mii_timer = &bond->mii_timer;
+ struct timer_list *arp_timer = &bond->arp_timer;
bond->kill_timers = 0;
if ((bond->params.mode == BOND_MODE_TLB) ||
(bond->params.mode == BOND_MODE_ALB)) {
+ struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer);
+
/* bond_alb_initialize must be called before the timer
* is started.
*/
return -1;
}
- INIT_WORK(&bond->alb_work, bond_alb_monitor, (void *)bond);
- queue_delayed_work(bond->wq, &bond->alb_work, 0);
+ init_timer(alb_timer);
+ alb_timer->expires = jiffies + 1;
+ alb_timer->data = (unsigned long)bond;
+ alb_timer->function = (void *)&bond_alb_monitor;
+ add_timer(alb_timer);
}
if (bond->params.miimon) { /* link check interval, in milliseconds. */
- INIT_WORK(&bond->mii_work, bond_mii_monitor, (void *)bond);
- queue_delayed_work(bond->wq, &bond->mii_work, 0);
+ init_timer(mii_timer);
+ mii_timer->expires = jiffies + 1;
+ mii_timer->data = (unsigned long)bond_dev;
+ mii_timer->function = (void *)&bond_mii_monitor;
+ add_timer(mii_timer);
}
if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
- if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
- INIT_WORK(&bond->arp_work,
- bond_activebackup_arp_mon,
- (void *)bond);
- else
- INIT_WORK(&bond->arp_work,
- bond_loadbalance_arp_mon,
- (void *)bond);
-
- queue_delayed_work(bond->wq, &bond->arp_work, 0);
+ init_timer(arp_timer);
+ arp_timer->expires = jiffies + 1;
+ arp_timer->data = (unsigned long)bond_dev;
+ if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
+ arp_timer->function = (void *)&bond_activebackup_arp_mon;
+ } else {
+ arp_timer->function = (void *)&bond_loadbalance_arp_mon;
+ }
if (bond->params.arp_validate)
bond_register_arp(bond);
+
+ add_timer(arp_timer);
}
if (bond->params.mode == BOND_MODE_8023AD) {
- INIT_WORK(&bond->ad_work, bond_3ad_state_machine_handler, (void *)bond);
- queue_delayed_work(bond->wq, &bond->ad_work, 0);
+ struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer);
+ init_timer(ad_timer);
+ ad_timer->expires = jiffies + 1;
+ ad_timer->data = (unsigned long)bond;
+ ad_timer->function = (void *)&bond_3ad_state_machine_handler;
+ add_timer(ad_timer);
+
/* register to receive LACPDUs */
bond_register_lacpdu(bond);
}
write_unlock_bh(&bond->lock);
+ /* del_timer_sync must run without holding the bond->lock
+ * because a running timer might be trying to hold it too
+ */
+
if (bond->params.miimon) { /* link check interval, in milliseconds. */
- cancel_delayed_work(&bond->mii_work);
+ del_timer_sync(&bond->mii_timer);
}
if (bond->params.arp_interval) { /* arp interval, in milliseconds. */
- cancel_delayed_work(&bond->arp_work);
+ del_timer_sync(&bond->arp_timer);
}
switch (bond->params.mode) {
case BOND_MODE_8023AD:
- cancel_delayed_work(&bond->ad_work);
+ del_timer_sync(&(BOND_AD_INFO(bond).ad_timer));
break;
case BOND_MODE_TLB:
case BOND_MODE_ALB:
- cancel_delayed_work(&bond->alb_work);
+ del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer));
break;
default:
break;
if (mii->reg_num == 1) {
struct bonding *bond = bond_dev->priv;
mii->val_out = 0;
- read_lock(&bond->lock);
+ read_lock_bh(&bond->lock);
read_lock(&bond->curr_slave_lock);
if (netif_carrier_ok(bond->dev)) {
mii->val_out = BMSR_LSTATUS;
}
read_unlock(&bond->curr_slave_lock);
- read_unlock(&bond->lock);
+ read_unlock_bh(&bond->lock);
}
return 0;
dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None"));
- /*
- * If fail_over_mac is enabled, do nothing and return success.
- * Returning an error causes ifenslave to fail.
- */
- if (bond->params.fail_over_mac)
- return 0;
-
if (!is_valid_ether_addr(sa->sa_data)) {
return -EADDRNOTAVAIL;
}
{
struct bonding *bond = bond_dev->priv;
struct slave *slave, *start_at;
- int i, slave_no, res = 1;
+ int i;
+ int res = 1;
read_lock(&bond->lock);
goto out;
}
- /*
- * Concurrent TX may collide on rr_tx_counter; we accept that
- * as being rare enough not to justify using an atomic op here
- */
- slave_no = bond->rr_tx_counter++ % bond->slave_cnt;
+ read_lock(&bond->curr_slave_lock);
+ slave = start_at = bond->curr_active_slave;
+ read_unlock(&bond->curr_slave_lock);
- bond_for_each_slave(bond, slave, i) {
- slave_no--;
- if (slave_no < 0) {
- break;
- }
+ if (!slave) {
+ goto out;
}
- start_at = slave;
bond_for_each_slave_from(bond, slave, i, start_at) {
if (IS_UP(slave->dev) &&
(slave->link == BOND_LINK_UP) &&
(slave->state == BOND_STATE_ACTIVE)) {
res = bond_dev_queue_xmit(bond, skb, slave->dev);
+
+ write_lock(&bond->curr_slave_lock);
+ bond->curr_active_slave = slave->next;
+ write_unlock(&bond->curr_slave_lock);
+
break;
}
}
+
out:
if (res) {
/* no suitable interface, frame not sent */
/*------------------------- Device initialization ---------------------------*/
-static void bond_set_xmit_hash_policy(struct bonding *bond)
-{
- switch (bond->params.xmit_policy) {
- case BOND_XMIT_POLICY_LAYER23:
- bond->xmit_hash_policy = bond_xmit_hash_policy_l23;
- break;
- case BOND_XMIT_POLICY_LAYER34:
- bond->xmit_hash_policy = bond_xmit_hash_policy_l34;
- break;
- case BOND_XMIT_POLICY_LAYER2:
- default:
- bond->xmit_hash_policy = bond_xmit_hash_policy_l2;
- break;
- }
-}
-
/*
* set bond mode specific net device operations
*/
break;
case BOND_MODE_XOR:
bond_dev->hard_start_xmit = bond_xmit_xor;
- bond_set_xmit_hash_policy(bond);
+ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34)
+ bond->xmit_hash_policy = bond_xmit_hash_policy_l34;
+ else
+ bond->xmit_hash_policy = bond_xmit_hash_policy_l2;
break;
case BOND_MODE_BROADCAST:
bond_dev->hard_start_xmit = bond_xmit_broadcast;
case BOND_MODE_8023AD:
bond_set_master_3ad_flags(bond);
bond_dev->hard_start_xmit = bond_3ad_xmit_xor;
- bond_set_xmit_hash_policy(bond);
+ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34)
+ bond->xmit_hash_policy = bond_xmit_hash_policy_l34;
+ else
+ bond->xmit_hash_policy = bond_xmit_hash_policy_l2;
break;
case BOND_MODE_ALB:
bond_set_master_alb_flags(bond);
bond->params = *params; /* copy params struct */
- bond->wq = create_singlethread_workqueue(bond_dev->name);
- if (!bond->wq)
- return -ENOMEM;
-
/* Initialize pointers */
bond->first_slave = NULL;
bond->curr_active_slave = NULL;
bond->current_arp_slave = NULL;
bond->primary_slave = NULL;
bond->dev = bond_dev;
- bond->send_grat_arp = 0;
- bond->setup_by_slave = 0;
INIT_LIST_HEAD(&bond->vlan_list);
/* Initialize the device entry points */
#ifdef CONFIG_PROC_FS
bond_create_proc_entry(bond);
#endif
+
list_add_tail(&bond->bond_list, &bond_dev_list);
return 0;
/* De-initialize device specific data.
* Caller must hold rtnl_lock.
*/
-static void bond_deinit(struct net_device *bond_dev)
+void bond_deinit(struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
#endif
}
-static void bond_work_cancel_all(struct bonding *bond)
-{
- write_lock_bh(&bond->lock);
- bond->kill_timers = 1;
- write_unlock_bh(&bond->lock);
-
- if (bond->params.miimon && delayed_work_pending(&bond->mii_work))
- cancel_delayed_work(&bond->mii_work);
-
- if (bond->params.arp_interval && delayed_work_pending(&bond->arp_work))
- cancel_delayed_work(&bond->arp_work);
-
- if (bond->params.mode == BOND_MODE_ALB &&
- delayed_work_pending(&bond->alb_work))
- cancel_delayed_work(&bond->alb_work);
-
- if (bond->params.mode == BOND_MODE_8023AD &&
- delayed_work_pending(&bond->ad_work))
- cancel_delayed_work(&bond->ad_work);
-}
-
/* Unregister and free all bond devices.
* Caller must hold rtnl_lock.
*/
list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
struct net_device *bond_dev = bond->dev;
- bond_work_cancel_all(bond);
bond_mc_list_destroy(bond);
/* Release the bonded slaves */
bond_release_all(bond_dev);
- bond_deinit(bond_dev);
unregister_netdevice(bond_dev);
+ bond_deinit(bond_dev);
}
#ifdef CONFIG_PROC_FS
for (i = 0; tbl[i].modename; i++) {
if ((isdigit(*mode_arg) &&
tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) ||
- (strcmp(mode_arg, tbl[i].modename) == 0)) {
+ (strncmp(mode_arg, tbl[i].modename,
+ strlen(tbl[i].modename)) == 0)) {
return tbl[i].mode;
}
}
arp_ip_target[arp_ip_count]);
arp_interval = 0;
} else {
- __be32 ip = in_aton(arp_ip_target[arp_ip_count]);
+ u32 ip = in_aton(arp_ip_target[arp_ip_count]);
arp_target[arp_ip_count] = ip;
}
}
primary = NULL;
}
- if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP))
- printk(KERN_WARNING DRV_NAME
- ": Warning: fail_over_mac only affects "
- "active-backup mode.\n");
-
/* fill params struct with the proper values */
params->mode = bond_mode;
params->xmit_policy = xmit_hashtype;
params->use_carrier = use_carrier;
params->lacp_fast = lacp_fast;
params->primary[0] = 0;
- params->fail_over_mac = fail_over_mac;
if (primary) {
strncpy(params->primary, primary, IFNAMSIZ);
{
int i;
int res;
- struct bonding *bond, *nxt;
printk(KERN_INFO "%s", version);
goto out;
err:
- list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
- bond_work_cancel_all(bond);
- destroy_workqueue(bond->wq);
- }
-
rtnl_lock();
bond_free_all();
bond_destroy_sysfs();
#include <linux/inetdevice.h>
#include <linux/in.h>
#include <linux/sysfs.h>
+#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/inet.h>
#include <linux/rtnetlink.h>
static struct class *netdev_class;
/*--------------------------- Data Structures -----------------------------*/
-/* Bonding sysfs lock. Why can't we just use the subsystem lock?
+/* Bonding sysfs lock. Why can't we just use the subsytem lock?
* Because kobject_register tries to acquire the subsystem lock. If
* we already hold the lock (which we would if the user was creating
* a new bond through the sysfs interface), we deadlock.
* "show" function for the bond_masters attribute.
* The class parameter is ignored.
*/
-static ssize_t bonding_show_bonds(struct class *cls, char *buf)
+static ssize_t bonding_show_bonds(struct class *cls, char *buffer)
{
int res = 0;
struct bonding *bond;
/* not enough space for another interface name */
if ((PAGE_SIZE - res) > 10)
res = PAGE_SIZE - 10;
- res += sprintf(buf + res, "++more++ ");
+ res += sprintf(buffer + res, "++more++");
break;
}
- res += sprintf(buf + res, "%s ", bond->dev->name);
+ res += sprintf(buffer + res, "%s ",
+ bond->dev->name);
}
- if (res)
- buf[res-1] = '\n'; /* eat the leftover space */
+ res += sprintf(buffer + res, "\n");
+ res++;
up_read(&(bonding_rwsem));
return res;
}
printk(KERN_INFO DRV_NAME
": %s is being deleted...\n",
bond->dev->name);
- bond_destroy(bond);
+ unregister_netdevice(bond->dev);
+ bond_deinit(bond->dev);
+ bond_destroy_sysfs_entry(bond);
rtnl_unlock();
goto out;
}
int i, res = 0;
struct bonding *bond = to_bond(cd);
- read_lock(&bond->lock);
+ read_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i) {
if (res > (PAGE_SIZE - IFNAMSIZ)) {
/* not enough space for another interface name */
if ((PAGE_SIZE - res) > 10)
res = PAGE_SIZE - 10;
- res += sprintf(buf + res, "++more++ ");
+ res += sprintf(buf + res, "++more++");
break;
}
res += sprintf(buf + res, "%s ", slave->dev->name);
}
- read_unlock(&bond->lock);
- if (res)
- buf[res-1] = '\n'; /* eat the leftover space */
+ read_unlock_bh(&bond->lock);
+ res += sprintf(buf + res, "\n");
+ res++;
return res;
}
/* Got a slave name in ifname. Is it already in the list? */
found = 0;
- read_lock(&bond->lock);
+ read_lock_bh(&bond->lock);
bond_for_each_slave(bond, slave, i)
if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
printk(KERN_ERR DRV_NAME
": %s: Interface %s is already enslaved!\n",
bond->dev->name, ifname);
ret = -EPERM;
- read_unlock(&bond->lock);
+ read_unlock_bh(&bond->lock);
goto out;
}
- read_unlock(&bond->lock);
+ read_unlock_bh(&bond->lock);
printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n",
bond->dev->name, ifname);
dev = dev_get_by_name(ifname);
printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n",
bond->dev->name, dev->name);
rtnl_lock();
- if (bond->setup_by_slave)
- res = bond_release_and_destroy(bond->dev, dev);
- else
- res = bond_release(bond->dev, dev);
+ res = bond_release(bond->dev, dev);
rtnl_unlock();
if (res) {
ret = res;
return sprintf(buf, "%s %d\n",
bond_mode_tbl[bond->params.mode].modename,
- bond->params.mode);
+ bond->params.mode) + 1;
}
static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count)
*/
static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf)
{
+ int count;
struct bonding *bond = to_bond(cd);
- return sprintf(buf, "%s %d\n",
+ if ((bond->params.mode != BOND_MODE_XOR) &&
+ (bond->params.mode != BOND_MODE_8023AD)) {
+ // Not Applicable
+ count = sprintf(buf, "NA\n") + 1;
+ } else {
+ count = sprintf(buf, "%s %d\n",
xmit_hashtype_tbl[bond->params.xmit_policy].modename,
- bond->params.xmit_policy);
+ bond->params.xmit_policy) + 1;
+ }
+
+ return count;
}
static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, size_t count)
goto out;
}
+ if ((bond->params.mode != BOND_MODE_XOR) &&
+ (bond->params.mode != BOND_MODE_8023AD)) {
+ printk(KERN_ERR DRV_NAME
+ "%s: Transmit hash policy is irrelevant in this mode.\n",
+ bond->dev->name);
+ ret = -EPERM;
+ goto out;
+ }
+
new_value = bond_parse_parm((char *)buf, xmit_hashtype_tbl);
if (new_value < 0) {
printk(KERN_ERR DRV_NAME
return sprintf(buf, "%s %d\n",
arp_validate_tbl[bond->params.arp_validate].modename,
- bond->params.arp_validate);
+ bond->params.arp_validate) + 1;
}
static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count)
static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
-/*
- * Show and store fail_over_mac. User only allowed to change the
- * value when there are no slaves.
- */
-static ssize_t bonding_show_fail_over_mac(struct class_device *cd, char *buf)
-{
- struct bonding *bond = to_bond(cd);
-
- return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1;
-}
-
-static ssize_t bonding_store_fail_over_mac(struct class_device *cd, const char *buf, size_t count)
-{
- int new_value;
- int ret = count;
- struct bonding *bond = to_bond(cd);
-
- if (bond->slave_cnt != 0) {
- printk(KERN_ERR DRV_NAME
- ": %s: Can't alter fail_over_mac with slaves in bond.\n",
- bond->dev->name);
- ret = -EPERM;
- goto out;
- }
-
- if (sscanf(buf, "%d", &new_value) != 1) {
- printk(KERN_ERR DRV_NAME
- ": %s: no fail_over_mac value specified.\n",
- bond->dev->name);
- ret = -EINVAL;
- goto out;
- }
-
- if ((new_value == 0) || (new_value == 1)) {
- bond->params.fail_over_mac = new_value;
- printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n",
- bond->dev->name, new_value);
- } else {
- printk(KERN_INFO DRV_NAME
- ": %s: Ignoring invalid fail_over_mac value %d.\n",
- bond->dev->name, new_value);
- }
-out:
- return ret;
-}
-
-static CLASS_DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac);
-
/*
* Show and set the arp timer interval. There are two tricky bits
* here. First, if ARP monitoring is activated, then we must disable
{
struct bonding *bond = to_bond(cd);
- return sprintf(buf, "%d\n", bond->params.arp_interval);
+ return sprintf(buf, "%d\n", bond->params.arp_interval) + 1;
}
static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *buf, size_t count)
"%s Disabling MII monitoring.\n",
bond->dev->name, bond->dev->name);
bond->params.miimon = 0;
- if (delayed_work_pending(&bond->mii_work)) {
- cancel_delayed_work(&bond->mii_work);
- flush_workqueue(bond->wq);
+ /* Kill MII timer, else it brings bond's link down */
+ if (bond->arp_timer.function) {
+ printk(KERN_INFO DRV_NAME
+ ": %s: Kill MII timer, else it brings bond's link down...\n",
+ bond->dev->name);
+ del_timer_sync(&bond->mii_timer);
}
}
if (!bond->params.arp_targets[0]) {
* timer will get fired off when the open function
* is called.
*/
- if (!delayed_work_pending(&bond->arp_work)) {
- if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
- INIT_WORK(&bond->arp_work,
- bond_activebackup_arp_mon,
- bond);
- else
- INIT_WORK(&bond->arp_work,
- bond_loadbalance_arp_mon,
- bond);
-
- queue_delayed_work(bond->wq, &bond->arp_work, 0);
+ if (bond->arp_timer.function) {
+ /* The timer's already set up, so fire it off */
+ mod_timer(&bond->arp_timer, jiffies + 1);
+ } else {
+ /* Set up the timer. */
+ init_timer(&bond->arp_timer);
+ bond->arp_timer.expires = jiffies + 1;
+ bond->arp_timer.data =
+ (unsigned long) bond->dev;
+ if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
+ bond->arp_timer.function =
+ (void *)
+ &bond_activebackup_arp_mon;
+ } else {
+ bond->arp_timer.function =
+ (void *)
+ &bond_loadbalance_arp_mon;
+ }
+ add_timer(&bond->arp_timer);
}
}
NIPQUAD(bond->params.arp_targets[i]));
}
if (res)
- buf[res-1] = '\n'; /* eat the leftover space */
+ res--; /* eat the leftover space */
+ res += sprintf(buf + res, "\n");
+ res++;
return res;
}
static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *buf, size_t count)
{
- __be32 newtarget;
+ u32 newtarget;
int i = 0, done = 0, ret = count;
struct bonding *bond = to_bond(cd);
- __be32 *targets;
+ u32 *targets;
targets = bond->params.arp_targets;
newtarget = in_aton(buf + 1);
/* look for adds */
if (buf[0] == '+') {
- if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
+ if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) {
printk(KERN_ERR DRV_NAME
": %s: invalid ARP target %u.%u.%u.%u specified for addition\n",
bond->dev->name, NIPQUAD(newtarget));
}
else if (buf[0] == '-') {
- if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
+ if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) {
printk(KERN_ERR DRV_NAME
": %s: invalid ARP target %d.%d.%d.%d specified for removal\n",
bond->dev->name, NIPQUAD(newtarget));
{
struct bonding *bond = to_bond(cd);
- return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon);
+ return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon) + 1;
}
static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, size_t count)
{
struct bonding *bond = to_bond(cd);
- return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon);
+ return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon) + 1;
}
return sprintf(buf, "%s %d\n",
bond_lacp_tbl[bond->params.lacp_fast].modename,
- bond->params.lacp_fast);
+ bond->params.lacp_fast) + 1;
}
static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size_t count)
{
struct bonding *bond = to_bond(cd);
- return sprintf(buf, "%d\n", bond->params.miimon);
+ return sprintf(buf, "%d\n", bond->params.miimon) + 1;
}
static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, size_t count)
bond->params.arp_validate =
BOND_ARP_VALIDATE_NONE;
}
- if (delayed_work_pending(&bond->arp_work)) {
- cancel_delayed_work(&bond->arp_work);
- flush_workqueue(bond->wq);
+ /* Kill ARP timer, else it brings bond's link down */
+ if (bond->mii_timer.function) {
+ printk(KERN_INFO DRV_NAME
+ ": %s: Kill ARP timer, else it brings bond's link down...\n",
+ bond->dev->name);
+ del_timer_sync(&bond->arp_timer);
}
}
* timer will get fired off when the open function
* is called.
*/
- if (!delayed_work_pending(&bond->mii_work)) {
- INIT_WORK(&bond->mii_work,
- bond_mii_monitor,
- bond);
- queue_delayed_work(bond->wq,
- &bond->mii_work, 0);
+ if (bond->mii_timer.function) {
+ /* The timer's already set up, so fire it off */
+ mod_timer(&bond->mii_timer, jiffies + 1);
+ } else {
+ /* Set up the timer. */
+ init_timer(&bond->mii_timer);
+ bond->mii_timer.expires = jiffies + 1;
+ bond->mii_timer.data =
+ (unsigned long) bond->dev;
+ bond->mii_timer.function =
+ (void *) &bond_mii_monitor;
+ add_timer(&bond->mii_timer);
}
}
}
struct bonding *bond = to_bond(cd);
if (bond->primary_slave)
- count = sprintf(buf, "%s\n", bond->primary_slave->dev->name);
+ count = sprintf(buf, "%s\n", bond->primary_slave->dev->name) + 1;
+ else
+ count = sprintf(buf, "\n") + 1;
return count;
}
struct slave *slave;
struct bonding *bond = to_bond(cd);
- rtnl_lock();
- read_lock(&bond->lock);
- write_lock_bh(&bond->curr_slave_lock);
-
+ write_lock_bh(&bond->lock);
if (!USES_PRIMARY(bond->params.mode)) {
printk(KERN_INFO DRV_NAME
": %s: Unable to set primary slave; %s is in mode %d\n",
}
}
out:
- write_unlock_bh(&bond->curr_slave_lock);
- read_unlock(&bond->lock);
- rtnl_unlock();
-
+ write_unlock_bh(&bond->lock);
return count;
}
static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
{
struct bonding *bond = to_bond(cd);
- return sprintf(buf, "%d\n", bond->params.use_carrier);
+ return sprintf(buf, "%d\n", bond->params.use_carrier) + 1;
}
static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, size_t count)
{
struct slave *curr;
struct bonding *bond = to_bond(cd);
- int count = 0;
+ int count;
+
read_lock(&bond->curr_slave_lock);
curr = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock);
if (USES_PRIMARY(bond->params.mode) && curr)
- count = sprintf(buf, "%s\n", curr->dev->name);
+ count = sprintf(buf, "%s\n", curr->dev->name) + 1;
+ else
+ count = sprintf(buf, "\n") + 1;
return count;
}
struct slave *new_active = NULL;
struct bonding *bond = to_bond(cd);
- rtnl_lock();
- read_lock(&bond->lock);
- write_lock_bh(&bond->curr_slave_lock);
-
+ write_lock_bh(&bond->lock);
if (!USES_PRIMARY(bond->params.mode)) {
printk(KERN_INFO DRV_NAME
": %s: Unable to change active slave; %s is in mode %d\n",
}
}
out:
- write_unlock_bh(&bond->curr_slave_lock);
- read_unlock(&bond->lock);
- rtnl_unlock();
-
+ write_unlock_bh(&bond->lock);
return count;
}
curr = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock);
- return sprintf(buf, "%s\n", (curr) ? "up" : "down");
+ return sprintf(buf, "%s\n", (curr) ? "up" : "down") + 1;
}
static CLASS_DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
- count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.aggregator_id);
+ count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.aggregator_id) + 1;
}
+ else
+ count = sprintf(buf, "\n") + 1;
return count;
}
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
- count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0: ad_info.ports);
+ count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0: ad_info.ports) + 1;
}
+ else
+ count = sprintf(buf, "\n") + 1;
return count;
}
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
- count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.actor_key);
+ count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.actor_key) + 1;
}
+ else
+ count = sprintf(buf, "\n") + 1;
return count;
}
if (bond->params.mode == BOND_MODE_8023AD) {
struct ad_info ad_info;
- count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.partner_key);
+ count = sprintf(buf, "%d\n", (bond_3ad_get_active_agg_info(bond, &ad_info)) ? 0 : ad_info.partner_key) + 1;
}
+ else
+ count = sprintf(buf, "\n") + 1;
return count;
}
ad_info.partner_system[2],
ad_info.partner_system[3],
ad_info.partner_system[4],
- ad_info.partner_system[5]);
+ ad_info.partner_system[5]) + 1;
}
}
+ else
+ count = sprintf(buf, "\n") + 1;
return count;
}
static struct attribute *per_bond_attrs[] = {
&class_device_attr_slaves.attr,
&class_device_attr_mode.attr,
- &class_device_attr_fail_over_mac.attr,
&class_device_attr_arp_validate.attr,
&class_device_attr_arp_interval.attr,
&class_device_attr_arp_ip_target.attr,
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.2.3"
-#define DRV_RELDATE "December 6, 2007"
+#define DRV_VERSION "3.1.2"
+#define DRV_RELDATE "January 20, 2007"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
int arp_interval;
int arp_validate;
int use_carrier;
- int fail_over_mac;
int updelay;
int downdelay;
int lacp_fast;
char primary[IFNAMSIZ];
- __be32 arp_targets[BOND_MAX_ARP_TARGETS];
+ u32 arp_targets[BOND_MAX_ARP_TARGETS];
};
struct bond_parm_tbl {
struct vlan_entry {
struct list_head vlan_list;
- __be32 vlan_ip;
+ u32 vlan_ip;
unsigned short vlan_id;
};
s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
rwlock_t lock;
rwlock_t curr_slave_lock;
+ struct timer_list mii_timer;
+ struct timer_list arp_timer;
s8 kill_timers;
- s8 send_grat_arp;
- s8 setup_by_slave;
struct net_device_stats stats;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_entry;
struct list_head bond_list;
struct dev_mc_list *mc_list;
int (*xmit_hash_policy)(struct sk_buff *, struct net_device *, int);
- __be32 master_ip;
+ u32 master_ip;
u16 flags;
- u16 rr_tx_counter;
struct ad_bond_info ad_info;
struct alb_bond_info alb_info;
struct bond_params params;
struct list_head vlan_list;
struct vlan_group *vlgrp;
struct packet_type arp_mon_pt;
- struct workqueue_struct *wq;
- struct work_struct mii_work;
- struct work_struct arp_work;
- struct work_struct alb_work;
- struct work_struct ad_work;
};
/**
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
int bond_create(char *name, struct bond_params *params, struct bonding **newbond);
-void bond_destroy(struct bonding *bond);
-int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev);
+void bond_deinit(struct net_device *bond_dev);
int bond_create_sysfs(void);
void bond_destroy_sysfs(void);
void bond_destroy_sysfs_entry(struct bonding *bond);
void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *slave);
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev);
int bond_release(struct net_device *bond_dev, struct net_device *slave_dev);
-void bond_mii_monitor(void *);
-void bond_loadbalance_arp_mon(void *);
-void bond_activebackup_arp_mon(void *);
+int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev);
+void bond_mii_monitor(struct net_device *bond_dev);
+void bond_loadbalance_arp_mon(struct net_device *bond_dev);
+void bond_activebackup_arp_mon(struct net_device *bond_dev);
void bond_set_mode_ops(struct bonding *bond, int mode);
int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl);
+const char *bond_mode_name(int mode);
void bond_select_active_slave(struct bonding *bond);
void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
void bond_register_arp(struct bonding *);
/* hashing types */
#define BOND_XMIT_POLICY_LAYER2 0 /* layer 2 (MAC only), default */
-#define BOND_XMIT_POLICY_LAYER34 1 /* layer 3+4 (IP ^ (TCP || UDP)) */
-#define BOND_XMIT_POLICY_LAYER23 2 /* layer 2+3 (IP ^ MAC) */
+#define BOND_XMIT_POLICY_LAYER34 1 /* layer 3+4 (IP ^ MAC) */
typedef struct ifbond {
__s32 bond_mode;
extern void linkwatch_run_queue(void);
-extern int netdev_compute_features(unsigned long all, unsigned long one);
-
static inline int net_gso_ok(int features, int gso_type)
{
int feature = gso_type << NETIF_F_GSO_SHIFT;
return ret;
}
-static inline int delayed_work_pending(struct work_struct *work)
-{
- return test_bit(0, &work->pending);
-}
-
#endif
dev->priv_flags = IFF_EBRIDGE;
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
- NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX;
+ NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST;
}
void br_features_recompute(struct net_bridge *br)
{
struct net_bridge_port *p;
- unsigned long features;
+ unsigned long features, checksum;
- features = br->feature_mask;
+ checksum = br->feature_mask & NETIF_F_ALL_CSUM ? NETIF_F_NO_CSUM : 0;
+ features = br->feature_mask & ~NETIF_F_ALL_CSUM;
list_for_each_entry(p, &br->port_list, list) {
- features = netdev_compute_features(features, p->dev->features);
+ unsigned long feature = p->dev->features;
+
+ if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM))
+ checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
+ if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM))
+ checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM;
+ if (!(feature & NETIF_F_IP_CSUM))
+ checksum = 0;
+
+ if (feature & NETIF_F_GSO)
+ feature |= NETIF_F_GSO_SOFTWARE;
+ feature |= NETIF_F_GSO;
+
+ features &= feature;
}
-
- br->dev->features = features;
+
+ if (!(checksum & NETIF_F_ALL_CSUM))
+ features &= ~NETIF_F_SG;
+ if (!(features & NETIF_F_SG))
+ features &= ~NETIF_F_GSO_MASK;
+
+ br->dev->features = features | checksum | NETIF_F_LLTX |
+ NETIF_F_GSO_ROBUST;
}
/* called with RTNL */
*
*/
-/**
- * netdev_compute_feature - compute conjunction of two feature sets
- * @all: first feature set
- * @one: second feature set
- *
- * Computes a new feature set after adding a device with feature set
- * @one to the master device with current feature set @all. Returns
- * the new feature set.
- */
-int netdev_compute_features(unsigned long all, unsigned long one)
-{
- /* if device needs checksumming, downgrade to hw checksumming */
- if (all & NETIF_F_NO_CSUM && !(one & NETIF_F_NO_CSUM))
- all ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
-
- /* if device can't do all checksum, downgrade to ipv4/ipv6 */
- if (all & NETIF_F_HW_CSUM && !(one & NETIF_F_HW_CSUM))
- all ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM;
-
- if (one & NETIF_F_GSO)
- one |= NETIF_F_GSO_SOFTWARE;
- one |= NETIF_F_GSO;
-
- /* If even one device supports robust GSO, enable it for all. */
- if (one & NETIF_F_GSO_ROBUST)
- all |= NETIF_F_GSO_ROBUST;
-
- all &= one | NETIF_F_LLTX;
-
- if (!(all & NETIF_F_ALL_CSUM))
- all &= ~NETIF_F_SG;
- if (!(all & NETIF_F_SG))
- all &= ~NETIF_F_GSO_MASK;
-
- return all;
-}
-EXPORT_SYMBOL(netdev_compute_features);
-
/*
* This is called single threaded during boot, so no need
* to take the rtnl semaphore.