net, neigh: Enable state migration between NUD_PERMANENT and NTF_USE
[ Upstream commit 3dc20f4762c62d3b3f0940644881ed818aa7b2f5 ] Currently, it is not possible to migrate a neighbor entry between NUD_PERMANENT state and NTF_USE flag with a dynamic NUD state from a user space control plane. Similarly, it is not possible to add/remove NTF_EXT_LEARNED flag from an existing neighbor entry in combination with NTF_USE flag. This is due to the latter directly calling into neigh_event_send() without any meta data updates as happening in __neigh_update(). Thus, to enable this use case, extend the latter with a NEIGH_UPDATE_F_USE flag where we break the NUD_PERMANENT state in particular so that a latter neigh_event_send() is able to re-resolve a neighbor entry. Before fix, NUD_PERMANENT -> NUD_* & NTF_USE: # ./ip/ip n replace 192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a # ./ip/ip n 192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a PERMANENT [...] # ./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 PERMANENT [...] As can be seen, despite the admin-triggered replace, the entry remains in the NUD_PERMANENT state. After fix, NUD_PERMANENT -> NUD_* & NTF_USE: # ./ip/ip n replace 192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a # ./ip/ip n 192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a PERMANENT [...] # ./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 [...] # ./ip/ip n 192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a extern_learn STALE [...] # ./ip/ip n replace 192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a # ./ip/ip n 192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a PERMANENT [...] After the fix, the admin-triggered replace switches to a dynamic state from the NTF_USE flag which triggered a new neighbor resolution. Likewise, we can transition back from there, if needed, into NUD_PERMANENT. Similar before/after behavior can be observed for below transitions: Before fix, NTF_USE -> NTF_USE | NTF_EXT_LEARNED -> NTF_USE: # ./ip/ip n replace 192.168.178.30 dev enp5s0 use # ./ip/ip n 192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a REACHABLE [...] # ./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, NTF_USE -> NTF_USE | NTF_EXT_LEARNED -> NTF_USE: # ./ip/ip n replace 192.168.178.30 dev enp5s0 use # ./ip/ip n 192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a REACHABLE [...] # ./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 [...] # ./ip/ip n replace 192.168.178.30 dev enp5s0 use # ./ip/ip n 192.168.178.30 dev enp5s0 lladdr f4:8c:50:5e:71:9a REACHABLE [..] Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Roopa Prabhu <roopa@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
0bf5c6a1e4
commit
a8cdf34ff8
@ -253,6 +253,7 @@ static inline void *neighbour_priv(const struct neighbour *n)
|
|||||||
#define NEIGH_UPDATE_F_OVERRIDE 0x00000001
|
#define NEIGH_UPDATE_F_OVERRIDE 0x00000001
|
||||||
#define NEIGH_UPDATE_F_WEAK_OVERRIDE 0x00000002
|
#define NEIGH_UPDATE_F_WEAK_OVERRIDE 0x00000002
|
||||||
#define NEIGH_UPDATE_F_OVERRIDE_ISROUTER 0x00000004
|
#define NEIGH_UPDATE_F_OVERRIDE_ISROUTER 0x00000004
|
||||||
|
#define NEIGH_UPDATE_F_USE 0x10000000
|
||||||
#define NEIGH_UPDATE_F_EXT_LEARNED 0x20000000
|
#define NEIGH_UPDATE_F_EXT_LEARNED 0x20000000
|
||||||
#define NEIGH_UPDATE_F_ISROUTER 0x40000000
|
#define NEIGH_UPDATE_F_ISROUTER 0x40000000
|
||||||
#define NEIGH_UPDATE_F_ADMIN 0x80000000
|
#define NEIGH_UPDATE_F_ADMIN 0x80000000
|
||||||
|
@ -1222,7 +1222,7 @@ static void neigh_update_hhs(struct neighbour *neigh)
|
|||||||
lladdr instead of overriding it
|
lladdr instead of overriding it
|
||||||
if it is different.
|
if it is different.
|
||||||
NEIGH_UPDATE_F_ADMIN means that the change is administrative.
|
NEIGH_UPDATE_F_ADMIN means that the change is administrative.
|
||||||
|
NEIGH_UPDATE_F_USE means that the entry is user triggered.
|
||||||
NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
|
NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing
|
||||||
NTF_ROUTER flag.
|
NTF_ROUTER flag.
|
||||||
NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
|
NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as
|
||||||
@ -1260,6 +1260,12 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ext_learn_change = neigh_update_ext_learned(neigh, flags, ¬ify);
|
ext_learn_change = neigh_update_ext_learned(neigh, flags, ¬ify);
|
||||||
|
if (flags & NEIGH_UPDATE_F_USE) {
|
||||||
|
new = old & ~NUD_PERMANENT;
|
||||||
|
neigh->nud_state = new;
|
||||||
|
err = 0;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(new & NUD_VALID)) {
|
if (!(new & NUD_VALID)) {
|
||||||
neigh_del_timer(neigh);
|
neigh_del_timer(neigh);
|
||||||
@ -1971,22 +1977,20 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||||||
|
|
||||||
if (protocol)
|
if (protocol)
|
||||||
neigh->protocol = protocol;
|
neigh->protocol = protocol;
|
||||||
|
|
||||||
if (ndm->ndm_flags & NTF_EXT_LEARNED)
|
if (ndm->ndm_flags & NTF_EXT_LEARNED)
|
||||||
flags |= NEIGH_UPDATE_F_EXT_LEARNED;
|
flags |= NEIGH_UPDATE_F_EXT_LEARNED;
|
||||||
|
|
||||||
if (ndm->ndm_flags & NTF_ROUTER)
|
if (ndm->ndm_flags & NTF_ROUTER)
|
||||||
flags |= NEIGH_UPDATE_F_ISROUTER;
|
flags |= NEIGH_UPDATE_F_ISROUTER;
|
||||||
|
if (ndm->ndm_flags & NTF_USE)
|
||||||
|
flags |= NEIGH_UPDATE_F_USE;
|
||||||
|
|
||||||
if (ndm->ndm_flags & NTF_USE) {
|
err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
|
||||||
|
NETLINK_CB(skb).portid, extack);
|
||||||
|
if (!err && ndm->ndm_flags & NTF_USE) {
|
||||||
neigh_event_send(neigh, NULL);
|
neigh_event_send(neigh, NULL);
|
||||||
err = 0;
|
err = 0;
|
||||||
} else
|
}
|
||||||
err = __neigh_update(neigh, lladdr, ndm->ndm_state, flags,
|
|
||||||
NETLINK_CB(skb).portid, extack);
|
|
||||||
|
|
||||||
neigh_release(neigh);
|
neigh_release(neigh);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user