Skip to content

Commit

Permalink
net: Remove all_adj_list and its references
Browse files Browse the repository at this point in the history
Only direct adjacencies are maintained. All upper or lower devices can
be learned via the new walk API which recursively walks the adj_list for
upper devices or lower devices.

Signed-off-by: David Ahern <dsa@cumulusnetworks.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David Ahern authored and David S. Miller committed Oct 18, 2016
1 parent cf2d674 commit f1170fd
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 230 deletions.
25 changes: 0 additions & 25 deletions include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -1456,7 +1456,6 @@ enum netdev_priv_flags {
* @ptype_specific: Device-specific, protocol-specific packet handlers
*
* @adj_list: Directly linked devices, like slaves for bonding
* @all_adj_list: All linked devices, *including* neighbours
* @features: Currently active device features
* @hw_features: User-changeable features
*
Expand Down Expand Up @@ -1675,11 +1674,6 @@ struct net_device {
struct list_head lower;
} adj_list;

struct {
struct list_head upper;
struct list_head lower;
} all_adj_list;

netdev_features_t features;
netdev_features_t hw_features;
netdev_features_t wanted_features;
Expand Down Expand Up @@ -3771,13 +3765,6 @@ struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev,
updev; \
updev = netdev_upper_get_next_dev_rcu(dev, &(iter)))

/* iterate through upper list, must be called under RCU read lock */
#define netdev_for_each_all_upper_dev_rcu(dev, updev, iter) \
for (iter = &(dev)->all_adj_list.upper, \
updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter)); \
updev; \
updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter)))

int netdev_walk_all_upper_dev_rcu(struct net_device *dev,
int (*fn)(struct net_device *upper_dev,
void *data),
Expand Down Expand Up @@ -3817,18 +3804,6 @@ struct net_device *netdev_all_lower_get_next(struct net_device *dev,
struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev,
struct list_head **iter);

#define netdev_for_each_all_lower_dev(dev, ldev, iter) \
for (iter = (dev)->all_adj_list.lower.next, \
ldev = netdev_all_lower_get_next(dev, &(iter)); \
ldev; \
ldev = netdev_all_lower_get_next(dev, &(iter)))

#define netdev_for_each_all_lower_dev_rcu(dev, ldev, iter) \
for (iter = (dev)->all_adj_list.lower.next, \
ldev = netdev_all_lower_get_next_rcu(dev, &(iter)); \
ldev; \
ldev = netdev_all_lower_get_next_rcu(dev, &(iter)))

int netdev_walk_all_lower_dev(struct net_device *dev,
int (*fn)(struct net_device *lower_dev,
void *data),
Expand Down
223 changes: 18 additions & 205 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -5137,6 +5137,13 @@ static struct netdev_adjacent *__netdev_find_adj(struct net_device *adj_dev,
return NULL;
}

static int __netdev_has_upper_dev(struct net_device *upper_dev, void *data)
{
struct net_device *dev = data;

return upper_dev == dev;
}

/**
* netdev_has_upper_dev - Check if device is linked to an upper device
* @dev: device
Expand All @@ -5151,7 +5158,8 @@ bool netdev_has_upper_dev(struct net_device *dev,
{
ASSERT_RTNL();

return __netdev_find_adj(upper_dev, &dev->all_adj_list.upper);
return netdev_walk_all_upper_dev_rcu(dev, __netdev_has_upper_dev,
upper_dev);
}
EXPORT_SYMBOL(netdev_has_upper_dev);

Expand All @@ -5165,13 +5173,6 @@ EXPORT_SYMBOL(netdev_has_upper_dev);
* The caller must hold rcu lock.
*/

static int __netdev_has_upper_dev(struct net_device *upper_dev, void *data)
{
struct net_device *dev = data;

return upper_dev == dev;
}

bool netdev_has_upper_dev_all_rcu(struct net_device *dev,
struct net_device *upper_dev)
{
Expand All @@ -5191,7 +5192,7 @@ static bool netdev_has_any_upper_dev(struct net_device *dev)
{
ASSERT_RTNL();

return !list_empty(&dev->all_adj_list.upper);
return !list_empty(&dev->adj_list.upper);
}

/**
Expand Down Expand Up @@ -5254,32 +5255,6 @@ struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
}
EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu);

/**
* netdev_all_upper_get_next_dev_rcu - Get the next dev from upper list
* @dev: device
* @iter: list_head ** of the current position
*
* Gets the next device from the dev's upper list, starting from iter
* position. The caller must hold RCU read lock.
*/
struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev,
struct list_head **iter)
{
struct netdev_adjacent *upper;

WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held());

upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list);

if (&upper->list == &dev->all_adj_list.upper)
return NULL;

*iter = &upper->list;

return upper->dev;
}
EXPORT_SYMBOL(netdev_all_upper_get_next_dev_rcu);

