All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Ahern <dsahern@kernel.org>
To: netdev@vger.kernel.org
Cc: davem@davemloft.net, roopa@cumulusnetworks.com,
	David Ahern <dsahern@gmail.com>
Subject: [PATCH net-next 5/5] neighbor: Remove externally learned entries from gc_list
Date: Tue, 11 Dec 2018 18:57:25 -0700	[thread overview]
Message-ID: <20181212015725.12297-6-dsahern@kernel.org> (raw)
In-Reply-To: <20181212015725.12297-1-dsahern@kernel.org>

From: David Ahern <dsahern@gmail.com>

Externally learned entries are similar to PERMANENT entries in the
sense they are managed by userspace and can not be garbage collected.
As such remove them from the gc_list, remove the flags check from
neigh_forced_gc and skip threshold checks in neigh_alloc. As with
PERMANENT entries, this allows unlimited number of NTF_EXT_LEARNED
entries.

Signed-off-by: David Ahern <dsahern@gmail.com>
---
 net/core/neighbour.c | 49 ++++++++++++++++++++++++++++---------------------
 1 file changed, 28 insertions(+), 21 deletions(-)

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 2401040f799b..42b413774370 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -129,21 +129,22 @@ static void neigh_mark_dead(struct neighbour *n)
 
 static void neigh_update_gc_list(struct neighbour *n)
 {
-	bool on_gc_list, new_is_perm;
+	bool on_gc_list, exempt_from_gc;
 
 	write_lock_bh(&n->tbl->lock);
 	write_lock(&n->lock);
 
-	/* remove from the gc list if new state is permanent;
-	 * add to the gc list if new state is not permanent
+	/* remove from the gc list if new state is permanent or if neighbor
+	 * is externally learned; otherwise entry should be on the gc list
 	 */
-	new_is_perm = n->nud_state & NUD_PERMANENT;
+	exempt_from_gc = n->nud_state & NUD_PERMANENT ||
+			 n->flags & NTF_EXT_LEARNED;
 	on_gc_list = !list_empty(&n->gc_list);
 
-	if (new_is_perm && on_gc_list) {
+	if (exempt_from_gc && on_gc_list) {
 		list_del_init(&n->gc_list);
 		atomic_dec(&n->tbl->gc_entries);
-	} else if (!new_is_perm && !on_gc_list) {
+	} else if (!exempt_from_gc && !on_gc_list) {
 		/* add entries to the tail; cleaning removes from the front */
 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
 		atomic_inc(&n->tbl->gc_entries);
@@ -153,13 +154,14 @@ static void neigh_update_gc_list(struct neighbour *n)
 	write_unlock_bh(&n->tbl->lock);
 }
 
-static void neigh_update_ext_learned(struct neighbour *neigh, u32 flags,
+static bool neigh_update_ext_learned(struct neighbour *neigh, u32 flags,
 				     int *notify)
 {
+	bool rc = false;
 	u8 ndm_flags;
 
 	if (!(flags & NEIGH_UPDATE_F_ADMIN))
-		return;
+		return rc;
 
 	ndm_flags = (flags & NEIGH_UPDATE_F_EXT_LEARNED) ? NTF_EXT_LEARNED : 0;
 	if ((neigh->flags ^ ndm_flags) & NTF_EXT_LEARNED) {
@@ -167,8 +169,11 @@ static void neigh_update_ext_learned(struct neighbour *neigh, u32 flags,
 			neigh->flags |= NTF_EXT_LEARNED;
 		else
 			neigh->flags &= ~NTF_EXT_LEARNED;
+		rc = true;
 		*notify = 1;
 	}
+
+	return rc;
 }
 
 static bool neigh_del(struct neighbour *n, struct neighbour __rcu **np,
@@ -219,7 +224,6 @@ static int neigh_forced_gc(struct neigh_table *tbl)
 {
 	int max_clean = atomic_read(&tbl->gc_entries) - tbl->gc_thresh2;
 	unsigned long tref = jiffies - 5 * HZ;
-	u8 flags = NTF_EXT_LEARNED;
 	struct neighbour *n, *tmp;
 	int shrunk = 0;
 
@@ -233,7 +237,7 @@ static int neigh_forced_gc(struct neigh_table *tbl)
 
 			write_lock(&n->lock);
 			if ((n->nud_state == NUD_FAILED) ||
-			    (!(n->flags & flags) && time_after(tref, n->updated)))
+			    time_after(tref, n->updated))
 				remove = true;
 			write_unlock(&n->lock);
 
@@ -371,13 +375,13 @@ EXPORT_SYMBOL(neigh_ifdown);
 
 static struct neighbour *neigh_alloc(struct neigh_table *tbl,
 				     struct net_device *dev,
-				     bool permanent)
+				     bool exempt_from_gc)
 {
 	struct neighbour *n = NULL;
 	unsigned long now = jiffies;
 	int entries;
 
-	if (permanent)
+	if (exempt_from_gc)
 		goto do_alloc;
 
 	entries = atomic_inc_return(&tbl->gc_entries) - 1;
@@ -419,7 +423,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl,
 	return n;
 
 out_entries:
-	if (!permanent)
+	if (!exempt_from_gc)
 		atomic_dec(&tbl->gc_entries);
 	goto out;
 }
@@ -566,9 +570,9 @@ EXPORT_SYMBOL(neigh_lookup_nodev);
 static struct neighbour *___neigh_create(struct neigh_table *tbl,
 					 const void *pkey,
 					 struct net_device *dev,
-					 bool permanent, bool want_ref)
+					 bool exempt_from_gc, bool want_ref)
 {
-	struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev, permanent);
+	struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev, exempt_from_gc);
 	u32 hash_val;
 	unsigned int key_len = tbl->key_len;
 	int error;
@@ -634,7 +638,7 @@ static struct neighbour *___neigh_create(struct neigh_table *tbl,
 	}
 
 	n->dead = 0;
-	if (!permanent)
+	if (!exempt_from_gc)
 		list_add_tail(&n->gc_list, &n->tbl->gc_list);
 
 	if (want_ref)
@@ -1210,6 +1214,7 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
 			  u8 new, u32 flags, u32 nlmsg_pid,
 			  struct netlink_ext_ack *extack)
 {
+	bool ext_learn_change = false;
 	u8 old;
 	int err;
 	int notify = 0;
@@ -1230,7 +1235,7 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
 		goto out;
 	}
 
-	neigh_update_ext_learned(neigh, flags, &notify);
+	ext_learn_change = neigh_update_ext_learned(neigh, flags, &notify);
 
 	if (!(new & NUD_VALID)) {
 		neigh_del_timer(neigh);
@@ -1376,7 +1381,7 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
 		neigh_update_is_router(neigh, flags, &notify);
 	write_unlock_bh(&neigh->lock);
 
-	if ((new ^ old) & NUD_PERMANENT)
+	if (((new ^ old) & NUD_PERMANENT) || ext_learn_change)
 		neigh_update_gc_list(neigh);
 
 	if (notify)
@@ -1881,14 +1886,16 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 	neigh = neigh_lookup(tbl, dst, dev);
 	if (neigh == NULL) {
+		bool exempt_from_gc;
+
 		if (!(nlh->nlmsg_flags & NLM_F_CREATE)) {
 			err = -ENOENT;
 			goto out;
 		}
 
-		neigh = ___neigh_create(tbl, dst, dev,
-					ndm->ndm_state & NUD_PERMANENT,
-					true);
+		exempt_from_gc = ndm->ndm_state & NUD_PERMANENT ||
+				 ndm->ndm_flags & NTF_EXT_LEARNED;
+		neigh = ___neigh_create(tbl, dst, dev, exempt_from_gc, true);
 		if (IS_ERR(neigh)) {
 			err = PTR_ERR(neigh);
 			goto out;
-- 
2.11.0

  parent reply	other threads:[~2018-12-12  1:57 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-12  1:57 [PATCH net-next 0/5] neighbor: More gc_list changes David Ahern
2018-12-12  1:57 ` [PATCH net-next 1/5] neighbor: Fix locking order for " David Ahern
2018-12-12  1:57 ` [PATCH net-next 2/5] neighbor: Fix state check in neigh_forced_gc David Ahern
2018-12-12  1:57 ` [PATCH net-next 3/5] neighbor: Remove state and flags arguments to neigh_del David Ahern
2018-12-12  1:57 ` [PATCH net-next 4/5] neighbor: Move neigh_update_ext_learned to core file David Ahern
2018-12-12  1:57 ` David Ahern [this message]
2018-12-14 23:45 ` [PATCH net-next 0/5] neighbor: More gc_list changes David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181212015725.12297-6-dsahern@kernel.org \
    --to=dsahern@kernel.org \
    --cc=davem@davemloft.net \
    --cc=dsahern@gmail.com \
    --cc=netdev@vger.kernel.org \
    --cc=roopa@cumulusnetworks.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.