aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/bonding
diff options
context:
space:
mode:
authordingtianhong <dingtianhong@huawei.com>2014-03-25 05:44:43 -0400
committerDavid S. Miller <davem@davemloft.net>2014-03-26 16:41:28 -0400
commitfbd929f2dce460456807a51e18d623db3db9f077 (patch)
tree694dfa9feb788b33564035630d31cd9ffb98299f /drivers/net/bonding
parent71e415e44c1f9b7a4f05dac4f8038575dbef0c6f (diff)
bonding: support QinQ for bond arp interval
The bond send arp request to indicate that the slave is active, and if the bond dev is a vlan dev, it will set the vlan tag in skb to notice the vlan group, but the bond could only send a skb with 802.1q proto, not support for QinQ. So add outer tag for lower vlan tag and inner tag for upper vlan tag to support QinQ, The new skb will be consist of two vlan tag just like this: dst mac | src mac | outer vlan tag | inner vlan tag | data | ..... If We don't need QinQ, the inner vlan tag could be set to 0 and use outer vlan tag as a normal vlan group. Using "ip link" to configure the bond for QinQ and add test log: ip link add link bond0 bond0.20 type vlan proto 802.1ad id 20 ip link add link bond0.20 bond0.20.200 type vlan proto 802.1q id 200 ifconfig bond0.20 11.11.20.36/24 ifconfig bond0.20.200 11.11.200.36/24 echo +11.11.200.37 > /sys/class/net/bond0/bonding/arp_ip_target 90:e2:ba:07:4a:5c (oui Unknown) > Broadcast, ethertype 802.1Q-QinQ (0x88a8),length 50: vlan 20, p 0,ethertype 802.1Q, vlan 200, p 0, ethertype ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 11.11.200.37 tell 11.11.200.36, length 28 90:e2:ba:06:f9:86 (oui Unknown) > 90:e2:ba:07:4a:5c (oui Unknown), ethertype 802.1Q-QinQ (0x88a8), length 50: vlan 20, p 0, ethertype 802.1Q, vlan 200, p 0, ethertype ARP, Ethernet (len 6), IPv4 (len 4), Reply 11.11.200.37 is-at 90:e2:ba:06:f9:86 (oui Unknown), length 28 v1->v2: remove the comment "TODO: QinQ?". Cc: Jay Vosburgh <fubar@us.ibm.com> Cc: Veaceslav Falico <vfalico@redhat.com> Cc: Andy Gospodarek <andy@greyhouse.net> Signed-off-by: Ding Tianhong <dingtianhong@huawei.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r--drivers/net/bonding/bond_main.c63
-rw-r--r--drivers/net/bonding/bonding.h5
2 files changed, 50 insertions, 18 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index cbadd6dccb2b..7802c2ebdb0d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2124,12 +2124,15 @@ static bool bond_has_this_ip(struct bonding *bond, __be32 ip)
2124 * switches in VLAN mode (especially if ports are configured as 2124 * switches in VLAN mode (especially if ports are configured as
2125 * "native" to a VLAN) might not pass non-tagged frames. 2125 * "native" to a VLAN) might not pass non-tagged frames.
2126 */ 2126 */
2127static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ip, __be32 src_ip, unsigned short vlan_id) 2127static void bond_arp_send(struct net_device *slave_dev, int arp_op,
2128 __be32 dest_ip, __be32 src_ip,
2129 struct bond_vlan_tag *inner,
2130 struct bond_vlan_tag *outer)
2128{ 2131{
2129 struct sk_buff *skb; 2132 struct sk_buff *skb;
2130 2133
2131 pr_debug("arp %d on slave %s: dst %pI4 src %pI4 vid %d\n", 2134 pr_debug("arp %d on slave %s: dst %pI4 src %pI4\n",
2132 arp_op, slave_dev->name, &dest_ip, &src_ip, vlan_id); 2135 arp_op, slave_dev->name, &dest_ip, &src_ip);
2133 2136
2134 skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip, 2137 skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip,
2135 NULL, slave_dev->dev_addr, NULL); 2138 NULL, slave_dev->dev_addr, NULL);
@@ -2138,10 +2141,22 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_
2138 pr_err("ARP packet allocation failed\n"); 2141 pr_err("ARP packet allocation failed\n");
2139 return; 2142 return;
2140 } 2143 }
2141 if (vlan_id) { 2144 if (outer->vlan_id) {
2142 skb = vlan_put_tag(skb, htons(ETH_P_8021Q), vlan_id); 2145 if (inner->vlan_id) {
2146 pr_debug("inner tag: proto %X vid %X\n",
2147 ntohs(inner->vlan_proto), inner->vlan_id);
2148 skb = __vlan_put_tag(skb, inner->vlan_proto, inner->vlan_id);
2149 if (!skb) {
2150 pr_err("failed to insert inner VLAN tag\n");
2151 return;
2152 }
2153 }
2154
2155 pr_debug("outer reg: proto %X vid %X\n",
2156 ntohs(outer->vlan_proto), outer->vlan_id);
2157 skb = vlan_put_tag(skb, outer->vlan_proto, outer->vlan_id);
2143 if (!skb) { 2158 if (!skb) {
2144 pr_err("failed to insert VLAN tag\n"); 2159 pr_err("failed to insert outer VLAN tag\n");
2145 return; 2160 return;
2146 } 2161 }
2147 } 2162 }
@@ -2154,11 +2169,16 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
2154 struct net_device *upper, *vlan_upper; 2169 struct net_device *upper, *vlan_upper;
2155 struct list_head *iter, *vlan_iter; 2170 struct list_head *iter, *vlan_iter;
2156 struct rtable *rt; 2171 struct rtable *rt;
2172 struct bond_vlan_tag inner, outer;
2157 __be32 *targets = bond->params.arp_targets, addr; 2173 __be32 *targets = bond->params.arp_targets, addr;
2158 int i, vlan_id; 2174 int i;
2159 2175
2160 for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) { 2176 for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) {
2161 pr_debug("basa: target %pI4\n", &targets[i]); 2177 pr_debug("basa: target %pI4\n", &targets[i]);
2178 inner.vlan_proto = 0;
2179 inner.vlan_id = 0;
2180 outer.vlan_proto = 0;
2181 outer.vlan_id = 0;
2162 2182
2163 /* Find out through which dev should the packet go */ 2183 /* Find out through which dev should the packet go */
2164 rt = ip_route_output(dev_net(bond->dev), targets[i], 0, 2184 rt = ip_route_output(dev_net(bond->dev), targets[i], 0,
@@ -2170,12 +2190,10 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
2170 if (bond->params.arp_validate && net_ratelimit()) 2190 if (bond->params.arp_validate && net_ratelimit())
2171 pr_warn("%s: no route to arp_ip_target %pI4 and arp_validate is set\n", 2191 pr_warn("%s: no route to arp_ip_target %pI4 and arp_validate is set\n",
2172 bond->dev->name, &targets[i]); 2192 bond->dev->name, &targets[i]);
2173 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 0, 0); 2193 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 0, &inner, &outer);
2174 continue; 2194 continue;
2175 } 2195 }
2176 2196
2177 vlan_id = 0;
2178
2179 /* bond device itself */ 2197 /* bond device itself */
2180 if (rt->dst.dev == bond->dev) 2198 if (rt->dst.dev == bond->dev)
2181 goto found; 2199 goto found;
@@ -2185,17 +2203,30 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
2185 * found we verify its upper dev list, searching for the 2203 * found we verify its upper dev list, searching for the
2186 * rt->dst.dev. If found we save the tag of the vlan and 2204 * rt->dst.dev. If found we save the tag of the vlan and
2187 * proceed to send the packet. 2205 * proceed to send the packet.
2188 *
2189 * TODO: QinQ?
2190 */ 2206 */
2191 netdev_for_each_all_upper_dev_rcu(bond->dev, vlan_upper, 2207 netdev_for_each_all_upper_dev_rcu(bond->dev, vlan_upper,
2192 vlan_iter) { 2208 vlan_iter) {
2193 if (!is_vlan_dev(vlan_upper)) 2209 if (!is_vlan_dev(vlan_upper))
2194 continue; 2210 continue;
2211
2212 if (vlan_upper == rt->dst.dev) {
2213 outer.vlan_proto = vlan_dev_vlan_proto(vlan_upper);
2214 outer.vlan_id = vlan_dev_vlan_id(vlan_upper);
2215 rcu_read_unlock();
2216 goto found;
2217 }
2195 netdev_for_each_all_upper_dev_rcu(vlan_upper, upper, 2218 netdev_for_each_all_upper_dev_rcu(vlan_upper, upper,
2196 iter) { 2219 iter) {
2197 if (upper == rt->dst.dev) { 2220 if (upper == rt->dst.dev) {
2198 vlan_id = vlan_dev_vlan_id(vlan_upper); 2221 /* If the upper dev is a vlan dev too,
2222 * set the vlan tag to inner tag.
2223 */
2224 if (is_vlan_dev(upper)) {
2225 inner.vlan_proto = vlan_dev_vlan_proto(upper);
2226 inner.vlan_id = vlan_dev_vlan_id(upper);
2227 }
2228 outer.vlan_proto = vlan_dev_vlan_proto(vlan_upper);
2229 outer.vlan_id = vlan_dev_vlan_id(vlan_upper);
2199 rcu_read_unlock(); 2230 rcu_read_unlock();
2200 goto found; 2231 goto found;
2201 } 2232 }
@@ -2208,10 +2239,6 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
2208 */ 2239 */
2209 netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) { 2240 netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
2210 if (upper == rt->dst.dev) { 2241 if (upper == rt->dst.dev) {
2211 /* if it's a vlan - get its VID */
2212 if (is_vlan_dev(upper))
2213 vlan_id = vlan_dev_vlan_id(upper);
2214
2215 rcu_read_unlock(); 2242 rcu_read_unlock();
2216 goto found; 2243 goto found;
2217 } 2244 }
@@ -2230,7 +2257,7 @@ found:
2230 addr = bond_confirm_addr(rt->dst.dev, targets[i], 0); 2257 addr = bond_confirm_addr(rt->dst.dev, targets[i], 0);
2231 ip_rt_put(rt); 2258 ip_rt_put(rt);
2232 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 2259 bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
2233 addr, vlan_id); 2260 addr, &inner, &outer);
2234 } 2261 }
2235} 2262}
2236 2263
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 0896f1db24db..b8bdd0acc8f3 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -266,6 +266,11 @@ struct bonding {
266#define bond_slave_get_rtnl(dev) \ 266#define bond_slave_get_rtnl(dev) \
267 ((struct slave *) rtnl_dereference(dev->rx_handler_data)) 267 ((struct slave *) rtnl_dereference(dev->rx_handler_data))
268 268
269struct bond_vlan_tag {
270 __be16 vlan_proto;
271 unsigned short vlan_id;
272};
273
269/** 274/**
270 * Returns NULL if the net_device does not belong to any of the bond's slaves 275 * Returns NULL if the net_device does not belong to any of the bond's slaves
271 * 276 *