static struct net_device *netdev_next_upper_dev_rcu(struct net_device *dev,
struct list_head **iter)
{
Expand Down Expand Up @@ -5406,31 +5381,6 @@ void *netdev_lower_get_next(struct net_device *dev, struct list_head **iter)
}
EXPORT_SYMBOL(netdev_lower_get_next);

/**
* netdev_all_lower_get_next - Get the next device from all lower neighbour list
* @dev: device
* @iter: list_head ** of the current position
*
* Gets the next netdev_adjacent from the dev's all lower neighbour
* list, starting from iter position. The caller must hold RTNL lock or
* its own locking that guarantees that the neighbour all lower
* list will remain unchanged.
*/
struct net_device *netdev_all_lower_get_next(struct net_device *dev, struct list_head **iter)
{
struct netdev_adjacent *lower;

lower = list_entry(*iter, struct netdev_adjacent, list);

if (&lower->list == &dev->all_adj_list.lower)
return NULL;

*iter = lower->list.next;

return lower->dev;
}
EXPORT_SYMBOL(netdev_all_lower_get_next);

static struct net_device *netdev_next_lower_dev(struct net_device *dev,
struct list_head **iter)
{
Expand Down Expand Up @@ -5474,27 +5424,6 @@ int netdev_walk_all_lower_dev(struct net_device *dev,
}
EXPORT_SYMBOL_GPL(netdev_walk_all_lower_dev);

/**
* netdev_all_lower_get_next_rcu - Get the next device from all
* lower neighbour list, RCU variant
* @dev: device
* @iter: list_head ** of the current position
*
* Gets the next netdev_adjacent from the dev's all lower neighbour
* list, starting from iter position. The caller must hold RCU read lock.
*/
struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev,
struct list_head **iter)
{
struct netdev_adjacent *lower;

lower = list_first_or_null_rcu(&dev->all_adj_list.lower,
struct netdev_adjacent, list);

return lower ? lower->dev : NULL;
}
EXPORT_SYMBOL(netdev_all_lower_get_next_rcu);

static struct net_device *netdev_next_lower_dev_rcu(struct net_device *dev,
struct list_head **iter)
{
Expand Down Expand Up @@ -5722,15 +5651,6 @@ static int __netdev_adjacent_dev_link_lists(struct net_device *dev,
return 0;
}

static int __netdev_adjacent_dev_link(struct net_device *dev,
struct net_device *upper_dev)
{
return __netdev_adjacent_dev_link_lists(dev, upper_dev,
&dev->all_adj_list.upper,
&upper_dev->all_adj_list.lower,
NULL, false);
}

static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev,
struct net_device *upper_dev,
u16 ref_nr,
Expand All @@ -5741,40 +5661,19 @@ static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev,
__netdev_adjacent_dev_remove(upper_dev, dev, ref_nr, down_list);
}

static void __netdev_adjacent_dev_unlink(struct net_device *dev,
struct net_device *upper_dev,
u16 ref_nr)
{
__netdev_adjacent_dev_unlink_lists(dev, upper_dev, ref_nr,
&dev->all_adj_list.upper,
&upper_dev->all_adj_list.lower);
}

static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev,
struct net_device *upper_dev,
void *private, bool master)
{
int ret = __netdev_adjacent_dev_link(dev, upper_dev);

if (ret)
return ret;

ret = __netdev_adjacent_dev_link_lists(dev, upper_dev,
&dev->adj_list.upper,
&upper_dev->adj_list.lower,
private, master);
if (ret) {
__netdev_adjacent_dev_unlink(dev, upper_dev, 1);
return ret;
}

return 0;
return __netdev_adjacent_dev_link_lists(dev, upper_dev,
&dev->adj_list.upper,
&upper_dev->adj_list.lower,
private, master);
}

static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
struct net_device *upper_dev)
{
__netdev_adjacent_dev_unlink(dev, upper_dev, 1);
__netdev_adjacent_dev_unlink_lists(dev, upper_dev, 1,
&dev->adj_list.upper,
&upper_dev->adj_list.lower);
Expand All @@ -5785,7 +5684,6 @@ static int __netdev_upper_dev_link(struct net_device *dev,
void *upper_priv, void *upper_info)
{
struct netdev_notifier_changeupper_info changeupper_info;
struct netdev_adjacent *i, *j, *to_i, *to_j;
int ret = 0;

ASSERT_RTNL();
Expand All @@ -5794,10 +5692,10 @@ static int __netdev_upper_dev_link(struct net_device *dev,
return -EBUSY;

/* To prevent loops, check if dev is not upper device to upper_dev. */
if (__netdev_find_adj(dev, &upper_dev->all_adj_list.upper))
if (netdev_has_upper_dev(upper_dev, dev))
return -EBUSY;

if (__netdev_find_adj(upper_dev, &dev->adj_list.upper))
if (netdev_has_upper_dev(dev, upper_dev))
return -EEXIST;

if (master && netdev_master_upper_dev_get(dev))
Expand All @@ -5819,80 +5717,15 @@ static int __netdev_upper_dev_link(struct net_device *dev,
if (ret)
return ret;

/* Now that we linked these devs, make all the upper_dev's
* all_adj_list.upper visible to every dev's all_adj_list.lower an
* versa, and don't forget the devices itself. All of these
* links are non-neighbours.
*/
list_for_each_entry(i, &dev->all_adj_list.lower, list) {
list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
pr_debug("Interlinking %s with %s, non-neighbour\n",
i->dev->name, j->dev->name);
ret = __netdev_adjacent_dev_link(i->dev, j->dev);
if (ret)
goto rollback_mesh;
}
}

/* add dev to every upper_dev's upper device */
list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
pr_debug("linking %s's upper device %s with %s\n",
upper_dev->name, i->dev->name, dev->name);
ret = __netdev_adjacent_dev_link(dev, i->dev);
if (ret)
goto rollback_upper_mesh;
}

/* add upper_dev to every dev's lower device */
list_for_each_entry(i, &dev->all_adj_list.lower, list) {
pr_debug("linking %s's lower device %s with %s\n", dev->name,
i->dev->name, upper_dev->name);
ret = __netdev_adjacent_dev_link(i->dev, upper_dev);
if (ret)
goto rollback_lower_mesh;
}

ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
&changeupper_info.info);
ret = notifier_to_errno(ret);
if (ret)
goto rollback_lower_mesh;
goto rollback;

return 0;

rollback_lower_mesh:
to_i = i;
list_for_each_entry(i, &dev->all_adj_list.lower, list) {
if (i == to_i)
break;
__netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);
}

i = NULL;

rollback_upper_mesh:
to_i = i;
list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) {
if (i == to_i)
break;
__netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
}

i = j = NULL;

rollback_mesh:
to_i = i;
to_j = j;
list_for_each_entry(i, &dev->all_adj_list.lower, list) {
list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) {
if (i == to_i && j == to_j)
break;
__netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);
}
if (i == to_i)
break;
}

rollback:
__netdev_adjacent_dev_unlink_neighbour(dev, upper_dev);

return ret;
Expand Down Expand Up @@ -5949,7 +5782,6 @@ void netdev_upper_dev_unlink(struct net_device *dev,
struct net_device *upper_dev)
{
struct netdev_notifier_changeupper_info changeupper_info;
struct netdev_adjacent *i, *j;
ASSERT_RTNL();

changeupper_info.upper_dev = upper_dev;
Expand All @@ -5961,23 +5793,6 @@ void netdev_upper_dev_unlink(struct net_device *dev,

__netdev_adjacent_dev_unlink_neighbour(dev, upper_dev);

/* Here is the tricky part. We must remove all dev's lower
* devices from all upper_dev's upper devices and vice
* versa, to maintain the graph relationship.
*/
list_for_each_entry(i, &dev->all_adj_list.lower, list)
list_for_each_entry(j, &upper_dev->all_adj_list.upper, list)
__netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr);

/* remove also the devices itself from lower/upper device
* list
*/
list_for_each_entry(i, &dev->all_adj_list.lower, list)
__netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr);

list_for_each_entry(i, &upper_dev->all_adj_list.upper, list)
__netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);

call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
&changeupper_info.info);
}
Expand Down Expand Up @@ -7679,8 +7494,6 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
INIT_LIST_HEAD(&dev->link_watch_list);
INIT_LIST_HEAD(&dev->adj_list.upper);
INIT_LIST_HEAD(&dev->adj_list.lower);
INIT_LIST_HEAD(&dev->all_adj_list.upper);
INIT_LIST_HEAD(&dev->all_adj_list.lower);
INIT_LIST_HEAD(&dev->ptype_all);
INIT_LIST_HEAD(&dev->ptype_specific);
#ifdef CONFIG_NET_SCHED
Expand Down

0 comments on commit f1170fd

Please sign in to comment.