Commit dc2a27e5 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Jakub Kicinski
Browse files

neighbour: Update pneigh_entry in pneigh_create().



neigh_add() updates pneigh_entry() found or created by pneigh_create().

This update is serialised by RTNL, but we will remove it.

Let's move the update part to pneigh_create() and make it return errno
instead of a pointer of pneigh_entry.

Now, the pneigh code is RTNL free.

Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20250716221221.442239-16-kuniyu@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 13a936bb
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -382,8 +382,9 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
		    struct sk_buff *skb);
struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, struct net *net,
				   const void *key, struct net_device *dev);
struct pneigh_entry *pneigh_create(struct neigh_table *tbl, struct net *net,
				   const void *key, struct net_device *dev);
int pneigh_create(struct neigh_table *tbl, struct net *net, const void *key,
		  struct net_device *dev, u32 flags, u8 protocol,
		  bool permanent);
int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *key,
		  struct net_device *dev);

+16 −18
Original line number Diff line number Diff line
@@ -747,24 +747,27 @@ struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl,
}
EXPORT_IPV6_MOD(pneigh_lookup);

struct pneigh_entry *pneigh_create(struct neigh_table *tbl,
				   struct net *net, const void *pkey,
				   struct net_device *dev)
int pneigh_create(struct neigh_table *tbl, struct net *net,
		  const void *pkey, struct net_device *dev,
		  u32 flags, u8 protocol, bool permanent)
{
	struct pneigh_entry *n;
	unsigned int key_len;
	u32 hash_val;
	int err = 0;

	mutex_lock(&tbl->phash_lock);

	n = pneigh_lookup(tbl, net, pkey, dev);
	if (n)
		goto out;
		goto update;

	key_len = tbl->key_len;
	n = kzalloc(sizeof(*n) + key_len, GFP_KERNEL);
	if (!n)
	if (!n) {
		err = -ENOBUFS;
		goto out;
	}

	write_pnet(&n->net, net);
	memcpy(n->key, pkey, key_len);
@@ -774,16 +777,20 @@ struct pneigh_entry *pneigh_create(struct neigh_table *tbl,
	if (tbl->pconstructor && tbl->pconstructor(n)) {
		netdev_put(dev, &n->dev_tracker);
		kfree(n);
		n = NULL;
		err = -ENOBUFS;
		goto out;
	}

	hash_val = pneigh_hash(pkey, key_len);
	n->next = tbl->phash_buckets[hash_val];
	rcu_assign_pointer(tbl->phash_buckets[hash_val], n);
update:
	WRITE_ONCE(n->flags, flags);
	n->permanent = permanent;
	WRITE_ONCE(n->protocol, protocol);
out:
	mutex_unlock(&tbl->phash_lock);
	return n;
	return err;
}

static void pneigh_destroy(struct rcu_head *rcu)
@@ -2015,22 +2022,13 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
	if (tb[NDA_PROTOCOL])
		protocol = nla_get_u8(tb[NDA_PROTOCOL]);
	if (ndm_flags & NTF_PROXY) {
		struct pneigh_entry *pn;

		if (ndm_flags & (NTF_MANAGED | NTF_EXT_VALIDATED)) {
			NL_SET_ERR_MSG(extack, "Invalid NTF_* flag combination");
			goto out;
		}

		err = -ENOBUFS;
		pn = pneigh_create(tbl, net, dst, dev);
		if (pn) {
			WRITE_ONCE(pn->flags, ndm_flags);
			pn->permanent = !!(ndm->ndm_state & NUD_PERMANENT);
			if (protocol)
				WRITE_ONCE(pn->protocol, protocol);
			err = 0;
		}
		err = pneigh_create(tbl, net, dst, dev, ndm_flags, protocol,
				    !!(ndm->ndm_state & NUD_PERMANENT));
		goto out;
	}

+1 −3
Original line number Diff line number Diff line
@@ -1089,9 +1089,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
	if (mask) {
		__be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;

		if (!pneigh_create(&arp_tbl, net, &ip, dev))
			return -ENOBUFS;
		return 0;
		return pneigh_create(&arp_tbl, net, &ip, dev, 0, 0, false);
	}

	return arp_req_set_proxy(net, dev, 1);