Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: core: add ignore flag to netdev_adjacent structure

In order to link an adjacent node, netdev_upper_dev_link() is used
and in order to unlink an adjacent node, netdev_upper_dev_unlink() is used.
unlink operation does not fail, but link operation can fail.

In order to exchange adjacent nodes, we should unlink an old adjacent
node first. then, link a new adjacent node.
If link operation is failed, we should link an old adjacent node again.
But this link operation can fail too.
It eventually breaks the adjacent link relationship.

This patch adds an ignore flag into the netdev_adjacent structure.
If this flag is set, netdev_upper_dev_link() ignores an old adjacent
node for a moment.

This patch also adds new functions for other modules.
netdev_adjacent_change_prepare()
netdev_adjacent_change_commit()
netdev_adjacent_change_abort()

netdev_adjacent_change_prepare() inserts new device into adjacent list
but new device is not allowed to use immediately.
If netdev_adjacent_change_prepare() fails, it internally rollbacks
adjacent list so that we don't need any other action.
netdev_adjacent_change_commit() deletes old device in the adjacent list
and allows new device to use.
netdev_adjacent_change_abort() rollbacks adjacent list.

Signed-off-by: Taehee Yoo <ap420073@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Taehee Yoo and committed by
David S. Miller
32b6d34f 2bce1ebe

