Re: [PATCH bpf v2] selftests/bpf: Rewrite test_tc_redirect.sh as prog_tests/tc_redirect.c

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, May 3, 2021 at 4:12 AM Jussi Maki <joamaki@xxxxxxxxx> wrote:
>
> Ports test_tc_redirect.sh to the test_progs framework and removes the
> old test. This makes it more in line with rest of the tests and makes
> it possible to run this test with vmtest.sh and under the bpf CI.
>
> Signed-off-by: Jussi Maki <joamaki@xxxxxxxxx>
> ---

One bug and few mostly mechanical nits. It would be great to get a
code review from someone that knows something about iproute2 and the
whole networking stuff :)

>  tools/testing/selftests/bpf/network_helpers.c |   2 +-
>  tools/testing/selftests/bpf/network_helpers.h |   1 +
>  .../selftests/bpf/prog_tests/tc_redirect.c    | 594 ++++++++++++++++++
>  .../selftests/bpf/progs/test_tc_neigh.c       |  33 +-
>  .../selftests/bpf/progs/test_tc_neigh_fib.c   |   9 +-
>  .../selftests/bpf/progs/test_tc_peer.c        |  33 +-
>  .../testing/selftests/bpf/test_tc_redirect.sh | 216 -------
>  7 files changed, 622 insertions(+), 266 deletions(-)
>  create mode 100644 tools/testing/selftests/bpf/prog_tests/tc_redirect.c
>  delete mode 100755 tools/testing/selftests/bpf/test_tc_redirect.sh
>

[...]

> +
> +/**
> + * modify_proc() - Modify entry in /proc
> + *
> + * Modifies an entry in /proc and saves the original value for later
> + * restoration with restore_proc().
> + */
> +static int modify_proc(const char *path, const char *newval)
> +{
> +       struct proc_mod *mod;
> +       FILE *f;
> +
> +       f = fopen(path, "r+");
> +       if (!f)
> +               return -1;
> +
> +       if (num_proc_mods + 1 > MAX_PROC_MODS)
> +               goto fail;

you'll decrement num_proc_mods without incrementing it

> +
> +       num_proc_mods++;
> +       mod = &proc_mods[num_proc_mods-1];
> +
> +       strncpy(mod->path, path, PATH_MAX);
> +
> +       if (!fread(mod->oldval, 1, MAX_PROC_VALUE_LEN, f)) {
> +               log_err("reading from %s failed", path);
> +               goto fail;
> +       }
> +       rewind(f);
> +       if (fwrite(newval, strlen(newval), 1, f) != 1) {
> +               log_err("writing to %s failed", path);
> +               goto fail;
> +       }
> +
> +       fclose(f);
> +       return 0;
> +fail:
> +
> +       fclose(f);
> +       num_proc_mods--;
> +       return -1;
> +}
> +
> +/**
> + * restore_proc() - Restore all /proc modifications
> + */
> +static void restore_proc(void)
> +{
> +       int i;
> +
> +       for (i = 0; i < num_proc_mods; i++) {
> +               struct proc_mod *mod = &proc_mods[i];
> +               FILE *f = fopen(mod->path, "w");

we typically split variable declaration and function calls when the
function can fail, so pretty much anything non-trivial will be done as
a separate statement (followed immediately by error check)

> +
> +               if (!f) {
> +                       log_err("fopen of %s failed", mod->path);
> +                       continue;
> +               }
> +
> +               if (fwrite(mod->oldval, mod->oldlen, 1, f) != 1)
> +                       log_err("fwrite to %s failed", mod->path);
> +
> +               fclose(f);
> +       }
> +       num_proc_mods = 0;
> +}
> +

[...]

