Skip to content

Commit 44a4085

Browse files
Vlad Yasevichdavem330
authored andcommitted
bonding: Fix stacked device detection in arp monitoring
Prior to commit fbd929f bonding: support QinQ for bond arp interval the arp monitoring code allowed for proper detection of devices stacked on top of vlans. Since the above commit, the code can still detect a device stacked on top of single vlan, but not a device stacked on top of Q-in-Q configuration. The search will only set the inner vlan tag if the route device is the vlan device. However, this is not always the case, as it is possible to extend the stacked configuration. With this patch it is possible to provision devices on top Q-in-Q vlan configuration that should be used as a source of ARP monitoring information. For example: ip link add link bond0 vlan10 type vlan proto 802.1q id 10 ip link add link vlan10 vlan100 type vlan proto 802.1q id 100 ip link add link vlan100 type macvlan Note: This patch limites the number of stacked VLANs to 2, just like before. The original, however had another issue in that if we had more then 2 levels of VLANs, we would end up generating incorrectly tagged traffic. This is no longer possible. Fixes: fbd929f (bonding: support QinQ for bond arp interval) CC: Jay Vosburgh <[email protected]> CC: Veaceslav Falico <[email protected]> CC: Andy Gospodarek <[email protected]> CC: Ding Tianhong <[email protected]> CC: Patric McHardy <[email protected]> Signed-off-by: Vlad Yasevich <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6bd64ac commit 44a4085

File tree

5 files changed

+107
-69
lines changed

5 files changed

+107
-69
lines changed

drivers/net/bonding/bond_main.c

Lines changed: 65 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,10 +2126,10 @@ static bool bond_has_this_ip(struct bonding *bond, __be32 ip)
21262126
*/
21272127
static void bond_arp_send(struct net_device *slave_dev, int arp_op,
21282128
__be32 dest_ip, __be32 src_ip,
2129-
struct bond_vlan_tag *inner,
2130-
struct bond_vlan_tag *outer)
2129+
struct bond_vlan_tag *tags)
21312130
{
21322131
struct sk_buff *skb;
2132+
int i;
21332133

21342134
pr_debug("arp %d on slave %s: dst %pI4 src %pI4\n",
21352135
arp_op, slave_dev->name, &dest_ip, &src_ip);
@@ -2141,21 +2141,26 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op,
21412141
net_err_ratelimited("ARP packet allocation failed\n");
21422142
return;
21432143
}
2144-
if (outer->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,
2149-
inner->vlan_id);
2150-
if (!skb) {
2151-
net_err_ratelimited("failed to insert inner VLAN tag\n");
2152-
return;
2153-
}
2154-
}
21552144

