netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 net-next 0/7] neighbour: Convert RTM_GETNEIGH and RTM_{GET,SET}NEIGHTBL to RCU.
@ 2025-04-16  0:41 Kuniyuki Iwashima
  2025-04-16  0:41 ` [PATCH v1 net-next 1/7] neighbour: Make neigh_valid_get_req() return ndmsg Kuniyuki Iwashima
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Kuniyuki Iwashima @ 2025-04-16  0:41 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev

Patch 1 - 4 moves validations and skb allocation in neigh_get()
as prep for patch 5, which converts RTM_GETNEIGH to RCU.

Patch 6 & 7 converts RTM_GETNEIGHTBL and RTM_SETNEIGHTBL to RCU,
which requires almost nothing.


Kuniyuki Iwashima (7):
  neighbour: Make neigh_valid_get_req() return ndmsg.
  neighbour: Move two validations from neigh_get() to
    neigh_valid_get_req().
  neighbour: Allocate skb in neigh_get().
  neighbour: Move neigh_find_table() to neigh_get().
  neighbour: Convert RTM_GETNEIGH to RCU.
  neighbour: Convert RTM_GETNEIGHTBL to RCU.
  neighbour: Convert RTM_SETNEIGHTBL to RCU.

 net/core/neighbour.c | 208 +++++++++++++++++++++----------------------
 1 file changed, 101 insertions(+), 107 deletions(-)

-- 
2.49.0


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v1 net-next 1/7] neighbour: Make neigh_valid_get_req() return ndmsg.
  2025-04-16  0:41 [PATCH v1 net-next 0/7] neighbour: Convert RTM_GETNEIGH and RTM_{GET,SET}NEIGHTBL to RCU Kuniyuki Iwashima
@ 2025-04-16  0:41 ` Kuniyuki Iwashima
  2025-04-17 12:53   ` Simon Horman
  2025-04-17 20:57   ` Kuniyuki Iwashima
  2025-04-16  0:41 ` [PATCH v1 net-next 2/7] neighbour: Move two validations from neigh_get() to neigh_valid_get_req() Kuniyuki Iwashima
                   ` (5 subsequent siblings)
  6 siblings, 2 replies; 10+ messages in thread
From: Kuniyuki Iwashima @ 2025-04-16  0:41 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev

neigh_get() passes 4 local variable pointers to neigh_valid_get_req().

If it returns a pointer of struct ndmsg, we do not need to pass two
of them.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
 net/core/neighbour.c | 49 ++++++++++++++++++++++----------------------
 1 file changed, 24 insertions(+), 25 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 65cf582b5dac..8384a025e7c0 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2846,43 +2846,42 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 	return err;
 }
 
-static int neigh_valid_get_req(const struct nlmsghdr *nlh,
-			       struct neigh_table **tbl,
-			       void **dst, int *dev_idx, u8 *ndm_flags,
-			       struct netlink_ext_ack *extack)
+static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh,
+					 struct neigh_table **tbl, void **dst,
+					 struct netlink_ext_ack *extack)
 {
 	struct nlattr *tb[NDA_MAX + 1];
 	struct ndmsg *ndm;
-	int err, i;
+	int err = -EINVAL;
+	int i;
 
 	ndm = nlmsg_payload(nlh, sizeof(*ndm));
 	if (!ndm) {
 		NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
-		return -EINVAL;
+		goto err;
 	}
 
 	if (ndm->ndm_pad1  || ndm->ndm_pad2  || ndm->ndm_state ||
 	    ndm->ndm_type) {
 		NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
-		return -EINVAL;
+		goto err;
 	}
 
 	if (ndm->ndm_flags & ~NTF_PROXY) {
 		NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
-		return -EINVAL;
+		goto err;
 	}
 
 	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
 					    NDA_MAX, nda_policy, extack);
 	if (err < 0)
-		return err;
+		goto err;
 
