Skip to content

Commit 32b6d34

Browse files
TaeheeYoodavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2bce1eb commit 32b6d34

File tree

2 files changed

+219
-21
lines changed

2 files changed

+219
-21
lines changed

include/linux/netdevice.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4324,6 +4324,16 @@ int netdev_master_upper_dev_link(struct net_device *dev,
43244324
struct netlink_ext_ack *extack);
43254325
void netdev_upper_dev_unlink(struct net_device *dev,
43264326
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);
43274337
void netdev_adjacent_rename_links(struct net_device *dev, char *oldname);
43284338
void *netdev_lower_dev_get_private(struct net_device *dev,
43294339
struct net_device *lower_dev);

net/core/dev.c

Lines changed: 209 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6408,6 +6408,9 @@ struct netdev_adjacent {
64086408
/* upper master flag, there can only be one master device per list */
64096409
bool master;
64106410

6411+
/* lookup ignore flag */
6412+
bool ignore;
6413+
64116414
/* counter for the number of times this device was added to us */
64126415
u16 ref_nr;
64136416

@@ -6430,7 +6433,7 @@ static struct netdev_adjacent *__netdev_find_adj(struct net_device *adj_dev,
64306433
return NULL;
64316434
}
64326435

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)
64346437
{
64356438
struct net_device *dev = data;
64366439

@@ -6451,7 +6454,7 @@ bool netdev_has_upper_dev(struct net_device *dev,
64516454
{
64526455
ASSERT_RTNL();
64536456

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,
64556458
upper_dev);
64566459
}
64576460
EXPORT_SYMBOL(netdev_has_upper_dev);
@@ -6469,7 +6472,7 @@ EXPORT_SYMBOL(netdev_has_upper_dev);
64696472
bool netdev_has_upper_dev_all_rcu(struct net_device *dev,
64706473
struct net_device *upper_dev)
64716474
{
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,
64736476
upper_dev);
64746477
}
64756478
EXPORT_SYMBOL(netdev_has_upper_dev_all_rcu);
@@ -6513,6 +6516,22 @@ struct net_device *netdev_master_upper_dev_get(struct net_device *dev)
65136516
}
65146517
EXPORT_SYMBOL(netdev_master_upper_dev_get);
65156518

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+
65166535
/**
65176536
* netdev_has_any_lower_dev - Check if device is linked to some device
65186537
* @dev: device
@@ -6563,8 +6582,9 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
65636582
}
65646583
EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu);
65656584

6566-
static struct net_device *netdev_next_upper_dev(struct net_device *dev,
6567-
struct list_head **iter)
6585+
static struct net_device *__netdev_next_upper_dev(struct net_device *dev,
6586+
struct list_head **iter,
6587+
bool *ignore)
65686588
{
65696589
struct netdev_adjacent *upper;
65706590

@@ -6574,6 +6594,7 @@ static struct net_device *netdev_next_upper_dev(struct net_device *dev,
65746594
return NULL;
65756595

65766596
*iter = &upper->list;
6597+
*ignore = upper->ignore;
65776598

65786599
return upper->dev;
65796600
}
@@ -6595,14 +6616,15 @@ static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
65956616
return upper->dev;
65966617
}
65976618

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)
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)
66026623
{
66036624
struct net_device *udev, *next, *now, *dev_stack[MAX_NEST_DEV + 1];
66046625
struct list_head *niter, *iter, *iter_stack[MAX_NEST_DEV + 1];
66056626
int ret, cur = 0;
6627+
bool ignore;
66066628

66076629
now = dev;
66086630
iter = &dev->adj_list.upper;
@@ -6616,9 +6638,11 @@ static int netdev_walk_all_upper_dev(struct net_device *dev,
66166638

66176639
next = NULL;
66186640
while (1) {
6619-
udev = netdev_next_upper_dev(now, &iter);
6641+
udev = __netdev_next_upper_dev(now, &iter, &ignore);
66206642
if (!udev)
66216643
break;
6644+
if (ignore)
6645+
continue;
66226646

66236647
next = udev;
66246648
niter = &udev->adj_list.upper;
@@ -6688,6 +6712,15 @@ int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
66886712
}
66896713
EXPORT_SYMBOL_GPL(netdev_walk_all_upper_dev_rcu);
66906714

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+
66916724
/**
66926725
* netdev_lower_get_next_private - Get the next ->private from the
66936726
* lower neighbour list
@@ -6784,6 +6817,23 @@ static struct net_device *netdev_next_lower_dev(struct net_device *dev,
67846817
return lower->dev;
67856818
}
67866819

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+
67876837
int netdev_walk_all_lower_dev(struct net_device *dev,
67886838
int (*fn)(struct net_device *dev,
67896839
void *data),
@@ -6831,6 +6881,55 @@ int netdev_walk_all_lower_dev(struct net_device *dev,
68316881
}
68326882
EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev);
68336883

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+
68346933
static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
68356934
struct list_head **iter)
68366935
{
@@ -6850,11 +6949,14 @@ static u8 __netdev_upper_depth(struct net_device *dev)
68506949
struct net_device *udev;
68516950
struct list_head *iter;
68526951
u8 max_depth = 0;
6952+
bool ignore;
68536953

68546954
for (iter = &dev->adj_list.upper,
6855-
udev = netdev_next_upper_dev(dev, &iter);
6955+
udev = __netdev_next_upper_dev(dev, &iter, &ignore);
68566956
udev;
6857-
udev = netdev_next_upper_dev(dev, &iter)) {
6957+
udev = __netdev_next_upper_dev(dev, &iter, &ignore)) {
6958+
if (ignore)
6959+
continue;
68586960
if (max_depth < udev->upper_level)
68596961
max_depth = udev->upper_level;
68606962
}
@@ -6867,11 +6969,14 @@ static u8 __netdev_lower_depth(struct net_device *dev)
68676969
struct net_device *ldev;
68686970
struct list_head *iter;
68696971
u8 max_depth = 0;
6972+
bool ignore;
68706973

68716974
for (iter = &dev->adj_list.lower,
6872-
ldev = netdev_next_lower_dev(dev, &iter);
6975+
ldev = __netdev_next_lower_dev(dev, &iter, &ignore);
68736976
ldev;
6874-
ldev = netdev_next_lower_dev(dev, &iter)) {
6977+
ldev = __netdev_next_lower_dev(dev, &iter, &ignore)) {
6978+
if (ignore)
6979+
continue;
68756980
if (max_depth < ldev->lower_level)
68766981
max_depth = ldev->lower_level;
68776982
}
@@ -7035,6 +7140,7 @@ static int __netdev_adjacent_dev_insert(struct net_device *dev,
70357140
adj->master = master;
70367141
adj->ref_nr = 1;
70377142
adj->private = private;
7143+
adj->ignore = false;
70387144
dev_hold(adj_dev);
70397145

70407146
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,
71857291
return -EBUSY;
71867292

71877293
/* 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))
71897295
return -EBUSY;
71907296

71917297
if ((dev->lower_level + upper_dev->upper_level) > MAX_NEST_DEV)
71927298
return -EMLINK;
71937299

71947300
if (!master) {
7195-
if (netdev_has_upper_dev(dev, upper_dev))
7301+
if (__netdev_has_upper_dev(dev, upper_dev))
71967302
return -EEXIST;
71977303
} else {
7198-
master_dev = netdev_master_upper_dev_get(dev);
7304+
master_dev = __netdev_master_upper_dev_get(dev);
71997305
if (master_dev)
72007306
return master_dev == upper_dev ? -EEXIST : -EBUSY;
72017307
}
@@ -7218,10 +7324,11 @@ static int __netdev_upper_dev_link(struct net_device *dev,
72187324
goto rollback;
72197325

72207326
__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);
72227328

72237329
__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);
72257332

72267333
return 0;
72277334

@@ -7307,13 +7414,94 @@ void netdev_upper_dev_unlink(struct net_device *dev,
73077414
&changeupper_info.info);
73087415

73097416
__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);
73117418

73127419
__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);
73147422
}
73157423
EXPORT_SYMBOL(netdev_upper_dev_unlink);
73167424

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+
73177505
/**
73187506
* netdev_bonding_info_change - Dispatch event about slave change
73197507
* @dev: device

0 commit comments

Comments
 (0)