Commit 3e0b8f52 authored by Arun Ajith S's avatar Arun Ajith S Committed by Paolo Abeni

net/ipv6: Expand and rename accept_unsolicited_na to accept_untracked_na

RFC 9131 changes default behaviour of handling RX of NA messages when the
corresponding entry is absent in the neighbour cache. The current
implementation is limited to accept just unsolicited NAs. However, the
RFC is more generic where it also accepts solicited NAs. Both types
should result in adding a STALE entry for this case.

Expand accept_untracked_na behaviour to also accept solicited NAs to
be compliant with the RFC and rename the sysctl knob to
accept_untracked_na.

Fixes: f9a2fb73 ("net/ipv6: Introduce accept_unsolicited_na knob to implement router-side changes for RFC9131")
Signed-off-by: default avatarArun Ajith S <aajith@arista.com>
Reviewed-by: default avatarDavid Ahern <dsahern@kernel.org>
Link: https://lore.kernel.org/r/20220530101414.65439-1-aajith@arista.comSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 4a1f14df
...@@ -2474,21 +2474,16 @@ drop_unsolicited_na - BOOLEAN ...@@ -2474,21 +2474,16 @@ drop_unsolicited_na - BOOLEAN
By default this is turned off. By default this is turned off.
accept_unsolicited_na - BOOLEAN accept_untracked_na - BOOLEAN
Add a new neighbour cache entry in STALE state for routers on receiving an Add a new neighbour cache entry in STALE state for routers on receiving a
unsolicited neighbour advertisement with target link-layer address option neighbour advertisement (either solicited or unsolicited) with target
specified. This is as per router-side behavior documented in RFC9131. link-layer address option specified if no neighbour entry is already
This has lower precedence than drop_unsolicited_na. present for the advertised IPv6 address. Without this knob, NAs received
for untracked addresses (absent in neighbour cache) are silently ignored.
This is as per router-side behaviour documented in RFC9131.
==== ====== ====== ============================================== This has lower precedence than drop_unsolicited_na.
drop accept fwding behaviour
---- ------ ------ ----------------------------------------------
1 X X Drop NA packet and don't pass up the stack
0 0 X Pass NA packet up the stack, don't update NC
0 1 0 Pass NA packet up the stack, don't update NC
0 1 1 Pass NA packet up the stack, and add a STALE
NC entry
==== ====== ====== ==============================================
This will optimize the return path for the initial off-link communication This will optimize the return path for the initial off-link communication
that is initiated by a directly connected host, by ensuring that that is initiated by a directly connected host, by ensuring that
......
...@@ -61,7 +61,7 @@ struct ipv6_devconf { ...@@ -61,7 +61,7 @@ struct ipv6_devconf {
__s32 suppress_frag_ndisc; __s32 suppress_frag_ndisc;
__s32 accept_ra_mtu; __s32 accept_ra_mtu;
__s32 drop_unsolicited_na; __s32 drop_unsolicited_na;
__s32 accept_unsolicited_na; __s32 accept_untracked_na;
struct ipv6_stable_secret { struct ipv6_stable_secret {
bool initialized; bool initialized;
struct in6_addr secret; struct in6_addr secret;
......
...@@ -194,7 +194,7 @@ enum { ...@@ -194,7 +194,7 @@ enum {
DEVCONF_IOAM6_ID, DEVCONF_IOAM6_ID,
DEVCONF_IOAM6_ID_WIDE, DEVCONF_IOAM6_ID_WIDE,
DEVCONF_NDISC_EVICT_NOCARRIER, DEVCONF_NDISC_EVICT_NOCARRIER,
DEVCONF_ACCEPT_UNSOLICITED_NA, DEVCONF_ACCEPT_UNTRACKED_NA,
DEVCONF_MAX DEVCONF_MAX
}; };
......
...@@ -5586,7 +5586,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, ...@@ -5586,7 +5586,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
array[DEVCONF_IOAM6_ID] = cnf->ioam6_id; array[DEVCONF_IOAM6_ID] = cnf->ioam6_id;
array[DEVCONF_IOAM6_ID_WIDE] = cnf->ioam6_id_wide; array[DEVCONF_IOAM6_ID_WIDE] = cnf->ioam6_id_wide;
array[DEVCONF_NDISC_EVICT_NOCARRIER] = cnf->ndisc_evict_nocarrier; array[DEVCONF_NDISC_EVICT_NOCARRIER] = cnf->ndisc_evict_nocarrier;
array[DEVCONF_ACCEPT_UNSOLICITED_NA] = cnf->accept_unsolicited_na; array[DEVCONF_ACCEPT_UNTRACKED_NA] = cnf->accept_untracked_na;
} }
static inline size_t inet6_ifla6_size(void) static inline size_t inet6_ifla6_size(void)
...@@ -7038,8 +7038,8 @@ static const struct ctl_table addrconf_sysctl[] = { ...@@ -7038,8 +7038,8 @@ static const struct ctl_table addrconf_sysctl[] = {
.extra2 = (void *)SYSCTL_ONE, .extra2 = (void *)SYSCTL_ONE,
}, },
{ {
.procname = "accept_unsolicited_na", .procname = "accept_untracked_na",
.data = &ipv6_devconf.accept_unsolicited_na, .data = &ipv6_devconf.accept_untracked_na,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec_minmax, .proc_handler = proc_dointvec_minmax,
......
...@@ -979,7 +979,7 @@ static void ndisc_recv_na(struct sk_buff *skb) ...@@ -979,7 +979,7 @@ static void ndisc_recv_na(struct sk_buff *skb)
struct inet6_dev *idev = __in6_dev_get(dev); struct inet6_dev *idev = __in6_dev_get(dev);
struct inet6_ifaddr *ifp; struct inet6_ifaddr *ifp;
struct neighbour *neigh; struct neighbour *neigh;
bool create_neigh; u8 new_state;
if (skb->len < sizeof(struct nd_msg)) { if (skb->len < sizeof(struct nd_msg)) {
ND_PRINTK(2, warn, "NA: packet too short\n"); ND_PRINTK(2, warn, "NA: packet too short\n");
...@@ -1000,7 +1000,7 @@ static void ndisc_recv_na(struct sk_buff *skb) ...@@ -1000,7 +1000,7 @@ static void ndisc_recv_na(struct sk_buff *skb)
/* For some 802.11 wireless deployments (and possibly other networks), /* For some 802.11 wireless deployments (and possibly other networks),
* there will be a NA proxy and unsolicitd packets are attacks * there will be a NA proxy and unsolicitd packets are attacks
* and thus should not be accepted. * and thus should not be accepted.
* drop_unsolicited_na takes precedence over accept_unsolicited_na * drop_unsolicited_na takes precedence over accept_untracked_na
*/ */
if (!msg->icmph.icmp6_solicited && idev && if (!msg->icmph.icmp6_solicited && idev &&
idev->cnf.drop_unsolicited_na) idev->cnf.drop_unsolicited_na)
...@@ -1041,25 +1041,33 @@ static void ndisc_recv_na(struct sk_buff *skb) ...@@ -1041,25 +1041,33 @@ static void ndisc_recv_na(struct sk_buff *skb)
in6_ifa_put(ifp); in6_ifa_put(ifp);
return; return;
} }
neigh = neigh_lookup(&nd_tbl, &msg->target, dev);
/* RFC 9131 updates original Neighbour Discovery RFC 4861. /* RFC 9131 updates original Neighbour Discovery RFC 4861.
* An unsolicited NA can now create a neighbour cache entry * NAs with Target LL Address option without a corresponding
* on routers if it has Target LL Address option. * entry in the neighbour cache can now create a STALE neighbour
* cache entry on routers.
*
* entry accept fwding solicited behaviour
* ------- ------ ------ --------- ----------------------
* present X X 0 Set state to STALE
* present X X 1 Set state to REACHABLE
* absent 0 X X Do nothing
* absent 1 0 X Do nothing
* absent 1 1 X Add a new STALE entry
* *
* drop accept fwding behaviour
* ---- ------ ------ ----------------------------------------------
* 1 X X Drop NA packet and don't pass up the stack
* 0 0 X Pass NA packet up the stack, don't update NC
* 0 1 0 Pass NA packet up the stack, don't update NC
* 0 1 1 Pass NA packet up the stack, and add a STALE
* NC entry
* Note that we don't do a (daddr == all-routers-mcast) check. * Note that we don't do a (daddr == all-routers-mcast) check.
*/ */
create_neigh = !msg->icmph.icmp6_solicited && lladdr && new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE;
idev && idev->cnf.forwarding && if (!neigh && lladdr &&
idev->cnf.accept_unsolicited_na; idev && idev->cnf.forwarding &&
neigh = __neigh_lookup(&nd_tbl, &msg->target, dev, create_neigh); idev->cnf.accept_untracked_na) {
neigh = neigh_create(&nd_tbl, &msg->target, dev);
new_state = NUD_STALE;
}
if (neigh) { if (neigh && !IS_ERR(neigh)) {
u8 old_flags = neigh->flags; u8 old_flags = neigh->flags;
struct net *net = dev_net(dev); struct net *net = dev_net(dev);
...@@ -1079,7 +1087,7 @@ static void ndisc_recv_na(struct sk_buff *skb) ...@@ -1079,7 +1087,7 @@ static void ndisc_recv_na(struct sk_buff *skb)
} }
ndisc_update(dev, neigh, lladdr, ndisc_update(dev, neigh, lladdr,
msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, new_state,
NEIGH_UPDATE_F_WEAK_OVERRIDE| NEIGH_UPDATE_F_WEAK_OVERRIDE|
(msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)| (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)|
NEIGH_UPDATE_F_OVERRIDE_ISROUTER| NEIGH_UPDATE_F_OVERRIDE_ISROUTER|
......
#!/bin/bash #!/bin/bash
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
# This test is for the accept_unsolicited_na feature to # This test is for the accept_untracked_na feature to
# enable RFC9131 behaviour. The following is the test-matrix. # enable RFC9131 behaviour. The following is the test-matrix.
# drop accept fwding behaviour # drop accept fwding behaviour
# ---- ------ ------ ---------------------------------------------- # ---- ------ ------ ----------------------------------------------
# 1 X X Drop NA packet and don't pass up the stack # 1 X X Don't update NC
# 0 0 X Pass NA packet up the stack, don't update NC # 0 0 X Don't update NC
# 0 1 0 Pass NA packet up the stack, don't update NC # 0 1 0 Don't update NC
# 0 1 1 Pass NA packet up the stack, and add a STALE # 0 1 1 Add a STALE NC entry
# NC entry
ret=0 ret=0
# Kselftest framework requirement - SKIP code is 4. # Kselftest framework requirement - SKIP code is 4.
...@@ -72,7 +71,7 @@ setup() ...@@ -72,7 +71,7 @@ setup()
set -e set -e
local drop_unsolicited_na=$1 local drop_unsolicited_na=$1
local accept_unsolicited_na=$2 local accept_untracked_na=$2
local forwarding=$3 local forwarding=$3
# Setup two namespaces and a veth tunnel across them. # Setup two namespaces and a veth tunnel across them.
...@@ -93,7 +92,7 @@ setup() ...@@ -93,7 +92,7 @@ setup()
${IP_ROUTER_EXEC} sysctl -qw \ ${IP_ROUTER_EXEC} sysctl -qw \
${ROUTER_CONF}.drop_unsolicited_na=${drop_unsolicited_na} ${ROUTER_CONF}.drop_unsolicited_na=${drop_unsolicited_na}
${IP_ROUTER_EXEC} sysctl -qw \ ${IP_ROUTER_EXEC} sysctl -qw \
${ROUTER_CONF}.accept_unsolicited_na=${accept_unsolicited_na} ${ROUTER_CONF}.accept_untracked_na=${accept_untracked_na}
${IP_ROUTER_EXEC} sysctl -qw ${ROUTER_CONF}.disable_ipv6=0 ${IP_ROUTER_EXEC} sysctl -qw ${ROUTER_CONF}.disable_ipv6=0
${IP_ROUTER} addr add ${ROUTER_ADDR_WITH_MASK} dev ${ROUTER_INTF} ${IP_ROUTER} addr add ${ROUTER_ADDR_WITH_MASK} dev ${ROUTER_INTF}
...@@ -144,13 +143,13 @@ link_up() { ...@@ -144,13 +143,13 @@ link_up() {
verify_ndisc() { verify_ndisc() {
local drop_unsolicited_na=$1 local drop_unsolicited_na=$1
local accept_unsolicited_na=$2 local accept_untracked_na=$2
local forwarding=$3 local forwarding=$3
neigh_show_output=$(${IP_ROUTER} neigh show \ neigh_show_output=$(${IP_ROUTER} neigh show \
to ${HOST_ADDR} dev ${ROUTER_INTF} nud stale) to ${HOST_ADDR} dev ${ROUTER_INTF} nud stale)
if [ ${drop_unsolicited_na} -eq 0 ] && \ if [ ${drop_unsolicited_na} -eq 0 ] && \
[ ${accept_unsolicited_na} -eq 1 ] && \ [ ${accept_untracked_na} -eq 1 ] && \
[ ${forwarding} -eq 1 ]; then [ ${forwarding} -eq 1 ]; then
# Neighbour entry expected to be present for 011 case # Neighbour entry expected to be present for 011 case
[[ ${neigh_show_output} ]] [[ ${neigh_show_output} ]]
...@@ -179,14 +178,14 @@ test_unsolicited_na_combination() { ...@@ -179,14 +178,14 @@ test_unsolicited_na_combination() {
test_unsolicited_na_common $1 $2 $3 test_unsolicited_na_common $1 $2 $3
test_msg=("test_unsolicited_na: " test_msg=("test_unsolicited_na: "
"drop_unsolicited_na=$1 " "drop_unsolicited_na=$1 "
"accept_unsolicited_na=$2 " "accept_untracked_na=$2 "
"forwarding=$3") "forwarding=$3")
log_test $? 0 "${test_msg[*]}" log_test $? 0 "${test_msg[*]}"
cleanup cleanup
} }
test_unsolicited_na_combinations() { test_unsolicited_na_combinations() {
# Args: drop_unsolicited_na accept_unsolicited_na forwarding # Args: drop_unsolicited_na accept_untracked_na forwarding
# Expect entry # Expect entry
test_unsolicited_na_combination 0 1 1 test_unsolicited_na_combination 0 1 1
......
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