From mboxrd@z Thu Jan 1 00:00:00 1970 From: David Ahern Subject: [PATCH net-next 5/5] neighbor: Remove externally learned entries from gc_list Date: Tue, 11 Dec 2018 18:57:25 -0700 Message-ID: <20181212015725.12297-6-dsahern@kernel.org> References: <20181212015725.12297-1-dsahern@kernel.org> Cc: davem@davemloft.net, roopa@cumulusnetworks.com, David Ahern To: netdev@vger.kernel.org Return-path: Received: from mail.kernel.org ([198.145.29.99]:53624 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726362AbeLLB5d (ORCPT ); Tue, 11 Dec 2018 20:57:33 -0500 In-Reply-To: <20181212015725.12297-1-dsahern@kernel.org> Sender: netdev-owner@vger.kernel.org List-ID: From: David Ahern 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 --- 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, ¬ify); + ext_learn_change = neigh_update_ext_learned(neigh, flags, ¬ify); 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, ¬ify); 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