-	*ndm_flags = ndm->ndm_flags;
-	*dev_idx = ndm->ndm_ifindex;
 	*tbl = neigh_find_table(ndm->ndm_family);
-	if (*tbl == NULL) {
+	if (!*tbl) {
 		NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
-		return -EAFNOSUPPORT;
+		err = -EAFNOSUPPORT;
+		goto err;
 	}
 
 	for (i = 0; i <= NDA_MAX; ++i) {
@@ -2893,17 +2892,19 @@ static int neigh_valid_get_req(const struct nlmsghdr *nlh,
 		case NDA_DST:
 			if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
 				NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
-				return -EINVAL;
+				goto err;
 			}
 			*dst = nla_data(tb[i]);
 			break;
 		default:
 			NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
-			return -EINVAL;
+			goto err;
 		}
 	}
 
-	return 0;
+	return ndm;
+err:
+	return ERR_PTR(err);
 }
 
 static inline size_t neigh_nlmsg_size(void)
@@ -2974,18 +2975,16 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 	struct net_device *dev = NULL;
 	struct neigh_table *tbl = NULL;
 	struct neighbour *neigh;
+	struct ndmsg *ndm;
 	void *dst = NULL;
-	u8 ndm_flags = 0;
-	int dev_idx = 0;
 	int err;
 
-	err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
-				  extack);
-	if (err < 0)
-		return err;
+	ndm = neigh_valid_get_req(nlh, &tbl, &dst, extack);
+	if (IS_ERR(ndm))
+		return PTR_ERR(ndm);
 
-	if (dev_idx) {
-		dev = __dev_get_by_index(net, dev_idx);
+	if (ndm->ndm_ifindex) {
+		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
 		if (!dev) {
 			NL_SET_ERR_MSG(extack, "Unknown device ifindex");
 			return -ENODEV;
@@ -2997,7 +2996,7 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 		return -EINVAL;
 	}
 
-	if (ndm_flags & NTF_PROXY) {
+	if (ndm->ndm_flags & NTF_PROXY) {
 		struct pneigh_entry *pn;
 
 		pn = pneigh_lookup(tbl, net, dst, dev, 0);
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v1 net-next 2/7] neighbour: Move two validations from neigh_get() to neigh_valid_get_req().
  2025-04-16  0:41 [PATCH v1 net-next 0/7] neighbour: Convert RTM_GETNEIGH and RTM_{GET,SET}NEIGHTBL to RCU Kuniyuki Iwashima
  2025-04-16  0:41 ` [PATCH v1 net-next 1/7] neighbour: Make neigh_valid_get_req() return ndmsg Kuniyuki Iwashima
@ 2025-04-16  0:41 ` Kuniyuki Iwashima
  2025-04-16  0:41 ` [PATCH v1 net-next 3/7] neighbour: Allocate skb in neigh_get() Kuniyuki Iwashima
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Kuniyuki Iwashima @ 2025-04-16  0:41 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev

We will remove RTNL for neigh_get() and run it under RCU instead.

neigh_get() returns -EINVAL in the following cases:

  * NDA_DST is not specified
  * Both ndm->ndm_ifindex and NTF_PROXY are not specified

These validations do not require RCU.

Let's move them to neigh_valid_get_req().

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
 net/core/neighbour.c | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 8384a025e7c0..af84515fb86a 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2872,6 +2872,11 @@ static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh,
 		goto err;
 	}
 
+	if (!(ndm->ndm_flags & NTF_PROXY) && !ndm->ndm_ifindex) {
+		NL_SET_ERR_MSG(extack, "No device specified");
+		goto err;
+	}
+
 	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct ndmsg), tb,
 					    NDA_MAX, nda_policy, extack);
 	if (err < 0)
@@ -2885,11 +2890,13 @@ static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh,
 	}
 
 	for (i = 0; i <= NDA_MAX; ++i) {
-		if (!tb[i])
-			continue;
-
 		switch (i) {
 		case NDA_DST:
+			if (!tb[i]) {
+				NL_SET_ERR_MSG(extack, "Network address not specified");
+				goto err;
+			}
+
 			if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
 				NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
 				goto err;
@@ -2897,6 +2904,9 @@ static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh,
 			*dst = nla_data(tb[i]);
 			break;
 		default:
+			if (!tb[i])
+				continue;
+
 			NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
 			goto err;
 		}
@@ -2991,11 +3001,6 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 		}
 	}
 
-	if (!dst) {
-		NL_SET_ERR_MSG(extack, "Network address not specified");
-		return -EINVAL;
-	}
-
 	if (ndm->ndm_flags & NTF_PROXY) {
 		struct pneigh_entry *pn;
 
@@ -3008,11 +3013,6 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 					nlh->nlmsg_seq, tbl);
 	}
 
-	if (!dev) {
-		NL_SET_ERR_MSG(extack, "No device specified");
-		return -EINVAL;
-	}
-
 	neigh = neigh_lookup(tbl, dst, dev);
 	if (!neigh) {
 		NL_SET_ERR_MSG(extack, "Neighbour entry not found");
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v1 net-next 3/7] neighbour: Allocate skb in neigh_get().
  2025-04-16  0:41 [PATCH v1 net-next 0/7] neighbour: Convert RTM_GETNEIGH and RTM_{GET,SET}NEIGHTBL to RCU Kuniyuki Iwashima
  2025-04-16  0:41 ` [PATCH v1 net-next 1/7] neighbour: Make neigh_valid_get_req() return ndmsg Kuniyuki Iwashima
  2025-04-16  0:41 ` [PATCH v1 net-next 2/7] neighbour: Move two validations from neigh_get() to neigh_valid_get_req() Kuniyuki Iwashima
@ 2025-04-16  0:41 ` Kuniyuki Iwashima
  2025-04-16  0:41 ` [PATCH v1 net-next 4/7] neighbour: Move neigh_find_table() to neigh_get() Kuniyuki Iwashima
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Kuniyuki Iwashima @ 2025-04-16  0:41 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev

We will remove RTNL for neigh_get() and run it under RCU instead.

neigh_get_reply() and pneigh_get_reply() allocate skb with GFP_KERNEL.

Let's move the allocation before __dev_get_by_index() in neigh_get().

Now, neigh_get_reply() and pneigh_get_reply() are inlined and
rtnl_unicast() is factorised.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
 net/core/neighbour.c | 88 ++++++++++++++++----------------------------
 1 file changed, 32 insertions(+), 56 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index af84515fb86a..297954ff13a8 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2928,27 +2928,6 @@ static inline size_t neigh_nlmsg_size(void)
 	       + nla_total_size(1); /* NDA_PROTOCOL */
 }
 
-static int neigh_get_reply(struct net *net, struct neighbour *neigh,
-			   u32 pid, u32 seq)
-{
-	struct sk_buff *skb;
-	int err = 0;
-
-	skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
-	if (!skb)
-		return -ENOBUFS;
-
-	err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
-	if (err) {
-		kfree_skb(skb);
-		goto errout;
-	}
-
-	err = rtnl_unicast(skb, net, pid);
-errout:
-	return err;
-}
-
 static inline size_t pneigh_nlmsg_size(void)
 {
 	return NLMSG_ALIGN(sizeof(struct ndmsg))
@@ -2957,34 +2936,16 @@ static inline size_t pneigh_nlmsg_size(void)
 	       + nla_total_size(1); /* NDA_PROTOCOL */
 }
 
-static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
-			    u32 pid, u32 seq, struct neigh_table *tbl)
-{
-	struct sk_buff *skb;
-	int err = 0;
-
-	skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
-	if (!skb)
-		return -ENOBUFS;
-
-	err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
-	if (err) {
-		kfree_skb(skb);
-		goto errout;
-	}
-
-	err = rtnl_unicast(skb, net, pid);
-errout:
-	return err;
-}
-
 static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 		     struct netlink_ext_ack *extack)
 {
 	struct net *net = sock_net(in_skb->sk);
+	u32 pid = NETLINK_CB(in_skb).portid;
 	struct net_device *dev = NULL;
 	struct neigh_table *tbl = NULL;
+	u32 seq = nlh->nlmsg_seq;
 	struct neighbour *neigh;
+	struct sk_buff *skb;
 	struct ndmsg *ndm;
 	void *dst = NULL;
 	int err;
@@ -2993,11 +2954,19 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 	if (IS_ERR(ndm))
 		return PTR_ERR(ndm);
 
+	if (ndm->ndm_flags & NTF_PROXY)
+		skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
+	else
+		skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
+	if (!skb)
+		return -ENOBUFS;
+
 	if (ndm->ndm_ifindex) {
 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
 		if (!dev) {
 			NL_SET_ERR_MSG(extack, "Unknown device ifindex");
-			return -ENODEV;
+			err = -ENODEV;
+			goto err;
 		}
 	}
 
@@ -3007,23 +2976,30 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 		pn = pneigh_lookup(tbl, net, dst, dev, 0);
 		if (!pn) {
 			NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
-			return -ENOENT;
+			err = -ENOENT;
+			goto err;
 		}
-		return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
-					nlh->nlmsg_seq, tbl);
-	}
-
-	neigh = neigh_lookup(tbl, dst, dev);
-	if (!neigh) {
-		NL_SET_ERR_MSG(extack, "Neighbour entry not found");
-		return -ENOENT;
-	}
 
-	err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
-			      nlh->nlmsg_seq);
+		err = pneigh_fill_info(skb, pn, pid, seq, RTM_NEWNEIGH, 0, tbl);
+		if (err)
+			goto err;
+	} else {
+		neigh = neigh_lookup(tbl, dst, dev);
+		if (!neigh) {
+			NL_SET_ERR_MSG(extack, "Neighbour entry not found");
+			err = -ENOENT;
+			goto err;
+		}
 
-	neigh_release(neigh);
+		err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
+		neigh_release(neigh);
+		if (err)
+			goto err;
+	}
 
+	return rtnl_unicast(skb, net, pid);
+err:
+	kfree_skb(skb);
 	return err;
 }
 
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v1 net-next 4/7] neighbour: Move neigh_find_table() to neigh_get().
  2025-04-16  0:41 [PATCH v1 net-next 0/7] neighbour: Convert RTM_GETNEIGH and RTM_{GET,SET}NEIGHTBL to RCU Kuniyuki Iwashima
                   ` (2 preceding siblings ...)
  2025-04-16  0:41 ` [PATCH v1 net-next 3/7] neighbour: Allocate skb in neigh_get() Kuniyuki Iwashima
@ 2025-04-16  0:41 ` Kuniyuki Iwashima
  2025-04-16  0:41 ` [PATCH v1 net-next 5/7] neighbour: Convert RTM_GETNEIGH to RCU Kuniyuki Iwashima
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Kuniyuki Iwashima @ 2025-04-16  0:41 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev

neigh_valid_get_req() calls neigh_find_table() to fetch neigh_tables[].

neigh_find_table() uses rcu_dereference_rtnl(), but RTNL actually does
not protect it at all; neigh_table_clear() can be called without RTNL
and only waits for RCU readers by synchronize_rcu().

Fortunately, there is no bug because IPv4 is built-in, IPv6 cannot be
unloaded, and DECNET was removed.

To fetch neigh_tables[] by rcu_dereference() later, let's move
neigh_find_table() from neigh_valid_get_req() to neigh_get().

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
 net/core/neighbour.c | 38 ++++++++++++++++++++------------------
 1 file changed, 20 insertions(+), 18 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 297954ff13a8..58a6821dae3d 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2847,10 +2847,9 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 }
 
 static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh,
-					 struct neigh_table **tbl, void **dst,
+					 struct nlattr **tb,
 					 struct netlink_ext_ack *extack)
 {
-	struct nlattr *tb[NDA_MAX + 1];
 	struct ndmsg *ndm;
 	int err = -EINVAL;
 	int i;
@@ -2882,13 +2881,6 @@ static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh,
 	if (err < 0)
 		goto err;
 
-	*tbl = neigh_find_table(ndm->ndm_family);
-	if (!*tbl) {
-		NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
-		err = -EAFNOSUPPORT;
-		goto err;
-	}
-
 	for (i = 0; i <= NDA_MAX; ++i) {
 		switch (i) {
 		case NDA_DST:
@@ -2896,12 +2888,6 @@ static struct ndmsg *neigh_valid_get_req(const struct nlmsghdr *nlh,
 				NL_SET_ERR_MSG(extack, "Network address not specified");
 				goto err;
 			}
-
-			if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
-				NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
-				goto err;
-			}
-			*dst = nla_data(tb[i]);
 			break;
 		default:
 			if (!tb[i])
@@ -2941,16 +2927,17 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 {
 	struct net *net = sock_net(in_skb->sk);
 	u32 pid = NETLINK_CB(in_skb).portid;
+	struct nlattr *tb[NDA_MAX + 1];
 	struct net_device *dev = NULL;
-	struct neigh_table *tbl = NULL;
 	u32 seq = nlh->nlmsg_seq;
+	struct neigh_table *tbl;
 	struct neighbour *neigh;
 	struct sk_buff *skb;
 	struct ndmsg *ndm;
-	void *dst = NULL;
+	void *dst;
 	int err;
 
-	ndm = neigh_valid_get_req(nlh, &tbl, &dst, extack);
+	ndm = neigh_valid_get_req(nlh, tb, extack);
 	if (IS_ERR(ndm))
 		return PTR_ERR(ndm);
 
@@ -2961,6 +2948,21 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 	if (!skb)
 		return -ENOBUFS;
 
+	tbl = neigh_find_table(ndm->ndm_family);
+	if (!tbl) {
+		NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
+		err = -EAFNOSUPPORT;
+		goto err;
+	}
+
+	if (nla_len(tb[NDA_DST]) != (int)tbl->key_len) {
+		NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
+		err = -EINVAL;
+		goto err;
+	}
+
+	dst = nla_data(tb[NDA_DST]);
+
 	if (ndm->ndm_ifindex) {
 		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
 		if (!dev) {
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v1 net-next 5/7] neighbour: Convert RTM_GETNEIGH to RCU.
  2025-04-16  0:41 [PATCH v1 net-next 0/7] neighbour: Convert RTM_GETNEIGH and RTM_{GET,SET}NEIGHTBL to RCU Kuniyuki Iwashima
                   ` (3 preceding siblings ...)
  2025-04-16  0:41 ` [PATCH v1 net-next 4/7] neighbour: Move neigh_find_table() to neigh_get() Kuniyuki Iwashima
@ 2025-04-16  0:41 ` Kuniyuki Iwashima
  2025-04-16  0:41 ` [PATCH v1 net-next 6/7] neighbour: Convert RTM_GETNEIGHTBL " Kuniyuki Iwashima
  2025-04-16  0:41 ` [PATCH v1 net-next 7/7] neighbour: Convert RTM_SETNEIGHTBL " Kuniyuki Iwashima
  6 siblings, 0 replies; 10+ messages in thread
From: Kuniyuki Iwashima @ 2025-04-16  0:41 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev

Only __dev_get_by_index() is the RTNL dependant in neigh_get().

Let's replace it with dev_get_by_index_rcu() and convert RTM_GETNEIGH
to RCU.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
 net/core/neighbour.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 58a6821dae3d..698999398747 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2948,6 +2948,8 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 	if (!skb)
 		return -ENOBUFS;
 
+	rcu_read_lock();
+
 	tbl = neigh_find_table(ndm->ndm_family);
 	if (!tbl) {
 		NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
@@ -2964,7 +2966,7 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 	dst = nla_data(tb[NDA_DST]);
 
 	if (ndm->ndm_ifindex) {
-		dev = __dev_get_by_index(net, ndm->ndm_ifindex);
+		dev = dev_get_by_index_rcu(net, ndm->ndm_ifindex);
 		if (!dev) {
 			NL_SET_ERR_MSG(extack, "Unknown device ifindex");
 			err = -ENODEV;
@@ -2999,8 +3001,11 @@ static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
 			goto err;
 	}
 
+	rcu_read_unlock();
+
 	return rtnl_unicast(skb, net, pid);
 err:
+	rcu_read_unlock();
 	kfree_skb(skb);
 	return err;
 }
@@ -3800,7 +3805,7 @@ static const struct rtnl_msg_handler neigh_rtnl_msg_handlers[] __initconst = {
 	{.msgtype = RTM_NEWNEIGH, .doit = neigh_add},
 	{.msgtype = RTM_DELNEIGH, .doit = neigh_delete},
 	{.msgtype = RTM_GETNEIGH, .doit = neigh_get, .dumpit = neigh_dump_info,
-	 .flags = RTNL_FLAG_DUMP_UNLOCKED},
+	 .flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED},
 	{.msgtype = RTM_GETNEIGHTBL, .dumpit = neightbl_dump_info},
 	{.msgtype = RTM_SETNEIGHTBL, .doit = neightbl_set},
 };
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v1 net-next 6/7] neighbour: Convert RTM_GETNEIGHTBL to RCU.
  2025-04-16  0:41 [PATCH v1 net-next 0/7] neighbour: Convert RTM_GETNEIGH and RTM_{GET,SET}NEIGHTBL to RCU Kuniyuki Iwashima
                   ` (4 preceding siblings ...)
  2025-04-16  0:41 ` [PATCH v1 net-next 5/7] neighbour: Convert RTM_GETNEIGH to RCU Kuniyuki Iwashima
@ 2025-04-16  0:41 ` Kuniyuki Iwashima
  2025-04-16  0:41 ` [PATCH v1 net-next 7/7] neighbour: Convert RTM_SETNEIGHTBL " Kuniyuki Iwashima
  6 siblings, 0 replies; 10+ messages in thread
From: Kuniyuki Iwashima @ 2025-04-16  0:41 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev

neightbl_dump_info() calls neightbl_fill_info() and
neightbl_fill_param_info() for each neigh_tables[] entry.

Both functions rely on the table lock (read_lock_bh(&tbl->lock)),
so RTNL is not needed.

Let's fetch the table under RCU and convert RTM_GETNEIGHTBL to RCU.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
 net/core/neighbour.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 698999398747..817f0bdc1861 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2467,10 +2467,12 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 
 	family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family;
 
+	rcu_read_lock();
+
 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
 		struct neigh_parms *p;
 
-		tbl = rcu_dereference_rtnl(neigh_tables[tidx]);
+		tbl = rcu_dereference(neigh_tables[tidx]);
 		if (!tbl)
 			continue;
 
@@ -2504,6 +2506,8 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
 		neigh_skip = 0;
 	}
 out:
+	rcu_read_unlock();
+
 	cb->args[0] = tidx;
 	cb->args[1] = nidx;
 
@@ -3806,7 +3810,8 @@ static const struct rtnl_msg_handler neigh_rtnl_msg_handlers[] __initconst = {
 	{.msgtype = RTM_DELNEIGH, .doit = neigh_delete},
 	{.msgtype = RTM_GETNEIGH, .doit = neigh_get, .dumpit = neigh_dump_info,
 	 .flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED},
-	{.msgtype = RTM_GETNEIGHTBL, .dumpit = neightbl_dump_info},
+	{.msgtype = RTM_GETNEIGHTBL, .dumpit = neightbl_dump_info,
+	 .flags = RTNL_FLAG_DUMP_UNLOCKED},
 	{.msgtype = RTM_SETNEIGHTBL, .doit = neightbl_set},
 };
 
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v1 net-next 7/7] neighbour: Convert RTM_SETNEIGHTBL to RCU.
  2025-04-16  0:41 [PATCH v1 net-next 0/7] neighbour: Convert RTM_GETNEIGH and RTM_{GET,SET}NEIGHTBL to RCU Kuniyuki Iwashima
                   ` (5 preceding siblings ...)
  2025-04-16  0:41 ` [PATCH v1 net-next 6/7] neighbour: Convert RTM_GETNEIGHTBL " Kuniyuki Iwashima
