Skip to content

Commit

Permalink
rtnetlink: Add assertion helpers for per-netns RTNL.
Browse files Browse the repository at this point in the history
Once an RTNL scope is converted with rtnl_net_lock(), we will replace
RTNL helper functions inside the scope with the following per-netns
alternatives:

  ASSERT_RTNL()           -> ASSERT_RTNL_NET(net)
  rcu_dereference_rtnl(p) -> rcu_dereference_rtnl_net(net, p)

Note that the per-netns helpers are equivalent to the conventional
helpers unless CONFIG_DEBUG_NET_SMALL_RTNL is enabled.

Signed-off-by: Kuniyuki Iwashima <[email protected]>
Reviewed-by: Eric Dumazet <[email protected]>
Signed-off-by: Paolo Abeni <[email protected]>
  • Loading branch information
q2ven authored and Paolo Abeni committed Oct 8, 2024
1 parent 76aed95 commit 844e5e7
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 4 deletions.
45 changes: 41 additions & 4 deletions include/linux/rtnetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ extern atomic_t dev_unreg_count;
extern struct rw_semaphore pernet_ops_rwsem;
extern struct rw_semaphore net_rwsem;

#define ASSERT_RTNL() \
WARN_ONCE(!rtnl_is_locked(), \
"RTNL: assertion failed at %s (%d)\n", __FILE__, __LINE__)

#ifdef CONFIG_PROVE_LOCKING
extern bool lockdep_rtnl_is_held(void);
#else
Expand Down Expand Up @@ -98,6 +102,22 @@ void __rtnl_net_unlock(struct net *net);
void rtnl_net_lock(struct net *net);
void rtnl_net_unlock(struct net *net);
int rtnl_net_lock_cmp_fn(const struct lockdep_map *a, const struct lockdep_map *b);

bool rtnl_net_is_locked(struct net *net);

#define ASSERT_RTNL_NET(net) \
WARN_ONCE(!rtnl_net_is_locked(net), \
"RTNL_NET: assertion failed at %s (%d)\n", \
__FILE__, __LINE__)

bool lockdep_rtnl_net_is_held(struct net *net);

#define rcu_dereference_rtnl_net(net, p) \
rcu_dereference_check(p, lockdep_rtnl_net_is_held(net))
#define rtnl_net_dereference(net, p) \
rcu_dereference_protected(p, lockdep_rtnl_net_is_held(net))
#define rcu_replace_pointer_rtnl_net(net, rp, p) \
rcu_replace_pointer(rp, p, lockdep_rtnl_net_is_held(net))
#else
static inline void __rtnl_net_lock(struct net *net) {}
static inline void __rtnl_net_unlock(struct net *net) {}
Expand All @@ -111,6 +131,27 @@ static inline void rtnl_net_unlock(struct net *net)
{
rtnl_unlock();
}

static inline void ASSERT_RTNL_NET(struct net *net)
{
ASSERT_RTNL();
}

static inline void *rcu_dereference_rtnl_net(struct net *net, void *p)
{
return rcu_dereference_rtnl(p);
}

static inline void *rtnl_net_dereference(struct net *net, void *p)
{
return rtnl_dereference(p);
}

static inline void *rcu_replace_pointer_rtnl_net(struct net *net,
void *rp, void *p)
{
return rcu_replace_pointer_rtnl(rp, p);
}
#endif

static inline struct netdev_queue *dev_ingress_queue(struct net_device *dev)
Expand Down Expand Up @@ -140,10 +181,6 @@ void rtnetlink_init(void);
void __rtnl_unlock(void);
void rtnl_kfree_skbs(struct sk_buff *head, struct sk_buff *tail);

#define ASSERT_RTNL() \
WARN_ONCE(!rtnl_is_locked(), \
"RTNL: assertion failed at %s (%d)\n", __FILE__, __LINE__)

extern int ndo_dflt_fdb_dump(struct sk_buff *skb,
struct netlink_callback *cb,
struct net_device *dev,
Expand Down
12 changes: 12 additions & 0 deletions net/core/rtnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,18 @@ int rtnl_net_lock_cmp_fn(const struct lockdep_map *a, const struct lockdep_map *

return rtnl_net_cmp_locks(net_a, net_b);
}

bool rtnl_net_is_locked(struct net *net)
{
return rtnl_is_locked() && mutex_is_locked(&net->rtnl_mutex);
}
EXPORT_SYMBOL(rtnl_net_is_locked);

bool lockdep_rtnl_net_is_held(struct net *net)
{
return lockdep_rtnl_is_held() && lockdep_is_held(&net->rtnl_mutex);
}
EXPORT_SYMBOL(lockdep_rtnl_net_is_held);
#endif

static struct rtnl_link __rcu *__rcu *rtnl_msg_handlers[RTNL_FAMILY_MAX + 1];
Expand Down

0 comments on commit 844e5e7

Please sign in to comment.