Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
sudo: required
language: bash
dist: bionic
services:
- docker

env:
global:
- PROJECT_NAME='libbpf'
- AUTHOR_EMAIL="$(git log -1 --pretty=\"%aE\")"
- REPO_ROOT="$TRAVIS_BUILD_DIR"
- CI_ROOT="$REPO_ROOT/travis-ci"
- VMTEST_ROOT="$CI_ROOT/vmtest"

addons:
apt:
packages:
- qemu-kvm
- zstd
- binutils-dev
- elfutils
- libcap-dev
- libelf-dev
- libdw-dev
- python3-docutils

jobs:
include:
- stage: Builds & Tests
name: Kernel LATEST + selftests
language: bash
env: KERNEL=LATEST
script: $CI_ROOT/vmtest/run_vmtest.sh || travis_terminate 1
2 changes: 1 addition & 1 deletion kernel/bpf/verifier.c
Original file line number Diff line number Diff line change
Expand Up @@ -3943,7 +3943,7 @@ static int resolve_map_arg_type(struct bpf_verifier_env *env,
case BPF_MAP_TYPE_SOCKMAP:
case BPF_MAP_TYPE_SOCKHASH:
if (*arg_type == ARG_PTR_TO_MAP_VALUE) {
*arg_type = ARG_PTR_TO_SOCKET;
*arg_type = ARG_PTR_TO_BTF_ID_SOCK_COMMON;
} else {
verbose(env, "invalid arg_type for sockmap/sockhash\n");
return -EINVAL;
Expand Down
3 changes: 3 additions & 0 deletions net/core/sock_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,9 @@ static int sock_map_update_elem(struct bpf_map *map, void *key,
struct sock *sk = (struct sock *)value;
int ret;

if (unlikely(!sk || !sk_fullsock(sk)))
return -EINVAL;

if (!sock_map_sk_is_suitable(sk))
return -EOPNOTSUPP;

Expand Down
100 changes: 62 additions & 38 deletions tools/testing/selftests/bpf/prog_tests/sockmap_basic.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
#include "test_sockmap_invalid_update.skel.h"
#include "bpf_iter_sockmap.skel.h"

#include "progs/bpf_iter_sockmap.h"

#define TCP_REPAIR 19 /* TCP sock is under repair right now */

#define TCP_REPAIR_ON 1
Expand Down Expand Up @@ -50,6 +48,37 @@ static int connected_socket_v4(void)
return -1;
}

static void compare_cookies(struct bpf_map *src, struct bpf_map *dst)
{
__u32 i, max_entries = bpf_map__max_entries(src);
int err, duration, src_fd, dst_fd;

src_fd = bpf_map__fd(src);
dst_fd = bpf_map__fd(dst);

for (i = 0; i < max_entries; i++) {
__u64 src_cookie, dst_cookie;

err = bpf_map_lookup_elem(src_fd, &i, &src_cookie);
if (err && errno == ENOENT) {
err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie);
CHECK(!err, "map_lookup_elem(dst)", "element %u not deleted\n", i);
CHECK(err && errno != ENOENT, "map_lookup_elem(dst)", "%s\n",
strerror(errno));
continue;
}
if (CHECK(err, "lookup_elem(src)", "%s\n", strerror(errno)))
continue;

err = bpf_map_lookup_elem(dst_fd, &i, &dst_cookie);
if (CHECK(err, "lookup_elem(dst)", "%s\n", strerror(errno)))
continue;

CHECK(dst_cookie != src_cookie, "cookie mismatch",
"%llu != %llu (pos %u)\n", dst_cookie, src_cookie, i);
}
}

/* Create a map, populate it with one socket, and free the map. */
static void test_sockmap_create_update_free(enum bpf_map_type map_type)
{
Expand Down Expand Up @@ -109,9 +138,9 @@ static void test_skmsg_helpers(enum bpf_map_type map_type)
static void test_sockmap_update(enum bpf_map_type map_type)
{
struct bpf_prog_test_run_attr tattr;
int err, prog, src, dst, duration = 0;
int err, prog, src, duration = 0;
struct test_sockmap_update *skel;
__u64 src_cookie, dst_cookie;
struct bpf_map *dst_map;
const __u32 zero = 0;
char dummy[14] = {0};
__s64 sk;
Expand All @@ -127,18 +156,14 @@ static void test_sockmap_update(enum bpf_map_type map_type)
prog = bpf_program__fd(skel->progs.copy_sock_map);
src = bpf_map__fd(skel->maps.src);
if (map_type == BPF_MAP_TYPE_SOCKMAP)
dst = bpf_map__fd(skel->maps.dst_sock_map);
dst_map = skel->maps.dst_sock_map;
else
dst = bpf_map__fd(skel->maps.dst_sock_hash);
dst_map = skel->maps.dst_sock_hash;

err = bpf_map_update_elem(src, &zero, &sk, BPF_NOEXIST);
if (CHECK(err, "update_elem(src)", "errno=%u\n", errno))
goto out;

err = bpf_map_lookup_elem(src, &zero, &src_cookie);
if (CHECK(err, "lookup_elem(src, cookie)", "errno=%u\n", errno))
goto out;

tattr = (struct bpf_prog_test_run_attr){
.prog_fd = prog,
.repeat = 1,
Expand All @@ -151,12 +176,7 @@ static void test_sockmap_update(enum bpf_map_type map_type)
"errno=%u retval=%u\n", errno, tattr.retval))
goto out;

err = bpf_map_lookup_elem(dst, &zero, &dst_cookie);
if (CHECK(err, "lookup_elem(dst, cookie)", "errno=%u\n", errno))
goto out;

CHECK(dst_cookie != src_cookie, "cookie mismatch", "%llu != %llu\n",
dst_cookie, src_cookie);
compare_cookies(skel->maps.src, dst_map);

out:
test_sockmap_update__destroy(skel);
Expand All @@ -174,14 +194,14 @@ static void test_sockmap_invalid_update(void)
test_sockmap_invalid_update__destroy(skel);
}

static void test_sockmap_iter(enum bpf_map_type map_type)
static void test_sockmap_copy(enum bpf_map_type map_type)
{
DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
int err, len, src_fd, iter_fd, duration = 0;
union bpf_iter_link_info linfo = {0};
__s64 sock_fd[SOCKMAP_MAX_ENTRIES];
__u32 i, num_sockets, max_elems;
__u32 i, num_sockets, num_elems;
struct bpf_iter_sockmap *skel;
__s64 *sock_fd = NULL;
struct bpf_link *link;
struct bpf_map *src;
char buf[64];
Expand All @@ -190,22 +210,23 @@ static void test_sockmap_iter(enum bpf_map_type map_type)
if (CHECK(!skel, "bpf_iter_sockmap__open_and_load", "skeleton open_and_load failed\n"))
return;

for (i = 0; i < ARRAY_SIZE(sock_fd); i++)
sock_fd[i] = -1;

/* Make sure we have at least one "empty" entry to test iteration of
* an empty slot.
*/
num_sockets = ARRAY_SIZE(sock_fd) - 1;

if (map_type == BPF_MAP_TYPE_SOCKMAP) {
src = skel->maps.sockmap;
max_elems = bpf_map__max_entries(src);
num_elems = bpf_map__max_entries(src);
num_sockets = num_elems - 1;
} else {
src = skel->maps.sockhash;
max_elems = num_sockets;
num_elems = bpf_map__max_entries(src) - 1;
num_sockets = num_elems;
}

sock_fd = calloc(num_sockets, sizeof(*sock_fd));
if (CHECK(!sock_fd, "calloc(sock_fd)", "failed to allocate\n"))
goto out;

for (i = 0; i < num_sockets; i++)
sock_fd[i] = -1;

src_fd = bpf_map__fd(src);

for (i = 0; i < num_sockets; i++) {
Expand All @@ -221,7 +242,7 @@ static void test_sockmap_iter(enum bpf_map_type map_type)
linfo.map.map_fd = src_fd;
opts.link_info = &linfo;
opts.link_info_len = sizeof(linfo);
link = bpf_program__attach_iter(skel->progs.count_elems, &opts);
link = bpf_program__attach_iter(skel->progs.copy, &opts);
if (CHECK(IS_ERR(link), "attach_iter", "attach_iter failed\n"))
goto out;

Expand All @@ -236,23 +257,26 @@ static void test_sockmap_iter(enum bpf_map_type map_type)
goto close_iter;

/* test results */
if (CHECK(skel->bss->elems != max_elems, "elems", "got %u expected %u\n",
skel->bss->elems, max_elems))
if (CHECK(skel->bss->elems != num_elems, "elems", "got %u expected %u\n",
skel->bss->elems, num_elems))
goto close_iter;

if (CHECK(skel->bss->socks != num_sockets, "socks", "got %u expected %u\n",
skel->bss->socks, num_sockets))
goto close_iter;

compare_cookies(src, skel->maps.dst);

close_iter:
close(iter_fd);
free_link:
bpf_link__destroy(link);
out:
for (i = 0; i < num_sockets; i++) {
for (i = 0; sock_fd && i < num_sockets; i++)
if (sock_fd[i] >= 0)
close(sock_fd[i]);
}
if (sock_fd)
free(sock_fd);
bpf_iter_sockmap__destroy(skel);
}

Expand All @@ -272,8 +296,8 @@ void test_sockmap_basic(void)
test_sockmap_update(BPF_MAP_TYPE_SOCKHASH);
if (test__start_subtest("sockmap update in unsafe context"))
test_sockmap_invalid_update();
if (test__start_subtest("sockmap iter"))
test_sockmap_iter(BPF_MAP_TYPE_SOCKMAP);
if (test__start_subtest("sockhash iter"))
test_sockmap_iter(BPF_MAP_TYPE_SOCKHASH);
if (test__start_subtest("sockmap copy"))
test_sockmap_copy(BPF_MAP_TYPE_SOCKMAP);
if (test__start_subtest("sockhash copy"))
test_sockmap_copy(BPF_MAP_TYPE_SOCKHASH);
}
32 changes: 24 additions & 8 deletions tools/testing/selftests/bpf/progs/bpf_iter_sockmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
/* Copyright (c) 2020 Cloudflare */
#include "bpf_iter.h"
#include "bpf_tracing_net.h"
#include "bpf_iter_sockmap.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <errno.h>
Expand All @@ -11,33 +10,50 @@ char _license[] SEC("license") = "GPL";

struct {
__uint(type, BPF_MAP_TYPE_SOCKMAP);
__uint(max_entries, SOCKMAP_MAX_ENTRIES);
__uint(max_entries, 64);
__type(key, __u32);
__type(value, __u64);
} sockmap SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_SOCKHASH);
__uint(max_entries, SOCKMAP_MAX_ENTRIES);
__uint(max_entries, 64);
__type(key, __u32);
__type(value, __u64);
} sockhash SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_SOCKHASH);
__uint(max_entries, 64);
__type(key, __u32);
__type(value, __u64);
} dst SEC(".maps");

__u32 elems = 0;
__u32 socks = 0;

SEC("iter/sockmap")
int count_elems(struct bpf_iter__sockmap *ctx)
int copy(struct bpf_iter__sockmap *ctx)
{
struct sock *sk = ctx->sk;
__u32 tmp, *key = ctx->key;
int ret;

if (key)
elems++;
if (!key)
return 0;

elems++;

/* We need a temporary buffer on the stack, since the verifier doesn't
* let us use the pointer from the context as an argument to the helper.
*/
tmp = *key;

if (sk)
if (sk) {
socks++;
return bpf_map_update_elem(&dst, &tmp, sk, 0) != 0;
}

return 0;
ret = bpf_map_delete_elem(&dst, &tmp);
return ret && ret != -ENOENT;
}
3 changes: 0 additions & 3 deletions tools/testing/selftests/bpf/progs/bpf_iter_sockmap.h

This file was deleted.

Loading