@ 2025-04-16  0:41 ` Kuniyuki Iwashima
  6 siblings, 0 replies; 10+ messages in thread
From: Kuniyuki Iwashima @ 2025-04-16  0:41 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Simon Horman, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev

neightbl_set() fetches neigh_tables[] and updates attributes under
write_lock_bh(&tbl->lock), so RTNL is not needed.

Let's fetch the table under RCU and drop RTNL for RTM_SETNEIGHTBL.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
 net/core/neighbour.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 817f0bdc1861..6b24353571d1 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -2281,8 +2281,10 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	ndtmsg = nlmsg_data(nlh);
 
+	rcu_read_lock();
+
 	for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) {
-		tbl = rcu_dereference_rtnl(neigh_tables[tidx]);
+		tbl = rcu_dereference(neigh_tables[tidx]);
 		if (!tbl)
 			continue;
 		if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family)
@@ -2293,8 +2295,10 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
 		}
 	}
 
-	if (!found)
-		return -ENOENT;
+	if (!found) {
+		err = -ENOENT;
+		goto errout_rcu;
+	}
 
 	/*
 	 * We acquire tbl->lock to be nice to the periodic timers and
@@ -2421,6 +2425,8 @@ static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 errout_tbl_lock:
 	write_unlock_bh(&tbl->lock);
+errout_rcu:
+	rcu_read_unlock();
 errout:
 	return err;
 }
@@ -3812,7 +3818,8 @@ static const struct rtnl_msg_handler neigh_rtnl_msg_handlers[] __initconst = {
 	 .flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED},
 	{.msgtype = RTM_GETNEIGHTBL, .dumpit = neightbl_dump_info,
 	 .flags = RTNL_FLAG_DUMP_UNLOCKED},
-	{.msgtype = RTM_SETNEIGHTBL, .doit = neightbl_set},
+	{.msgtype = RTM_SETNEIGHTBL, .doit = neightbl_set,
+	 .flags = RTNL_FLAG_DOIT_UNLOCKED},
 };
 
 static int __init neigh_init(void)
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 net-next 1/7] neighbour: Make neigh_valid_get_req() return ndmsg.
  2025-04-16  0:41 ` [PATCH v1 net-next 1/7] neighbour: Make neigh_valid_get_req() return ndmsg Kuniyuki Iwashima
