diff options
-rw-r--r-- | include/linux/netdevice.h | 10 | ||||
-rw-r--r-- | net/core/dev.c | 230 |
2 files changed, 219 insertions, 21 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c93df7cf187b..6c6490e15cd4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -4324,6 +4324,16 @@ int netdev_master_upper_dev_link(struct net_device *dev, | |||
4324 | struct netlink_ext_ack *extack); | 4324 | struct netlink_ext_ack *extack); |
4325 | void netdev_upper_dev_unlink(struct net_device *dev, | 4325 | void netdev_upper_dev_unlink(struct net_device *dev, |
4326 | struct net_device *upper_dev); | 4326 | struct net_device *upper_dev); |
4327 | int netdev_adjacent_change_prepare(struct net_device *old_dev, | ||
4328 | struct net_device *new_dev, | ||
4329 | struct net_device *dev, | ||
4330 | struct netlink_ext_ack *extack); | ||
4331 | void netdev_adjacent_change_commit(struct net_device *old_dev, | ||
4332 | struct net_device *new_dev, | ||
4333 | struct net_device *dev); | ||
4334 | void netdev_adjacent_change_abort(struct net_device *old_dev, | ||
4335 | struct net_device *new_dev, | ||
4336 | struct net_device *dev); | ||
4327 | void netdev_adjacent_rename_links(struct net_device *dev, char *oldname); | 4337 | void netdev_adjacent_rename_links(struct net_device *dev, char *oldname); |
4328 | void *netdev_lower_dev_get_private(struct net_device *dev, | 4338 | void *netdev_lower_dev_get_private(struct net_device *dev, |
4329 | struct net_device *lower_dev); | 4339 | struct net_device *lower_dev); |
diff --git a/net/core/dev.c b/net/core/dev.c index 5722a81b6edd..092c094038b6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -6408,6 +6408,9 @@ struct netdev_adjacent { | |||
6408 | /* upper master flag, there can only be one master device per list */ | 6408 | /* upper master flag, there can only be one master device per list */ |
6409 | bool master; | 6409 | bool master; |
6410 | 6410 | ||
6411 | /* lookup ignore flag */ | ||
6412 | bool ignore; | ||
6413 | |||
6411 | /* counter for the number of times this device was added to us */ | 6414 | /* counter for the number of times this device was added to us */ |
6412 | u16 ref_nr; | 6415 | u16 ref_nr; |
6413 | 6416 | ||
@@ -6430,7 +6433,7 @@ static struct netdev_adjacent *__netdev_find_adj(struct net_device *adj_dev, | |||
6430 | return NULL; | 6433 | return NULL; |
6431 | } | 6434 | } |
6432 | 6435 | ||
6433 | static int __netdev_has_upper_dev(struct net_device *upper_dev, void *data) | 6436 | static int ____netdev_has_upper_dev(struct net_device *upper_dev, void *data) |
6434 | { | 6437 | { |
6435 | struct net_device *dev = data; | 6438 | struct net_device *dev = data; |
6436 | 6439 | ||
@@ -6451,7 +6454,7 @@ bool netdev_has_upper_dev(struct net_device *dev, | |||
6451 | { | 6454 | { |
6452 | ASSERT_RTNL(); | 6455 | ASSERT_RTNL(); |
6453 | 6456 | ||
6454 | return netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, | 6457 | return netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev, |
6455 | upper_dev); | 6458 | upper_dev); |
6456 | } | 6459 | } |
6457 | EXPORT_SYMBOL(netdev_has_upper_dev); | 6460 | EXPORT_SYMBOL(netdev_has_upper_dev); |
@@ -6469,7 +6472,7 @@ EXPORT_SYMBOL(netdev_has_upper_dev); | |||
6469 | bool netdev_has_upper_dev_all_rcu(struct net_device *dev, | 6472 | bool netdev_has_upper_dev_all_rcu(struct net_device *dev, |
6470 | struct net_device *upper_dev) | 6473 | struct net_device *upper_dev) |
6471 | { | 6474 | { |
6472 | return !!netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, | 6475 | return !!netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev, |
6473 | upper_dev); | 6476 | upper_dev); |
6474 | } | 6477 | } |
6475 | EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu); | 6478 | EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu); |
@@ -6513,6 +6516,22 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev) | |||
6513 | } | 6516 | } |
6514 | EXPORT_SYMBOL(netdev_master_upper_dev_get); | 6517 | EXPORT_SYMBOL(netdev_master_upper_dev_get); |
6515 | 6518 | ||
6519 | static struct net_device *__netdev_master_upper_dev_get(struct net_device *dev) | ||
6520 | { | ||
6521 | struct netdev_adjacent *upper; | ||
6522 | |||
6523 | ASSERT_RTNL(); | ||
6524 | |||
6525 | if (list_empty(&dev->adj_list.upper)) | ||
6526 | return NULL; | ||
6527 | |||
6528 | upper = list_first_entry(&dev->adj_list.upper, | ||
6529 | struct netdev_adjacent, list); | ||
6530 | if (likely(upper->master) && !upper->ignore) | ||
6531 | return upper->dev; | ||
6532 | return NULL; | ||
6533 | } | ||
6534 | |||
6516 | /** | 6535 | /** |
6517 | * netdev_has_any_lower_dev - Check if device is linked to some device | 6536 | * netdev_has_any_lower_dev - Check if device is linked to some device |
6518 | * @dev: device | 6537 | * @dev: device |
@@ -6563,8 +6582,9 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, | |||
6563 | } | 6582 | } |
6564 | EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu); | 6583 | EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu); |
6565 | 6584 | ||
6566 | static struct net_device *netdev_next_upper_dev(struct net_device *dev, | 6585 | static struct net_device *__netdev_next_upper_dev(struct net_device *dev, |
6567 | struct list_head **iter) | 6586 | struct list_head **iter, |
6587 | bool *ignore) | ||
6568 | { | 6588 | { |
6569 | struct netdev_adjacent *upper; | 6589 | struct netdev_adjacent *upper; |
6570 | 6590 | ||
@@ -6574,6 +6594,7 @@ static struct net_device *netdev_next_upper_dev(struct net_device *dev, | |||
6574 | return NULL; | 6594 | return NULL; |
6575 | 6595 | ||
6576 | *iter = &upper->list; | 6596 | *iter = &upper->list; |
6597 | *ignore = upper->ignore; | ||
6577 | 6598 | ||
6578 | return upper->dev; | 6599 | return upper->dev; |
6579 | } | 6600 | } |
@@ -6595,14 +6616,15 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev, | |||
6595 | return upper->dev; | 6616 | return upper->dev; |
6596 | } | 6617 | } |
6597 | 6618 | ||
6598 | static int netdev_walk_all_upper_dev(struct net_device *dev, | 6619 | static int __netdev_walk_all_upper_dev(struct net_device *dev, |
6599 | int (*fn)(struct net_device *dev, | 6620 | int (*fn)(struct net_device *dev, |
6600 | void *data), | 6621 | void *data), |
6601 | void *data) | 6622 | void *data) |
6602 | { | 6623 | { |
6603 | struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; | 6624 | struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; |
6604 | struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; | 6625 | struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; |
6605 | int ret, cur = 0; | 6626 | int ret, cur = 0; |
6627 | bool ignore; | ||
6606 | 6628 | ||
6607 | now = dev; | 6629 | now = dev; |
6608 | iter = &dev->adj_list.upper; | 6630 | iter = &dev->adj_list.upper; |
@@ -6616,9 +6638,11 @@ static int netdev_walk_all_upper_dev(struct net_device *dev, | |||
6616 | 6638 | ||
6617 | next = NULL; | 6639 | next = NULL; |
6618 | while (1) { | 6640 | while (1) { |
6619 | udev = netdev_next_upper_dev(now, &iter); | 6641 | udev = __netdev_next_upper_dev(now, &iter, &ignore); |
6620 | if (!udev) | 6642 | if (!udev) |
6621 | break; | 6643 | break; |
6644 | if (ignore) | ||
6645 | continue; | ||
6622 | 6646 | ||
6623 | next = udev; | 6647 | next = udev; |
6624 | niter = &udev->adj_list.upper; | 6648 | niter = &udev->adj_list.upper; |
@@ -6688,6 +6712,15 @@ int netdev_walk_all_upper_dev_rcu(struct net_device *dev, | |||
6688 | } | 6712 | } |
6689 | EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu); | 6713 | EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu); |
6690 | 6714 | ||
6715 | static bool __netdev_has_upper_dev(struct net_device *dev, | ||
6716 | struct net_device *upper_dev) | ||
6717 | { | ||
6718 | ASSERT_RTNL(); | ||
6719 | |||
6720 | return __netdev_walk_all_upper_dev(dev, ____netdev_has_upper_dev, | ||
6721 | upper_dev); | ||
6722 | } | ||
6723 | |||
6691 | /** | 6724 | /** |
6692 | * netdev_lower_get_next_private - Get the next ->private from the | 6725 | * netdev_lower_get_next_private - Get the next ->private from the |
6693 | * lower neighbour list | 6726 | * lower neighbour list |
@@ -6784,6 +6817,23 @@ static struct net_device *netdev_next_lower_dev(struct net_device *dev, | |||
6784 | return lower->dev; | 6817 | return lower->dev; |
6785 | } | 6818 | } |
6786 | 6819 | ||
6820 | static struct net_device *__netdev_next_lower_dev(struct net_device *dev, | ||
6821 | struct list_head **iter, | ||
6822 | bool *ignore) | ||
6823 | { | ||
6824 | struct netdev_adjacent *lower; | ||
6825 | |||
6826 | lower = list_entry((*iter)->next, struct netdev_adjacent, list); | ||
6827 | |||
6828 | if (&lower->list == &dev->adj_list.lower) | ||
6829 | return NULL; | ||
6830 | |||
6831 | *iter = &lower->list; | ||
6832 | *ignore = lower->ignore; | ||
6833 | |||
6834 | return lower->dev; | ||
6835 | } | ||
6836 | |||
6787 | int netdev_walk_all_lower_dev(struct net_device *dev, | 6837 | int netdev_walk_all_lower_dev(struct net_device *dev, |
6788 | int (*fn)(struct net_device *dev, | 6838 | int (*fn)(struct net_device *dev, |
6789 | void *data), | 6839 | void *data), |
@@ -6831,6 +6881,55 @@ int netdev_walk_all_lower_dev(struct net_device *dev, | |||
6831 | } | 6881 | } |
6832 | EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev); | 6882 | EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev); |
6833 | 6883 | ||
6884 | static int __netdev_walk_all_lower_dev(struct net_device *dev, | ||
6885 | int (*fn)(struct net_device *dev, | ||
6886 | void *data), | ||
6887 | void *data) | ||
6888 | { | ||
6889 | struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; | ||
6890 | struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; | ||
6891 | int ret, cur = 0; | ||
6892 | bool ignore; | ||
6893 | |||
6894 | now = dev; | ||
6895 | iter = &dev->adj_list.lower; | ||
6896 | |||
6897 | while (1) { | ||
6898 | if (now != dev) { | ||
6899 | ret = fn(now, data); | ||
6900 | if (ret) | ||
6901 | return ret; | ||
6902 | } | ||
6903 | |||
6904 | next = NULL; | ||
6905 | while (1) { | ||
6906 | ldev = __netdev_next_lower_dev(now, &iter, &ignore); | ||
6907 | if (!ldev) | ||
6908 | break; | ||
6909 | if (ignore) | ||
6910 | continue; | ||
6911 | |||
6912 | next = ldev; | ||
6913 | niter = &ldev->adj_list.lower; | ||
6914 | dev_stack[cur] = now; | ||
6915 | iter_stack[cur++] = iter; | ||
6916 | break; | ||
6917 | } | ||
6918 | |||
6919 | if (!next) { | ||
6920 | if (!cur) | ||
6921 | return 0; | ||
6922 | next = dev_stack[--cur]; | ||
6923 | niter = iter_stack[cur]; | ||
6924 | } | ||
6925 | |||
6926 | now = next; | ||
6927 | iter = niter; | ||
6928 | } | ||
6929 | |||
6930 | return 0; | ||
6931 | } | ||
6932 | |||
6834 | static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev, | 6933 | static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev, |
6835 | struct list_head **iter) | 6934 | struct list_head **iter) |
6836 | { | 6935 | { |
@@ -6850,11 +6949,14 @@ static u8 __netdev_upper_depth(struct net_device *dev) | |||
6850 | struct net_device *udev; | 6949 | struct net_device *udev; |
6851 | struct list_head *iter; | 6950 | struct list_head *iter; |
6852 | u8 max_depth = 0; | 6951 | u8 max_depth = 0; |
6952 | bool ignore; | ||
6853 | 6953 | ||
6854 | for (iter = &dev->adj_list.upper, | 6954 | for (iter = &dev->adj_list.upper, |
6855 | udev = netdev_next_upper_dev(dev, &iter); | 6955 | udev = __netdev_next_upper_dev(dev, &iter, &ignore); |
6856 | udev; | 6956 | udev; |
6857 | udev = netdev_next_upper_dev(dev, &iter)) { | 6957 | udev = __netdev_next_upper_dev(dev, &iter, &ignore)) { |
6958 | if (ignore) | ||
6959 | continue; | ||
6858 | if (max_depth < udev->upper_level) | 6960 | if (max_depth < udev->upper_level) |
6859 | max_depth = udev->upper_level; | 6961 | max_depth = udev->upper_level; |
6860 | } | 6962 | } |
@@ -6867,11 +6969,14 @@ static u8 __netdev_lower_depth(struct net_device *dev) | |||
6867 | struct net_device *ldev; | 6969 | struct net_device *ldev; |
6868 | struct list_head *iter; | 6970 | struct list_head *iter; |
6869 | u8 max_depth = 0; | 6971 | u8 max_depth = 0; |
6972 | bool ignore; | ||
6870 | 6973 | ||
6871 | for (iter = &dev->adj_list.lower, | 6974 | for (iter = &dev->adj_list.lower, |
6872 | ldev = netdev_next_lower_dev(dev, &iter); | 6975 | ldev = __netdev_next_lower_dev(dev, &iter, &ignore); |
6873 | ldev; | 6976 | ldev; |
6874 | ldev = netdev_next_lower_dev(dev, &iter)) { | 6977 | ldev = __netdev_next_lower_dev(dev, &iter, &ignore)) { |
6978 | if (ignore) | ||
6979 | continue; | ||
6875 | if (max_depth < ldev->lower_level) | 6980 | if (max_depth < ldev->lower_level) |
6876 | max_depth = ldev->lower_level; | 6981 | max_depth = ldev->lower_level; |
6877 | } | 6982 | } |
@@ -7035,6 +7140,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev, | |||
7035 | adj->master = master; | 7140 | adj->master = master; |
7036 | adj->ref_nr = 1; | 7141 | adj->ref_nr = 1; |
7037 | adj->private = private; | 7142 | adj->private = private; |
7143 | adj->ignore = false; | ||
7038 | dev_hold(adj_dev); | 7144 | dev_hold(adj_dev); |
7039 | 7145 | ||
7040 | pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d; dev_hold on %s\n", | 7146 | pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d; dev_hold on %s\n", |
@@ -7185,17 +7291,17 @@ static int __netdev_upper_dev_link(struct net_device *dev, | |||
7185 | return -EBUSY; | 7291 | return -EBUSY; |
7186 | 7292 | ||
7187 | /* To prevent loops, check if dev is not upper device to upper_dev. */ | 7293 | /* To prevent loops, check if dev is not upper device to upper_dev. */ |
7188 | if (netdev_has_upper_dev(upper_dev, dev)) | 7294 | if (__netdev_has_upper_dev(upper_dev, dev)) |
7189 | return -EBUSY; | 7295 | return -EBUSY; |
7190 | 7296 | ||
7191 | if ((dev->lower_level + upper_dev->upper_level) > MAX_NEST_DEV) | 7297 | if ((dev->lower_level + upper_dev->upper_level) > MAX_NEST_DEV) |
7192 | return -EMLINK; | 7298 | return -EMLINK; |
7193 | 7299 | ||
7194 | if (!master) { | 7300 | if (!master) { |
7195 | if (netdev_has_upper_dev(dev, upper_dev)) | 7301 | if (__netdev_has_upper_dev(dev, upper_dev)) |
7196 | return -EEXIST; | 7302 | return -EEXIST; |
7197 | } else { | 7303 | } else { |
7198 | master_dev = netdev_master_upper_dev_get(dev); | 7304 | master_dev = __netdev_master_upper_dev_get(dev); |
7199 | if (master_dev) | 7305 | if (master_dev) |
7200 | return master_dev == upper_dev ? -EEXIST : -EBUSY; | 7306 | return master_dev == upper_dev ? -EEXIST : -EBUSY; |
7201 | } | 7307 | } |
@@ -7218,10 +7324,11 @@ static int __netdev_upper_dev_link(struct net_device *dev, | |||
7218 | goto rollback; | 7324 | goto rollback; |
7219 | 7325 | ||
7220 | __netdev_update_upper_level(dev, NULL); | 7326 | __netdev_update_upper_level(dev, NULL); |
7221 | netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL); | 7327 | __netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL); |
7222 | 7328 | ||
7223 | __netdev_update_lower_level(upper_dev, NULL); | 7329 | __netdev_update_lower_level(upper_dev, NULL); |
7224 | netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, NULL); | 7330 | __netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, |
7331 | NULL); | ||
7225 | 7332 | ||
7226 | return 0; | 7333 | return 0; |
7227 | 7334 | ||
@@ -7307,13 +7414,94 @@ void netdev_upper_dev_unlink(struct net_device *dev, | |||
7307 | &changeupper_info.info); | 7414 | &changeupper_info.info); |
7308 | 7415 | ||
7309 | __netdev_update_upper_level(dev, NULL); | 7416 | __netdev_update_upper_level(dev, NULL); |
7310 | netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL); | 7417 | __netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL); |
7311 | 7418 | ||
7312 | __netdev_update_lower_level(upper_dev, NULL); | 7419 | __netdev_update_lower_level(upper_dev, NULL); |
7313 | netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, NULL); | 7420 | __netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, |
7421 | NULL); | ||
7314 | } | 7422 | } |
7315 | EXPORT_SYMBOL(netdev_upper_dev_unlink); | 7423 | EXPORT_SYMBOL(netdev_upper_dev_unlink); |
7316 | 7424 | ||
7425 | static void __netdev_adjacent_dev_set(struct net_device *upper_dev, | ||
7426 | struct net_device *lower_dev, | ||
7427 | bool val) | ||
7428 | { | ||
7429 | struct netdev_adjacent *adj; | ||
7430 | |||
7431 | adj = __netdev_find_adj(lower_dev, &upper_dev->adj_list.lower); | ||
7432 | if (adj) | ||
7433 | adj->ignore = val; | ||
7434 | |||
7435 | adj = __netdev_find_adj(upper_dev, &lower_dev->adj_list.upper); | ||
7436 | if (adj) | ||
7437 | adj->ignore = val; | ||
7438 | } | ||
7439 | |||
7440 | static void netdev_adjacent_dev_disable(struct net_device *upper_dev, | ||
7441 | struct net_device *lower_dev) | ||
7442 | { | ||
7443 | __netdev_adjacent_dev_set(upper_dev, lower_dev, true); | ||
7444 | } | ||
7445 | |||
7446 | static void netdev_adjacent_dev_enable(struct net_device *upper_dev, | ||
7447 | struct net_device *lower_dev) | ||
7448 | { | ||
7449 | __netdev_adjacent_dev_set(upper_dev, lower_dev, false); | ||
7450 | } | ||
7451 | |||
7452 | int netdev_adjacent_change_prepare(struct net_device *old_dev, | ||
7453 | struct net_device *new_dev, | ||
7454 | struct net_device *dev, | ||
7455 | struct netlink_ext_ack *extack) | ||
7456 | { | ||
7457 | int err; | ||
7458 | |||
7459 | if (!new_dev) | ||
7460 | return 0; | ||
7461 | |||
7462 | if (old_dev && new_dev != old_dev) | ||
7463 | netdev_adjacent_dev_disable(dev, old_dev); | ||
7464 | |||
7465 | err = netdev_upper_dev_link(new_dev, dev, extack); | ||
7466 | if (err) { | ||
7467 | if (old_dev && new_dev != old_dev) | ||
7468 | netdev_adjacent_dev_enable(dev, old_dev); | ||
7469 | return err; | ||
7470 | } | ||
7471 | |||
7472 | return 0; | ||
7473 | } | ||
7474 | EXPORT_SYMBOL(netdev_adjacent_change_prepare); | ||
7475 | |||
7476 | void netdev_adjacent_change_commit(struct net_device *old_dev, | ||
7477 | struct net_device *new_dev, | ||
7478 | struct net_device *dev) | ||
7479 | { | ||
7480 | if (!new_dev || !old_dev) | ||
7481 | return; | ||
7482 | |||
7483 | if (new_dev == old_dev) | ||
7484 | return; | ||
7485 | |||
7486 | netdev_adjacent_dev_enable(dev, old_dev); | ||
7487 | netdev_upper_dev_unlink(old_dev, dev); | ||
7488 | } | ||
7489 | EXPORT_SYMBOL(netdev_adjacent_change_commit); | ||
7490 | |||
7491 | void netdev_adjacent_change_abort(struct net_device *old_dev, | ||
7492 | struct net_device *new_dev, | ||
7493 | struct net_device *dev) | ||
7494 | { | ||
7495 | if (!new_dev) | ||
7496 | return; | ||
7497 | |||
7498 | if (old_dev && new_dev != old_dev) | ||
7499 | netdev_adjacent_dev_enable(dev, old_dev); | ||
7500 | |||
7501 | netdev_upper_dev_unlink(new_dev, dev); | ||
7502 | } | ||
7503 | EXPORT_SYMBOL(netdev_adjacent_change_abort); | ||
7504 | |||
7317 | /** | 7505 | /** |
7318 | * netdev_bonding_info_change - Dispatch event about slave change | 7506 | * netdev_bonding_info_change - Dispatch event about slave change |
7319 | * @dev: device | 7507 | * @dev: device |