forked from mirrors/linux
		
	net/ipv6: Introduce accept_unsolicited_na knob to implement router-side changes for RFC9131
Add a new neighbour cache entry in STALE state for routers on receiving an unsolicited (gratuitous) neighbour advertisement with target link-layer-address option specified. This is similar to the arp_accept configuration for IPv4. A new sysctl endpoint is created to turn on this behaviour: /proc/sys/net/ipv6/conf/interface/accept_unsolicited_na. Signed-off-by: Arun Ajith S <aajith@arista.com> Reviewed-by: David Ahern <dsahern@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									0339d25a28
								
							
						
					
					
						commit
						f9a2fb7331
					
				
					 7 changed files with 314 additions and 1 deletions
				
			
		| 
						 | 
					@ -2467,6 +2467,33 @@ drop_unsolicited_na - BOOLEAN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	By default this is turned off.
 | 
						By default this is turned off.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					accept_unsolicited_na - BOOLEAN
 | 
				
			||||||
 | 
						Add a new neighbour cache entry in STALE state for routers on receiving an
 | 
				
			||||||
 | 
						unsolicited neighbour advertisement with target link-layer address option
 | 
				
			||||||
 | 
						specified. This is as per router-side behavior 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
 | 
				
			||||||
 | 
						that is initiated by a directly connected host, by ensuring that
 | 
				
			||||||
 | 
						the first-hop router which turns on this setting doesn't have to
 | 
				
			||||||
 | 
						buffer the initial return packets to do neighbour-solicitation.
 | 
				
			||||||
 | 
						The prerequisite is that the host is configured to send
 | 
				
			||||||
 | 
						unsolicited neighbour advertisements on interface bringup.
 | 
				
			||||||
 | 
						This setting should be used in conjunction with the ndisc_notify setting
 | 
				
			||||||
 | 
						on the host to satisfy this prerequisite.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						By default this is turned off.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enhanced_dad - BOOLEAN
 | 
					enhanced_dad - BOOLEAN
 | 
				
			||||||
	Include a nonce option in the IPv6 neighbor solicitation messages used for
 | 
						Include a nonce option in the IPv6 neighbor solicitation messages used for
 | 
				
			||||||
	duplicate address detection per RFC7527. A received DAD NS will only signal
 | 
						duplicate address detection per RFC7527. A received DAD NS will only signal
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,6 +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;
 | 
				
			||||||
	struct ipv6_stable_secret {
 | 
						struct ipv6_stable_secret {
 | 
				
			||||||
		bool initialized;
 | 
							bool initialized;
 | 
				
			||||||
		struct in6_addr secret;
 | 
							struct in6_addr secret;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,6 +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_MAX
 | 
						DEVCONF_MAX
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5587,6 +5587,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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline size_t inet6_ifla6_size(void)
 | 
					static inline size_t inet6_ifla6_size(void)
 | 
				
			||||||
| 
						 | 
					@ -7037,6 +7038,15 @@ static const struct ctl_table addrconf_sysctl[] = {
 | 
				
			||||||
		.extra1		= (void *)SYSCTL_ZERO,
 | 
							.extra1		= (void *)SYSCTL_ZERO,
 | 
				
			||||||
		.extra2		= (void *)SYSCTL_ONE,
 | 
							.extra2		= (void *)SYSCTL_ONE,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.procname	= "accept_unsolicited_na",
 | 
				
			||||||
 | 
							.data		= &ipv6_devconf.accept_unsolicited_na,
 | 
				
			||||||
 | 
							.maxlen		= sizeof(int),
 | 
				
			||||||
 | 
							.mode		= 0644,
 | 
				
			||||||
 | 
							.proc_handler	= proc_dointvec,
 | 
				
			||||||
 | 
							.extra1		= (void *)SYSCTL_ZERO,
 | 
				
			||||||
 | 
							.extra2		= (void *)SYSCTL_ONE,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		/* sentinel */
 | 
							/* sentinel */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -979,6 +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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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");
 | 
				
			||||||
| 
						 | 
					@ -999,6 +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
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (!msg->icmph.icmp6_solicited && idev &&
 | 
						if (!msg->icmph.icmp6_solicited && idev &&
 | 
				
			||||||
	    idev->cnf.drop_unsolicited_na)
 | 
						    idev->cnf.drop_unsolicited_na)
 | 
				
			||||||
| 
						 | 
					@ -1039,7 +1041,23 @@ 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.
 | 
				
			||||||
 | 
						 * An unsolicited NA can now create a neighbour cache entry
 | 
				
			||||||
 | 
						 * on routers if it has Target LL Address option.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * 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.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						create_neigh = !msg->icmph.icmp6_solicited && lladdr &&
 | 
				
			||||||
 | 
							       idev && idev->cnf.forwarding &&
 | 
				
			||||||
 | 
							       idev->cnf.accept_unsolicited_na;
 | 
				
			||||||
 | 
						neigh = __neigh_lookup(&nd_tbl, &msg->target, dev, create_neigh);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (neigh) {
 | 
						if (neigh) {
 | 
				
			||||||
		u8 old_flags = neigh->flags;
 | 
							u8 old_flags = neigh->flags;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,7 @@ TEST_PROGS += srv6_end_dt4_l3vpn_test.sh
 | 
				
			||||||
TEST_PROGS += srv6_end_dt6_l3vpn_test.sh
 | 
					TEST_PROGS += srv6_end_dt6_l3vpn_test.sh
 | 
				
			||||||
TEST_PROGS += vrf_strict_mode_test.sh
 | 
					TEST_PROGS += vrf_strict_mode_test.sh
 | 
				
			||||||
TEST_PROGS += arp_ndisc_evict_nocarrier.sh
 | 
					TEST_PROGS += arp_ndisc_evict_nocarrier.sh
 | 
				
			||||||
 | 
					TEST_PROGS += ndisc_unsolicited_na_test.sh
 | 
				
			||||||
TEST_PROGS_EXTENDED := in_netns.sh setup_loopback.sh setup_veth.sh
 | 
					TEST_PROGS_EXTENDED := in_netns.sh setup_loopback.sh setup_veth.sh
 | 
				
			||||||
TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh
 | 
					TEST_PROGS_EXTENDED += toeplitz_client.sh toeplitz.sh
 | 
				
			||||||
TEST_GEN_FILES =  socket nettest
 | 
					TEST_GEN_FILES =  socket nettest
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										255
									
								
								tools/testing/selftests/net/ndisc_unsolicited_na_test.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										255
									
								
								tools/testing/selftests/net/ndisc_unsolicited_na_test.sh
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,255 @@
 | 
				
			||||||
 | 
					#!/bin/bash
 | 
				
			||||||
 | 
					# SPDX-License-Identifier: GPL-2.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This test is for the accept_unsolicited_na feature to
 | 
				
			||||||
 | 
					# enable RFC9131 behaviour. The following is the test-matrix.
 | 
				
			||||||
 | 
					# 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ret=0
 | 
				
			||||||
 | 
					# Kselftest framework requirement - SKIP code is 4.
 | 
				
			||||||
 | 
					ksft_skip=4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PAUSE_ON_FAIL=no
 | 
				
			||||||
 | 
					PAUSE=no
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HOST_NS="ns-host"
 | 
				
			||||||
 | 
					ROUTER_NS="ns-router"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HOST_INTF="veth-host"
 | 
				
			||||||
 | 
					ROUTER_INTF="veth-router"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ROUTER_ADDR="2000:20::1"
 | 
				
			||||||
 | 
					HOST_ADDR="2000:20::2"
 | 
				
			||||||
 | 
					SUBNET_WIDTH=64
 | 
				
			||||||
 | 
					ROUTER_ADDR_WITH_MASK="${ROUTER_ADDR}/${SUBNET_WIDTH}"
 | 
				
			||||||
 | 
					HOST_ADDR_WITH_MASK="${HOST_ADDR}/${SUBNET_WIDTH}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IP_HOST="ip -6 -netns ${HOST_NS}"
 | 
				
			||||||
 | 
					IP_HOST_EXEC="ip netns exec ${HOST_NS}"
 | 
				
			||||||
 | 
					IP_ROUTER="ip -6 -netns ${ROUTER_NS}"
 | 
				
			||||||
 | 
					IP_ROUTER_EXEC="ip netns exec ${ROUTER_NS}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tcpdump_stdout=
 | 
				
			||||||
 | 
					tcpdump_stderr=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log_test()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						local rc=$1
 | 
				
			||||||
 | 
						local expected=$2
 | 
				
			||||||
 | 
						local msg="$3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if [ ${rc} -eq ${expected} ]; then
 | 
				
			||||||
 | 
							printf "    TEST: %-60s  [ OK ]\n" "${msg}"
 | 
				
			||||||
 | 
							nsuccess=$((nsuccess+1))
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							ret=1
 | 
				
			||||||
 | 
							nfail=$((nfail+1))
 | 
				
			||||||
 | 
							printf "    TEST: %-60s  [FAIL]\n" "${msg}"
 | 
				
			||||||
 | 
							if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
 | 
				
			||||||
 | 
							echo
 | 
				
			||||||
 | 
								echo "hit enter to continue, 'q' to quit"
 | 
				
			||||||
 | 
								read a
 | 
				
			||||||
 | 
								[ "$a" = "q" ] && exit 1
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if [ "${PAUSE}" = "yes" ]; then
 | 
				
			||||||
 | 
							echo
 | 
				
			||||||
 | 
							echo "hit enter to continue, 'q' to quit"
 | 
				
			||||||
 | 
							read a
 | 
				
			||||||
 | 
							[ "$a" = "q" ] && exit 1
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					setup()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						set -e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local drop_unsolicited_na=$1
 | 
				
			||||||
 | 
						local accept_unsolicited_na=$2
 | 
				
			||||||
 | 
						local forwarding=$3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Setup two namespaces and a veth tunnel across them.
 | 
				
			||||||
 | 
						# On end of the tunnel is a router and the other end is a host.
 | 
				
			||||||
 | 
						ip netns add ${HOST_NS}
 | 
				
			||||||
 | 
						ip netns add ${ROUTER_NS}
 | 
				
			||||||
 | 
						${IP_ROUTER} link add ${ROUTER_INTF} type veth \
 | 
				
			||||||
 | 
					                peer name ${HOST_INTF} netns ${HOST_NS}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Enable IPv6 on both router and host, and configure static addresses.
 | 
				
			||||||
 | 
						# The router here is the DUT
 | 
				
			||||||
 | 
						# Setup router configuration as specified by the arguments.
 | 
				
			||||||
 | 
						# forwarding=0 case is to check that a non-router
 | 
				
			||||||
 | 
						# doesn't add neighbour entries.
 | 
				
			||||||
 | 
					        ROUTER_CONF=net.ipv6.conf.${ROUTER_INTF}
 | 
				
			||||||
 | 
						${IP_ROUTER_EXEC} sysctl -qw \
 | 
				
			||||||
 | 
					                ${ROUTER_CONF}.forwarding=${forwarding}
 | 
				
			||||||
 | 
						${IP_ROUTER_EXEC} sysctl -qw \
 | 
				
			||||||
 | 
					                ${ROUTER_CONF}.drop_unsolicited_na=${drop_unsolicited_na}
 | 
				
			||||||
 | 
						${IP_ROUTER_EXEC} sysctl -qw \
 | 
				
			||||||
 | 
					                ${ROUTER_CONF}.accept_unsolicited_na=${accept_unsolicited_na}
 | 
				
			||||||
 | 
						${IP_ROUTER_EXEC} sysctl -qw ${ROUTER_CONF}.disable_ipv6=0
 | 
				
			||||||
 | 
						${IP_ROUTER} addr add ${ROUTER_ADDR_WITH_MASK} dev ${ROUTER_INTF}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Turn on ndisc_notify on host interface so that
 | 
				
			||||||
 | 
						# the host sends unsolicited NAs.
 | 
				
			||||||
 | 
						HOST_CONF=net.ipv6.conf.${HOST_INTF}
 | 
				
			||||||
 | 
						${IP_HOST_EXEC} sysctl -qw ${HOST_CONF}.ndisc_notify=1
 | 
				
			||||||
 | 
						${IP_HOST_EXEC} sysctl -qw ${HOST_CONF}.disable_ipv6=0
 | 
				
			||||||
 | 
						${IP_HOST} addr add ${HOST_ADDR_WITH_MASK} dev ${HOST_INTF}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set +e
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					start_tcpdump() {
 | 
				
			||||||
 | 
						set -e
 | 
				
			||||||
 | 
						tcpdump_stdout=`mktemp`
 | 
				
			||||||
 | 
						tcpdump_stderr=`mktemp`
 | 
				
			||||||
 | 
						${IP_ROUTER_EXEC} timeout 15s \
 | 
				
			||||||
 | 
					                tcpdump --immediate-mode -tpni ${ROUTER_INTF} -c 1 \
 | 
				
			||||||
 | 
					                "icmp6 && icmp6[0] == 136 && src ${HOST_ADDR}" \
 | 
				
			||||||
 | 
					                > ${tcpdump_stdout} 2> /dev/null
 | 
				
			||||||
 | 
						set +e
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cleanup_tcpdump()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						set -e
 | 
				
			||||||
 | 
						[[ ! -z  ${tcpdump_stdout} ]] && rm -f ${tcpdump_stdout}
 | 
				
			||||||
 | 
						[[ ! -z  ${tcpdump_stderr} ]] && rm -f ${tcpdump_stderr}
 | 
				
			||||||
 | 
						tcpdump_stdout=
 | 
				
			||||||
 | 
						tcpdump_stderr=
 | 
				
			||||||
 | 
						set +e
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cleanup()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						cleanup_tcpdump
 | 
				
			||||||
 | 
						ip netns del ${HOST_NS}
 | 
				
			||||||
 | 
						ip netns del ${ROUTER_NS}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					link_up() {
 | 
				
			||||||
 | 
						set -e
 | 
				
			||||||
 | 
						${IP_ROUTER} link set dev ${ROUTER_INTF} up
 | 
				
			||||||
 | 
						${IP_HOST} link set dev ${HOST_INTF} up
 | 
				
			||||||
 | 
						set +e
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					verify_ndisc() {
 | 
				
			||||||
 | 
						local drop_unsolicited_na=$1
 | 
				
			||||||
 | 
						local accept_unsolicited_na=$2
 | 
				
			||||||
 | 
						local forwarding=$3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						neigh_show_output=$(${IP_ROUTER} neigh show \
 | 
				
			||||||
 | 
					                to ${HOST_ADDR} dev ${ROUTER_INTF} nud stale)
 | 
				
			||||||
 | 
						if [ ${drop_unsolicited_na} -eq 0 ] && \
 | 
				
			||||||
 | 
								[ ${accept_unsolicited_na} -eq 1 ] && \
 | 
				
			||||||
 | 
								[ ${forwarding} -eq 1 ]; then
 | 
				
			||||||
 | 
							# Neighbour entry expected to be present for 011 case
 | 
				
			||||||
 | 
							[[ ${neigh_show_output} ]]
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							# Neighbour entry expected to be absent for all other cases
 | 
				
			||||||
 | 
							[[ -z ${neigh_show_output} ]]
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_unsolicited_na_common()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						# Setup the test bed, but keep links down
 | 
				
			||||||
 | 
						setup $1 $2 $3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Bring the link up, wait for the NA,
 | 
				
			||||||
 | 
						# and add a delay to ensure neighbour processing is done.
 | 
				
			||||||
 | 
						link_up
 | 
				
			||||||
 | 
						start_tcpdump
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Verify the neighbour table
 | 
				
			||||||
 | 
						verify_ndisc $1 $2 $3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_unsolicited_na_combination() {
 | 
				
			||||||
 | 
						test_unsolicited_na_common $1 $2 $3
 | 
				
			||||||
 | 
						test_msg=("test_unsolicited_na: "
 | 
				
			||||||
 | 
							"drop_unsolicited_na=$1 "
 | 
				
			||||||
 | 
							"accept_unsolicited_na=$2 "
 | 
				
			||||||
 | 
							"forwarding=$3")
 | 
				
			||||||
 | 
						log_test $? 0 "${test_msg[*]}"
 | 
				
			||||||
 | 
						cleanup
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_unsolicited_na_combinations() {
 | 
				
			||||||
 | 
						# Args: drop_unsolicited_na accept_unsolicited_na forwarding
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Expect entry
 | 
				
			||||||
 | 
						test_unsolicited_na_combination 0 1 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# Expect no entry
 | 
				
			||||||
 | 
						test_unsolicited_na_combination 0 0 0
 | 
				
			||||||
 | 
						test_unsolicited_na_combination 0 0 1
 | 
				
			||||||
 | 
						test_unsolicited_na_combination 0 1 0
 | 
				
			||||||
 | 
						test_unsolicited_na_combination 1 0 0
 | 
				
			||||||
 | 
						test_unsolicited_na_combination 1 0 1
 | 
				
			||||||
 | 
						test_unsolicited_na_combination 1 1 0
 | 
				
			||||||
 | 
						test_unsolicited_na_combination 1 1 1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					# usage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					usage()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						cat <<EOF
 | 
				
			||||||
 | 
					usage: ${0##*/} OPTS
 | 
				
			||||||
 | 
					        -p          Pause on fail
 | 
				
			||||||
 | 
					        -P          Pause after each test before cleanup
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###############################################################################
 | 
				
			||||||
 | 
					# main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					while getopts :pPh o
 | 
				
			||||||
 | 
					do
 | 
				
			||||||
 | 
						case $o in
 | 
				
			||||||
 | 
							p) PAUSE_ON_FAIL=yes;;
 | 
				
			||||||
 | 
							P) PAUSE=yes;;
 | 
				
			||||||
 | 
							h) usage; exit 0;;
 | 
				
			||||||
 | 
							*) usage; exit 1;;
 | 
				
			||||||
 | 
						esac
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# make sure we don't pause twice
 | 
				
			||||||
 | 
					[ "${PAUSE}" = "yes" ] && PAUSE_ON_FAIL=no
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ "$(id -u)" -ne 0 ];then
 | 
				
			||||||
 | 
						echo "SKIP: Need root privileges"
 | 
				
			||||||
 | 
						exit $ksft_skip;
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ ! -x "$(command -v ip)" ]; then
 | 
				
			||||||
 | 
						echo "SKIP: Could not run test without ip tool"
 | 
				
			||||||
 | 
						exit $ksft_skip
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ ! -x "$(command -v tcpdump)" ]; then
 | 
				
			||||||
 | 
						echo "SKIP: Could not run test without tcpdump tool"
 | 
				
			||||||
 | 
						exit $ksft_skip
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# start clean
 | 
				
			||||||
 | 
					cleanup &> /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test_unsolicited_na_combinations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					printf "\nTests passed: %3d\n" ${nsuccess}
 | 
				
			||||||
 | 
					printf "Tests failed: %3d\n"   ${nfail}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit $ret
 | 
				
			||||||
		Loading…
	
		Reference in a new issue