diff mbox series

[v1,bpf-next,2/2] selftests/bpf: Add BPF_FIB_LOOKUP_MARK tests

Message ID 20240322140244.50971-3-aspsk@isovalent.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series BPF: support mark in bpf_fib_lookup | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 8 this patch: 8
netdev/build_tools success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 9 maintainers not CCed: haoluo@google.com linux-kselftest@vger.kernel.org john.fastabend@gmail.com eddyz87@gmail.com song@kernel.org kpsingh@kernel.org yonghong.song@linux.dev shuah@kernel.org mykolal@fb.com
netdev/build_clang success Errors and warnings before: 8 this patch: 8
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns WARNING: line length of 87 exceeds 80 columns WARNING: line length of 93 exceeds 80 columns WARNING: line length of 95 exceeds 80 columns WARNING: line length of 99 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-next-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-17 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-18 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-34 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-next-VM_Test-35 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-42 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for s390x-gcc / test (test_maps, false, 360) / test_maps on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-36 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18 and -O2 optimization
bpf/vmtest-bpf-next-VM_Test-15 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-31 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-39 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-41 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-38 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17 and -O2 optimization

Commit Message

Anton Protopopov March 22, 2024, 2:02 p.m. UTC
This patch extends the fib_lookup test suite by adding a few test
cases for each IP family to test the new BPF_FIB_LOOKUP_MARK flag
to the bpf_fib_lookup:

  * Test destination IP address selection with and without a mark
    and/or the BPF_FIB_LOOKUP_MARK flag set

To test this functionality another network namespace and a new veth
pair were added to the test.

Signed-off-by: Anton Protopopov <aspsk@isovalent.com>
Acked-by: Daniel Borkmann <daniel@iogearbox.net>
---
 .../selftests/bpf/prog_tests/fib_lookup.c     | 160 ++++++++++++++----
 1 file changed, 131 insertions(+), 29 deletions(-)

Comments

Martin KaFai Lau March 23, 2024, 10:34 p.m. UTC | #1
On 3/22/24 7:02 AM, Anton Protopopov wrote:
> This patch extends the fib_lookup test suite by adding a few test
> cases for each IP family to test the new BPF_FIB_LOOKUP_MARK flag
> to the bpf_fib_lookup:
> 
>    * Test destination IP address selection with and without a mark
>      and/or the BPF_FIB_LOOKUP_MARK flag set
> 
> To test this functionality another network namespace and a new veth
> pair were added to the test.
> 

[ ... ]

>   static const struct fib_lookup_test tests[] = {
> @@ -90,10 +105,47 @@ static const struct fib_lookup_test tests[] = {
>   	  .daddr = IPV6_ADDR_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
>   	  .expected_src = IPV6_IFACE_ADDR_SEC,
>   	  .lookup_flags = BPF_FIB_LOOKUP_SRC | BPF_FIB_LOOKUP_SKIP_NEIGH, },
> +	/* policy routing */
> +	{ .desc = "IPv4 policy routing, default",
> +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH, },
> +	{ .desc = "IPv4 policy routing, mark doesn't point to a policy",
> +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> +	  .mark = MARK_NO_POLICY, },
> +	{ .desc = "IPv4 policy routing, mark points to a policy",
> +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> +	  .expected_dst = IPV4_GW2, .ifname = "veth3",
> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> +	  .mark = MARK, },
> +	{ .desc = "IPv4 policy routing, mark points to a policy, but no flag",
> +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
> +	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH,
> +	  .mark = MARK, },
> +	{ .desc = "IPv6 policy routing, default",
> +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH, },
> +	{ .desc = "IPv6 policy routing, mark doesn't point to a policy",
> +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> +	  .mark = MARK_NO_POLICY, },
> +	{ .desc = "IPv6 policy routing, mark points to a policy",
> +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> +	  .expected_dst = IPV6_GW2, .ifname = "veth3",
> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> +	  .mark = MARK, },
> +	{ .desc = "IPv6 policy routing, mark points to a policy, but no flag",
> +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
> +	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH,
> +	  .mark = MARK, },
>   };
>   
> -static int ifindex;
> -
>   static int setup_netns(void)
>   {
>   	int err;
> @@ -144,12 +196,40 @@ static int setup_netns(void)
>   	if (!ASSERT_OK(err, "write_sysctl(net.ipv6.conf.veth1.forwarding)"))
>   		goto fail;
>   
> +	/* Setup for policy routing tests */
> +	SYS(fail, "ip link add veth3 type veth peer name veth4");
> +	SYS(fail, "ip link set dev veth3 up");
> +	SYS(fail, "ip link set dev veth4 netns %s up", NS_REMOTE);
> +
> +	SYS(fail, "ip addr add %s/24 dev veth3", IPV4_LOCAL);
> +	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW1);
> +	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW2);
> +	SYS(fail, "ip addr add %s/64 dev veth3 nodad", IPV6_LOCAL);
> +	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW1);
> +	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW2);

Trying to see if the setup can be simplified.

Does it need to add another netns and setup a reachable IPV[46]_GW[12] gateway?

The test is not sending any traffic and it is a BPF_FIB_LOOKUP_SKIP_NEIGH test.

