linux/tools/testing/selftests/bpf/prog_tests/btf_skc_cls_ingress.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (c) 2020 Facebook */
   3
   4#define _GNU_SOURCE
   5#include <netinet/in.h>
   6#include <arpa/inet.h>
   7#include <unistd.h>
   8#include <stdlib.h>
   9#include <string.h>
  10#include <errno.h>
  11#include <sched.h>
  12#include <linux/compiler.h>
  13#include <bpf/libbpf.h>
  14
  15#include "network_helpers.h"
  16#include "test_progs.h"
  17#include "test_btf_skc_cls_ingress.skel.h"
  18
  19static struct test_btf_skc_cls_ingress *skel;
  20static struct sockaddr_in6 srv_sa6;
  21static __u32 duration;
  22
  23#define PROG_PIN_FILE "/sys/fs/bpf/btf_skc_cls_ingress"
  24
  25static int write_sysctl(const char *sysctl, const char *value)
  26{
  27        int fd, err, len;
  28
  29        fd = open(sysctl, O_WRONLY);
  30        if (CHECK(fd == -1, "open sysctl", "open(%s): %s (%d)\n",
  31                  sysctl, strerror(errno), errno))
  32                return -1;
  33
  34        len = strlen(value);
  35        err = write(fd, value, len);
  36        close(fd);
  37        if (CHECK(err != len, "write sysctl",
  38                  "write(%s, %s, %d): err:%d %s (%d)\n",
  39                  sysctl, value, len, err, strerror(errno), errno))
  40                return -1;
  41
  42        return 0;
  43}
  44
  45static int prepare_netns(void)
  46{
  47        if (CHECK(unshare(CLONE_NEWNET), "create netns",
  48                  "unshare(CLONE_NEWNET): %s (%d)",
  49                  strerror(errno), errno))
  50                return -1;
  51
  52        if (CHECK(system("ip link set dev lo up"),
  53                  "ip link set dev lo up", "failed\n"))
  54                return -1;
  55
  56        if (CHECK(system("tc qdisc add dev lo clsact"),
  57                  "tc qdisc add dev lo clsact", "failed\n"))
  58                return -1;
  59
  60        if (CHECK(system("tc filter add dev lo ingress bpf direct-action object-pinned " PROG_PIN_FILE),
  61                  "install tc cls-prog at ingress", "failed\n"))
  62                return -1;
  63
  64        /* Ensure 20 bytes options (i.e. in total 40 bytes tcp header) for the
  65         * bpf_tcp_gen_syncookie() helper.
  66         */
  67        if (write_sysctl("/proc/sys/net/ipv4/tcp_window_scaling", "1") ||
  68            write_sysctl("/proc/sys/net/ipv4/tcp_timestamps", "1") ||
  69            write_sysctl("/proc/sys/net/ipv4/tcp_sack", "1"))
  70                return -1;
  71
  72        return 0;
  73}
  74
  75static void reset_test(void)
  76{
  77        memset(&skel->bss->srv_sa6, 0, sizeof(skel->bss->srv_sa6));
  78        skel->bss->listen_tp_sport = 0;
  79        skel->bss->req_sk_sport = 0;
  80        skel->bss->recv_cookie = 0;
  81        skel->bss->gen_cookie = 0;
  82        skel->bss->linum = 0;
  83}
  84
  85static void print_err_line(void)
  86{
  87        if (skel->bss->linum)
  88                printf("bpf prog error at line %u\n", skel->bss->linum);
  89}
  90
  91static void test_conn(void)
  92{
  93        int listen_fd = -1, cli_fd = -1, err;
  94        socklen_t addrlen = sizeof(srv_sa6);
  95        int srv_port;
  96
  97        if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "1"))
  98                return;
  99
 100        listen_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0);
 101        if (CHECK_FAIL(listen_fd == -1))
 102                return;
 103
 104        err = getsockname(listen_fd, (struct sockaddr *)&srv_sa6, &addrlen);
 105        if (CHECK(err, "getsockname(listen_fd)", "err:%d errno:%d\n", err,
 106                  errno))
 107                goto done;
 108        memcpy(&skel->bss->srv_sa6, &srv_sa6, sizeof(srv_sa6));
 109        srv_port = ntohs(srv_sa6.sin6_port);
 110
 111        cli_fd = connect_to_fd(listen_fd, 0);
 112        if (CHECK_FAIL(cli_fd == -1))
 113                goto done;
 114
 115        if (CHECK(skel->bss->listen_tp_sport != srv_port ||
 116                  skel->bss->req_sk_sport != srv_port,
 117                  "Unexpected sk src port",
 118                  "listen_tp_sport:%u req_sk_sport:%u expected:%u\n",
 119                  skel->bss->listen_tp_sport, skel->bss->req_sk_sport,
 120                  srv_port))
 121                goto done;
 122
 123        if (CHECK(skel->bss->gen_cookie || skel->bss->recv_cookie,
 124                  "Unexpected syncookie states",
 125                  "gen_cookie:%u recv_cookie:%u\n",
 126                  skel->bss->gen_cookie, skel->bss->recv_cookie))
 127                goto done;
 128
 129        CHECK(skel->bss->linum, "bpf prog detected error", "at line %u\n",
 130              skel->bss->linum);
 131
 132done:
 133        if (listen_fd != -1)
 134                close(listen_fd);
 135        if (cli_fd != -1)
 136                close(cli_fd);
 137}
 138
 139static void test_syncookie(void)
 140{
 141        int listen_fd = -1, cli_fd = -1, err;
 142        socklen_t addrlen = sizeof(srv_sa6);
 143        int srv_port;
 144
 145        /* Enforce syncookie mode */
 146        if (write_sysctl("/proc/sys/net/ipv4/tcp_syncookies", "2"))
 147                return;
 148
 149        listen_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0);
 150        if (CHECK_FAIL(listen_fd == -1))
 151                return;
 152
 153        err = getsockname(listen_fd, (struct sockaddr *)&srv_sa6, &addrlen);
 154        if (CHECK(err, "getsockname(listen_fd)", "err:%d errno:%d\n", err,
 155                  errno))
 156                goto done;
 157        memcpy(&skel->bss->srv_sa6, &srv_sa6, sizeof(srv_sa6));
 158        srv_port = ntohs(srv_sa6.sin6_port);
 159
 160        cli_fd = connect_to_fd(listen_fd, 0);
 161        if (CHECK_FAIL(cli_fd == -1))
 162                goto done;
 163
 164        if (CHECK(skel->bss->listen_tp_sport != srv_port,
 165                  "Unexpected tp src port",
 166                  "listen_tp_sport:%u expected:%u\n",
 167                  skel->bss->listen_tp_sport, srv_port))
 168                goto done;
 169
 170        if (CHECK(skel->bss->req_sk_sport,
 171                  "Unexpected req_sk src port",
 172                  "req_sk_sport:%u expected:0\n",
 173                   skel->bss->req_sk_sport))
 174                goto done;
 175
 176        if (CHECK(!skel->bss->gen_cookie ||
 177                  skel->bss->gen_cookie != skel->bss->recv_cookie,
 178                  "Unexpected syncookie states",
 179                  "gen_cookie:%u recv_cookie:%u\n",
 180                  skel->bss->gen_cookie, skel->bss->recv_cookie))
 181                goto done;
 182
 183        CHECK(skel->bss->linum, "bpf prog detected error", "at line %u\n",
 184              skel->bss->linum);
 185
 186done:
 187        if (listen_fd != -1)
 188                close(listen_fd);
 189        if (cli_fd != -1)
 190                close(cli_fd);
 191}
 192
 193struct test {
 194        const char *desc;
 195        void (*run)(void);
 196};
 197
 198#define DEF_TEST(name) { #name, test_##name }
 199static struct test tests[] = {
 200        DEF_TEST(conn),
 201        DEF_TEST(syncookie),
 202};
 203
 204void test_btf_skc_cls_ingress(void)
 205{
 206        int i, err;
 207
 208        skel = test_btf_skc_cls_ingress__open_and_load();
 209        if (CHECK(!skel, "test_btf_skc_cls_ingress__open_and_load", "failed\n"))
 210                return;
 211
 212        err = bpf_program__pin(skel->progs.cls_ingress, PROG_PIN_FILE);
 213        if (CHECK(err, "bpf_program__pin",
 214                  "cannot pin bpf prog to %s. err:%d\n", PROG_PIN_FILE, err)) {
 215                test_btf_skc_cls_ingress__destroy(skel);
 216                return;
 217        }
 218
 219        for (i = 0; i < ARRAY_SIZE(tests); i++) {
 220                if (!test__start_subtest(tests[i].desc))
 221                        continue;
 222
 223                if (prepare_netns())
 224                        break;
 225
 226                tests[i].run();
 227
 228                print_err_line();
 229                reset_test();
 230        }
 231
 232        bpf_program__unpin(skel->progs.cls_ingress, PROG_PIN_FILE);
 233        test_btf_skc_cls_ingress__destroy(skel);
 234}
 235