@ 2025-04-17 12:53   ` Simon Horman
  2025-04-17 20:57   ` Kuniyuki Iwashima
  1 sibling, 0 replies; 10+ messages in thread
From: Simon Horman @ 2025-04-17 12:53 UTC (permalink / raw)
  To: Kuniyuki Iwashima
  Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Kuniyuki Iwashima, netdev

On Tue, Apr 15, 2025 at 05:41:24PM -0700, Kuniyuki Iwashima wrote:
> neigh_get() passes 4 local variable pointers to neigh_valid_get_req().
> 
> If it returns a pointer of struct ndmsg, we do not need to pass two
> of them.
> 
> Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>

...

> @@ -2893,17 +2892,19 @@ static int neigh_valid_get_req(const struct nlmsghdr *nlh,
>  		case NDA_DST:
>  			if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
>  				NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
> -				return -EINVAL;

Hi Iwashima-san,

I think you need the following here:

				err = -EINVAL;

> +				goto err;
>  			}
>  			*dst = nla_data(tb[i]);
>  			break;
>  		default:
>  			NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
> -			return -EINVAL;

And here.

Flagged by Smatch as:

  .../neighbour.c:2907 neigh_valid_get_req() warn: passing zero to 'ERR_PTR'

> +			goto err;
>  		}
>  	}
>  
> -	return 0;
> +	return ndm;
> +err:
> +	return ERR_PTR(err);
>  }
>  
>  static inline size_t neigh_nlmsg_size(void)