> +	SYS(fail, "ip route add %s/32 via %s", IPV4_REMOTE_DST, IPV4_GW1);
> +	SYS(fail, "ip route add %s/32 via %s table %s", IPV4_REMOTE_DST, IPV4_GW2, MARK_TABLE);
> +	SYS(fail, "ip -6 route add %s/128 via %s", IPV6_REMOTE_DST, IPV6_GW1);
> +	SYS(fail, "ip -6 route add %s/128 via %s table %s", IPV6_REMOTE_DST, IPV6_GW2, MARK_TABLE);
> +	SYS(fail, "ip rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
> +	SYS(fail, "ip -6 rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
> +
> +	err = write_sysctl("/proc/sys/net/ipv4/conf/veth3/forwarding", "1");
> +	if (!ASSERT_OK(err, "write_sysctl(net.ipv4.conf.veth3.forwarding)"))
> +		goto fail;
> +
> +	err = write_sysctl("/proc/sys/net/ipv6/conf/veth3/forwarding", "1");
> +	if (!ASSERT_OK(err, "write_sysctl(net.ipv6.conf.veth3.forwarding)"))
> +		goto fail;
> +
>   	return 0;
>   fail:
>   	return -1;
>   }

[ ... ]

> @@ -248,6 +337,7 @@ void test_fib_lookup(void)
>   	prog_fd = bpf_program__fd(skel->progs.fib_lookup);
>   
>   	SYS(fail, "ip netns add %s", NS_TEST);
> +	SYS(fail, "ip netns add %s", NS_REMOTE);
Anton Protopopov March 24, 2024, 3:04 p.m. UTC | #2
On Sat, Mar 23, 2024 at 03:34:10PM -0700, Martin KaFai Lau wrote:
> On 3/22/24 7:02 AM, Anton Protopopov wrote:
> > This patch extends the fib_lookup test suite by adding a few test
> > cases for each IP family to test the new BPF_FIB_LOOKUP_MARK flag
> > to the bpf_fib_lookup:
> > 
> >    * Test destination IP address selection with and without a mark
> >      and/or the BPF_FIB_LOOKUP_MARK flag set
> > 
> > To test this functionality another network namespace and a new veth
> > pair were added to the test.
> > 
> 
> [ ... ]
> 
> >   static const struct fib_lookup_test tests[] = {
> > @@ -90,10 +105,47 @@ static const struct fib_lookup_test tests[] = {
> >   	  .daddr = IPV6_ADDR_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> >   	  .expected_src = IPV6_IFACE_ADDR_SEC,
> >   	  .lookup_flags = BPF_FIB_LOOKUP_SRC | BPF_FIB_LOOKUP_SKIP_NEIGH, },
> > +	/* policy routing */
> > +	{ .desc = "IPv4 policy routing, default",
> > +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
> > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH, },
> > +	{ .desc = "IPv4 policy routing, mark doesn't point to a policy",
> > +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
> > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> > +	  .mark = MARK_NO_POLICY, },
> > +	{ .desc = "IPv4 policy routing, mark points to a policy",
> > +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > +	  .expected_dst = IPV4_GW2, .ifname = "veth3",
> > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> > +	  .mark = MARK, },
> > +	{ .desc = "IPv4 policy routing, mark points to a policy, but no flag",
> > +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
> > +	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH,
> > +	  .mark = MARK, },
> > +	{ .desc = "IPv6 policy routing, default",
> > +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
> > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH, },
> > +	{ .desc = "IPv6 policy routing, mark doesn't point to a policy",
> > +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
> > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> > +	  .mark = MARK_NO_POLICY, },
> > +	{ .desc = "IPv6 policy routing, mark points to a policy",
> > +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > +	  .expected_dst = IPV6_GW2, .ifname = "veth3",
> > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> > +	  .mark = MARK, },
> > +	{ .desc = "IPv6 policy routing, mark points to a policy, but no flag",
> > +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
> > +	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH,
> > +	  .mark = MARK, },
> >   };
> > -static int ifindex;
> > -
> >   static int setup_netns(void)
> >   {
> >   	int err;
> > @@ -144,12 +196,40 @@ static int setup_netns(void)
> >   	if (!ASSERT_OK(err, "write_sysctl(net.ipv6.conf.veth1.forwarding)"))
> >   		goto fail;
> > +	/* Setup for policy routing tests */
> > +	SYS(fail, "ip link add veth3 type veth peer name veth4");
> > +	SYS(fail, "ip link set dev veth3 up");
> > +	SYS(fail, "ip link set dev veth4 netns %s up", NS_REMOTE);
> > +
> > +	SYS(fail, "ip addr add %s/24 dev veth3", IPV4_LOCAL);
> > +	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW1);
> > +	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW2);
> > +	SYS(fail, "ip addr add %s/64 dev veth3 nodad", IPV6_LOCAL);
> > +	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW1);
> > +	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW2);
> 
> Trying to see if the setup can be simplified.
> 
> Does it need to add another netns and setup a reachable IPV[46]_GW[12] gateway?
> 
> The test is not sending any traffic and it is a BPF_FIB_LOOKUP_SKIP_NEIGH test.

I think this will not work without another namespace, as FIB lookup will
return DST="final destination", not DST="gateway", as the gateway is in the
same namespace and can be skipped.

