bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Andrii Nakryiko <andrii.nakryiko@gmail.com>
To: Jussi Maki <joamaki@gmail.com>
Cc: bpf <bpf@vger.kernel.org>, Daniel Borkmann <daniel@iogearbox.net>
Subject: Re: [PATCH bpf v2] selftests/bpf: Rewrite test_tc_redirect.sh as prog_tests/tc_redirect.c
Date: Mon, 3 May 2021 16:08:28 -0700	[thread overview]
Message-ID: <CAEf4BzY0fK3SGJbci0QoPxW1VkerNQ4BGZ4qWOH6WoANw5SAPQ@mail.gmail.com> (raw)
In-Reply-To: <20210503111203.3948860-1-joamaki@gmail.com>

On Mon, May 3, 2021 at 4:12 AM Jussi Maki <joamaki@gmail.com> 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@gmail.com>
> ---

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();
> +}
> +

[...]

  reply	other threads:[~2021-05-03 23:08 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-04-29 15:30 [PATCH bpf] selftests/bpf: Rewrite test_tc_redirect.sh as prog_tests/tc_redirect.c Jussi Maki
2021-04-30 19:56 ` Andrii Nakryiko
2021-05-03 10:58   ` Jussi Maki
2021-05-03 11:12 ` [PATCH bpf v2] " Jussi Maki
2021-05-03 23:08   ` Andrii Nakryiko [this message]
2021-05-05  8:59 ` [PATCH bpf v3] " Jussi Maki
2021-05-11 21:30   ` patchwork-bot+netdevbpf
2021-07-19 23:26 ` [PATCH bpf] " Andrii Nakryiko
2021-07-08  2:17   ` [PATCH bpf] selftests/bpf: Use ping6 only if available in tc_redirect Jussi Maki
2021-07-27 18:02     ` Andrii Nakryiko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAEf4BzY0fK3SGJbci0QoPxW1VkerNQ4BGZ4qWOH6WoANw5SAPQ@mail.gmail.com \
    --to=andrii.nakryiko@gmail.com \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=joamaki@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).