Skip to content

Commit

Permalink
bonding: make it possible to have unlimited nested upper vlans
Browse files Browse the repository at this point in the history
Currently we're limited by a constant level of vlan nestings, and fail to
find anything beyound that level (currently 2).

To fix this - remove the limit of nestings when going through device tree,
and when the end device is found - allocate the needed amount of vlan tags
and return them, instead of found/not found.

CC: Jay Vosburgh <j.vosburgh@gmail.com>
CC: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Veaceslav Falico <vfalico@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Veaceslav Falico authored and David S. Miller committed Jul 21, 2014
1 parent 224e923 commit 3e403a7
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 39 deletions.
8 changes: 5 additions & 3 deletions drivers/net/bonding/bond_alb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1042,7 +1042,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
struct bonding *bond = bond_get_bond_by_slave(slave);
struct net_device *upper;
struct list_head *iter;
struct bond_vlan_tag tags[BOND_MAX_VLAN_ENCAP];
struct bond_vlan_tag *tags;

/* send untagged */
alb_send_lp_vid(slave, mac_addr, 0, 0);
Expand Down Expand Up @@ -1070,10 +1070,12 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[],
* when strict_match is turned off.
*/
if (netif_is_macvlan(upper) && !strict_match) {
memset(tags, 0, sizeof(tags));
bond_verify_device_path(bond->dev, upper, tags);
tags = bond_verify_device_path(bond->dev, upper, 0);
if (IS_ERR_OR_NULL(tags))
BUG();
alb_send_lp_vid(slave, upper->dev_addr,
tags[0].vlan_proto, tags[0].vlan_id);
kfree(tags);
}
}
rcu_read_unlock();
Expand Down
82 changes: 50 additions & 32 deletions drivers/net/bonding/bond_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2145,7 +2145,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op,
struct bond_vlan_tag *tags)
{
struct sk_buff *skb;
int i;
struct bond_vlan_tag *outer_tag = tags;

netdev_dbg(slave_dev, "arp %d on slave %s: dst %pI4 src %pI4\n",
arp_op, slave_dev->name, &dest_ip, &src_ip);
Expand All @@ -2158,30 +2158,42 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op,
return;
}

if (!tags || tags->vlan_proto == VLAN_N_VID)
goto xmit;

tags++;

/* Go through all the tags backwards and add them to the packet */
for (i = BOND_MAX_VLAN_ENCAP - 1; i > 0; i--) {
if (!tags[i].vlan_id)
while (tags->vlan_proto != VLAN_N_VID) {
if (!tags->vlan_id) {
tags++;
continue;
}

netdev_dbg(slave_dev, "inner tag: proto %X vid %X\n",
ntohs(tags[i].vlan_proto), tags[i].vlan_id);
skb = __vlan_put_tag(skb, tags[i].vlan_proto,
tags[i].vlan_id);
ntohs(outer_tag->vlan_proto), tags->vlan_id);
skb = __vlan_put_tag(skb, tags->vlan_proto,
tags->vlan_id);
if (!skb) {
net_err_ratelimited("failed to insert inner VLAN tag\n");
return;
}

tags++;
}
/* Set the outer tag */
if (tags[0].vlan_id) {
if (outer_tag->vlan_id) {
netdev_dbg(slave_dev, "outer tag: proto %X vid %X\n",
ntohs(tags[0].vlan_proto), tags[0].vlan_id);
skb = vlan_put_tag(skb, tags[0].vlan_proto, tags[0].vlan_id);
ntohs(outer_tag->vlan_proto), outer_tag->vlan_id);
skb = vlan_put_tag(skb, outer_tag->vlan_proto,
outer_tag->vlan_id);
if (!skb) {
net_err_ratelimited("failed to insert outer VLAN tag\n");
return;
}
}

xmit:
arp_xmit(skb);
}

Expand All @@ -2191,46 +2203,50 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op,
* When the path is validated, collect any vlan information in the
* path.
*/
bool bond_verify_device_path(struct net_device *start_dev,
struct net_device *end_dev,
struct bond_vlan_tag *tags)
struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev,
struct net_device *end_dev,
int level)
{
struct bond_vlan_tag *tags;
struct net_device *upper;
struct list_head *iter;
int idx;

if (start_dev == end_dev)
return true;
if (start_dev == end_dev) {
tags = kzalloc(sizeof(*tags) * (level + 1), GFP_ATOMIC);
if (!tags)
return ERR_PTR(-ENOMEM);
tags[level].vlan_proto = VLAN_N_VID;
return tags;
}

netdev_for_each_upper_dev_rcu(start_dev, upper, iter) {
if (bond_verify_device_path(upper, end_dev, tags)) {
if (is_vlan_dev(upper)) {
idx = vlan_get_encap_level(upper);
if (idx >= BOND_MAX_VLAN_ENCAP)
return false;

tags[idx].vlan_proto =
vlan_dev_vlan_proto(upper);
tags[idx].vlan_id = vlan_dev_vlan_id(upper);
}
return true;
tags = bond_verify_device_path(upper, end_dev, level + 1);
if (IS_ERR_OR_NULL(tags)) {
if (IS_ERR(tags))
return tags;
continue;
}
if (is_vlan_dev(upper)) {
tags[level].vlan_proto = vlan_dev_vlan_proto(upper);
tags[level].vlan_id = vlan_dev_vlan_id(upper);
}

return tags;
}

return false;
return NULL;
}

static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
{
struct rtable *rt;
struct bond_vlan_tag tags[BOND_MAX_VLAN_ENCAP];
struct bond_vlan_tag *tags;
__be32 *targets = bond->params.arp_targets, addr;
int i;
bool ret;

for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) {
netdev_dbg(bond->dev, "basa: target %pI4\n", &targets[i]);
memset(tags, 0, sizeof(tags));
tags = NULL;

/* Find out through which dev should the packet go */
rt = ip_route_output(dev_net(bond->dev), targets[i], 0,
Expand All @@ -2253,10 +2269,10 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
goto found;

rcu_read_lock();
ret = bond_verify_device_path(bond->dev, rt->dst.dev, tags);
tags = bond_verify_device_path(bond->dev, rt->dst.dev, 0);
rcu_read_unlock();

if (ret)
if (!IS_ERR_OR_NULL(tags))
goto found;

/* Not our device - skip */
Expand All @@ -2271,6 +2287,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
ip_rt_put(rt);
bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
addr, tags);
if (!tags)
kfree(tags);
}
}

Expand Down
7 changes: 3 additions & 4 deletions drivers/net/bonding/bonding.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@

#define bond_version DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"

#define BOND_MAX_VLAN_ENCAP 2
#define BOND_MAX_ARP_TARGETS 16

#define BOND_DEFAULT_MIIMON 100
Expand Down Expand Up @@ -525,9 +524,9 @@ int bond_netlink_init(void);
void bond_netlink_fini(void);
struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond);
const char *bond_slave_link_status(s8 link);
bool bond_verify_device_path(struct net_device *start_dev,
struct net_device *end_dev,
struct bond_vlan_tag *tags);
struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev,
struct net_device *end_dev,
int level);

#ifdef CONFIG_PROC_FS
void bond_create_proc_entry(struct bonding *bond);
Expand Down

0 comments on commit 3e403a7

Please sign in to comment.