Instead of adding a new namespace I can move the second interface to the
root namespace. This will work, but then we're interfering with the root
namespace.

> > +	SYS(fail, "ip route add %s/32 via %s", IPV4_REMOTE_DST, IPV4_GW1);
> > +	SYS(fail, "ip route add %s/32 via %s table %s", IPV4_REMOTE_DST, IPV4_GW2, MARK_TABLE);
> > +	SYS(fail, "ip -6 route add %s/128 via %s", IPV6_REMOTE_DST, IPV6_GW1);
> > +	SYS(fail, "ip -6 route add %s/128 via %s table %s", IPV6_REMOTE_DST, IPV6_GW2, MARK_TABLE);
> > +	SYS(fail, "ip rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
> > +	SYS(fail, "ip -6 rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
> > +
> > +	err = write_sysctl("/proc/sys/net/ipv4/conf/veth3/forwarding", "1");
> > +	if (!ASSERT_OK(err, "write_sysctl(net.ipv4.conf.veth3.forwarding)"))
> > +		goto fail;
> > +
> > +	err = write_sysctl("/proc/sys/net/ipv6/conf/veth3/forwarding", "1");
> > +	if (!ASSERT_OK(err, "write_sysctl(net.ipv6.conf.veth3.forwarding)"))
> > +		goto fail;
> > +
> >   	return 0;
> >   fail:
> >   	return -1;
> >   }
> 
> [ ... ]
> 
> > @@ -248,6 +337,7 @@ void test_fib_lookup(void)
> >   	prog_fd = bpf_program__fd(skel->progs.fib_lookup);
> >   	SYS(fail, "ip netns add %s", NS_TEST);
> > +	SYS(fail, "ip netns add %s", NS_REMOTE);
> 
>
Martin KaFai Lau March 25, 2024, 6:12 p.m. UTC | #3
On 3/24/24 8:04 AM, Anton Protopopov wrote:
> On Sat, Mar 23, 2024 at 03:34:10PM -0700, Martin KaFai Lau wrote:
>> On 3/22/24 7:02 AM, Anton Protopopov wrote:
>>> This patch extends the fib_lookup test suite by adding a few test
>>> cases for each IP family to test the new BPF_FIB_LOOKUP_MARK flag
>>> to the bpf_fib_lookup:
>>>
>>>     * Test destination IP address selection with and without a mark
>>>       and/or the BPF_FIB_LOOKUP_MARK flag set
>>>
>>> To test this functionality another network namespace and a new veth
>>> pair were added to the test.
>>>
>>
>> [ ... ]
>>
>>>    static const struct fib_lookup_test tests[] = {
>>> @@ -90,10 +105,47 @@ static const struct fib_lookup_test tests[] = {
>>>    	  .daddr = IPV6_ADDR_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
>>>    	  .expected_src = IPV6_IFACE_ADDR_SEC,
>>>    	  .lookup_flags = BPF_FIB_LOOKUP_SRC | BPF_FIB_LOOKUP_SKIP_NEIGH, },
>>> +	/* policy routing */
>>> +	{ .desc = "IPv4 policy routing, default",
>>> +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
>>> +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
>>> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH, },
>>> +	{ .desc = "IPv4 policy routing, mark doesn't point to a policy",
>>> +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
>>> +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
>>> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
>>> +	  .mark = MARK_NO_POLICY, },
>>> +	{ .desc = "IPv4 policy routing, mark points to a policy",
>>> +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
>>> +	  .expected_dst = IPV4_GW2, .ifname = "veth3",
>>> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
>>> +	  .mark = MARK, },
>>> +	{ .desc = "IPv4 policy routing, mark points to a policy, but no flag",
>>> +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
>>> +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
>>> +	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH,
>>> +	  .mark = MARK, },
>>> +	{ .desc = "IPv6 policy routing, default",
>>> +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
>>> +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
>>> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH, },
>>> +	{ .desc = "IPv6 policy routing, mark doesn't point to a policy",
>>> +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
>>> +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
>>> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
>>> +	  .mark = MARK_NO_POLICY, },
>>> +	{ .desc = "IPv6 policy routing, mark points to a policy",
>>> +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
>>> +	  .expected_dst = IPV6_GW2, .ifname = "veth3",
>>> +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
>>> +	  .mark = MARK, },
>>> +	{ .desc = "IPv6 policy routing, mark points to a policy, but no flag",
>>> +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
>>> +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
>>> +	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH,
>>> +	  .mark = MARK, },
>>>    };
>>> -static int ifindex;
>>> -
>>>    static int setup_netns(void)
>>>    {
>>>    	int err;
>>> @@ -144,12 +196,40 @@ static int setup_netns(void)
>>>    	if (!ASSERT_OK(err, "write_sysctl(net.ipv6.conf.veth1.forwarding)"))
>>>    		goto fail;
>>> +	/* Setup for policy routing tests */
>>> +	SYS(fail, "ip link add veth3 type veth peer name veth4");
>>> +	SYS(fail, "ip link set dev veth3 up");
>>> +	SYS(fail, "ip link set dev veth4 netns %s up", NS_REMOTE);
>>> +
>>> +	SYS(fail, "ip addr add %s/24 dev veth3", IPV4_LOCAL);
>>> +	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW1);
>>> +	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW2);
>>> +	SYS(fail, "ip addr add %s/64 dev veth3 nodad", IPV6_LOCAL);
>>> +	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW1);
>>> +	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW2);
>>
>> Trying to see if the setup can be simplified.
>>
>> Does it need to add another netns and setup a reachable IPV[46]_GW[12] gateway?
>>
>> The test is not sending any traffic and it is a BPF_FIB_LOOKUP_SKIP_NEIGH test.
> 
> I think this will not work without another namespace, as FIB lookup will
> return DST="final destination", not DST="gateway", as the gateway is in the
> same namespace and can be skipped.

