Commit 9aa3749c authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller
Browse files

selftests: net: local_termination: don't use xfail_on_veth()



xfail_on_veth() for this test is an incorrect approximation which gives
false positives and false negatives.

When local_termination fails with "reception succeeded, but should have failed",
it is because the DUT ($h2) accepts packets even when not configured as
promiscuous. This is not something specific to veth; even the bridge
behaves that way, but this is not captured by the xfail_on_veth test.

The IFF_UNICAST_FLT flag is not explicitly exported to user space, but
it can somewhat be determined from the interface's behavior. We have to
create a macvlan upper with a different MAC address. This forces a
dev_uc_add() call in the kernel. When the unicast filtering list is
not empty, but the device doesn't support IFF_UNICAST_FLT,
__dev_set_rx_mode() force-enables promiscuity on the interface, to
ensure correct behavior (that the requested address is received).

We can monitor the change in the promiscuity flag and infer from it
whether the device supports unicast filtering.

There is no equivalent thing for allmulti, unfortunately. We never know
what's hiding behind a device which has allmulti=off. Whether it will
actually perform RX multicast filtering of unknown traffic is a strong
"maybe". The bridge driver, for example, completely ignores the flag.
We'll have to keep the xfail behavior, but instead of XFAIL on just
veth, always XFAIL.

Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5fea8bb0
Loading
Loading
Loading
Loading
+57 −0
Original line number Diff line number Diff line
@@ -500,6 +500,11 @@ check_err_fail()
	fi
}

xfail()
{
	FAIL_TO_XFAIL=yes "$@"
}

xfail_on_slow()
{
	if [[ $KSFT_MACHINE_SLOW = yes ]]; then
@@ -1113,6 +1118,39 @@ mac_get()
	ip -j link show dev $if_name | jq -r '.[]["address"]'
}

ether_addr_to_u64()
{
	local addr="$1"
	local order="$((1 << 40))"
	local val=0
	local byte

	addr="${addr//:/ }"

	for byte in $addr; do
		byte="0x$byte"
		val=$((val + order * byte))
		order=$((order >> 8))
	done

	printf "0x%x" $val
}

u64_to_ether_addr()
{
	local val=$1
	local byte
	local i

	for ((i = 40; i >= 0; i -= 8)); do
		byte=$(((val & (0xff << i)) >> i))
		printf "%02x" $byte
		if [ $i -ne 0 ]; then
			printf ":"
		fi
	done
}

ipv6_lladdr_get()
{
	local if_name=$1
@@ -2229,3 +2267,22 @@ absval()

	echo $((v > 0 ? v : -v))
}

