Merge branch 'mpls-remove-rtnl-dependency'

Kuniyuki Iwashima says:

====================
mpls: Remove RTNL dependency.

MPLS uses RTNL

  1) to guarantee the lifetime of struct mpls_nh.nh_dev
  2) to protect net->mpls.platform_label

, but neither actually requires RTNL.

If struct mpls_nh holds a refcnt for nh_dev, we do not need RTNL,
and it can be replaced with a dedicated mutex.

The series removes RTNL from net/mpls/.

Overview:

  Patch 1 is misc cleanup.

  Patch 2 - 9 are prep to drop RTNL for RTM_{NEW,DEL,GET}ROUTE
  handlers.

  Patch 10 & 11 converts mpls_dump_routes() and RTM_GETNETCONF to RCU.

  Patch 12 replaces RTNL with a new per-netns mutex.

  Patch 13 drops RTNL from RTM_{NEW,DEL,GET}ROUTE.
====================

Link: https://patch.msgid.link/20251029173344.2934622-1-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2025-11-03 17:41:01 -08:00
5 changed files with 224 additions and 128 deletions
+5
View File
@@ -347,6 +347,11 @@ static inline struct inet6_dev *__in6_dev_get(const struct net_device *dev)
return rcu_dereference_rtnl(dev->ip6_ptr);
}
static inline struct inet6_dev *in6_dev_rcu(const struct net_device *dev)
{
return rcu_dereference(dev->ip6_ptr);
}
static inline struct inet6_dev *__in6_dev_get_rtnl_net(const struct net_device *dev)
{
return rtnl_net_dereference(dev_net(dev), dev->ip6_ptr);
+1
View File
@@ -16,6 +16,7 @@ struct netns_mpls {
int default_ttl;
size_t platform_labels;
struct mpls_route __rcu * __rcu *platform_label;
struct mutex platform_mutex;
struct ctl_table_header *ctl;
};
+199 -122
View File
File diff suppressed because it is too large Load Diff
+16 -3
View File
@@ -88,6 +88,7 @@ enum mpls_payload_type {
struct mpls_nh { /* next hop label forwarding entry */
struct net_device *nh_dev;
netdevice_tracker nh_dev_tracker;
/* nh_flags is accessed under RCU in the packet path; it is
* modified handling netdev events with rtnl lock held
@@ -184,9 +185,20 @@ static inline struct mpls_entry_decoded mpls_entry_decode(struct mpls_shim_hdr *
return result;
}
static inline struct mpls_dev *mpls_dev_get(const struct net_device *dev)
#define mpls_dereference(net, p) \
rcu_dereference_protected( \
(p), \
lockdep_is_held(&(net)->mpls.platform_mutex))
static inline struct mpls_dev *mpls_dev_rcu(const struct net_device *dev)
{
return rcu_dereference_rtnl(dev->mpls_ptr);
return rcu_dereference(dev->mpls_ptr);
}
static inline struct mpls_dev *mpls_dev_get(const struct net *net,
const struct net_device *dev)
{
return mpls_dereference(net, dev->mpls_ptr);
}
int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels,
@@ -196,7 +208,8 @@ int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
bool mpls_output_possible(const struct net_device *dev);
unsigned int mpls_dev_mtu(const struct net_device *dev);
bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu);
void mpls_stats_inc_outucastpkts(struct net_device *dev,
void mpls_stats_inc_outucastpkts(struct net *net,
struct net_device *dev,
const struct sk_buff *skb);
#endif /* MPLS_INTERNAL_H */
+3 -3
View File
@@ -53,7 +53,7 @@ static int mpls_xmit(struct sk_buff *skb)
/* Find the output device */
out_dev = dst->dev;
net = dev_net(out_dev);
net = dev_net_rcu(out_dev);
if (!mpls_output_possible(out_dev) ||
!dst->lwtstate || skb_warn_if_lro(skb))
@@ -128,7 +128,7 @@ static int mpls_xmit(struct sk_buff *skb)
bos = false;
}
mpls_stats_inc_outucastpkts(out_dev, skb);
mpls_stats_inc_outucastpkts(net, out_dev, skb);
if (rt) {
if (rt->rt_gw_family == AF_INET6)
@@ -153,7 +153,7 @@ static int mpls_xmit(struct sk_buff *skb)
return LWTUNNEL_XMIT_DONE;
drop:
out_mdev = out_dev ? mpls_dev_get(out_dev) : NULL;
out_mdev = out_dev ? mpls_dev_rcu(out_dev) : NULL;
if (out_mdev)
MPLS_INC_STATS(out_mdev, tx_errors);
kfree_skb(skb);