diff options
author | Veaceslav Falico <vfalico@redhat.com> | 2013-09-25 03:20:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-09-26 16:02:04 -0400 |
commit | 2f268f129c2d1a05d297fe3ee34d393f862d2b22 (patch) | |
tree | 5373446c2933311d0aeeeaa85a6823cb621710d4 | |
parent | 7863c054d1b4fd35f76c13e2e918f7f483fe48f4 (diff) |
net: add adj_list to save only neighbours
Currently, we distinguish neighbours (first-level linked devices) from
non-neighbours by the neighbour bool in the netdev_adjacent. This could be
quite time-consuming in case we would like to traverse *only* through
neighbours - cause we'd have to traverse through all devices and check for
this flag, and in a (quite common) scenario where we have lots of vlans on
top of bridge, which is on top of a bond - the bonding would have to go
through all those vlans to get its upper neighbour linked devices.
This situation is really unpleasant, cause there are already a lot of cases
when a device with slaves needs to go through them in hot path.
To fix this, introduce a new upper/lower device lists structure -
adj_list, which contains only the neighbours. It works always in
pair with the all_adj_list structure (renamed from upper/lower_dev_list),
i.e. both of them contain the same links, only that all_adj_list contains
also non-neighbour device links. It's really a small change visible,
currently, only for __netdev_adjacent_dev_insert/remove(), and doesn't
change the main linked logic at all.
Also, add some comments a fix a name collision in
netdev_for_each_upper_dev_rcu() and rework the naming by the following
rules:
netdev_(all_)(upper|lower)_*
If "all_" is present, then we work with the whole list of upper/lower
devices, otherwise - only with direct neighbours. Uninline functions - to
get better stack traces.
CC: "David S. Miller" <davem@davemloft.net>
CC: Eric Dumazet <edumazet@google.com>
CC: Jiri Pirko <jiri@resnulli.us>
CC: Alexander Duyck <alexander.h.duyck@intel.com>
CC: Cong Wang <amwang@redhat.com>
Signed-off-by: Veaceslav Falico <vfalico@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/bonding/bond_alb.c | 2 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 10 | ||||
-rw-r--r-- | include/linux/netdevice.h | 28 | ||||
-rw-r--r-- | net/core/dev.c | 203 |
4 files changed, 129 insertions, 114 deletions
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index f428ef574372..8524e33e6754 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c | |||
@@ -1019,7 +1019,7 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) | |||
1019 | 1019 | ||
1020 | /* loop through vlans and send one packet for each */ | 1020 | /* loop through vlans and send one packet for each */ |
1021 | rcu_read_lock(); | 1021 | rcu_read_lock(); |
1022 | netdev_for_each_upper_dev_rcu(bond->dev, upper, iter) { | 1022 | netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) { |
1023 | if (upper->priv_flags & IFF_802_1Q_VLAN) | 1023 | if (upper->priv_flags & IFF_802_1Q_VLAN) |
1024 | alb_send_lp_vid(slave, mac_addr, | 1024 | alb_send_lp_vid(slave, mac_addr, |
1025 | vlan_dev_vlan_id(upper)); | 1025 | vlan_dev_vlan_id(upper)); |
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 55bbb8b8200c..91c4ab8913b1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -2267,7 +2267,7 @@ static bool bond_has_this_ip(struct bonding *bond, __be32 ip) | |||
2267 | return true; | 2267 | return true; |
2268 | 2268 | ||
2269 | rcu_read_lock(); | 2269 | rcu_read_lock(); |
2270 | netdev_for_each_upper_dev_rcu(bond->dev, upper, iter) { | 2270 | netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) { |
2271 | if (ip == bond_confirm_addr(upper, 0, ip)) { | 2271 | if (ip == bond_confirm_addr(upper, 0, ip)) { |
2272 | ret = true; | 2272 | ret = true; |
2273 | break; | 2273 | break; |
@@ -2342,10 +2342,12 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) | |||
2342 | * | 2342 | * |
2343 | * TODO: QinQ? | 2343 | * TODO: QinQ? |
2344 | */ | 2344 | */ |
2345 | netdev_for_each_upper_dev_rcu(bond->dev, vlan_upper, vlan_iter) { | 2345 | netdev_for_each_all_upper_dev_rcu(bond->dev, vlan_upper, |
2346 | vlan_iter) { | ||
2346 | if (!is_vlan_dev(vlan_upper)) | 2347 | if (!is_vlan_dev(vlan_upper)) |
2347 | continue; | 2348 | continue; |
2348 | netdev_for_each_upper_dev_rcu(vlan_upper, upper, iter) { | 2349 | netdev_for_each_all_upper_dev_rcu(vlan_upper, upper, |
2350 | iter) { | ||
2349 | if (upper == rt->dst.dev) { | 2351 | if (upper == rt->dst.dev) { |
2350 | vlan_id = vlan_dev_vlan_id(vlan_upper); | 2352 | vlan_id = vlan_dev_vlan_id(vlan_upper); |
2351 | rcu_read_unlock(); | 2353 | rcu_read_unlock(); |
@@ -2358,7 +2360,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) | |||
2358 | * our upper vlans, then just search for any dev that | 2360 | * our upper vlans, then just search for any dev that |
2359 | * matches, and in case it's a vlan - save the id | 2361 | * matches, and in case it's a vlan - save the id |
2360 | */ | 2362 | */ |
2361 | netdev_for_each_upper_dev_rcu(bond->dev, upper, iter) { | 2363 | netdev_for_each_all_upper_dev_rcu(bond->dev, upper, iter) { |
2362 | if (upper == rt->dst.dev) { | 2364 | if (upper == rt->dst.dev) { |
2363 | /* if it's a vlan - get its VID */ | 2365 | /* if it's a vlan - get its VID */ |
2364 | if (is_vlan_dev(upper)) | 2366 | if (is_vlan_dev(upper)) |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3de49aca4519..514045c704a8 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -1143,8 +1143,18 @@ struct net_device { | |||
1143 | struct list_head dev_list; | 1143 | struct list_head dev_list; |
1144 | struct list_head napi_list; | 1144 | struct list_head napi_list; |
1145 | struct list_head unreg_list; | 1145 | struct list_head unreg_list; |
1146 | struct list_head upper_dev_list; /* List of upper devices */ | 1146 | |
1147 | struct list_head lower_dev_list; | 1147 | /* directly linked devices, like slaves for bonding */ |
1148 | struct { | ||
1149 | struct list_head upper; | ||
1150 | struct list_head lower; | ||
1151 | } adj_list; | ||
1152 | |||
1153 | /* all linked devices, *including* neighbours */ | ||
1154 | struct { | ||
1155 | struct list_head upper; | ||
1156 | struct list_head lower; | ||
1157 | } all_adj_list; | ||
1148 | 1158 | ||
1149 | 1159 | ||
1150 | /* currently active device features */ | 1160 | /* currently active device features */ |
@@ -2813,15 +2823,15 @@ extern int bpf_jit_enable; | |||
2813 | extern bool netdev_has_upper_dev(struct net_device *dev, | 2823 | extern bool netdev_has_upper_dev(struct net_device *dev, |
2814 | struct net_device *upper_dev); | 2824 | struct net_device *upper_dev); |
2815 | extern bool netdev_has_any_upper_dev(struct net_device *dev); | 2825 | extern bool netdev_has_any_upper_dev(struct net_device *dev); |
2816 | extern struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, | 2826 | extern struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev, |
2817 | struct list_head **iter); | 2827 | struct list_head **iter); |
2818 | 2828 | ||
2819 | /* iterate through upper list, must be called under RCU read lock */ | 2829 | /* iterate through upper list, must be called under RCU read lock */ |
2820 | #define netdev_for_each_upper_dev_rcu(dev, upper, iter) \ | 2830 | #define netdev_for_each_all_upper_dev_rcu(dev, updev, iter) \ |
2821 | for (iter = &(dev)->upper_dev_list, \ | 2831 | for (iter = &(dev)->all_adj_list.upper, \ |
2822 | upper = netdev_upper_get_next_dev_rcu(dev, &(iter)); \ | 2832 | updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter)); \ |
2823 | upper; \ | 2833 | updev; \ |
2824 | upper = netdev_upper_get_next_dev_rcu(dev, &(iter))) | 2834 | updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter))) |
2825 | 2835 | ||
2826 | extern struct net_device *netdev_master_upper_dev_get(struct net_device *dev); | 2836 | extern struct net_device *netdev_master_upper_dev_get(struct net_device *dev); |
2827 | extern struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev); | 2837 | extern struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev); |
diff --git a/net/core/dev.c b/net/core/dev.c index 9be79377a0f3..9a395e03da74 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -4373,9 +4373,6 @@ struct netdev_adjacent { | |||
4373 | /* upper master flag, there can only be one master device per list */ | 4373 | /* upper master flag, there can only be one master device per list */ |
4374 | bool master; | 4374 | bool master; |
4375 | 4375 | ||
4376 | /* indicates that this dev is our first-level lower/upper device */ | ||
4377 | bool neighbour; | ||
4378 | |||
4379 | /* counter for the number of times this device was added to us */ | 4376 | /* counter for the number of times this device was added to us */ |
4380 | u16 ref_nr; | 4377 | u16 ref_nr; |
4381 | 4378 | ||
@@ -4385,29 +4382,17 @@ struct netdev_adjacent { | |||
4385 | 4382 | ||
4386 | static struct netdev_adjacent *__netdev_find_adj(struct net_device *dev, | 4383 | static struct netdev_adjacent *__netdev_find_adj(struct net_device *dev, |
4387 | struct net_device *adj_dev, | 4384 | struct net_device *adj_dev, |
4388 | struct list_head *dev_list) | 4385 | struct list_head *adj_list) |
4389 | { | 4386 | { |
4390 | struct netdev_adjacent *adj; | 4387 | struct netdev_adjacent *adj; |
4391 | 4388 | ||
4392 | list_for_each_entry(adj, dev_list, list) { | 4389 | list_for_each_entry(adj, adj_list, list) { |
4393 | if (adj->dev == adj_dev) | 4390 | if (adj->dev == adj_dev) |
4394 | return adj; | 4391 | return adj; |
4395 | } | 4392 | } |
4396 | return NULL; | 4393 | return NULL; |
4397 | } | 4394 | } |
4398 | 4395 | ||
4399 | static inline struct netdev_adjacent *__netdev_find_upper(struct net_device *dev, | ||
4400 | struct net_device *udev) | ||
4401 | { | ||
4402 | return __netdev_find_adj(dev, udev, &dev->upper_dev_list); | ||
4403 | } | ||
4404 | |||
4405 | static inline struct netdev_adjacent *__netdev_find_lower(struct net_device *dev, | ||
4406 | struct net_device *ldev) | ||
4407 | { | ||
4408 | return __netdev_find_adj(dev, ldev, &dev->lower_dev_list); | ||
4409 | } | ||
4410 | |||
4411 | /** | 4396 | /** |
4412 | * netdev_has_upper_dev - Check if device is linked to an upper device | 4397 | * netdev_has_upper_dev - Check if device is linked to an upper device |
4413 | * @dev: device | 4398 | * @dev: device |
@@ -4422,7 +4407,7 @@ bool netdev_has_upper_dev(struct net_device *dev, | |||
4422 | { | 4407 | { |
4423 | ASSERT_RTNL(); | 4408 | ASSERT_RTNL(); |
4424 | 4409 | ||
4425 | return __netdev_find_upper(dev, upper_dev); | 4410 | return __netdev_find_adj(dev, upper_dev, &dev->all_adj_list.upper); |
4426 | } | 4411 | } |
4427 | EXPORT_SYMBOL(netdev_has_upper_dev); | 4412 | EXPORT_SYMBOL(netdev_has_upper_dev); |
4428 | 4413 | ||
@@ -4437,7 +4422,7 @@ bool netdev_has_any_upper_dev(struct net_device *dev) | |||
4437 | { | 4422 | { |
4438 | ASSERT_RTNL(); | 4423 | ASSERT_RTNL(); |
4439 | 4424 | ||
4440 | return !list_empty(&dev->upper_dev_list); | 4425 | return !list_empty(&dev->all_adj_list.upper); |
4441 | } | 4426 | } |
4442 | EXPORT_SYMBOL(netdev_has_any_upper_dev); | 4427 | EXPORT_SYMBOL(netdev_has_any_upper_dev); |
4443 | 4428 | ||
@@ -4454,10 +4439,10 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev) | |||
4454 | 4439 | ||
4455 | ASSERT_RTNL(); | 4440 | ASSERT_RTNL(); |
4456 | 4441 | ||
4457 | if (list_empty(&dev->upper_dev_list)) | 4442 | if (list_empty(&dev->adj_list.upper)) |
4458 | return NULL; | 4443 | return NULL; |
4459 | 4444 | ||
4460 | upper = list_first_entry(&dev->upper_dev_list, | 4445 | upper = list_first_entry(&dev->adj_list.upper, |
4461 | struct netdev_adjacent, list); | 4446 | struct netdev_adjacent, list); |
4462 | if (likely(upper->master)) | 4447 | if (likely(upper->master)) |
4463 | return upper->dev; | 4448 | return upper->dev; |
@@ -4465,15 +4450,15 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev) | |||
4465 | } | 4450 | } |
4466 | EXPORT_SYMBOL(netdev_master_upper_dev_get); | 4451 | EXPORT_SYMBOL(netdev_master_upper_dev_get); |
4467 | 4452 | ||
4468 | /* netdev_upper_get_next_dev_rcu - Get the next dev from upper list | 4453 | /* netdev_all_upper_get_next_dev_rcu - Get the next dev from upper list |
4469 | * @dev: device | 4454 | * @dev: device |
4470 | * @iter: list_head ** of the current position | 4455 | * @iter: list_head ** of the current position |
4471 | * | 4456 | * |
4472 | * Gets the next device from the dev's upper list, starting from iter | 4457 | * Gets the next device from the dev's upper list, starting from iter |
4473 | * position. The caller must hold RCU read lock. | 4458 | * position. The caller must hold RCU read lock. |
4474 | */ | 4459 | */ |
4475 | struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, | 4460 | struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev, |
4476 | struct list_head **iter) | 4461 | struct list_head **iter) |
4477 | { | 4462 | { |
4478 | struct netdev_adjacent *upper; | 4463 | struct netdev_adjacent *upper; |
4479 | 4464 | ||
@@ -4481,14 +4466,14 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, | |||
4481 | 4466 | ||
4482 | upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); | 4467 | upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); |
4483 | 4468 | ||
4484 | if (&upper->list == &dev->upper_dev_list) | 4469 | if (&upper->list == &dev->all_adj_list.upper) |
4485 | return NULL; | 4470 | return NULL; |
4486 | 4471 | ||
4487 | *iter = &upper->list; | 4472 | *iter = &upper->list; |
4488 | 4473 | ||
4489 | return upper->dev; | 4474 | return upper->dev; |
4490 | } | 4475 | } |
4491 | EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu); | 4476 | EXPORT_SYMBOL(netdev_all_upper_get_next_dev_rcu); |
4492 | 4477 | ||
4493 | /** | 4478 | /** |
4494 | * netdev_master_upper_dev_get_rcu - Get master upper device | 4479 | * netdev_master_upper_dev_get_rcu - Get master upper device |
@@ -4501,7 +4486,7 @@ struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev) | |||
4501 | { | 4486 | { |
4502 | struct netdev_adjacent *upper; | 4487 | struct netdev_adjacent *upper; |
4503 | 4488 | ||
4504 | upper = list_first_or_null_rcu(&dev->upper_dev_list, | 4489 | upper = list_first_or_null_rcu(&dev->adj_list.upper, |
4505 | struct netdev_adjacent, list); | 4490 | struct netdev_adjacent, list); |
4506 | if (upper && likely(upper->master)) | 4491 | if (upper && likely(upper->master)) |
4507 | return upper->dev; | 4492 | return upper->dev; |
@@ -4512,14 +4497,13 @@ EXPORT_SYMBOL(netdev_master_upper_dev_get_rcu); | |||
4512 | static int __netdev_adjacent_dev_insert(struct net_device *dev, | 4497 | static int __netdev_adjacent_dev_insert(struct net_device *dev, |
4513 | struct net_device *adj_dev, | 4498 | struct net_device *adj_dev, |
4514 | struct list_head *dev_list, | 4499 | struct list_head *dev_list, |
4515 | bool neighbour, bool master) | 4500 | bool master) |
4516 | { | 4501 | { |
4517 | struct netdev_adjacent *adj; | 4502 | struct netdev_adjacent *adj; |
4518 | 4503 | ||
4519 | adj = __netdev_find_adj(dev, adj_dev, dev_list); | 4504 | adj = __netdev_find_adj(dev, adj_dev, dev_list); |
4520 | 4505 | ||
4521 | if (adj) { | 4506 | if (adj) { |
4522 | BUG_ON(neighbour); | ||
4523 | adj->ref_nr++; | 4507 | adj->ref_nr++; |
4524 | return 0; | 4508 | return 0; |
4525 | } | 4509 | } |
@@ -4530,13 +4514,11 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, | |||
4530 | 4514 | ||
4531 | adj->dev = adj_dev; | 4515 | adj->dev = adj_dev; |
4532 | adj->master = master; | 4516 | adj->master = master; |
4533 | adj->neighbour = neighbour; | ||
4534 | adj->ref_nr = 1; | 4517 | adj->ref_nr = 1; |
4535 | |||
4536 | dev_hold(adj_dev); | 4518 | dev_hold(adj_dev); |
4537 | pr_debug("dev_hold for %s, because of %s link added from %s to %s\n", | 4519 | |
4538 | adj_dev->name, dev_list == &dev->upper_dev_list ? | 4520 | pr_debug("dev_hold for %s, because of link added from %s to %s\n", |
4539 | "upper" : "lower", dev->name, adj_dev->name); | 4521 | adj_dev->name, dev->name, adj_dev->name); |
4540 | 4522 | ||
4541 | /* Ensure that master link is always the first item in list. */ | 4523 | /* Ensure that master link is always the first item in list. */ |
4542 | if (master) | 4524 | if (master) |
@@ -4547,22 +4529,6 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, | |||
4547 | return 0; | 4529 | return 0; |
4548 | } | 4530 | } |
4549 | 4531 | ||
4550 | static inline int __netdev_upper_dev_insert(struct net_device *dev, | ||
4551 | struct net_device *udev, | ||
4552 | bool master, bool neighbour) | ||
4553 | { | ||
4554 | return __netdev_adjacent_dev_insert(dev, udev, &dev->upper_dev_list, | ||
4555 | neighbour, master); | ||
4556 | } | ||
4557 | |||
4558 | static inline int __netdev_lower_dev_insert(struct net_device *dev, | ||
4559 | struct net_device *ldev, | ||
4560 | bool neighbour) | ||
4561 | { | ||
4562 | return __netdev_adjacent_dev_insert(dev, ldev, &dev->lower_dev_list, | ||
4563 | neighbour, false); | ||
4564 | } | ||
4565 | |||
4566 | void __netdev_adjacent_dev_remove(struct net_device *dev, | 4532 | void __netdev_adjacent_dev_remove(struct net_device *dev, |
4567 | struct net_device *adj_dev, | 4533 | struct net_device *adj_dev, |
4568 | struct list_head *dev_list) | 4534 | struct list_head *dev_list) |
@@ -4571,73 +4537,102 @@ void __netdev_adjacent_dev_remove(struct net_device *dev, | |||
4571 | 4537 | ||
4572 | adj = __netdev_find_adj(dev, adj_dev, dev_list); | 4538 | adj = __netdev_find_adj(dev, adj_dev, dev_list); |
4573 | 4539 | ||
4574 | if (!adj) | 4540 | if (!adj) { |
4541 | pr_err("tried to remove device %s from %s\n", | ||
4542 | dev->name, adj_dev->name); | ||
4575 | BUG(); | 4543 | BUG(); |
4544 | } | ||
4576 | 4545 | ||
4577 | if (adj->ref_nr > 1) { | 4546 | if (adj->ref_nr > 1) { |
4547 | pr_debug("%s to %s ref_nr-- = %d\n", dev->name, adj_dev->name, | ||
4548 | adj->ref_nr-1); | ||
4578 | adj->ref_nr--; | 4549 | adj->ref_nr--; |
4579 | return; | 4550 | return; |
4580 | } | 4551 | } |
4581 | 4552 | ||
4582 | list_del_rcu(&adj->list); | 4553 | list_del_rcu(&adj->list); |
4583 | pr_debug("dev_put for %s, because of %s link removed from %s to %s\n", | 4554 | pr_debug("dev_put for %s, because link removed from %s to %s\n", |
4584 | adj_dev->name, dev_list == &dev->upper_dev_list ? | 4555 | adj_dev->name, dev->name, adj_dev->name); |
4585 | "upper" : "lower", dev->name, adj_dev->name); | ||
4586 | dev_put(adj_dev); | 4556 | dev_put(adj_dev); |
4587 | kfree_rcu(adj, rcu); | 4557 | kfree_rcu(adj, rcu); |
4588 | } | 4558 | } |
4589 | 4559 | ||
4590 | static inline void __netdev_upper_dev_remove(struct net_device *dev, | 4560 | int __netdev_adjacent_dev_link_lists(struct net_device *dev, |
4591 | struct net_device *udev) | 4561 | struct net_device *upper_dev, |
4592 | { | 4562 | struct list_head *up_list, |
4593 | return __netdev_adjacent_dev_remove(dev, udev, &dev->upper_dev_list); | 4563 | struct list_head *down_list, |
4594 | } | 4564 | bool master) |
4595 | |||
4596 | static inline void __netdev_lower_dev_remove(struct net_device *dev, | ||
4597 | struct net_device *ldev) | ||
4598 | { | ||
4599 | return __netdev_adjacent_dev_remove(dev, ldev, &dev->lower_dev_list); | ||
4600 | } | ||
4601 | |||
4602 | int __netdev_adjacent_dev_insert_link(struct net_device *dev, | ||
4603 | struct net_device *upper_dev, | ||
4604 | bool master, bool neighbour) | ||
4605 | { | 4565 | { |
4606 | int ret; | 4566 | int ret; |
4607 | 4567 | ||
4608 | ret = __netdev_upper_dev_insert(dev, upper_dev, master, neighbour); | 4568 | ret = __netdev_adjacent_dev_insert(dev, upper_dev, up_list, master); |
4609 | if (ret) | 4569 | if (ret) |
4610 | return ret; | 4570 | return ret; |
4611 | 4571 | ||
4612 | ret = __netdev_lower_dev_insert(upper_dev, dev, neighbour); | 4572 | ret = __netdev_adjacent_dev_insert(upper_dev, dev, down_list, false); |
4613 | if (ret) { | 4573 | if (ret) { |
4614 | __netdev_upper_dev_remove(dev, upper_dev); | 4574 | __netdev_adjacent_dev_remove(dev, upper_dev, up_list); |
4615 | return ret; | 4575 | return ret; |
4616 | } | 4576 | } |
4617 | 4577 | ||
4618 | return 0; | 4578 | return 0; |
4619 | } | 4579 | } |
4620 | 4580 | ||
4621 | static inline int __netdev_adjacent_dev_link(struct net_device *dev, | 4581 | int __netdev_adjacent_dev_link(struct net_device *dev, |
4622 | struct net_device *udev) | 4582 | struct net_device *upper_dev) |
4623 | { | 4583 | { |
4624 | return __netdev_adjacent_dev_insert_link(dev, udev, false, false); | 4584 | return __netdev_adjacent_dev_link_lists(dev, upper_dev, |
4585 | &dev->all_adj_list.upper, | ||
4586 | &upper_dev->all_adj_list.lower, | ||
4587 | false); | ||
4625 | } | 4588 | } |
4626 | 4589 | ||
4627 | static inline int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, | 4590 | void __netdev_adjacent_dev_unlink_lists(struct net_device *dev, |
4628 | struct net_device *udev, | 4591 | struct net_device *upper_dev, |
4629 | bool master) | 4592 | struct list_head *up_list, |
4593 | struct list_head *down_list) | ||
4630 | { | 4594 | { |
4631 | return __netdev_adjacent_dev_insert_link(dev, udev, master, true); | 4595 | __netdev_adjacent_dev_remove(dev, upper_dev, up_list); |
4596 | __netdev_adjacent_dev_remove(upper_dev, dev, down_list); | ||
4632 | } | 4597 | } |
4633 | 4598 | ||
4634 | void __netdev_adjacent_dev_unlink(struct net_device *dev, | 4599 | void __netdev_adjacent_dev_unlink(struct net_device *dev, |
4635 | struct net_device *upper_dev) | 4600 | struct net_device *upper_dev) |
4636 | { | 4601 | { |
4637 | __netdev_upper_dev_remove(dev, upper_dev); | 4602 | __netdev_adjacent_dev_unlink_lists(dev, upper_dev, |
4638 | __netdev_lower_dev_remove(upper_dev, dev); | 4603 | &dev->all_adj_list.upper, |
4604 | &upper_dev->all_adj_list.lower); | ||
4605 | } | ||
4606 | |||
4607 | int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, | ||
4608 | struct net_device *upper_dev, | ||
4609 | bool master) | ||
4610 | { | ||
4611 | int ret = __netdev_adjacent_dev_link(dev, upper_dev); | ||
4612 | |||
4613 | if (ret) | ||
4614 | return ret; | ||
4615 | |||
4616 | ret = __netdev_adjacent_dev_link_lists(dev, upper_dev, | ||
4617 | &dev->adj_list.upper, | ||
4618 | &upper_dev->adj_list.lower, | ||
4619 | master); | ||
4620 | if (ret) { | ||
4621 | __netdev_adjacent_dev_unlink(dev, upper_dev); | ||
4622 | return ret; | ||
4623 | } | ||
4624 | |||
4625 | return 0; | ||
4639 | } | 4626 | } |
4640 | 4627 | ||
4628 | void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev, | ||
4629 | struct net_device *upper_dev) | ||
4630 | { | ||
4631 | __netdev_adjacent_dev_unlink(dev, upper_dev); | ||
4632 | __netdev_adjacent_dev_unlink_lists(dev, upper_dev, | ||
4633 | &dev->adj_list.upper, | ||
4634 | &upper_dev->adj_list.lower); | ||
4635 | } | ||
4641 | 4636 | ||
4642 | static int __netdev_upper_dev_link(struct net_device *dev, | 4637 | static int __netdev_upper_dev_link(struct net_device *dev, |
4643 | struct net_device *upper_dev, bool master) | 4638 | struct net_device *upper_dev, bool master) |
@@ -4651,10 +4646,10 @@ static int __netdev_upper_dev_link(struct net_device *dev, | |||
4651 | return -EBUSY; | 4646 | return -EBUSY; |
4652 | 4647 | ||
4653 | /* To prevent loops, check if dev is not upper device to upper_dev. */ | 4648 | /* To prevent loops, check if dev is not upper device to upper_dev. */ |
4654 | if (__netdev_find_upper(upper_dev, dev)) | 4649 | if (__netdev_find_adj(upper_dev, dev, &upper_dev->all_adj_list.upper)) |
4655 | return -EBUSY; | 4650 | return -EBUSY; |
4656 | 4651 | ||
4657 | if (__netdev_find_upper(dev, upper_dev)) | 4652 | if (__netdev_find_adj(dev, upper_dev, &dev->all_adj_list.upper)) |
4658 | return -EEXIST; | 4653 | return -EEXIST; |
4659 | 4654 | ||
4660 | if (master && netdev_master_upper_dev_get(dev)) | 4655 | if (master && netdev_master_upper_dev_get(dev)) |
@@ -4665,12 +4660,14 @@ static int __netdev_upper_dev_link(struct net_device *dev, | |||
4665 | return ret; | 4660 | return ret; |
4666 | 4661 | ||
4667 | /* Now that we linked these devs, make all the upper_dev's | 4662 | /* Now that we linked these devs, make all the upper_dev's |
4668 | * upper_dev_list visible to every dev's lower_dev_list and vice | 4663 | * all_adj_list.upper visible to every dev's all_adj_list.lower an |
4669 | * versa, and don't forget the devices itself. All of these | 4664 | * versa, and don't forget the devices itself. All of these |
4670 | * links are non-neighbours. | 4665 | * links are non-neighbours. |
4671 | */ | 4666 | */ |
4672 | list_for_each_entry(i, &dev->lower_dev_list, list) { | 4667 | list_for_each_entry(i, &dev->all_adj_list.lower, list) { |
4673 | list_for_each_entry(j, &upper_dev->upper_dev_list, list) { | 4668 | list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { |
4669 | pr_debug("Interlinking %s with %s, non-neighbour\n", | ||
4670 | i->dev->name, j->dev->name); | ||
4674 | ret = __netdev_adjacent_dev_link(i->dev, j->dev); | 4671 | ret = __netdev_adjacent_dev_link(i->dev, j->dev); |
4675 | if (ret) | 4672 | if (ret) |
4676 | goto rollback_mesh; | 4673 | goto rollback_mesh; |
@@ -4678,14 +4675,18 @@ static int __netdev_upper_dev_link(struct net_device *dev, | |||
4678 | } | 4675 | } |
4679 | 4676 | ||
4680 | /* add dev to every upper_dev's upper device */ | 4677 | /* add dev to every upper_dev's upper device */ |
4681 | list_for_each_entry(i, &upper_dev->upper_dev_list, list) { | 4678 | list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { |
4679 | pr_debug("linking %s's upper device %s with %s\n", | ||
4680 | upper_dev->name, i->dev->name, dev->name); | ||
4682 | ret = __netdev_adjacent_dev_link(dev, i->dev); | 4681 | ret = __netdev_adjacent_dev_link(dev, i->dev); |
4683 | if (ret) | 4682 | if (ret) |
4684 | goto rollback_upper_mesh; | 4683 | goto rollback_upper_mesh; |
4685 | } | 4684 | } |
4686 | 4685 | ||
4687 | /* add upper_dev to every dev's lower device */ | 4686 | /* add upper_dev to every dev's lower device */ |
4688 | list_for_each_entry(i, &dev->lower_dev_list, list) { | 4687 | list_for_each_entry(i, &dev->all_adj_list.lower, list) { |
4688 | pr_debug("linking %s's lower device %s with %s\n", dev->name, | ||
4689 | i->dev->name, upper_dev->name); | ||
4689 | ret = __netdev_adjacent_dev_link(i->dev, upper_dev); | 4690 | ret = __netdev_adjacent_dev_link(i->dev, upper_dev); |
4690 | if (ret) | 4691 | if (ret) |
4691 | goto rollback_lower_mesh; | 4692 | goto rollback_lower_mesh; |
@@ -4696,7 +4697,7 @@ static int __netdev_upper_dev_link(struct net_device *dev, | |||
4696 | 4697 | ||
4697 | rollback_lower_mesh: | 4698 | rollback_lower_mesh: |
4698 | to_i = i; | 4699 | to_i = i; |
4699 | list_for_each_entry(i, &dev->lower_dev_list, list) { | 4700 | list_for_each_entry(i, &dev->all_adj_list.lower, list) { |
4700 | if (i == to_i) | 4701 | if (i == to_i) |
4701 | break; | 4702 | break; |
4702 | __netdev_adjacent_dev_unlink(i->dev, upper_dev); | 4703 | __netdev_adjacent_dev_unlink(i->dev, upper_dev); |
@@ -4706,7 +4707,7 @@ rollback_lower_mesh: | |||
4706 | 4707 | ||
4707 | rollback_upper_mesh: | 4708 | rollback_upper_mesh: |
4708 | to_i = i; | 4709 | to_i = i; |
4709 | list_for_each_entry(i, &upper_dev->upper_dev_list, list) { | 4710 | list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { |
4710 | if (i == to_i) | 4711 | if (i == to_i) |
4711 | break; | 4712 | break; |
4712 | __netdev_adjacent_dev_unlink(dev, i->dev); | 4713 | __netdev_adjacent_dev_unlink(dev, i->dev); |
@@ -4717,8 +4718,8 @@ rollback_upper_mesh: | |||
4717 | rollback_mesh: | 4718 | rollback_mesh: |
4718 | to_i = i; | 4719 | to_i = i; |
4719 | to_j = j; | 4720 | to_j = j; |
4720 | list_for_each_entry(i, &dev->lower_dev_list, list) { | 4721 | list_for_each_entry(i, &dev->all_adj_list.lower, list) { |
4721 | list_for_each_entry(j, &upper_dev->upper_dev_list, list) { | 4722 | list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { |
4722 | if (i == to_i && j == to_j) | 4723 | if (i == to_i && j == to_j) |
4723 | break; | 4724 | break; |
4724 | __netdev_adjacent_dev_unlink(i->dev, j->dev); | 4725 | __netdev_adjacent_dev_unlink(i->dev, j->dev); |
@@ -4727,7 +4728,7 @@ rollback_mesh: | |||
4727 | break; | 4728 | break; |
4728 | } | 4729 | } |
4729 | 4730 | ||
4730 | __netdev_adjacent_dev_unlink(dev, upper_dev); | 4731 | __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); |
4731 | 4732 | ||
4732 | return ret; | 4733 | return ret; |
4733 | } | 4734 | } |
@@ -4781,23 +4782,23 @@ void netdev_upper_dev_unlink(struct net_device *dev, | |||
4781 | struct netdev_adjacent *i, *j; | 4782 | struct netdev_adjacent *i, *j; |
4782 | ASSERT_RTNL(); | 4783 | ASSERT_RTNL(); |
4783 | 4784 | ||
4784 | __netdev_adjacent_dev_unlink(dev, upper_dev); | 4785 | __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); |
4785 | 4786 | ||
4786 | /* Here is the tricky part. We must remove all dev's lower | 4787 | /* Here is the tricky part. We must remove all dev's lower |
4787 | * devices from all upper_dev's upper devices and vice | 4788 | * devices from all upper_dev's upper devices and vice |
4788 | * versa, to maintain the graph relationship. | 4789 | * versa, to maintain the graph relationship. |
4789 | */ | 4790 | */ |
4790 | list_for_each_entry(i, &dev->lower_dev_list, list) | 4791 | list_for_each_entry(i, &dev->all_adj_list.lower, list) |
4791 | list_for_each_entry(j, &upper_dev->upper_dev_list, list) | 4792 | list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) |
4792 | __netdev_adjacent_dev_unlink(i->dev, j->dev); | 4793 | __netdev_adjacent_dev_unlink(i->dev, j->dev); |
4793 | 4794 | ||
4794 | /* remove also the devices itself from lower/upper device | 4795 | /* remove also the devices itself from lower/upper device |
4795 | * list | 4796 | * list |
4796 | */ | 4797 | */ |
4797 | list_for_each_entry(i, &dev->lower_dev_list, list) | 4798 | list_for_each_entry(i, &dev->all_adj_list.lower, list) |
4798 | __netdev_adjacent_dev_unlink(i->dev, upper_dev); | 4799 | __netdev_adjacent_dev_unlink(i->dev, upper_dev); |
4799 | 4800 | ||
4800 | list_for_each_entry(i, &upper_dev->upper_dev_list, list) | 4801 | list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) |
4801 | __netdev_adjacent_dev_unlink(dev, i->dev); | 4802 | __netdev_adjacent_dev_unlink(dev, i->dev); |
4802 | 4803 | ||
4803 | call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); | 4804 | call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); |
@@ -6059,8 +6060,10 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, | |||
6059 | INIT_LIST_HEAD(&dev->napi_list); | 6060 | INIT_LIST_HEAD(&dev->napi_list); |
6060 | INIT_LIST_HEAD(&dev->unreg_list); | 6061 | INIT_LIST_HEAD(&dev->unreg_list); |
6061 | INIT_LIST_HEAD(&dev->link_watch_list); | 6062 | INIT_LIST_HEAD(&dev->link_watch_list); |
6062 | INIT_LIST_HEAD(&dev->upper_dev_list); | 6063 | INIT_LIST_HEAD(&dev->adj_list.upper); |
6063 | INIT_LIST_HEAD(&dev->lower_dev_list); | 6064 | INIT_LIST_HEAD(&dev->adj_list.lower); |
6065 | INIT_LIST_HEAD(&dev->all_adj_list.upper); | ||
6066 | INIT_LIST_HEAD(&dev->all_adj_list.lower); | ||
6064 | dev->priv_flags = IFF_XMIT_DST_RELEASE; | 6067 | dev->priv_flags = IFF_XMIT_DST_RELEASE; |
6065 | setup(dev); | 6068 | setup(dev); |
6066 | 6069 | ||