has_unicast_flt()
{
	local dev=$1; shift
	local mac_addr=$(mac_get $dev)
	local tmp=$(ether_addr_to_u64 $mac_addr)
	local promisc

	ip link set $dev up
	ip link add link $dev name macvlan-tmp type macvlan mode private
	ip link set macvlan-tmp address $(u64_to_ether_addr $((tmp + 1)))
	ip link set macvlan-tmp up

	promisc=$(ip -j -d link show dev $dev | jq -r '.[].promiscuity')

	ip link del macvlan-tmp

	[[ $promisc == 1 ]] && echo "no" || echo "yes"
}
+42 −16
Original line number Diff line number Diff line
@@ -109,9 +109,11 @@ run_test()
{
	local send_if_name=$1; shift
	local rcv_if_name=$1; shift
	local no_unicast_flt=$1; shift
	local test_name="$1"; shift
	local smac=$(mac_get $send_if_name)
	local rcv_dmac=$(mac_get $rcv_if_name)
	local should_receive

	tcpdump_start $rcv_if_name

@@ -160,26 +162,26 @@ run_test()
		"$smac > $MACVLAN_ADDR, ethertype IPv4 (0x0800)" \
		true "$test_name"

	xfail_on_veth $h1 \
	[ $no_unicast_flt = true ] && should_receive=true || should_receive=false
	check_rcv $rcv_if_name "Unicast IPv4 to unknown MAC address" \
		"$smac > $UNKNOWN_UC_ADDR1, ethertype IPv4 (0x0800)" \
			false "$test_name"
		$should_receive "$test_name"

	check_rcv $rcv_if_name "Unicast IPv4 to unknown MAC address, promisc" \
		"$smac > $UNKNOWN_UC_ADDR2, ethertype IPv4 (0x0800)" \
		true "$test_name"

	xfail_on_veth $h1 \
	[ $no_unicast_flt = true ] && should_receive=true || should_receive=false
	check_rcv $rcv_if_name \
		"Unicast IPv4 to unknown MAC address, allmulti" \
		"$smac > $UNKNOWN_UC_ADDR3, ethertype IPv4 (0x0800)" \
			false "$test_name"
		$should_receive "$test_name"

	check_rcv $rcv_if_name "Multicast IPv4 to joined group" \
		"$smac > $JOINED_MACV4_MC_ADDR, ethertype IPv4 (0x0800)" \
		true "$test_name"

	xfail_on_veth $h1 \
	xfail \
		check_rcv $rcv_if_name \
			"Multicast IPv4 to unknown group" \
			"$smac > $UNKNOWN_MACV4_MC_ADDR1, ethertype IPv4 (0x0800)" \
@@ -197,7 +199,7 @@ run_test()
		"$smac > $JOINED_MACV6_MC_ADDR, ethertype IPv6 (0x86dd)" \
		true "$test_name"

	xfail_on_veth $h1 \
	xfail \
		check_rcv $rcv_if_name "Multicast IPv6 to unknown group" \
			"$smac > $UNKNOWN_MACV6_MC_ADDR1, ethertype IPv6 (0x86dd)" \
			false "$test_name"
@@ -290,11 +292,17 @@ macvlan_destroy()

standalone()
{
	local no_unicast_flt=true

	if [ $(has_unicast_flt $h2) = yes ]; then
		no_unicast_flt=false
	fi

	h1_create
	h2_create
	macvlan_create $h2

	run_test $h1 $h2 "$h2"
	run_test $h1 $h2 $no_unicast_flt "$h2"

	macvlan_destroy
	h2_destroy
@@ -303,6 +311,7 @@ standalone()

test_bridge()
{
	local no_unicast_flt=true
	local vlan_filtering=$1

	h1_create
@@ -310,7 +319,7 @@ test_bridge()
	simple_if_init br0 $H2_IPV4/24 $H2_IPV6/64
	macvlan_create br0

	run_test $h1 br0 "vlan_filtering=$vlan_filtering bridge"
	run_test $h1 br0 $no_unicast_flt "vlan_filtering=$vlan_filtering bridge"

	macvlan_destroy
	simple_if_fini br0 $H2_IPV4/24 $H2_IPV6/64
@@ -330,11 +339,17 @@ vlan_aware_bridge()

test_vlan()
{
	local no_unicast_flt=true

	if [ $(has_unicast_flt $h2) = yes ]; then
		no_unicast_flt=false
	fi

	h1_vlan_create
	h2_vlan_create
	macvlan_create $h2.100

	run_test $h1.100 $h2.100 "VLAN upper"
	run_test $h1.100 $h2.100 $no_unicast_flt "VLAN upper"

	macvlan_destroy
	h2_vlan_destroy
@@ -343,14 +358,23 @@ test_vlan()

vlan_over_bridged_port()
{
	local no_unicast_flt=true
	local vlan_filtering=$1

	# br_manage_promisc() will not force a single vlan_filtering port to
	# promiscuous mode, so we should still expect unicast filtering to take
	# place if the device can do it.
	if [ $(has_unicast_flt $h2) = yes ] && [ $vlan_filtering = 1 ]; then
		no_unicast_flt=false
	fi

	h1_vlan_create
	h2_vlan_create
	bridge_create $vlan_filtering
	macvlan_create $h2.100

	run_test $h1.100 $h2.100 "VLAN over vlan_filtering=$vlan_filtering bridged port"
	run_test $h1.100 $h2.100 $no_unicast_flt \
		"VLAN over vlan_filtering=$vlan_filtering bridged port"

	macvlan_destroy
	bridge_destroy
@@ -370,6 +394,7 @@ vlan_over_vlan_aware_bridged_port()

vlan_over_bridge()
{
	local no_unicast_flt=true
	local vlan_filtering=$1

	h1_vlan_create
@@ -383,7 +408,8 @@ vlan_over_bridge()
		bridge vlan add dev br0 vid 100 self
	fi

	run_test $h1.100 br0.100 "VLAN over vlan_filtering=$vlan_filtering bridge"
	run_test $h1.100 br0.100 $no_unicast_flt \
		"VLAN over vlan_filtering=$vlan_filtering bridge"

	if [ $vlan_filtering = 1 ]; then
		bridge vlan del dev br0 vid 100 self