2156-
pr_debug("outer reg: proto %X vid %X\n",
2157-
ntohs(outer->vlan_proto), outer->vlan_id);
2158-
skb = vlan_put_tag(skb, outer->vlan_proto, outer->vlan_id);
2145+
/* Go through all the tags backwards and add them to the packet */
2146+
for (i = BOND_MAX_VLAN_ENCAP - 1; i > 0; i--) {
2147+
if (!tags[i].vlan_id)
2148+
continue;
2149+
2150+
pr_debug("inner tag: proto %X vid %X\n",
2151+
ntohs(tags[i].vlan_proto), tags[i].vlan_id);
2152+
skb = __vlan_put_tag(skb, tags[i].vlan_proto,
2153+
tags[i].vlan_id);
2154+
if (!skb) {
2155+
net_err_ratelimited("failed to insert inner VLAN tag\n");
2156+
return;
2157+
}
2158+
}
2159+
/* Set the outer tag */
2160+
if (tags[0].vlan_id) {
2161+
pr_debug("outer tag: proto %X vid %X\n",
2162+
ntohs(tags[0].vlan_proto), tags[0].vlan_id);
2163+
skb = vlan_put_tag(skb, tags[0].vlan_proto, tags[0].vlan_id);
21592164
if (!skb) {
21602165
net_err_ratelimited("failed to insert outer VLAN tag\n");
21612166
return;
@@ -2164,22 +2169,52 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op,
21642169
arp_xmit(skb);
21652170
}
21662171

2172+
/* Validate the device path between the @start_dev and the @end_dev.
2173+
* The path is valid if the @end_dev is reachable through device
2174+
* stacking.
2175+
* When the path is validated, collect any vlan information in the
2176+
* path.
2177+
*/
2178+
static bool bond_verify_device_path(struct net_device *start_dev,
2179+
struct net_device *end_dev,
2180+
struct bond_vlan_tag *tags)
2181+
{
2182+
struct net_device *upper;
2183+
struct list_head *iter;
2184+
int idx;
2185+
2186+
if (start_dev == end_dev)
2187+
return true;
2188+
2189+
netdev_for_each_upper_dev_rcu(start_dev, upper, iter) {
2190+
if (bond_verify_device_path(upper, end_dev, tags)) {
2191+
if (is_vlan_dev(upper)) {
2192+
idx = vlan_get_encap_level(upper);
2193+
if (idx >= BOND_MAX_VLAN_ENCAP)
2194+
return false;
2195+
2196+
tags[idx].vlan_proto =
2197+
vlan_dev_vlan_proto(upper);
2198+
tags[idx].vlan_id = vlan_dev_vlan_id(upper);
2199+
}
2200+
return true;
2201+
}
2202+
}
2203+
2204+
return false;
2205+
}
21672206

21682207
static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
21692208
{
2170-
struct net_device *upper, *vlan_upper;
2171-
struct list_head *iter, *vlan_iter;
21722209
struct rtable *rt;
2173-
struct bond_vlan_tag inner, outer;
2210+
struct bond_vlan_tag tags[BOND_MAX_VLAN_ENCAP];
21742211
__be32 *targets = bond->params.arp_targets, addr;
21752212
int i;
2213+
bool ret;
21762214

21772215
for (i = 0; i < BOND_MAX_ARP_TARGETS && targets[i]; i++) {
21782216
pr_debug("basa: target %pI4\n", &targets[i]);
2179-
inner.vlan_proto = 0;
2180-
inner.vlan_id = 0;
2181-
outer.vlan_proto = 0;
2182-
outer.vlan_id = 0;
2217+
memset(tags, 0, sizeof(tags));
21832218

21842219
/* Find out through which dev should the packet go */
21852220
rt = ip_route_output(dev_net(bond->dev), targets[i], 0,
@@ -2192,7 +2227,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
21922227
net_warn_ratelimited("%s: no route to arp_ip_target %pI4 and arp_validate is set\n",
21932228
bond->dev->name,
21942229
&targets[i]);
2195-
bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 0, &inner, &outer);
2230+
bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
2231+
0, tags);
21962232
continue;
21972233
}
21982234

@@ -2201,52 +2237,12 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
22012237
goto found;
22022238

22032239
rcu_read_lock();
2204-
/* first we search only for vlan devices. for every vlan
2205-
* found we verify its upper dev list, searching for the
2206-
* rt->dst.dev. If found we save the tag of the vlan and
2207-
* proceed to send the packet.
2208-
*/
2209-
netdev_for_each_all_upper_dev_rcu(bond->dev, vlan_upper,
2210-
vlan_iter) {
2211-
if (!is_vlan_dev(vlan_upper))
2212-
continue;
2213-
2214-
if (vlan_upper == rt->dst.dev) {
2215-
outer.vlan_proto = vlan_dev_vlan_proto(vlan_upper);
2216-
outer.vlan_id = vlan_dev_vlan_id(vlan_upper);
2217-
rcu_read_unlock();
2218-
goto found;
2219-
}
2220-
netdev_for_each_all_upper_dev_rcu(vlan_upper, upper,
2221-
iter) {
2222-
if (upper == rt->dst.dev) {
2223-
/* If the upper dev is a vlan dev too,
2224-
* set the vlan tag to inner tag.
2225-
*/
2226-
if (is_vlan_dev(upper)) {
2227-
inner.vlan_proto = vlan_dev_vlan_proto(upper);
2228-
inner.vlan_id = vlan_dev_vlan_id(upper);
2229-
}
2230-
outer.vlan_proto = vlan_dev_vlan_proto(vlan_upper);
2231-
outer.vlan_id = vlan_dev_vlan_id(vlan_upper);
2232-
rcu_read_unlock();
2233-
goto found;
2234-
}
2235-
}
2236-
}
2237-
2238-
/* if the device we're looking for is not on top of any of
2239-
* our upper vlans, then just search for any dev that
2240-
* matches, and in case it's a vlan - save the id
2241-
*/
2242-
netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) {
2243-
if (upper == rt->dst.dev) {
2244-
rcu_read_unlock();
2245-
goto found;
2246-
}
2247-
}
2240+
ret = bond_verify_device_path(bond->dev, rt->dst.dev, tags);
22482241
rcu_read_unlock();
22492242