...

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH v1 net-next 1/7] neighbour: Make neigh_valid_get_req() return ndmsg.
  2025-04-16  0:41 ` [PATCH v1 net-next 1/7] neighbour: Make neigh_valid_get_req() return ndmsg Kuniyuki Iwashima
  2025-04-17 12:53   ` Simon Horman
@ 2025-04-17 20:57   ` Kuniyuki Iwashima
  1 sibling, 0 replies; 10+ messages in thread
From: Kuniyuki Iwashima @ 2025-04-17 20:57 UTC (permalink / raw)
  To: kuniyu; +Cc: davem, edumazet, horms, kuba, kuni1840, netdev, pabeni

From: Simon Horman <horms@kernel.org>
Date: Thu, 17 Apr 2025 13:53:10 +0100
> On Tue, Apr 15, 2025 at 05:41:24PM -0700, Kuniyuki Iwashima wrote:
> > neigh_get() passes 4 local variable pointers to neigh_valid_get_req().
> > 
> > If it returns a pointer of struct ndmsg, we do not need to pass two
> > of them.
> > 
> > Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
> 
> ...
> 
> > @@ -2893,17 +2892,19 @@ static int neigh_valid_get_req(const struct nlmsghdr *nlh,
> >  		case NDA_DST:
> >  			if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
> >  				NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
> > -				return -EINVAL;
> 
> Hi Iwashima-san,
> 
> I think you need the following here:
> 
> 				err = -EINVAL;
> 
> > +				goto err;
> >  			}
> >  			*dst = nla_data(tb[i]);
> >  			break;
> >  		default:
> >  			NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
> > -			return -EINVAL;
> 
> And here.
> 
> Flagged by Smatch as:
> 
>   .../neighbour.c:2907 neigh_valid_get_req() warn: passing zero to 'ERR_PTR'
> 
> > +			goto err;

Thanks for catching!

I missed nlmsg_parse_deprecated_strict() reset err to 0.

I'll explicitly set err before goto in every path instead of
initialising it first.


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-04-17 20:59 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-16  0:41 [PATCH v1 net-next 0/7] neighbour: Convert RTM_GETNEIGH and RTM_{GET,SET}NEIGHTBL to RCU Kuniyuki Iwashima
2025-04-16  0:41 ` [PATCH v1 net-next 1/7] neighbour: Make neigh_valid_get_req() return ndmsg Kuniyuki Iwashima
2025-04-17 12:53   ` Simon Horman
2025-04-17 20:57   ` Kuniyuki Iwashima
2025-04-16  0:41 ` [PATCH v1 net-next 2/7] neighbour: Move two validations from neigh_get() to neigh_valid_get_req() Kuniyuki Iwashima
2025-04-16  0:41 ` [PATCH v1 net-next 3/7] neighbour: Allocate skb in neigh_get() Kuniyuki Iwashima
2025-04-16  0:41 ` [PATCH v1 net-next 4/7] neighbour: Move neigh_find_table() to neigh_get() Kuniyuki Iwashima
2025-04-16  0:41 ` [PATCH v1 net-next 5/7] neighbour: Convert RTM_GETNEIGH to RCU Kuniyuki Iwashima
2025-04-16  0:41 ` [PATCH v1 net-next 6/7] neighbour: Convert RTM_GETNEIGHTBL " Kuniyuki Iwashima
2025-04-16  0:41 ` [PATCH v1 net-next 7/7] neighbour: Convert RTM_SETNEIGHTBL " Kuniyuki Iwashima

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).