linux/tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (c) 2020 Cloudflare
   3#include <error.h>
   4
   5#include "test_progs.h"
   6#include "test_skmsg_load_helpers.skel.h"
   7#include "test_sockmap_update.skel.h"
   8#include "test_sockmap_invalid_update.skel.h"
   9#include "bpf_iter_sockmap.skel.h"
  10
  11#define TCP_REPAIR              19      /* TCP sock is under repair right now */
  12
  13#define TCP_REPAIR_ON           1
  14#define TCP_REPAIR_OFF_NO_WP    -1      /* Turn off without window probes */
  15
  16static int connected_socket_v4(void)
  17{
  18        struct sockaddr_in addr = {
  19                .sin_family = AF_INET,
  20                .sin_port = htons(80),
  21                .sin_addr = { inet_addr("127.0.0.1") },
  22        };
  23        socklen_t len = sizeof(addr);
  24        int s, repair, err;
  25
  26        s = socket(AF_INET, SOCK_STREAM, 0);
  27        if (CHECK_FAIL(s == -1))
  28                goto error;
  29
  30        repair = TCP_REPAIR_ON;
  31        err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair));
  32        if (CHECK_FAIL(err))
  33                goto error;
  34
  35        err = connect(s, (struct sockaddr *)&addr, len);
  36        if (CHECK_FAIL(err))
  37                goto error;
  38
  39        repair = TCP_REPAIR_OFF_NO_WP;
  40        err = setsockopt(s, SOL_TCP, TCP_REPAIR, &repair, sizeof(repair));
  41        if (CHECK_FAIL(err))
  42                goto error;
  43
  44        return s;
  45error:
  46        perror(__func__);
  47        close(s);
  48        return -1;
  49}
  50
  51static void compare_cookies(struct bpf_map *src, struct bpf_map *dst)
  52{
  53        __u32 i, max_entries = bpf_map__max_entries(src);
  54        int err, duration = 0, src_fd, dst_fd;
  55
  56        src_fd = bpf_map__fd(src);
  57        dst_fd = bpf_map__fd(dst);
  58
  59        for (i = 0; i < max_entries; i++) {
  60                __u64 src_cookie, dst_cookie;
  61
  62                err = bpf_map_lookup_elem(src_fd, &i, &src_cookie);
  63                if (err && errno == ENOENT) {
  64                        err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie);
  65                        CHECK(!err, "map_lookup_elem(dst)", "element %u not deleted\n", i);
  66                        CHECK(err && errno != ENOENT, "map_lookup_elem(dst)", "%s\n",
  67                              strerror(errno));
  68                        continue;
  69                }
  70                if (CHECK(err, "lookup_elem(src)", "%s\n", strerror(errno)))
  71                        continue;
  72
  73                err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie);
  74                if (CHECK(err, "lookup_elem(dst)", "%s\n", strerror(errno)))
  75                        continue;
  76
  77                CHECK(dst_cookie != src_cookie, "cookie mismatch",
  78                      "%llu != %llu (pos %u)\n", dst_cookie, src_cookie, i);
  79        }
  80}
  81
  82/* Create a map, populate it with one socket, and free the map. */
  83static void test_sockmap_create_update_free(enum bpf_map_type map_type)
  84{
  85        const int zero = 0;
  86        int s, map, err;
  87
  88        s = connected_socket_v4();
  89        if (CHECK_FAIL(s == -1))
  90                return;
  91
  92        map = bpf_create_map(map_type, sizeof(int), sizeof(int), 1, 0);
  93        if (CHECK_FAIL(map == -1)) {
  94                perror("bpf_create_map");
  95                goto out;
  96        }
  97
  98        err = bpf_map_update_elem(map, &zero, &s, BPF_NOEXIST);
  99        if (CHECK_FAIL(err)) {
 100                perror("bpf_map_update");
 101                goto out;
 102        }
 103
 104out:
 105        close(map);
 106        close(s);
 107}
 108
 109static void test_skmsg_helpers(enum bpf_map_type map_type)
 110{
 111        struct test_skmsg_load_helpers *skel;
 112        int err, map, verdict;
 113
 114        skel = test_skmsg_load_helpers__open_and_load();
 115        if (CHECK_FAIL(!skel)) {
 116                perror("test_skmsg_load_helpers__open_and_load");
 117                return;
 118        }
 119
 120        verdict = bpf_program__fd(skel->progs.prog_msg_verdict);
 121        map = bpf_map__fd(skel->maps.sock_map);
 122
 123        err = bpf_prog_attach(verdict, map, BPF_SK_MSG_VERDICT, 0);
 124        if (CHECK_FAIL(err)) {
 125                perror("bpf_prog_attach");
 126                goto out;
 127        }
 128
 129        err = bpf_prog_detach2(verdict, map, BPF_SK_MSG_VERDICT);
 130        if (CHECK_FAIL(err)) {
 131                perror("bpf_prog_detach2");
 132                goto out;
 133        }
 134out:
 135        test_skmsg_load_helpers__destroy(skel);
 136}
 137
 138static void test_sockmap_update(enum bpf_map_type map_type)
 139{
 140        struct bpf_prog_test_run_attr tattr;
 141        int err, prog, src, duration = 0;
 142        struct test_sockmap_update *skel;
 143        struct bpf_map *dst_map;
 144        const __u32 zero = 0;
 145        char dummy[14] = {0};
 146        __s64 sk;
 147
 148        sk = connected_socket_v4();
 149        if (CHECK(sk == -1, "connected_socket_v4", "cannot connect\n"))
 150                return;
 151
 152        skel = test_sockmap_update__open_and_load();
 153        if (CHECK(!skel, "open_and_load", "cannot load skeleton\n"))
 154                goto close_sk;
 155
 156        prog = bpf_program__fd(skel->progs.copy_sock_map);
 157        src = bpf_map__fd(skel->maps.src);
 158        if (map_type == BPF_MAP_TYPE_SOCKMAP)
 159                dst_map = skel->maps.dst_sock_map;
 160        else
 161                dst_map = skel->maps.dst_sock_hash;
 162
 163        err = bpf_map_update_elem(src, &zero, &sk, BPF_NOEXIST);
 164        if (CHECK(err, "update_elem(src)", "errno=%u\n", errno))
 165                goto out;
 166
 167        tattr = (struct bpf_prog_test_run_attr){
 168                .prog_fd = prog,
 169                .repeat = 1,
 170                .data_in = dummy,
 171                .data_size_in = sizeof(dummy),
 172        };
 173
 174        err = bpf_prog_test_run_xattr(&tattr);
 175        if (CHECK_ATTR(err || !tattr.retval, "bpf_prog_test_run",
 176                       "errno=%u retval=%u\n", errno, tattr.retval))
 177                goto out;
 178
 179        compare_cookies(skel->maps.src, dst_map);
 180
 181out:
 182        test_sockmap_update__destroy(skel);
 183close_sk:
 184        close(sk);
 185}
 186
 187static void test_sockmap_invalid_update(void)
 188{
 189        struct test_sockmap_invalid_update *skel;
 190        int duration = 0;
 191
 192        skel = test_sockmap_invalid_update__open_and_load();
 193        if (CHECK(skel, "open_and_load", "verifier accepted map_update\n"))
 194                test_sockmap_invalid_update__destroy(skel);
 195}
 196
 197static void test_sockmap_copy(enum bpf_map_type map_type)
 198{
 199        DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
 200        int err, len, src_fd, iter_fd, duration = 0;
 201        union bpf_iter_link_info linfo = {};
 202        __u32 i, num_sockets, num_elems;
 203        struct bpf_iter_sockmap *skel;
 204        __s64 *sock_fd = NULL;
 205        struct bpf_link *link;
 206        struct bpf_map *src;
 207        char buf[64];
 208
 209        skel = bpf_iter_sockmap__open_and_load();
 210        if (CHECK(!skel, "bpf_iter_sockmap__open_and_load", "skeleton open_and_load failed\n"))
 211                return;
 212
 213        if (map_type == BPF_MAP_TYPE_SOCKMAP) {
 214                src = skel->maps.sockmap;
 215                num_elems = bpf_map__max_entries(src);
 216                num_sockets = num_elems - 1;
 217        } else {
 218                src = skel->maps.sockhash;
 219                num_elems = bpf_map__max_entries(src) - 1;
 220                num_sockets = num_elems;
 221        }
 222
 223        sock_fd = calloc(num_sockets, sizeof(*sock_fd));
 224        if (CHECK(!sock_fd, "calloc(sock_fd)", "failed to allocate\n"))
 225                goto out;
 226
 227        for (i = 0; i < num_sockets; i++)
 228                sock_fd[i] = -1;
 229
 230        src_fd = bpf_map__fd(src);
 231
 232        for (i = 0; i < num_sockets; i++) {
 233                sock_fd[i] = connected_socket_v4();
 234                if (CHECK(sock_fd[i] == -1, "connected_socket_v4", "cannot connect\n"))
 235                        goto out;
 236
 237                err = bpf_map_update_elem(src_fd, &i, &sock_fd[i], BPF_NOEXIST);
 238                if (CHECK(err, "map_update", "failed: %s\n", strerror(errno)))
 239                        goto out;
 240        }
 241
 242        linfo.map.map_fd = src_fd;
 243        opts.link_info = &linfo;
 244        opts.link_info_len = sizeof(linfo);
 245        link = bpf_program__attach_iter(skel->progs.copy, &opts);
 246        if (CHECK(IS_ERR(link), "attach_iter", "attach_iter failed\n"))
 247                goto out;
 248
 249        iter_fd = bpf_iter_create(bpf_link__fd(link));
 250        if (CHECK(iter_fd < 0, "create_iter", "create_iter failed\n"))
 251                goto free_link;
 252
 253        /* do some tests */
 254        while ((len = read(iter_fd, buf, sizeof(buf))) > 0)
 255                ;
 256        if (CHECK(len < 0, "read", "failed: %s\n", strerror(errno)))
 257                goto close_iter;
 258
 259        /* test results */
 260        if (CHECK(skel->bss->elems != num_elems, "elems", "got %u expected %u\n",
 261                  skel->bss->elems, num_elems))
 262                goto close_iter;
 263
 264        if (CHECK(skel->bss->socks != num_sockets, "socks", "got %u expected %u\n",
 265                  skel->bss->socks, num_sockets))
 266                goto close_iter;
 267
 268        compare_cookies(src, skel->maps.dst);
 269
 270close_iter:
 271        close(iter_fd);
 272free_link:
 273        bpf_link__destroy(link);
 274out:
 275        for (i = 0; sock_fd && i < num_sockets; i++)
 276                if (sock_fd[i] >= 0)
 277                        close(sock_fd[i]);
 278        if (sock_fd)
 279                free(sock_fd);
 280        bpf_iter_sockmap__destroy(skel);
 281}
 282
 283void test_sockmap_basic(void)
 284{
 285        if (test__start_subtest("sockmap create_update_free"))
 286                test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKMAP);
 287        if (test__start_subtest("sockhash create_update_free"))
 288                test_sockmap_create_update_free(BPF_MAP_TYPE_SOCKHASH);
 289        if (test__start_subtest("sockmap sk_msg load helpers"))
 290                test_skmsg_helpers(BPF_MAP_TYPE_SOCKMAP);
 291        if (test__start_subtest("sockhash sk_msg load helpers"))
 292                test_skmsg_helpers(BPF_MAP_TYPE_SOCKHASH);
 293        if (test__start_subtest("sockmap update"))
 294                test_sockmap_update(BPF_MAP_TYPE_SOCKMAP);
 295        if (test__start_subtest("sockhash update"))
 296                test_sockmap_update(BPF_MAP_TYPE_SOCKHASH);
 297        if (test__start_subtest("sockmap update in unsafe context"))
 298                test_sockmap_invalid_update();
 299        if (test__start_subtest("sockmap copy"))
 300                test_sockmap_copy(BPF_MAP_TYPE_SOCKMAP);
 301        if (test__start_subtest("sockhash copy"))
 302                test_sockmap_copy(BPF_MAP_TYPE_SOCKHASH);
 303}
 304