2243+
if (ret)
2244+
goto found;
2245+
22502246
/* Not our device - skip */
22512247
pr_debug("%s: no path to arp_ip_target %pI4 via rt.dev %s\n",
22522248
bond->dev->name, &targets[i],
@@ -2259,7 +2255,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
22592255
addr = bond_confirm_addr(rt->dst.dev, targets[i], 0);
22602256
ip_rt_put(rt);
22612257
bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
2262-
addr, &inner, &outer);
2258+
addr, tags);
22632259
}
22642260
}
22652261

drivers/net/bonding/bonding.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

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

39+
#define BOND_MAX_VLAN_ENCAP 2
3940
#define BOND_MAX_ARP_TARGETS 16
4041

4142
#define BOND_DEFAULT_MIIMON 100

include/linux/if_vlan.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,4 +484,10 @@ static inline void vlan_set_encap_proto(struct sk_buff *skb,
484484
*/
485485
skb->protocol = htons(ETH_P_802_2);
486486
}
487+
488+
static inline int vlan_get_encap_level(struct net_device *dev)
489+
{
490+
BUG_ON(!is_vlan_dev(dev));
491+
return vlan_dev_priv(dev)->nest_level;
492+
}
487493
#endif /* !(_LINUX_IF_VLAN_H_) */

include/linux/netdevice.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3056,9 +3056,18 @@ extern int weight_p;
30563056
extern int bpf_jit_enable;
30573057

30583058
bool netdev_has_upper_dev(struct net_device *dev, struct net_device *upper_dev);
3059+
struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
3060+
struct list_head **iter);
30593061
struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev,
30603062
struct list_head **iter);
30613063

3064+
/* iterate through upper list, must be called under RCU read lock */
3065+
#define netdev_for_each_upper_dev_rcu(dev, updev, iter) \
3066+
for (iter = &(dev)->adj_list.upper, \
3067+
updev = netdev_upper_get_next_dev_rcu(dev, &(iter)); \
3068+
updev; \
3069+
updev = netdev_upper_get_next_dev_rcu(dev, &(iter)))
3070+
30623071
/* iterate through upper list, must be called under RCU read lock */
30633072
#define netdev_for_each_all_upper_dev_rcu(dev, updev, iter) \
30643073
for (iter = &(dev)->all_adj_list.upper, \

net/core/dev.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4541,6 +4541,32 @@ void *netdev_adjacent_get_private(struct list_head *adj_list)
45414541
}
45424542
EXPORT_SYMBOL(netdev_adjacent_get_private);
45434543

4544+
/**
4545+
* netdev_upper_get_next_dev_rcu - Get the next dev from upper list
4546+
* @dev: device
4547+
* @iter: list_head ** of the current position
4548+
*
4549+
* Gets the next device from the dev's upper list, starting from iter
4550+
* position. The caller must hold RCU read lock.
4551+
*/
4552+
struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
4553+
struct list_head **iter)
4554+
{
4555+
struct netdev_adjacent *upper;
4556+
4557+
WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held());
4558+
4559+
upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list);
4560+
4561+
if (&upper->list == &dev->adj_list.upper)
4562+
return NULL;
4563+
4564+
*iter = &upper->list;
4565+
4566+
return upper->dev;
4567+
}
4568+
EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu);
4569+
45444570
/**
45454571
* netdev_all_upper_get_next_dev_rcu - Get the next dev from upper list
45464572
* @dev: device

0 commit comments

Comments
 (0)