Commit 7d585d7e authored by Shmulik Hen's avatar Shmulik Hen Committed by Stephen Hemminger

[PATCH] Add VLAN support in TLB mode

Add capability to tag self generated learning packets that are
required to speed up port selection in the switch after a fail
over in bonding since some switches will only update their MAC
tables from tagged packets when VLAN support is turned on. All
VLAN Id's that have been configured on top of the bond interface
will be used in cyclic order.
parent 7e299113
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/if_bonding.h> #include <linux/if_bonding.h>
#include <linux/if_vlan.h>
#include <net/ipx.h> #include <net/ipx.h>
#include <net/arp.h> #include <net/arp.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
...@@ -79,7 +80,7 @@ ...@@ -79,7 +80,7 @@
#define TLB_NULL_INDEX 0xffffffff #define TLB_NULL_INDEX 0xffffffff
#define MAX_LP_RETRY 3 #define MAX_LP_BURST 3
/* rlb defs */ /* rlb defs */
#define RLB_HASH_TABLE_SIZE 256 #define RLB_HASH_TABLE_SIZE 256
...@@ -816,6 +817,7 @@ static void rlb_deinitialize(struct bonding *bond) ...@@ -816,6 +817,7 @@ static void rlb_deinitialize(struct bonding *bond)
static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
{ {
struct bonding *bond = bond_get_bond_by_slave(slave);
struct learning_pkt pkt; struct learning_pkt pkt;
int size = sizeof(struct learning_pkt); int size = sizeof(struct learning_pkt);
int i; int i;
...@@ -825,7 +827,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) ...@@ -825,7 +827,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
memcpy(pkt.mac_src, mac_addr, ETH_ALEN); memcpy(pkt.mac_src, mac_addr, ETH_ALEN);
pkt.type = __constant_htons(ETH_P_LOOP); pkt.type = __constant_htons(ETH_P_LOOP);
for (i = 0; i < MAX_LP_RETRY; i++) { for (i = 0; i < MAX_LP_BURST; i++) {
struct sk_buff *skb; struct sk_buff *skb;
char *data; char *data;
...@@ -843,6 +845,26 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) ...@@ -843,6 +845,26 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[])
skb->priority = TC_PRIO_CONTROL; skb->priority = TC_PRIO_CONTROL;
skb->dev = slave->dev; skb->dev = slave->dev;
if (!list_empty(&bond->vlan_list)) {
struct vlan_entry *vlan;
vlan = bond_next_vlan(bond,
bond->alb_info.current_alb_vlan);
bond->alb_info.current_alb_vlan = vlan;
if (!vlan) {
kfree_skb(skb);
continue;
}
skb = vlan_put_tag(skb, vlan->vlan_id);
if (!skb) {
printk(KERN_ERR DRV_NAME
": Error: failed to insert VLAN tag\n");
continue;
}
}
dev_queue_xmit(skb); dev_queue_xmit(skb);
} }
} }
...@@ -1588,3 +1610,11 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) ...@@ -1588,3 +1610,11 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr)
return 0; return 0;
} }
void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
{
if (bond->alb_info.current_alb_vlan &&
(bond->alb_info.current_alb_vlan->vlan_id == vlan_id)) {
bond->alb_info.current_alb_vlan = NULL;
}
}
...@@ -122,6 +122,7 @@ struct alb_bond_info { ...@@ -122,6 +122,7 @@ struct alb_bond_info {
* rx traffic should be * rx traffic should be
* rebalanced * rebalanced
*/ */
struct vlan_entry *current_alb_vlan;
}; };
int bond_alb_initialize(struct bonding *bond, int rlb_enabled); int bond_alb_initialize(struct bonding *bond, int rlb_enabled);
...@@ -133,6 +134,6 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave ...@@ -133,6 +134,6 @@ 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); int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev);
void bond_alb_monitor(struct bonding *bond); void bond_alb_monitor(struct bonding *bond);
int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr); 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__ */ #endif /* __BOND_ALB_H__ */
...@@ -676,6 +676,11 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) ...@@ -676,6 +676,11 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id)
if (vlan->vlan_id == vlan_id) { if (vlan->vlan_id == vlan_id) {
list_del(&vlan->vlan_list); list_del(&vlan->vlan_list);
if ((bond->params.mode == BOND_MODE_TLB) ||
(bond->params.mode == BOND_MODE_ALB)) {
bond_alb_clear_vlan(bond, vlan_id);
}
dprintk("removed VLAN ID %d from bond %s\n", vlan_id, dprintk("removed VLAN ID %d from bond %s\n", vlan_id,
bond->dev->name); bond->dev->name);
...@@ -730,6 +735,42 @@ static int bond_has_challenged_slaves(struct bonding *bond) ...@@ -730,6 +735,42 @@ static int bond_has_challenged_slaves(struct bonding *bond)
return 0; return 0;
} }
/**
* bond_next_vlan - safely skip to the next item in the vlans list.
* @bond: the bond we're working on
* @curr: item we're advancing from
*
* Returns %NULL if list is empty, bond->next_vlan if @curr is %NULL,
* or @curr->next otherwise (even if it is @curr itself again).
*
* Caller must hold bond->lock
*/
struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr)
{
struct vlan_entry *next, *last;
if (list_empty(&bond->vlan_list)) {
return NULL;
}
if (!curr) {
next = list_entry(bond->vlan_list.next,
struct vlan_entry, vlan_list);
} else {
last = list_entry(bond->vlan_list.prev,
struct vlan_entry, vlan_list);
if (last == curr) {
next = list_entry(bond->vlan_list.next,
struct vlan_entry, vlan_list);
} else {
next = list_entry(curr->vlan_list.next,
struct vlan_entry, vlan_list);
}
}
return next;
}
/** /**
* bond_dev_queue_xmit - Prepare skb for xmit. * bond_dev_queue_xmit - Prepare skb for xmit.
* *
......
...@@ -245,6 +245,7 @@ extern inline void bond_set_slave_active_flags(struct slave *slave) ...@@ -245,6 +245,7 @@ extern inline void bond_set_slave_active_flags(struct slave *slave)
slave->dev->flags &= ~IFF_NOARP; slave->dev->flags &= ~IFF_NOARP;
} }
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_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
#endif /* _LINUX_BONDING_H */ #endif /* _LINUX_BONDING_H */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment