Skip to content

Commit

Permalink
net: add netdev->up protected by netdev_lock()
Browse files Browse the repository at this point in the history
Some uAPI (netdev netlink) hide net_device's sub-objects while
the interface is down to ensure uniform behavior across drivers.
To remove the rtnl_lock dependency from those uAPIs we need a way
to safely tell if the device is down or up.

Add an indication of whether device is open or closed, protected
by netdev->lock. The semantics are the same as IFF_UP, but taking
netdev_lock around every write to ->flags would be a lot of code
churn.

We don't want to blanket the entire open / close path by netdev_lock,
because it will prevent us from applying it to specific structures -
core helpers won't be able to take that lock from any function
called by the drivers on open/close paths.

So the state of the flag is "pessimistic", as in it may report false
negatives, but never false positives.

Reviewed-by: Joe Damato <jdamato@fastly.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
Link: https://patch.msgid.link/20250115035319.559603-5-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Jan 16, 2025
1 parent 2628f49 commit 5112457
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 3 deletions.
14 changes: 13 additions & 1 deletion include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -2443,12 +2443,24 @@ struct net_device {
unsigned long gro_flush_timeout;
u32 napi_defer_hard_irqs;

/**
* @up: copy of @state's IFF_UP, but safe to read with just @lock.
* May report false negatives while the device is being opened
* or closed (@lock does not protect .ndo_open, or .ndo_close).
*/
bool up;

/**
* @lock: netdev-scope lock, protects a small selection of fields.
* Should always be taken using netdev_lock() / netdev_unlock() helpers.
* Drivers are free to use it for other protection.
*
* Protects: @reg_state, @net_shaper_hierarchy.
* Protects:
* @net_shaper_hierarchy, @reg_state
*
* Partially protects (writers must hold both @lock and rtnl_lock):
* @up
*
* Ordering: take after rtnl_lock.
*/
struct mutex lock;
Expand Down
4 changes: 2 additions & 2 deletions net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1619,7 +1619,7 @@ static int __dev_open(struct net_device *dev, struct netlink_ext_ack *extack)
if (ret)
clear_bit(__LINK_STATE_START, &dev->state);
else {
dev->flags |= IFF_UP;
netif_set_up(dev, true);
dev_set_rx_mode(dev);
dev_activate(dev);
add_device_randomness(dev->dev_addr, dev->addr_len);
Expand Down Expand Up @@ -1698,7 +1698,7 @@ static void __dev_close_many(struct list_head *head)
if (ops->ndo_stop)
ops->ndo_stop(dev);

dev->flags &= ~IFF_UP;
netif_set_up(dev, false);
netpoll_poll_enable(dev);
}
}
Expand Down
12 changes: 12 additions & 0 deletions net/core/dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ void __dev_notify_flags(struct net_device *dev, unsigned int old_flags,
void unregister_netdevice_many_notify(struct list_head *head,
u32 portid, const struct nlmsghdr *nlh);

static inline void netif_set_up(struct net_device *dev, bool value)
{
if (value)
dev->flags |= IFF_UP;
else
dev->flags &= ~IFF_UP;

netdev_lock(dev);
dev->up = value;
netdev_unlock(dev);
}

static inline void netif_set_gso_max_size(struct net_device *dev,
unsigned int size)
{
Expand Down

0 comments on commit 5112457

Please sign in to comment.