> +
> +static int netns_setup_links_and_routes(struct netns_setup_result *result)
> +{
> +       char veth_src_fwd_addr[IFADDR_STR_LEN+1] = {0,};
> +       char veth_dst_fwd_addr[IFADDR_STR_LEN+1] = {0,};

just "= {};". same effect, but not misleading notation

> +
> +       SYS("ip link add veth_src type veth peer name veth_src_fwd");
> +       SYS("ip link add veth_dst type veth peer name veth_dst_fwd");
> +       if (get_ifaddr("veth_src_fwd", veth_src_fwd_addr))
> +               goto fail;
> +       if (get_ifaddr("veth_dst_fwd", veth_dst_fwd_addr))
> +               goto fail;
> +
> +       result->ifindex_veth_src_fwd = get_ifindex("veth_src_fwd");
> +       if (result->ifindex_veth_src_fwd < 0)
> +               goto fail;
> +       result->ifindex_veth_dst_fwd = get_ifindex("veth_dst_fwd");
> +       if (result->ifindex_veth_dst_fwd < 0)
> +               goto fail;
> +

[...]

> +static void test_tcp(int family, const char *addr, __u16 port)
> +{
> +       int listen_fd = -1, accept_fd = -1, client_fd = -1;
> +       char buf[] = "testing testing";
> +
> +       if (!ASSERT_OK(setns_by_name(NS_DST), "setns dst"))
> +               return;
> +
> +       listen_fd = start_server(family, SOCK_STREAM, addr, port, 0);
> +       if (!ASSERT_GE(listen_fd, 0, "listen"))
> +               goto done;
> +
> +       if (!ASSERT_OK(setns_by_name(NS_SRC), "setns src"))
> +               goto done;
> +
> +       client_fd = connect_to_fd(listen_fd, TIMEOUT_MILLIS);
> +       if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
> +               goto done;
> +
> +       accept_fd = accept(listen_fd, NULL, NULL);
> +       if (!ASSERT_GE(accept_fd, 0, "accept"))
> +               goto done;
> +
> +       if (!ASSERT_OK(settimeo(accept_fd, TIMEOUT_MILLIS), "settimeo"))
> +               goto done;
> +
> +       if (!ASSERT_EQ(
> +               write(client_fd, buf, sizeof(buf)),
> +               sizeof(buf),
> +               "send to server"))
> +               goto done;

I think cases like this are much cleaner if written as:

n = write(client_fd, buf, sizeof(buf));
if (!ASSERT_EQ(n, sizeof(buf), "send to server"))
    goto done;

Don't try to do too much in a single if. Same below.

> +
> +       if (!ASSERT_EQ(
> +               read(accept_fd, buf, sizeof(buf)),
> +               sizeof(buf),
> +               "recv from server"))
> +               goto done;
> +
> +done:
> +       setns_root();
> +       if (listen_fd >= 0)
> +               close(listen_fd);
> +       if (accept_fd >= 0)
> +               close(accept_fd);
> +       if (client_fd >= 0)
> +               close(client_fd);
> +}
> +
> +static int test_ping(int family, const char *addr)
> +{
> +       const char *ping = family == AF_INET6 ? "ping6" : "ping";
> +
> +       SYS("ip netns exec " NS_SRC " %s " PING_ARGS " %s", ping, addr);
> +       return 0;
> +fail:
> +       return -1;
> +}
> +
> +static void test_connectivity(void)
> +{
> +       test_tcp(AF_INET, IP4_DST, IP4_PORT);
> +       test_ping(AF_INET, IP4_DST);
> +       test_tcp(AF_INET6, IP6_DST, IP6_PORT);
> +       test_ping(AF_INET6, IP6_DST);
> +}
> +
> +static void test_tc_redirect_neigh_fib(struct netns_setup_result *setup_result)
> +{
> +       struct test_tc_neigh_fib *skel;
> +
> +       skel = test_tc_neigh_fib__open();
> +       if (!ASSERT_OK_PTR(skel, "test_tc_neigh_fib__open"))
> +               return;
> +
> +       if (!ASSERT_OK(test_tc_neigh_fib__load(skel), "test_tc_neigh_fib__load")) {
> +               test_tc_neigh_fib__destroy(skel);
> +               return;
> +       }
> +
> +       if (!ASSERT_OK(
> +               bpf_program__pin(skel->progs.tc_src, SRC_PROG_PIN_FILE),
> +               "pin " SRC_PROG_PIN_FILE))
> +               goto done;
> +

see above, use

err = bpf_program__pin(...);
if (!ASSERT_OK(err, ...))

That actually makes it easier to debug as well, btw.

> +       if (!ASSERT_OK(
> +               bpf_program__pin(skel->progs.tc_chk, CHK_PROG_PIN_FILE),
> +               "pin " CHK_PROG_PIN_FILE))
> +               goto done;
> +
> +       if (!ASSERT_OK(
> +               bpf_program__pin(skel->progs.tc_dst, DST_PROG_PIN_FILE),
> +               "pin " DST_PROG_PIN_FILE))
> +               goto done;
> +
> +       if (netns_load_bpf())
> +               goto done;
> +
> +       /* bpf_fib_lookup() checks if forwarding is enabled */
> +       if (!ASSERT_OK(setns_by_name(NS_FWD), "setns fwd"))
> +               goto done;
> +       if (!ASSERT_OK(modify_proc("/proc/sys/net/ipv4/ip_forward", "1"),
> +                                  "set ipv4.ip_forward"))
> +               goto done;
> +       if (!ASSERT_OK(modify_proc("/proc/sys/net/ipv6/conf/all/forwarding", "1"),
> +                                  "set ipv6.forwarding"))
> +               goto done;
> +       setns_root();
> +
> +       test_connectivity();
> +done:
> +       bpf_program__unpin(skel->progs.tc_src, SRC_PROG_PIN_FILE);
> +       bpf_program__unpin(skel->progs.tc_chk, CHK_PROG_PIN_FILE);
> +       bpf_program__unpin(skel->progs.tc_dst, DST_PROG_PIN_FILE);
> +       test_tc_neigh_fib__destroy(skel);
> +       netns_unload_bpf();
> +       setns_root();
> +       restore_proc();
> +}
> +

[...]



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux