Hi Martin,
On Wed, Nov 30, 2022 at 8:41 PM Martin KaFai Lau martin.lau@linux.dev wrote:
On 11/29/22 5:20 AM, Eyal Birger wrote:
Test the xfrm_info kfunc helpers.
Note: the tests require support for xfrmi "external" mode in iproute2.
The test setup creates three name spaces - NS0, NS1, NS2.
XFRM tunnels are setup between NS0 and the two other NSs.
The kfunc helpers are used to steer traffic from NS0 to the other NSs based on a userspace populated map and validate that the return traffic had arrived from the desired NS.
Signed-off-by: Eyal Birger eyal.birger@gmail.com
v2:
- use an lwt route in NS1 for testing that flow as well
- indendation fix
tools/testing/selftests/bpf/config | 2 + .../selftests/bpf/prog_tests/test_xfrm_info.c | 343 ++++++++++++++++++ .../selftests/bpf/progs/test_xfrm_info_kern.c | 74 ++++ 3 files changed, 419 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/test_xfrm_info.c create mode 100644 tools/testing/selftests/bpf/progs/test_xfrm_info_kern.c
diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 9213565c0311..9f39943d6ebd 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -20,6 +20,7 @@ CONFIG_IKCONFIG_PROC=y CONFIG_IMA=y CONFIG_IMA_READ_POLICY=y CONFIG_IMA_WRITE_POLICY=y +CONFIG_INET_ESP=y CONFIG_IP_NF_FILTER=y CONFIG_IP_NF_RAW=y CONFIG_IP_NF_TARGET_SYNPROXY=y @@ -71,3 +72,4 @@ CONFIG_TEST_BPF=y CONFIG_USERFAULTFD=y CONFIG_VXLAN=y CONFIG_XDP_SOCKETS=y +CONFIG_XFRM_INTERFACE=y diff --git a/tools/testing/selftests/bpf/prog_tests/test_xfrm_info.c b/tools/testing/selftests/bpf/prog_tests/test_xfrm_info.c new file mode 100644 index 000000000000..3aef72540934 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/test_xfrm_info.c
Nit. Just xfrm_info.c
Ok.
@@ -0,0 +1,343 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
- Topology:
- NS0 namespace | NS1 namespace | NS2 namespace
| |
- +---------------+ | +---------------+ |
- | ipsec0 |---------| ipsec0 | |
- | 192.168.1.100 | | | 192.168.1.200 | |
- | if_id: bpf | | +---------------+ |
- +---------------+ | |
| | | +---------------+
| | | | ipsec0 |
\------------------------------------------| 192.168.1.200 |
| | +---------------+
| |
| | (overlay network)
------------------------------------------------------
| | (underlay network)
- +--------------+ | +--------------+ |
- | veth01 |----------| veth10 | |
- | 172.16.1.100 | | | 172.16.1.200 | |
- ---------------+ | +--------------+ |
| |
- +--------------+ | | +--------------+
- | veth02 |-----------------------------------| veth20 |
- | 172.16.2.100 | | | | 172.16.2.200 |
- +--------------+ | | +--------------+
[...]
+#define RUN_TEST(name) \
({ \
if (test__start_subtest(#name)) { \
test_ ## name(); \
} \
})
+static void *test_xfrm_info_run_tests(void *arg) +{
cleanup();
config_underlay();
config_overlay();
config_*() is returning ok/err but no error checking here. Does it make sense to continue if the config_*() failed?
I'll assert their success.
RUN_TEST(xfrm_info);
nit. Remove this macro indirection. There is only one test.
Ok. I was considering other possible tests in the future, but this can be added then.
cleanup();
return NULL;
+}
+static int probe_iproute2(void) +{
if (SYS_NOFAIL("ip link add type xfrm help 2>&1 | "
"grep external > /dev/null")) {
fprintf(stdout, "%s:SKIP: iproute2 with xfrm external support needed for this test\n", __func__);
Unfortunately, the BPF CI iproute2 does not have this support also :( I am worry it will just stay SKIP for some time and rot. Can you try to directly use netlink here?
Yeah, I wasn't sure if adding a libmnl (or alternative) dependency was ok here, and also didn't want to copy all that nl logic here. So I figured it would get there eventually.
I noticed libmnl is used by the nf tests, so maybe its inclusion isn't too bad. Unless there's a better approach.
As you noted, I should add this for the "external" support. However, I don't think adding the LWT route directly using nl is a good idea here so I'll make the NS1 use a regular xfrmi.
https://github.com/kernel-patches/bpf/actions/runs/3578467213/jobs/601937075...
return -1;
}
return 0;
+}
+void serial_test_xfrm_info(void)
Remove "serial_". New test must be able to run in parallel ("./test_progs -j").
Ok.
+{
pthread_t test_thread;
int err;
if (probe_iproute2()) {
test__skip();
return;
}
/* Run the tests in their own thread to isolate the namespace changes
* so they do not affect the environment of other tests.
* (specifically needed because of unshare(CLONE_NEWNS) in open_netns())
*/
I think this comment is mostly inherited from other tests (eg. tc_redirect.c) but the pthread dance is actually unnecessary. The test_progs.c will restore the original netns before running the next test. I am abort to remove this from the tc_redirect.c also. Please also avoid this pthread create here.
Ok. Indeed was inherited.
err = pthread_create(&test_thread, NULL, &test_xfrm_info_run_tests, NULL);
if (ASSERT_OK(err, "pthread_create"))
ASSERT_OK(pthread_join(test_thread, NULL), "pthread_join");
+} diff --git a/tools/testing/selftests/bpf/progs/test_xfrm_info_kern.c b/tools/testing/selftests/bpf/progs/test_xfrm_info_kern.c new file mode 100644 index 000000000000..98991a83c1e9 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_xfrm_info_kern.c
Nit. Same here. Just xfrm_info.c.
Ok.
@@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/bpf.h> +#include <linux/pkt_cls.h> +#include <bpf/bpf_helpers.h>
+#define log_err(__ret) bpf_printk("ERROR line:%d ret:%d\n", __LINE__, __ret)
Please try not to use unnecessary bpf_printk(). BPF CI is not capturing it also.
Ok.
+struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 2);
__type(key, __u32);
__type(value, __u32);
+} dst_if_id_map SEC(".maps");
It is easier to use global variables instead of a map.
Would these be available for read/write from the test application (as the map is currently populated/read from userspace)?
+struct bpf_xfrm_info {
__u32 if_id;
int link;
+};
This needs __attribute__((preserve_access_index) for CO-RE. It is easier to just include vmlinux.h to get the struct xfrm_md_info { ... }.
Ok.
+int bpf_skb_set_xfrm_info(struct __sk_buff *skb_ctx,
const struct bpf_xfrm_info *from) __ksym;
+int bpf_skb_get_xfrm_info(struct __sk_buff *skb_ctx,
struct bpf_xfrm_info *to) __ksym;
+SEC("tc") +int set_xfrm_info(struct __sk_buff *skb) +{
struct bpf_xfrm_info info = {};
__u32 *if_id = NULL;
__u32 index = 0;
int ret = -1;
if_id = bpf_map_lookup_elem(&dst_if_id_map, &index);
if (!if_id) {
log_err(ret);
return TC_ACT_SHOT;
}
info.if_id = *if_id;
ret = bpf_skb_set_xfrm_info(skb, &info);
if (ret < 0) {
log_err(ret);
return TC_ACT_SHOT;
}
return TC_ACT_UNSPEC;
+}
+SEC("tc") +int get_xfrm_info(struct __sk_buff *skb) +{
struct bpf_xfrm_info info = {};
__u32 *if_id = NULL;
__u32 index = 1;
int ret = -1;
if_id = bpf_map_lookup_elem(&dst_if_id_map, &index);
if (!if_id) {
log_err(ret);
return TC_ACT_SHOT;
}
ret = bpf_skb_get_xfrm_info(skb, &info);
if (ret < 0) {
log_err(ret);
return TC_ACT_SHOT;
}
*if_id = info.if_id;
return TC_ACT_UNSPEC;
+}
+char _license[] SEC("license") = "GPL";
Thanks for the review! Eyal.