+219 -21
+10
include/linux/netdevice.h
··· 4324 4324 struct netlink_ext_ack *extack); 4325 4325 void netdev_upper_dev_unlink(struct net_device *dev, 4326 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 4337 void netdev_adjacent_rename_links(struct net_device *dev, char *oldname); 4328 4338 void *netdev_lower_dev_get_private(struct net_device *dev, 4329 4339 struct net_device *lower_dev);
+209 -21
net/core/dev.c
··· 6408 6408 /* upper master flag, there can only be one master device per list */ 6409 6409 bool master; 6410 6410 6411 + /* lookup ignore flag */ 6412 + bool ignore; 6413 + 6411 6414 /* counter for the number of times this device was added to us */ 6412 6415 u16 ref_nr; 6413 6416 ··· 6433 6430 return NULL; 6434 6431 } 6435 6432 6436 - static int __netdev_has_upper_dev(struct net_device *upper_dev, void *data) 6433 + static int ____netdev_has_upper_dev(struct net_device *upper_dev, void *data) 6437 6434 { 6438 6435 struct net_device *dev = data; 6439 6436 ··· 6454 6451 { 6455 6452 ASSERT_RTNL(); 6456 6453 6457 - return netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, 6454 + return netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev, 6458 6455 upper_dev); 6459 6456 } 6460 6457 EXPORT_SYMBOL(netdev_has_upper_dev); ··· 6472 6469 bool netdev_has_upper_dev_all_rcu(struct net_device *dev, 6473 6470 struct net_device *upper_dev) 6474 6471 { 6475 - return !!netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev, 6472 + return !!netdev_walk_all_upper_dev_rcu(dev, ____netdev_has_upper_dev, 6476 6473 upper_dev); 6477 6474 } 6478 6475 EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu); ··· 6515 6512 return NULL; 6516 6513 } 6517 6514 EXPORT_SYMBOL(netdev_master_upper_dev_get); 6515 + 6516 + static struct net_device *__netdev_master_upper_dev_get(struct net_device *dev) 6517 + { 6518 + struct netdev_adjacent *upper; 6519 + 6520 + ASSERT_RTNL(); 6521 + 6522 + if (list_empty(&dev->adj_list.upper)) 6523 + return NULL; 6524 + 6525 + upper = list_first_entry(&dev->adj_list.upper, 6526 + struct netdev_adjacent, list); 6527 + if (likely(upper->master) && !upper->ignore) 6528 + return upper->dev; 6529 + return NULL; 6530 + } 6518 6531 6519 6532 /** 6520 6533 * netdev_has_any_lower_dev - Check if device is linked to some device ··· 6582 6563 } 6583 6564 EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu); 6584 6565 6585 - static struct net_device *netdev_next_upper_dev(struct net_device *dev, 6586 - struct list_head **iter) 6566 + static struct net_device *__netdev_next_upper_dev(struct net_device *dev, 6567 + struct list_head **iter, 6568 + bool *ignore) 6587 6569 { 6588 6570 struct netdev_adjacent *upper; 6589 6571 ··· 6594 6574 return NULL; 6595 6575 6596 6576 *iter = &upper->list; 6577 + *ignore = upper->ignore; 6597 6578 6598 6579 return upper->dev; 6599 6580 } ··· 6616 6595 return upper->dev; 6617 6596 } 6618 6597 6619 - static int netdev_walk_all_upper_dev(struct net_device *dev, 6620 - int (*fn)(struct net_device *dev, 6621 - void *data), 6622 - void *data) 6598 + static int __netdev_walk_all_upper_dev(struct net_device *dev, 6599 + int (*fn)(struct net_device *dev, 6600 + void *data), 6601 + void *data) 6623 6602 { 6624 6603 struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; 6625 6604 struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; 6626 6605 int ret, cur = 0; 6606 + bool ignore; 6627 6607 6628 6608 now = dev; 6629 6609 iter = &dev->adj_list.upper; ··· 6638 6616 6639 6617 next = NULL; 6640 6618 while (1) { 6641 - udev = netdev_next_upper_dev(now, &iter); 6619 + udev = __netdev_next_upper_dev(now, &iter, &ignore); 6642 6620 if (!udev) 6643 6621 break; 6622 + if (ignore) 6623 + continue; 6644 6624 6645 6625 next = udev; 6646 6626 niter = &udev->adj_list.upper; ··· 6711 6687 return 0; 6712 6688 } 6713 6689 EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu); 6690 + 6691 + static bool __netdev_has_upper_dev(struct net_device *dev, 6692 + struct net_device *upper_dev) 6693 + { 6694 + ASSERT_RTNL(); 6695 + 6696 + return __netdev_walk_all_upper_dev(dev, ____netdev_has_upper_dev, 6697 + upper_dev); 6698 + } 6714 6699 6715 6700 /** 6716 6701 * netdev_lower_get_next_private - Get the next ->private from the ··· 6817 6784 return lower->dev; 6818 6785 } 6819 6786 6787 + static struct net_device *__netdev_next_lower_dev(struct net_device *dev, 6788 + struct list_head **iter, 6789 + bool *ignore) 6790 + { 6791 + struct netdev_adjacent *lower; 6792 + 6793 + lower = list_entry((*iter)->next, struct netdev_adjacent, list); 6794 + 6795 + if (&lower->list == &dev->adj_list.lower) 6796 + return NULL; 6797 + 6798 + *iter = &lower->list; 6799 + *ignore = lower->ignore; 6800 + 6801 + return lower->dev; 6802 + } 6803 + 6820 6804 int netdev_walk_all_lower_dev(struct net_device *dev, 6821 6805 int (*fn)(struct net_device *dev, 6822 6806 void *data), ··· 6881 6831 } 6882 6832 EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev); 6883 6833 6834 + static int __netdev_walk_all_lower_dev(struct net_device *dev, 6835 + int (*fn)(struct net_device *dev, 6836 + void *data), 6837 + void *data) 6838 + { 6839 + struct net_device *ldev, *next, *now, *dev_stack[MAX_NEST_DEV + 1]; 6840 + struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1]; 6841 + int ret, cur = 0; 6842 + bool ignore; 6843 + 6844 + now = dev; 6845 + iter = &dev->adj_list.lower; 6846 + 6847 + while (1) { 6848 + if (now != dev) { 6849 + ret = fn(now, data); 6850 + if (ret) 6851 + return ret; 6852 + } 6853 + 6854 + next = NULL; 6855 + while (1) { 6856 + ldev = __netdev_next_lower_dev(now, &iter, &ignore); 6857 + if (!ldev) 6858 + break; 6859 + if (ignore) 6860 + continue; 6861 + 6862 + next = ldev; 6863 + niter = &ldev->adj_list.lower; 6864 + dev_stack[cur] = now; 6865 + iter_stack[cur++] = iter; 6866 + break; 6867 + } 6868 + 6869 + if (!next) { 6870 + if (!cur) 6871 + return 0; 6872 + next = dev_stack[--cur]; 6873 + niter = iter_stack[cur]; 6874 + } 6875 + 6876 + now = next; 6877 + iter = niter; 6878 + } 6879 + 6880 + return 0; 6881 + } 6882 + 6884 6883 static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev, 6885 6884 struct list_head **iter) 6886 6885 { ··· 6949 6850 struct net_device *udev; 6950 6851 struct list_head *iter; 6951 6852 u8 max_depth = 0; 6853 + bool ignore; 6952 6854 6953 6855 for (iter = &dev->adj_list.upper, 6954 - udev = netdev_next_upper_dev(dev, &iter); 6856 + udev = __netdev_next_upper_dev(dev, &iter, &ignore); 6955 6857 udev; 6956 - udev = netdev_next_upper_dev(dev, &iter)) { 6858 + udev = __netdev_next_upper_dev(dev, &iter, &ignore)) { 6859 + if (ignore) 6860 + continue; 6957 6861 if (max_depth < udev->upper_level) 6958 6862 max_depth = udev->upper_level; 6959 6863 } ··· 6969 6867 struct net_device *ldev; 6970 6868 struct list_head *iter; 6971 6869 u8 max_depth = 0; 6870 + bool ignore; 6972 6871 6973 6872 for (iter = &dev->adj_list.lower, 6974 - ldev = netdev_next_lower_dev(dev, &iter); 6873 + ldev = __netdev_next_lower_dev(dev, &iter, &ignore); 6975 6874 ldev; 6976 - ldev = netdev_next_lower_dev(dev, &iter)) { 6875 + ldev = __netdev_next_lower_dev(dev, &iter, &ignore)) { 6876 + if (ignore) 6877 + continue; 6977 6878 if (max_depth < ldev->lower_level) 6978 6879 max_depth = ldev->lower_level; 6979 6880 } ··· 7140 7035 adj->master = master; 7141 7036 adj->ref_nr = 1; 7142 7037 adj->private = private; 7038 + adj->ignore = false; 7143 7039 dev_hold(adj_dev); 7144 7040 7145 7041 pr_debug("Insert adjacency: dev %s adj_dev %s adj->ref_nr %d; dev_hold on %s\n", ··· 7291 7185 return -EBUSY; 7292 7186 7293 7187 /* To prevent loops, check if dev is not upper device to upper_dev. */ 7294 - if (netdev_has_upper_dev(upper_dev, dev)) 7188 + if (__netdev_has_upper_dev(upper_dev, dev)) 7295 7189 return -EBUSY; 7296 7190 7297 7191 if ((dev->lower_level + upper_dev->upper_level) > MAX_NEST_DEV) 7298 7192 return -EMLINK; 7299 7193 7300 7194 if (!master) { 7301 - if (netdev_has_upper_dev(dev, upper_dev)) 7195 + if (__netdev_has_upper_dev(dev, upper_dev)) 7302 7196 return -EEXIST; 7303 7197 } else { 7304 - master_dev = netdev_master_upper_dev_get(dev); 7198 + master_dev = __netdev_master_upper_dev_get(dev); 7305 7199 if (master_dev) 7306 7200 return master_dev == upper_dev ? -EEXIST : -EBUSY; 7307 7201 } ··· 7324 7218 goto rollback; 7325 7219 7326 7220 __netdev_update_upper_level(dev, NULL); 7327 - netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL); 7221 + __netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL); 7328 7222 7329 7223 __netdev_update_lower_level(upper_dev, NULL); 7330 - netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, NULL); 7224 + __netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, 7225 + NULL); 7331 7226 7332 7227 return 0; 7333 7228 ··· 7414 7307 &changeupper_info.info); 7415 7308 7416 7309 __netdev_update_upper_level(dev, NULL); 7417 - netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL); 7310 + __netdev_walk_all_lower_dev(dev, __netdev_update_upper_level, NULL); 7418 7311 7419 7312 __netdev_update_lower_level(upper_dev, NULL); 7420 - netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, NULL); 7313 + __netdev_walk_all_upper_dev(upper_dev, __netdev_update_lower_level, 7314 + NULL); 7421 7315 } 7422 7316 EXPORT_SYMBOL(netdev_upper_dev_unlink); 7317 + 7318 + static void __netdev_adjacent_dev_set(struct net_device *upper_dev, 7319 + struct net_device *lower_dev, 7320 + bool val) 7321 + { 7322 + struct netdev_adjacent *adj; 7323 + 7324 + adj = __netdev_find_adj(lower_dev, &upper_dev->adj_list.lower); 7325 + if (adj) 7326 + adj->ignore = val; 7327 + 7328 + adj = __netdev_find_adj(upper_dev, &lower_dev->adj_list.upper); 7329 + if (adj) 7330 + adj->ignore = val; 7331 + } 7332 + 7333 + static void netdev_adjacent_dev_disable(struct net_device *upper_dev, 7334 + struct net_device *lower_dev) 7335 + { 7336 + __netdev_adjacent_dev_set(upper_dev, lower_dev, true); 7337 + } 7338 + 7339 + static void netdev_adjacent_dev_enable(struct net_device *upper_dev, 7340 + struct net_device *lower_dev) 7341 + { 7342 + __netdev_adjacent_dev_set(upper_dev, lower_dev, false); 7343 + } 7344 + 7345 + int netdev_adjacent_change_prepare(struct net_device *old_dev, 7346 + struct net_device *new_dev, 7347 + struct net_device *dev, 7348 + struct netlink_ext_ack *extack) 7349 + { 7350 + int err; 7351 + 7352 + if (!new_dev) 7353 + return 0; 7354 + 7355 + if (old_dev && new_dev != old_dev) 7356 + netdev_adjacent_dev_disable(dev, old_dev); 7357 + 7358 + err = netdev_upper_dev_link(new_dev, dev, extack); 7359 + if (err) { 7360 + if (old_dev && new_dev != old_dev) 7361 + netdev_adjacent_dev_enable(dev, old_dev); 7362 + return err; 7363 + } 7364 + 7365 + return 0; 7366 + } 7367 + EXPORT_SYMBOL(netdev_adjacent_change_prepare); 7368 + 7369 + void netdev_adjacent_change_commit(struct net_device *old_dev, 7370 + struct net_device *new_dev, 7371 + struct net_device *dev) 7372 + { 7373 + if (!new_dev || !old_dev) 7374 + return; 7375 + 7376 + if (new_dev == old_dev) 7377 + return; 7378 + 7379 + netdev_adjacent_dev_enable(dev, old_dev); 7380 + netdev_upper_dev_unlink(old_dev, dev); 7381 + } 7382 + EXPORT_SYMBOL(netdev_adjacent_change_commit); 7383 + 7384 + void netdev_adjacent_change_abort(struct net_device *old_dev, 7385 + struct net_device *new_dev, 7386 + struct net_device *dev) 7387 + { 7388 + if (!new_dev) 7389 + return; 7390 + 7391 + if (old_dev && new_dev != old_dev) 7392 + netdev_adjacent_dev_enable(dev, old_dev); 7393 + 7394 + netdev_upper_dev_unlink(new_dev, dev); 7395 + } 7396 + EXPORT_SYMBOL(netdev_adjacent_change_abort); 7423 7397 7424 7398 /** 7425 7399 * netdev_bonding_info_change - Dispatch event about slave change