diff options
author | Veaceslav Falico <vfalico@gmail.com> | 2014-07-17 11:02:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-07-20 23:35:00 -0400 |
commit | 3e403a77779faf046862d91c36ef79fb4b12be9a (patch) | |
tree | 25f1b3b47eff4aa4e437d991b33f3438eed85eec /drivers/net/bonding | |
parent | 224e923cd9b001c612b7b68933264156271722f9 (diff) |
bonding: make it possible to have unlimited nested upper vlans
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>
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r-- | drivers/net/bonding/bond_alb.c | 8 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 82 | ||||
-rw-r--r-- | drivers/net/bonding/bonding.h | 7 |
3 files changed, 58 insertions, 39 deletions
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index d3c6801f101e..95dd1f58c260 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c | |||
@@ -1042,7 +1042,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[], | |||
1042 | struct bonding *bond = bond_get_bond_by_slave(slave); | 1042 | struct bonding *bond = bond_get_bond_by_slave(slave); |
1043 | struct net_device *upper; | 1043 | struct net_device *upper; |
1044 | struct list_head *iter; | 1044 | struct list_head *iter; |
1045 | struct bond_vlan_tag tags[BOND_MAX_VLAN_ENCAP]; | 1045 | struct bond_vlan_tag *tags; |
1046 | 1046 | ||
1047 | /* send untagged */ | 1047 | /* send untagged */ |
1048 | alb_send_lp_vid(slave, mac_addr, 0, 0); | 1048 | alb_send_lp_vid(slave, mac_addr, 0, 0); |
@@ -1070,10 +1070,12 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[], | |||
1070 | * when strict_match is turned off. | 1070 | * when strict_match is turned off. |
1071 | */ | 1071 | */ |
1072 | if (netif_is_macvlan(upper) && !strict_match) { | 1072 | if (netif_is_macvlan(upper) && !strict_match) { |
1073 | memset(tags, 0, sizeof(tags)); | 1073 | tags = bond_verify_device_path(bond->dev, upper, 0); |
1074 | bond_verify_device_path(bond->dev, upper, tags); | 1074 | if (IS_ERR_OR_NULL(tags)) |
1075 | BUG(); | ||
1075 | alb_send_lp_vid(slave, upper->dev_addr, | 1076 | alb_send_lp_vid(slave, upper->dev_addr, |
1076 | tags[0].vlan_proto, tags[0].vlan_id); | 1077 | tags[0].vlan_proto, tags[0].vlan_id); |
1078 | kfree(tags); | ||
1077 | } | 1079 | } |
1078 | } | 1080 | } |
1079 | rcu_read_unlock(); | 1081 | rcu_read_unlock(); |
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 14f789551616..023ec365209c 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -2145,7 +2145,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, | |||
2145 | struct bond_vlan_tag *tags) | 2145 | struct bond_vlan_tag *tags) |
2146 | { | 2146 | { |
2147 | struct sk_buff *skb; | 2147 | struct sk_buff *skb; |
2148 | int i; | 2148 | struct bond_vlan_tag *outer_tag = tags; |
2149 | 2149 | ||
2150 | netdev_dbg(slave_dev, "arp %d on slave %s: dst %pI4 src %pI4\n", | 2150 | netdev_dbg(slave_dev, "arp %d on slave %s: dst %pI4 src %pI4\n", |
2151 | arp_op, slave_dev->name, &dest_ip, &src_ip); | 2151 | arp_op, slave_dev->name, &dest_ip, &src_ip); |
@@ -2158,30 +2158,42 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, | |||
2158 | return; | 2158 | return; |
2159 | } | 2159 | } |
2160 | 2160 | ||
2161 | if (!tags || tags->vlan_proto == VLAN_N_VID) | ||
2162 | goto xmit; | ||
2163 | |||
2164 | tags++; | ||
2165 | |||
2161 | /* Go through all the tags backwards and add them to the packet */ | 2166 | /* Go through all the tags backwards and add them to the packet */ |
2162 | for (i = BOND_MAX_VLAN_ENCAP - 1; i > 0; i--) { | 2167 | while (tags->vlan_proto != VLAN_N_VID) { |
2163 | if (!tags[i].vlan_id) | 2168 | if (!tags->vlan_id) { |
2169 | tags++; | ||
2164 | continue; | 2170 | continue; |
2171 | } | ||
2165 | 2172 | ||
2166 | netdev_dbg(slave_dev, "inner tag: proto %X vid %X\n", | 2173 | netdev_dbg(slave_dev, "inner tag: proto %X vid %X\n", |
2167 | ntohs(tags[i].vlan_proto), tags[i].vlan_id); | 2174 | ntohs(outer_tag->vlan_proto), tags->vlan_id); |
2168 | skb = __vlan_put_tag(skb, tags[i].vlan_proto, | 2175 | skb = __vlan_put_tag(skb, tags->vlan_proto, |
2169 | tags[i].vlan_id); | 2176 | tags->vlan_id); |
2170 | if (!skb) { | 2177 | if (!skb) { |
2171 | net_err_ratelimited("failed to insert inner VLAN tag\n"); | 2178 | net_err_ratelimited("failed to insert inner VLAN tag\n"); |
2172 | return; | 2179 | return; |
2173 | } | 2180 | } |
2181 | |||
2182 | tags++; | ||
2174 | } | 2183 | } |
2175 | /* Set the outer tag */ | 2184 | /* Set the outer tag */ |
2176 | if (tags[0].vlan_id) { | 2185 | if (outer_tag->vlan_id) { |
2177 | netdev_dbg(slave_dev, "outer tag: proto %X vid %X\n", | 2186 | netdev_dbg(slave_dev, "outer tag: proto %X vid %X\n", |
2178 | ntohs(tags[0].vlan_proto), tags[0].vlan_id); | 2187 | ntohs(outer_tag->vlan_proto), outer_tag->vlan_id); |
2179 | skb = vlan_put_tag(skb, tags[0].vlan_proto, tags[0].vlan_id); | 2188 | skb = vlan_put_tag(skb, outer_tag->vlan_proto, |
2189 | outer_tag->vlan_id); | ||
2180 | if (!skb) { | 2190 | if (!skb) { |
2181 | net_err_ratelimited("failed to insert outer VLAN tag\n"); | 2191 | net_err_ratelimited("failed to insert outer VLAN tag\n"); |
2182 | return; | 2192 | return; |
2183 | } | 2193 | } |
2184 | } | 2194 | } |
2195 | |||
2196 | xmit: | ||
2185 | arp_xmit(skb); | 2197 | arp_xmit(skb); |
2186 | } | 2198 | } |
2187 | 2199 | ||
@@ -2191,46 +2203,50 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, | |||
2191 | * When the path is validated, collect any vlan information in the | 2203 | * When the path is validated, collect any vlan information in the |
2192 | * path. | 2204 | * path. |
2193 | */ | 2205 | */ |
2194 | bool bond_verify_device_path(struct net_device *start_dev, | 2206 | struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev, |
2195 | struct net_device *end_dev, | 2207 | struct net_device *end_dev, |
2196 | struct bond_vlan_tag *tags) | 2208 | int level) |
2197 | { | 2209 | { |
2210 | struct bond_vlan_tag *tags; | ||
2198 | struct net_device *upper; | 2211 | struct net_device *upper; |
2199 | struct list_head *iter; | 2212 | struct list_head *iter; |
2200 | int idx; | ||
2201 | 2213 | ||
2202 | if (start_dev == end_dev) | 2214 | if (start_dev == end_dev) { |
2203 | return true; | 2215 | tags = kzalloc(sizeof(*tags) * (level + 1), GFP_ATOMIC); |
2216 | if (!tags) | ||
2217 | return ERR_PTR(-ENOMEM); | ||
2218 | tags[level].vlan_proto = VLAN_N_VID; | ||
2219 | return tags; | ||
2220 | } | ||
2204 | 2221 | ||
2205 | netdev_for_each_upper_dev_rcu(start_dev, upper, iter) { | 2222 | netdev_for_each_upper_dev_rcu(start_dev, upper, iter) { |
2206 | if (bond_verify_device_path(upper, end_dev, tags)) { | 2223 | tags = bond_verify_device_path(upper, end_dev, level + 1); |
2207 | if (is_vlan_dev(upper)) { | 2224 | if (IS_ERR_OR_NULL(tags)) { |
2208 | idx = vlan_get_encap_level(upper); | 2225 | if (IS_ERR(tags)) |
2209 | if (idx >= BOND_MAX_VLAN_ENCAP) | 2226 | return tags; |
2210 | return false; | 2227 | continue; |
2211 | |||
2212 | tags[idx].vlan_proto = | ||
2213 | vlan_dev_vlan_proto(upper); | ||
2214 | tags[idx].vlan_id = vlan_dev_vlan_id(upper); | ||
2215 | } | ||
2216 | return true; | ||
2217 | } | 2228 | } |
2229 | if (is_vlan_dev(upper)) { | ||
2230 | tags[level].vlan_proto = vlan_dev_vlan_proto(upper); | ||
2231 | tags[level].vlan_id = vlan_dev_vlan_id(upper); | ||
2232 | } | ||
2233 | |||
2234 | return tags; | ||
2218 | } | 2235 | } |
2219 | 2236 | ||
2220 | return false; | 2237 | return NULL; |
2221 | } | 2238 | } |
2222 | 2239 | ||
2223 | static void bond_arp_send_all(struct bonding *bond, struct slave *slave) | 2240 | static void bond_arp_send_all(struct bonding *bond, struct slave *slave) |
2224 | { | 2241 | { |
2225 | struct rtable *rt; | 2242 | struct rtable *rt; |
2226 | struct bond_vlan_tag tags[BOND_MAX_VLAN_ENCAP]; | 2243 | struct bond_vlan_tag *tags; |
2227 | __be32 *targets = bond->params.arp_targets, addr; | 2244 | __be32 *targets = bond->params.arp_targets, addr; |
2228 | int i; | 2245 | int i; |
2229 | bool ret; | ||
2230 | 2246 | ||
2231 | for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) { | 2247 | for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) { |
2232 | netdev_dbg(bond->dev, "basa: target %pI4\n", &targets[i]); | 2248 | netdev_dbg(bond->dev, "basa: target %pI4\n", &targets[i]); |
2233 | memset(tags, 0, sizeof(tags)); | 2249 | tags = NULL; |
2234 | 2250 | ||
2235 | /* Find out through which dev should the packet go */ | 2251 | /* Find out through which dev should the packet go */ |
2236 | rt = ip_route_output(dev_net(bond->dev), targets[i], 0, | 2252 | rt = ip_route_output(dev_net(bond->dev), targets[i], 0, |
@@ -2253,10 +2269,10 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) | |||
2253 | goto found; | 2269 | goto found; |
2254 | 2270 | ||
2255 | rcu_read_lock(); | 2271 | rcu_read_lock(); |
2256 | ret = bond_verify_device_path(bond->dev, rt->dst.dev, tags); | 2272 | tags = bond_verify_device_path(bond->dev, rt->dst.dev, 0); |
2257 | rcu_read_unlock(); | 2273 | rcu_read_unlock(); |
2258 | 2274 | ||
2259 | if (ret) | 2275 | if (!IS_ERR_OR_NULL(tags)) |
2260 | goto found; | 2276 | goto found; |
2261 | 2277 | ||
2262 | /* Not our device - skip */ | 2278 | /* Not our device - skip */ |
@@ -2271,6 +2287,8 @@ found: | |||
2271 | ip_rt_put(rt); | 2287 | ip_rt_put(rt); |
2272 | bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], | 2288 | bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], |
2273 | addr, tags); | 2289 | addr, tags); |
2290 | if (!tags) | ||
2291 | kfree(tags); | ||
2274 | } | 2292 | } |
2275 | } | 2293 | } |
2276 | 2294 | ||
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index a85ca51eabf5..aace510d08d1 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
@@ -36,7 +36,6 @@ | |||
36 | 36 | ||
37 | #define bond_version DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n" | 37 | #define bond_version DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n" |
38 | 38 | ||
39 | #define BOND_MAX_VLAN_ENCAP 2 | ||
40 | #define BOND_MAX_ARP_TARGETS 16 | 39 | #define BOND_MAX_ARP_TARGETS 16 |
41 | 40 | ||
42 | #define BOND_DEFAULT_MIIMON 100 | 41 | #define BOND_DEFAULT_MIIMON 100 |
@@ -525,9 +524,9 @@ int bond_netlink_init(void); | |||
525 | void bond_netlink_fini(void); | 524 | void bond_netlink_fini(void); |
526 | struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); | 525 | struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); |
527 | const char *bond_slave_link_status(s8 link); | 526 | const char *bond_slave_link_status(s8 link); |
528 | bool bond_verify_device_path(struct net_device *start_dev, | 527 | struct bond_vlan_tag *bond_verify_device_path(struct net_device *start_dev, |
529 | struct net_device *end_dev, | 528 | struct net_device *end_dev, |
530 | struct bond_vlan_tag *tags); | 529 | int level); |
531 | 530 | ||
532 | #ifdef CONFIG_PROC_FS | 531 | #ifdef CONFIG_PROC_FS |
533 | void bond_create_proc_entry(struct bonding *bond); | 532 | void bond_create_proc_entry(struct bonding *bond); |