diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index cbadd6dccb2baac00c3cd39b278624d04a5660ec..5be34b72a048ead297bf3866571d1da2f369b102 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 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) 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 0896f1db24db6a334c91129e5716fb5c32d1c855..b8bdd0acc8f334ac97bca2ddfea602f473c3272f 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 d3d2306f00bf3b1b2dcf1e121bcac4b082f62d97..13bbbde00e68de454c8cf30f0581796d55eb0a40 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 35b3c192d7b90b97faaa684868b75fec47d200f7..3c32bd257b73975a33ba104c1c3b3797d9f29843 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)