Pull up following revision(s) (requested by ozaki-r in ticket #1285):

sys/netinet6/nd6.c: revision 1.255
	tests/net/ndp/t_ndp.sh: revision 1.32

nd6: restore a missing reachability confirmation

On sending a packet over a STALE cache, the cache should be tried a reachability
confirmation, which is described in RFC 2461/4861 7.3.3.  On the fast path in
nd6_resolve, however, the treatment for STALE caches has been skipped
accidentally.  So STALE caches never be back to the REACHABLE state.

To fix the issue, branch to the fast path only when the cache entry is the
REACHABLE state and leave other caches to the slow path that includes the
treatment.  To this end we need to allow to return a link-layer address if a
valid address is available on the slow path too, which is the same behavior as
FreeBSD and OpenBSD.

tests: test state transitions of neighbor caches
This commit is contained in:
martin 2019-07-08 16:30:58 +00:00
parent d9907716f7
commit 04ffffbbfd
2 changed files with 93 additions and 5 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6.c,v 1.232.2.9 2018/11/06 14:38:58 martin Exp $ */
/* $NetBSD: nd6.c,v 1.232.2.10 2019/07/08 16:30:58 martin Exp $ */
/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.9 2018/11/06 14:38:58 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.232.2.10 2019/07/08 16:30:58 martin Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@ -2311,8 +2311,8 @@ nd6_resolve(struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m,
/* Look up the neighbor cache for the nexthop */
ln = nd6_lookup(&dst->sin6_addr, ifp, false);
if (ln != NULL && (ln->la_flags & LLE_VALID) != 0) {
KASSERT(ln->ln_state > ND6_LLINFO_INCOMPLETE);
if (ln != NULL && (ln->la_flags & LLE_VALID) != 0 &&
ln->ln_state == ND6_LLINFO_REACHABLE) {
/* Fast path */
memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen));
LLE_RUNLOCK(ln);
@ -2374,6 +2374,18 @@ nd6_resolve(struct ifnet *ifp, const struct rtentry *rt, struct mbuf *m,
nd6_llinfo_settimer(ln, nd6_delay * hz);
}
/*
* If the neighbor cache entry has a state other than INCOMPLETE
* (i.e. its link-layer address is already resolved), just
* send the packet.
*/
if (ln->ln_state > ND6_LLINFO_INCOMPLETE) {
KASSERT((ln->la_flags & LLE_VALID) != 0);
memcpy(lldst, &ln->ll_addr, MIN(dstsize, ifp->if_addrlen));
LLE_WUNLOCK(ln);
return 0;
}
/*
* There is a neighbor cache entry, but no ethernet address
* response yet. Append this latest packet to the end of the

View File

@ -1,4 +1,4 @@
# $NetBSD: t_ndp.sh,v 1.19.2.2 2018/04/02 09:51:58 martin Exp $
# $NetBSD: t_ndp.sh,v 1.19.2.3 2019/07/08 16:30:58 martin Exp $
#
# Copyright (c) 2015 The NetBSD Foundation, Inc.
# All rights reserved.
@ -675,6 +675,81 @@ ndp_stray_entries_cleanup()
cleanup
}
atf_test_case ndp_cache_state cleanup
ndp_stray_entries_head()
{
atf_set "descr" "Tests states of neighbor cache entries"
atf_set "require.progs" "rump_server"
}
check_cache_state()
{
local dst=$1
local state=$2
$DEBUG && rump.ndp -n $dst
atf_check -s exit:0 -o match:"^$dst.*$state " rump.ndp -n $dst
}
wait_until_stalled()
{
local dst=$1
local state=$2
$DEBUG && rump.ndp -n $dst
while true; do
rump.ndp -n $dst | grep -q "^$dst.*S " && break
sleep 1
done
$DEBUG && rump.ndp -n $dst
}
ndp_cache_state_body()
{
rump_server_start $SOCKSRC netinet6
rump_server_start $SOCKDST netinet6
setup_dst_server
setup_src_server
export RUMP_SERVER=$SOCKSRC
#
# Reachability confirmation (RFC 4861 7.3.3)
#
atf_check -s exit:0 -o ignore rump.ping6 -n -X $TIMEOUT -c 1 $IP6DST
# Receiving a solicited NA packet changes the state of the cache to REACHABLE
check_cache_state $IP6DST R
# The state of the cache transits to STALE after a while
wait_until_stalled $IP6DST
# Sending a packet on the cache will run a reachability confirmation
atf_check -s exit:0 -o ignore rump.ping6 -n -X $TIMEOUT -c 1 $IP6DST
sleep 1
# The state of the cache is changed to DELAY and stay for 5s, then
# send a NS packet and change the state to PROBE
check_cache_state $IP6DST D
sleep $((5 + 1))
# If the reachability confirmation is success, the state of the cache
# is changed to REACHABLE
check_cache_state $IP6DST R
}
ndp_cache_state_cleanup()
{
$DEBUG && dump
cleanup
}
atf_init_test_cases()
{
atf_add_test_case ndp_cache_expiration
@ -687,4 +762,5 @@ atf_init_test_cases()
atf_add_test_case ndp_purge_on_route_delete
atf_add_test_case ndp_purge_on_ifdown
atf_add_test_case ndp_stray_entries
atf_add_test_case ndp_cache_state
}