hmm... not sure I understand why it would get "final destination". Am I missing something?
To be specific, there is no need to configure the IPV[46]_GW[12] address:

-	SYS(fail, "ip link set dev veth4 netns %s up", NS_REMOTE);

	SYS(fail, "ip addr add %s/24 dev veth3", IPV4_LOCAL);
-	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW1);
-	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW2);
	SYS(fail, "ip addr add %s/64 dev veth3 nodad", IPV6_LOCAL);
-	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW1);
-	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW2);
	SYS(fail, "ip route add %s/32 via %s", IPV4_REMOTE_DST, IPV4_GW1);
	SYS(fail, "ip route add %s/32 via %s table %s", IPV4_REMOTE_DST, IPV4_GW2, MARK_TABLE);
	SYS(fail, "ip -6 route add %s/128 via %s", IPV6_REMOTE_DST, IPV6_GW1);
	SYS(fail, "ip -6 route add %s/128 via %s table %s", IPV6_REMOTE_DST, IPV6_GW2, MARK_TABLE);
	SYS(fail, "ip rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
	SYS(fail, "ip -6 rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);

[root@arch-fb-vm1 ~]# ip netns exec fib_lookup_ns /bin/bash

[root@arch-fb-vm1 ~]# ip -6 rule
0:	from all lookup local
2:	from all fwmark 0x2a lookup 200
32766:	from all lookup main

[root@arch-fb-vm1 ~]# ip -6 route show table main
be:ef::b0:10 via fd01::1 dev veth3 metric 1024 linkdown pref medium

[root@arch-fb-vm1 ~]# ip -6 route show table 200
be:ef::b0:10 via fd01::2 dev veth3 metric 1024 linkdown pref medium

[root@arch-fb-vm1 ~]# ip -6 route get be:ef::b0:10
be:ef::b0:10 from :: via fd01::1 dev veth3 src fd01::3 metric 1024 pref medium

[root@arch-fb-vm1 ~]# ip -6 route get be:ef::b0:10 mark 0x2a
be:ef::b0:10 from :: via fd01::2 dev veth3 table 200 src fd01::3 metric 1024 pref medium

> 
> Instead of adding a new namespace I can move the second interface to the
> root namespace. This will work, but then we're interfering with the root
> namespace.
> 
>>> +	SYS(fail, "ip route add %s/32 via %s", IPV4_REMOTE_DST, IPV4_GW1);
>>> +	SYS(fail, "ip route add %s/32 via %s table %s", IPV4_REMOTE_DST, IPV4_GW2, MARK_TABLE);
>>> +	SYS(fail, "ip -6 route add %s/128 via %s", IPV6_REMOTE_DST, IPV6_GW1);
>>> +	SYS(fail, "ip -6 route add %s/128 via %s table %s", IPV6_REMOTE_DST, IPV6_GW2, MARK_TABLE);
>>> +	SYS(fail, "ip rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
>>> +	SYS(fail, "ip -6 rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
>>> +
>>> +	err = write_sysctl("/proc/sys/net/ipv4/conf/veth3/forwarding", "1");
>>> +	if (!ASSERT_OK(err, "write_sysctl(net.ipv4.conf.veth3.forwarding)"))
>>> +		goto fail;
>>> +
>>> +	err = write_sysctl("/proc/sys/net/ipv6/conf/veth3/forwarding", "1");
>>> +	if (!ASSERT_OK(err, "write_sysctl(net.ipv6.conf.veth3.forwarding)"))
>>> +		goto fail;
>>> +
>>>    	return 0;
>>>    fail:
>>>    	return -1;
>>>    }
>>
>> [ ... ]
>>
>>> @@ -248,6 +337,7 @@ void test_fib_lookup(void)
>>>    	prog_fd = bpf_program__fd(skel->progs.fib_lookup);
>>>    	SYS(fail, "ip netns add %s", NS_TEST);
>>> +	SYS(fail, "ip netns add %s", NS_REMOTE);
>>
>>
Anton Protopopov March 25, 2024, 8:03 p.m. UTC | #4
On Mon, Mar 25, 2024 at 11:12:39AM -0700, Martin KaFai Lau wrote:
> On 3/24/24 8:04 AM, Anton Protopopov wrote:
> > On Sat, Mar 23, 2024 at 03:34:10PM -0700, Martin KaFai Lau wrote:
> > > On 3/22/24 7:02 AM, Anton Protopopov wrote:
> > > > This patch extends the fib_lookup test suite by adding a few test
> > > > cases for each IP family to test the new BPF_FIB_LOOKUP_MARK flag
> > > > to the bpf_fib_lookup:
> > > > 
> > > >     * Test destination IP address selection with and without a mark
> > > >       and/or the BPF_FIB_LOOKUP_MARK flag set
> > > > 
> > > > To test this functionality another network namespace and a new veth
> > > > pair were added to the test.
> > > > 
> > > 
> > > [ ... ]
> > > 
> > > >    static const struct fib_lookup_test tests[] = {
> > > > @@ -90,10 +105,47 @@ static const struct fib_lookup_test tests[] = {
> > > >    	  .daddr = IPV6_ADDR_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > > >    	  .expected_src = IPV6_IFACE_ADDR_SEC,
> > > >    	  .lookup_flags = BPF_FIB_LOOKUP_SRC | BPF_FIB_LOOKUP_SKIP_NEIGH, },
> > > > +	/* policy routing */
> > > > +	{ .desc = "IPv4 policy routing, default",
> > > > +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > > > +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
> > > > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH, },
> > > > +	{ .desc = "IPv4 policy routing, mark doesn't point to a policy",
> > > > +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > > > +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
> > > > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> > > > +	  .mark = MARK_NO_POLICY, },
> > > > +	{ .desc = "IPv4 policy routing, mark points to a policy",
> > > > +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > > > +	  .expected_dst = IPV4_GW2, .ifname = "veth3",
> > > > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> > > > +	  .mark = MARK, },
> > > > +	{ .desc = "IPv4 policy routing, mark points to a policy, but no flag",
> > > > +	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > > > +	  .expected_dst = IPV4_GW1, .ifname = "veth3",
> > > > +	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH,
> > > > +	  .mark = MARK, },
> > > > +	{ .desc = "IPv6 policy routing, default",
> > > > +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > > > +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
> > > > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH, },
> > > > +	{ .desc = "IPv6 policy routing, mark doesn't point to a policy",
> > > > +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > > > +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
> > > > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> > > > +	  .mark = MARK_NO_POLICY, },
> > > > +	{ .desc = "IPv6 policy routing, mark points to a policy",
> > > > +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > > > +	  .expected_dst = IPV6_GW2, .ifname = "veth3",
> > > > +	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
> > > > +	  .mark = MARK, },
> > > > +	{ .desc = "IPv6 policy routing, mark points to a policy, but no flag",
> > > > +	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
> > > > +	  .expected_dst = IPV6_GW1, .ifname = "veth3",
> > > > +	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH,
> > > > +	  .mark = MARK, },
> > > >    };
> > > > -static int ifindex;
> > > > -
> > > >    static int setup_netns(void)
> > > >    {
> > > >    	int err;
> > > > @@ -144,12 +196,40 @@ static int setup_netns(void)
> > > >    	if (!ASSERT_OK(err, "write_sysctl(net.ipv6.conf.veth1.forwarding)"))
> > > >    		goto fail;
> > > > +	/* Setup for policy routing tests */
> > > > +	SYS(fail, "ip link add veth3 type veth peer name veth4");
> > > > +	SYS(fail, "ip link set dev veth3 up");
> > > > +	SYS(fail, "ip link set dev veth4 netns %s up", NS_REMOTE);
> > > > +
> > > > +	SYS(fail, "ip addr add %s/24 dev veth3", IPV4_LOCAL);
> > > > +	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW1);
> > > > +	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW2);
> > > > +	SYS(fail, "ip addr add %s/64 dev veth3 nodad", IPV6_LOCAL);
> > > > +	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW1);
> > > > +	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW2);
> > > 
> > > Trying to see if the setup can be simplified.
> > > 
> > > Does it need to add another netns and setup a reachable IPV[46]_GW[12] gateway?
> > > 
> > > The test is not sending any traffic and it is a BPF_FIB_LOOKUP_SKIP_NEIGH test.
> > 
> > I think this will not work without another namespace, as FIB lookup will
> > return DST="final destination", not DST="gateway", as the gateway is in the
> > same namespace and can be skipped.
> 
> hmm... not sure I understand why it would get "final destination". Am I missing something?
> To be specific, there is no need to configure the IPV[46]_GW[12] address:
> 
> -	SYS(fail, "ip link set dev veth4 netns %s up", NS_REMOTE);
> 
> 	SYS(fail, "ip addr add %s/24 dev veth3", IPV4_LOCAL);
> -	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW1);
> -	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW2);
> 	SYS(fail, "ip addr add %s/64 dev veth3 nodad", IPV6_LOCAL);
> -	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW1);
> -	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW2);
> 	SYS(fail, "ip route add %s/32 via %s", IPV4_REMOTE_DST, IPV4_GW1);
> 	SYS(fail, "ip route add %s/32 via %s table %s", IPV4_REMOTE_DST, IPV4_GW2, MARK_TABLE);
> 	SYS(fail, "ip -6 route add %s/128 via %s", IPV6_REMOTE_DST, IPV6_GW1);
> 	SYS(fail, "ip -6 route add %s/128 via %s table %s", IPV6_REMOTE_DST, IPV6_GW2, MARK_TABLE);
> 	SYS(fail, "ip rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
> 	SYS(fail, "ip -6 rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
> 
> [root@arch-fb-vm1 ~]# ip netns exec fib_lookup_ns /bin/bash
> 
> [root@arch-fb-vm1 ~]# ip -6 rule
> 0:	from all lookup local
> 2:	from all fwmark 0x2a lookup 200
> 32766:	from all lookup main
> 
> [root@arch-fb-vm1 ~]# ip -6 route show table main
> be:ef::b0:10 via fd01::1 dev veth3 metric 1024 linkdown pref medium
> 
> [root@arch-fb-vm1 ~]# ip -6 route show table 200
> be:ef::b0:10 via fd01::2 dev veth3 metric 1024 linkdown pref medium
> 
> [root@arch-fb-vm1 ~]# ip -6 route get be:ef::b0:10
> be:ef::b0:10 from :: via fd01::1 dev veth3 src fd01::3 metric 1024 pref medium
> 
> [root@arch-fb-vm1 ~]# ip -6 route get be:ef::b0:10 mark 0x2a
> be:ef::b0:10 from :: via fd01::2 dev veth3 table 200 src fd01::3 metric 1024 pref medium

Ok, thanks. I will send a v2 with a simplified test

> > 
> > Instead of adding a new namespace I can move the second interface to the
> > root namespace. This will work, but then we're interfering with the root
> > namespace.
> > 
> > > > +	SYS(fail, "ip route add %s/32 via %s", IPV4_REMOTE_DST, IPV4_GW1);
> > > > +	SYS(fail, "ip route add %s/32 via %s table %s", IPV4_REMOTE_DST, IPV4_GW2, MARK_TABLE);
> > > > +	SYS(fail, "ip -6 route add %s/128 via %s", IPV6_REMOTE_DST, IPV6_GW1);
> > > > +	SYS(fail, "ip -6 route add %s/128 via %s table %s", IPV6_REMOTE_DST, IPV6_GW2, MARK_TABLE);
> > > > +	SYS(fail, "ip rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
> > > > +	SYS(fail, "ip -6 rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
> > > > +
> > > > +	err = write_sysctl("/proc/sys/net/ipv4/conf/veth3/forwarding", "1");
> > > > +	if (!ASSERT_OK(err, "write_sysctl(net.ipv4.conf.veth3.forwarding)"))
> > > > +		goto fail;
> > > > +
> > > > +	err = write_sysctl("/proc/sys/net/ipv6/conf/veth3/forwarding", "1");
> > > > +	if (!ASSERT_OK(err, "write_sysctl(net.ipv6.conf.veth3.forwarding)"))
> > > > +		goto fail;
> > > > +
> > > >    	return 0;
> > > >    fail:
> > > >    	return -1;
> > > >    }
> > > 
> > > [ ... ]
> > > 
> > > > @@ -248,6 +337,7 @@ void test_fib_lookup(void)
> > > >    	prog_fd = bpf_program__fd(skel->progs.fib_lookup);
> > > >    	SYS(fail, "ip netns add %s", NS_TEST);
> > > > +	SYS(fail, "ip netns add %s", NS_REMOTE);
> > > 
> > > 
>
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/prog_tests/fib_lookup.c b/tools/testing/selftests/bpf/prog_tests/fib_lookup.c
index 3379df2d4cf2..a78316431f32 100644
--- a/tools/testing/selftests/bpf/prog_tests/fib_lookup.c
+++ b/tools/testing/selftests/bpf/prog_tests/fib_lookup.c
@@ -10,6 +10,7 @@ 
 #include "fib_lookup.skel.h"
 
 #define NS_TEST			"fib_lookup_ns"
+#define NS_REMOTE		"remote_ns"
 #define IPV6_IFACE_ADDR		"face::face"
 #define IPV6_IFACE_ADDR_SEC	"cafe::cafe"
 #define IPV6_ADDR_DST		"face::3"
@@ -26,6 +27,17 @@ 
 #define IPV6_TBID_ADDR		"fd00::FFFF"
 #define IPV6_TBID_NET		"fd00::"
 #define IPV6_TBID_DST		"fd00::2"
+#define MARK_NO_POLICY		33
+#define MARK			42
+#define MARK_TABLE		"200"
+#define IPV4_REMOTE_DST		"1.2.3.4"
+#define IPV4_LOCAL		"10.4.0.3"
+#define IPV4_GW1		"10.4.0.1"
+#define IPV4_GW2		"10.4.0.2"
+#define IPV6_REMOTE_DST		"be:ef::b0:10"
+#define IPV6_LOCAL		"fd01::3"
+#define IPV6_GW1		"fd01::1"
+#define IPV6_GW2		"fd01::2"
 #define DMAC			"11:11:11:11:11:11"
 #define DMAC_INIT { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, }
 #define DMAC2			"01:01:01:01:01:01"
@@ -36,9 +48,12 @@  struct fib_lookup_test {
 	const char *daddr;
 	int expected_ret;
 	const char *expected_src;
+	const char *expected_dst;
 	int lookup_flags;
 	__u32 tbid;
 	__u8 dmac[6];
+	__u32 mark;
+	const char *ifname;
 };
 
 static const struct fib_lookup_test tests[] = {
@@ -90,10 +105,47 @@  static const struct fib_lookup_test tests[] = {
 	  .daddr = IPV6_ADDR_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
 	  .expected_src = IPV6_IFACE_ADDR_SEC,
 	  .lookup_flags = BPF_FIB_LOOKUP_SRC | BPF_FIB_LOOKUP_SKIP_NEIGH, },
+	/* policy routing */
+	{ .desc = "IPv4 policy routing, default",
+	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
+	  .expected_dst = IPV4_GW1, .ifname = "veth3",
+	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH, },
+	{ .desc = "IPv4 policy routing, mark doesn't point to a policy",
+	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
+	  .expected_dst = IPV4_GW1, .ifname = "veth3",
+	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
+	  .mark = MARK_NO_POLICY, },
+	{ .desc = "IPv4 policy routing, mark points to a policy",
+	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
+	  .expected_dst = IPV4_GW2, .ifname = "veth3",
+	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
+	  .mark = MARK, },
+	{ .desc = "IPv4 policy routing, mark points to a policy, but no flag",
+	  .daddr = IPV4_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
+	  .expected_dst = IPV4_GW1, .ifname = "veth3",
+	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH,
+	  .mark = MARK, },
+	{ .desc = "IPv6 policy routing, default",
+	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
+	  .expected_dst = IPV6_GW1, .ifname = "veth3",
+	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH, },
+	{ .desc = "IPv6 policy routing, mark doesn't point to a policy",
+	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
+	  .expected_dst = IPV6_GW1, .ifname = "veth3",
+	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
+	  .mark = MARK_NO_POLICY, },
+	{ .desc = "IPv6 policy routing, mark points to a policy",
+	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
+	  .expected_dst = IPV6_GW2, .ifname = "veth3",
+	  .lookup_flags = BPF_FIB_LOOKUP_MARK | BPF_FIB_LOOKUP_SKIP_NEIGH,
+	  .mark = MARK, },
+	{ .desc = "IPv6 policy routing, mark points to a policy, but no flag",
+	  .daddr = IPV6_REMOTE_DST, .expected_ret = BPF_FIB_LKUP_RET_SUCCESS,
+	  .expected_dst = IPV6_GW1, .ifname = "veth3",
+	  .lookup_flags = BPF_FIB_LOOKUP_SKIP_NEIGH,
+	  .mark = MARK, },
 };
 
-static int ifindex;
-
 static int setup_netns(void)
 {
 	int err;
@@ -144,12 +196,40 @@  static int setup_netns(void)
 	if (!ASSERT_OK(err, "write_sysctl(net.ipv6.conf.veth1.forwarding)"))
 		goto fail;
 
+	/* Setup for policy routing tests */
+	SYS(fail, "ip link add veth3 type veth peer name veth4");
+	SYS(fail, "ip link set dev veth3 up");
+	SYS(fail, "ip link set dev veth4 netns %s up", NS_REMOTE);
+
+	SYS(fail, "ip addr add %s/24 dev veth3", IPV4_LOCAL);
+	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW1);
+	SYS(fail, "ip netns exec %s ip addr add %s/24 dev veth4", NS_REMOTE, IPV4_GW2);
+	SYS(fail, "ip addr add %s/64 dev veth3 nodad", IPV6_LOCAL);
+	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW1);
+	SYS(fail, "ip netns exec %s ip addr add %s/64 dev veth4 nodad", NS_REMOTE, IPV6_GW2);
+	SYS(fail, "ip route add %s/32 via %s", IPV4_REMOTE_DST, IPV4_GW1);
+	SYS(fail, "ip route add %s/32 via %s table %s", IPV4_REMOTE_DST, IPV4_GW2, MARK_TABLE);
+	SYS(fail, "ip -6 route add %s/128 via %s", IPV6_REMOTE_DST, IPV6_GW1);
+	SYS(fail, "ip -6 route add %s/128 via %s table %s", IPV6_REMOTE_DST, IPV6_GW2, MARK_TABLE);
+	SYS(fail, "ip rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
+	SYS(fail, "ip -6 rule add prio 2 fwmark %d lookup %s", MARK, MARK_TABLE);
+
+	err = write_sysctl("/proc/sys/net/ipv4/conf/veth3/forwarding", "1");
+	if (!ASSERT_OK(err, "write_sysctl(net.ipv4.conf.veth3.forwarding)"))
+		goto fail;
+
+	err = write_sysctl("/proc/sys/net/ipv6/conf/veth3/forwarding", "1");
+	if (!ASSERT_OK(err, "write_sysctl(net.ipv6.conf.veth3.forwarding)"))
+		goto fail;
+
 	return 0;
 fail:
 	return -1;
 }
 
-static int set_lookup_params(struct bpf_fib_lookup *params, const struct fib_lookup_test *test)
+static int set_lookup_params(struct bpf_fib_lookup *params,
+			     const struct fib_lookup_test *test,
+			     int ifindex)
 {
 	int ret;
 
@@ -159,6 +239,9 @@  static int set_lookup_params(struct bpf_fib_lookup *params, const struct fib_loo
 	params->ifindex = ifindex;
 	params->tbid = test->tbid;
 
+	if (test->lookup_flags & BPF_FIB_LOOKUP_MARK)
+		params->mark = test->mark;
+
 	if (inet_pton(AF_INET6, test->daddr, params->ipv6_dst) == 1) {
 		params->family = AF_INET6;
 		if (!(test->lookup_flags & BPF_FIB_LOOKUP_SRC)) {
@@ -190,40 +273,45 @@  static void mac_str(char *b, const __u8 *mac)
 		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
 }
 
-static void assert_src_ip(struct bpf_fib_lookup *fib_params, const char *expected_src)
+static void assert_ip_address(int family, void *addr, const char *expected_str)
 {
+	char str[INET6_ADDRSTRLEN];
+	u8 expected_addr[16];
+	int addr_len = 0;
 	int ret;
-	__u32 src6[4];
-	__be32 src4;
 
-	switch (fib_params->family) {
+	switch (family) {
 	case AF_INET6:
-		ret = inet_pton(AF_INET6, expected_src, src6);
-		ASSERT_EQ(ret, 1, "inet_pton(expected_src)");
-
-		ret = memcmp(src6, fib_params->ipv6_src, sizeof(fib_params->ipv6_src));
-		if (!ASSERT_EQ(ret, 0, "fib_lookup ipv6 src")) {
-			char str_src6[64];
-
-			inet_ntop(AF_INET6, fib_params->ipv6_src, str_src6,
-				  sizeof(str_src6));
-			printf("ipv6 expected %s actual %s ", expected_src,
-			       str_src6);
-		}
-
+		ret = inet_pton(AF_INET6, expected_str, expected_addr);
+		ASSERT_EQ(ret, 1, "inet_pton(AF_INET6, expected_str)");
+		addr_len = 16;
 		break;
 	case AF_INET:
-		ret = inet_pton(AF_INET, expected_src, &src4);
-		ASSERT_EQ(ret, 1, "inet_pton(expected_src)");
-
-		ASSERT_EQ(fib_params->ipv4_src, src4, "fib_lookup ipv4 src");
-
+		ret = inet_pton(AF_INET, expected_str, expected_addr);
+		ASSERT_EQ(ret, 1, "inet_pton(AF_INET, expected_str)");
+		addr_len = 4;
 		break;
 	default:
-		PRINT_FAIL("invalid addr family: %d", fib_params->family);
+		PRINT_FAIL("invalid address family: %d", family);
+		break;
+	}
+
+	if (memcmp(addr, expected_addr, addr_len)) {
+		inet_ntop(family, addr, str, sizeof(str));
+		PRINT_FAIL("expected %s actual %s ", expected_str, str);
 	}
 }
 
+static void assert_src_ip(struct bpf_fib_lookup *params, const char *expected)
+{
+	assert_ip_address(params->family, params->ipv6_src, expected);
+}
+
+static void assert_dst_ip(struct bpf_fib_lookup *params, const char *expected)
+{
+	assert_ip_address(params->family, params->ipv6_dst, expected);
+}
+
 void test_fib_lookup(void)
 {
 	struct bpf_fib_lookup *fib_params;
@@ -231,6 +319,7 @@  void test_fib_lookup(void)
 	struct __sk_buff skb = { };
 	struct fib_lookup *skel;
 	int prog_fd, err, ret, i;
+	int default_ifindex;
 
 	/* The test does not use the skb->data, so
 	 * use pkt_v6 for both v6 and v4 test.
@@ -248,6 +337,7 @@  void test_fib_lookup(void)
 	prog_fd = bpf_program__fd(skel->progs.fib_lookup);
 
 	SYS(fail, "ip netns add %s", NS_TEST);
+	SYS(fail, "ip netns add %s", NS_REMOTE);
 
 	nstoken = open_netns(NS_TEST);
 	if (!ASSERT_OK_PTR(nstoken, "open_netns"))
@@ -256,15 +346,23 @@  void test_fib_lookup(void)
 	if (setup_netns())
 		goto fail;
 
-	ifindex = if_nametoindex("veth1");
-	skb.ifindex = ifindex;
+	default_ifindex = if_nametoindex("veth1");
+	if (!ASSERT_NEQ(default_ifindex, 0, "if_nametoindex(veth1)"))
+		goto fail;
+
 	fib_params = &skel->bss->fib_params;
 
 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
 		printf("Testing %s ", tests[i].desc);
 
-		if (set_lookup_params(fib_params, &tests[i]))
+		if (tests[i].ifname)
+			skb.ifindex = if_nametoindex(tests[i].ifname);
+		else
+			skb.ifindex = default_ifindex;
+
+		if (set_lookup_params(fib_params, &tests[i], skb.ifindex))
 			continue;
+
 		skel->bss->fib_lookup_ret = -1;
 		skel->bss->lookup_flags = tests[i].lookup_flags;
 
@@ -278,6 +376,9 @@  void test_fib_lookup(void)
 		if (tests[i].expected_src)
 			assert_src_ip(fib_params, tests[i].expected_src);
 
+		if (tests[i].expected_dst)
+			assert_dst_ip(fib_params, tests[i].expected_dst);
+
 		ret = memcmp(tests[i].dmac, fib_params->dmac, sizeof(tests[i].dmac));
 		if (!ASSERT_EQ(ret, 0, "dmac not match")) {
 			char expected[18], actual[18];
@@ -299,5 +400,6 @@  void test_fib_lookup(void)
 	if (nstoken)
 		close_netns(nstoken);
 	SYS_NOFAIL("ip netns del " NS_TEST);
+	SYS_NOFAIL("ip netns del " NS_REMOTE);
 	fib_lookup__destroy(skel);
 }