summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-03-26 16:42:02 -0400
committerDavid S. Miller <davem@davemloft.net>2014-03-26 16:42:02 -0400
commitb620cb3e829f257f96845bd60813a94f598d6dec (patch)
treeea3955db51ca63b5f7117535aaee782cbb64382b
parent5a6b99170c7042702112c64bec46bcca9fbcc6d7 (diff)
parent4873ac3c8ed3b0285f18b81e501249c26284c2ca (diff)
Merge branch 'bonding-next'
Ding Tianhong says: ==================== bonding: support QinQ for bond arp interval v1->v2: remvoe the comment "TODO: QinQ?". convert pr_xxx() to pr_xxx_ratelimited() for arp interval. v2->v3: remove the unnecessary log for arp interval and add net ratelimit to avoid spam log. v3->v4: Add ratelimit for debugging is not a good idea, it will miss some message if the user turns the debugging on, so don't add ratelimited on debugging. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_main.c73
-rw-r--r--drivers/net/bonding/bonding.h5
-rw-r--r--include/linux/if_vlan.h7
-rw-r--r--net/8021q/vlan_core.c6
4 files changed, 69 insertions, 22 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index cbadd6dccb2..5be34b72a04 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2124,24 +2124,40 @@ static bool bond_has_this_ip(struct bonding *bond, __be32 ip)
* 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,
+ __be32 dest_ip, __be32 src_ip,
+ struct bond_vlan_tag *inner,
+ struct bond_vlan_tag *outer)
{
struct sk_buff *skb;
- pr_debug("arp %d on slave %s: dst %pI4 src %pI4 vid %d\n",
- arp_op, slave_dev->name, &dest_ip, &src_ip, vlan_id);
+ pr_debug("arp %d on slave %s: dst %pI4 src %pI4\n",
+ arp_op, slave_dev->name, &dest_ip, &src_ip);
skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip,
NULL, slave_dev->dev_addr, NULL);
if (!skb) {
- pr_err("ARP packet allocation failed\n");
+ net_err_ratelimited("ARP packet allocation failed\n");
return;
}
- if (vlan_id) {
- skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_id);
+ if (outer->vlan_id) {
+ if (inner->vlan_id) {
+ pr_debug("inner tag: proto %X vid %X\n",
+ ntohs(inner->vlan_proto), inner->vlan_id);
+ skb = __vlan_put_tag(skb, inner->vlan_proto,
+ inner->vlan_id);
+ if (!skb) {
+ net_err_ratelimited("failed to insert inner VLAN tag\n");
+ return;
+ }
+ }
+
+ pr_debug("outer reg: proto %X vid %X\n",
+ ntohs(outer->vlan_proto), outer->vlan_id);
+ skb = vlan_put_tag(skb, outer->vlan_proto, outer->vlan_id);
if (!skb) {
- pr_err("failed to insert VLAN tag\n");
+ net_err_ratelimited("failed to insert outer VLAN tag\n");
return;
}
}
@@ -2154,11 +2170,16 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
struct net_device *upper, *vlan_upper;
struct list_head *iter, *vlan_iter;
struct rtable *rt;
+ struct bond_vlan_tag inner, outer;
__be32 *targets = bond->params.arp_targets, addr;
- int i, vlan_id;
+ int i;
for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) {
pr_debug("basa: target %pI4\n", &targets[i]);
+ inner.vlan_proto = 0;
+ inner.vlan_id = 0;
+ outer.vlan_proto = 0;
+ outer.vlan_id = 0;
/* Find out through which dev should the packet go */
rt = ip_route_output(dev_net(bond->dev), targets[i], 0,
@@ -2167,15 +2188,14 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
/* there's no route to target - try to send arp
* probe to generate any traffic (arp_validate=0)
*/
- if (bond->params.arp_validate && net_ratelimit())
- pr_warn("%s: no route to arp_ip_target %pI4 and arp_validate is set\n",
- bond->dev->name, &targets[i]);
- bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 0, 0);
+ if (bond->params.arp_validate)
+ net_warn_ratelimited("%s: no route to arp_ip_target %pI4 and arp_validate is set\n",
+ bond->dev->name,
+ &targets[i]);
+ bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 0, &inner, &outer);
continue;
}
- vlan_id = 0;
-
/* bond device itself */
if (rt->dst.dev == bond->dev)
goto found;
@@ -2185,17 +2205,30 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
* found we verify its upper dev list, searching for the
* rt->dst.dev. If found we save the tag of the vlan and
* proceed to send the packet.
- *
- * TODO: QinQ?
*/
netdev_for_each_all_upper_dev_rcu(bond->dev, vlan_upper,
vlan_iter) {
if (!is_vlan_dev(vlan_upper))
continue;
+
+ if (vlan_upper == rt->dst.dev) {
+ outer.vlan_proto = vlan_dev_vlan_proto(vlan_upper);
+ outer.vlan_id = vlan_dev_vlan_id(vlan_upper);
+ rcu_read_unlock();
+ goto found;
+ }
netdev_for_each_all_upper_dev_rcu(vlan_upper, upper,
iter) {
if (upper == rt->dst.dev) {
- vlan_id = vlan_dev_vlan_id(vlan_upper);
+ /* If the upper dev is a vlan dev too,
+ * set the vlan tag to inner tag.
+ */
+ if (is_vlan_dev(upper)) {
+ inner.vlan_proto = vlan_dev_vlan_proto(upper);
+ inner.vlan_id = vlan_dev_vlan_id(upper);
+ }
+ outer.vlan_proto = vlan_dev_vlan_proto(vlan_upper);
+ outer.vlan_id = vlan_dev_vlan_id(vlan_upper);
rcu_read_unlock();
goto found;
}
@@ -2208,10 +2241,6 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
*/
netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
if (upper == rt->dst.dev) {
- /* if it's a vlan - get its VID */
- if (is_vlan_dev(upper))
- vlan_id = vlan_dev_vlan_id(upper);
-
rcu_read_unlock();
goto found;
}
@@ -2230,7 +2259,7 @@ found:
addr = bond_confirm_addr(rt->dst.dev, targets[i], 0);
ip_rt_put(rt);
bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
- addr, vlan_id);
+ addr, &inner, &outer);
}
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 0896f1db24d..b8bdd0acc8f 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -266,6 +266,11 @@ struct bonding {
#define bond_slave_get_rtnl(dev) \
((struct slave *) rtnl_dereference(dev->rx_handler_data))
+struct bond_vlan_tag {
+ __be16 vlan_proto;
+ unsigned short vlan_id;
+};
+
/**
* Returns NULL if the net_device does not belong to any of the bond's slaves
*
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index d3d2306f00b..13bbbde00e6 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -110,6 +110,7 @@ extern struct net_device *__vlan_find_dev_deep(struct net_device *real_dev,
__be16 vlan_proto, u16 vlan_id);
extern struct net_device *vlan_dev_real_dev(const struct net_device *dev);
extern u16 vlan_dev_vlan_id(const struct net_device *dev);
+extern __be16 vlan_dev_vlan_proto(const struct net_device *dev);
/**
* struct vlan_priority_tci_mapping - vlan egress priority mappings
@@ -216,6 +217,12 @@ static inline u16 vlan_dev_vlan_id(const struct net_device *dev)
return 0;
}
+static inline __be16 vlan_dev_vlan_proto(const struct net_device *dev)
+{
+ BUG();
+ return 0;
+}
+
static inline u16 vlan_dev_get_egress_qos_mask(struct net_device *dev,
u32 skprio)
{
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 35b3c192d7b..3c32bd257b7 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -106,6 +106,12 @@ u16 vlan_dev_vlan_id(const struct net_device *dev)
}
EXPORT_SYMBOL(vlan_dev_vlan_id);
+__be16 vlan_dev_vlan_proto(const struct net_device *dev)
+{
+ return vlan_dev_priv(dev)->vlan_proto;
+}
+EXPORT_SYMBOL(vlan_dev_vlan_proto);
+
static struct sk_buff *vlan_reorder_header(struct sk_buff *skb)
{
if (skb_cow(skb, skb_headroom(skb)) < 0)