Commit e4400bbf authored by Daniel Borkmann's avatar Daniel Borkmann Committed by David S. Miller

net, neigh: Fix NTF_EXT_LEARNED in combination with NTF_USE

The NTF_EXT_LEARNED neigh flag is usually propagated back to user space
upon dump of the neighbor table. However, when used in combination with
NTF_USE flag this is not the case despite exempting the entry from the
garbage collector. This results in inconsistent state since entries are
typically marked in neigh->flags with NTF_EXT_LEARNED, but here they are
not. Fix it by propagating the creation flag to ___neigh_create().

Before fix:

  # ./ip/ip n replace 192.168.178.30 dev enp5s0 use extern_learn
  # ./ip/ip n
  192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a REACHABLE
  [...]

After fix:

  # ./ip/ip n replace 192.168.178.30 dev enp5s0 use extern_learn
  # ./ip/ip n
  192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a extern_learn REACHABLE
  [...]

Fixes: 9ce33e46 ("neighbour: support for NTF_EXT_LEARNED flag")
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarRoopa Prabhu <roopa@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7bb39a39
...@@ -379,7 +379,7 @@ EXPORT_SYMBOL(neigh_ifdown); ...@@ -379,7 +379,7 @@ EXPORT_SYMBOL(neigh_ifdown);
static struct neighbour *neigh_alloc(struct neigh_table *tbl, static struct neighbour *neigh_alloc(struct neigh_table *tbl,
struct net_device *dev, struct net_device *dev,
bool exempt_from_gc) u8 flags, bool exempt_from_gc)
{ {
struct neighbour *n = NULL; struct neighbour *n = NULL;
unsigned long now = jiffies; unsigned long now = jiffies;
...@@ -412,6 +412,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl, ...@@ -412,6 +412,7 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl,
n->updated = n->used = now; n->updated = n->used = now;
n->nud_state = NUD_NONE; n->nud_state = NUD_NONE;
n->output = neigh_blackhole; n->output = neigh_blackhole;
n->flags = flags;
seqlock_init(&n->hh.hh_lock); seqlock_init(&n->hh.hh_lock);
n->parms = neigh_parms_clone(&tbl->parms); n->parms = neigh_parms_clone(&tbl->parms);
timer_setup(&n->timer, neigh_timer_handler, 0); timer_setup(&n->timer, neigh_timer_handler, 0);
...@@ -575,19 +576,18 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, ...@@ -575,19 +576,18 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net,
} }
EXPORT_SYMBOL(neigh_lookup_nodev); EXPORT_SYMBOL(neigh_lookup_nodev);
static struct neighbour *___neigh_create(struct neigh_table *tbl, static struct neighbour *
const void *pkey, ___neigh_create(struct neigh_table *tbl, const void *pkey,
struct net_device *dev, struct net_device *dev, u8 flags,
bool exempt_from_gc, bool want_ref) bool exempt_from_gc, bool want_ref)
{ {
struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev, exempt_from_gc); u32 hash_val, key_len = tbl->key_len;
u32 hash_val; struct neighbour *n1, *rc, *n;
unsigned int key_len = tbl->key_len;
int error;
struct neigh_hash_table *nht; struct neigh_hash_table *nht;
int error;
n = neigh_alloc(tbl, dev, flags, exempt_from_gc);
trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc); trace_neigh_create(tbl, dev, pkey, n, exempt_from_gc);
if (!n) { if (!n) {
rc = ERR_PTR(-ENOBUFS); rc = ERR_PTR(-ENOBUFS);
goto out; goto out;
...@@ -674,7 +674,7 @@ static struct neighbour *___neigh_create(struct neigh_table *tbl, ...@@ -674,7 +674,7 @@ static struct neighbour *___neigh_create(struct neigh_table *tbl,
struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey, struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey,
struct net_device *dev, bool want_ref) struct net_device *dev, bool want_ref)
{ {
return ___neigh_create(tbl, pkey, dev, false, want_ref); return ___neigh_create(tbl, pkey, dev, 0, false, want_ref);
} }
EXPORT_SYMBOL(__neigh_create); EXPORT_SYMBOL(__neigh_create);
...@@ -1942,7 +1942,9 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -1942,7 +1942,9 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
exempt_from_gc = ndm->ndm_state & NUD_PERMANENT || exempt_from_gc = ndm->ndm_state & NUD_PERMANENT ||
ndm->ndm_flags & NTF_EXT_LEARNED; ndm->ndm_flags & NTF_EXT_LEARNED;
neigh = ___neigh_create(tbl, dst, dev, exempt_from_gc, true); neigh = ___neigh_create(tbl, dst, dev,
ndm->ndm_flags & NTF_EXT_LEARNED,
exempt_from_gc, true);
if (IS_ERR(neigh)) { if (IS_ERR(neigh)) {
err = PTR_ERR(neigh); err = PTR_ERR(neigh);
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment