selftests/bpf: Tests for sockmap/sockhash holding listening sockets
Now that SOCKMAP and SOCKHASH map types can store listening sockets, user-space and BPF API is open to a new set of potential pitfalls. Exercise the map operations, with extra attention to code paths susceptible to races between map ops and socket cloning, and BPF helpers that work with SOCKMAP/SOCKHASH to gain confidence that all works as expected. Signed-off-by: Jakub Sitnicki <jakub@cloudflare.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: John Fastabend <john.fastabend@gmail.com> Link: https://lore.kernel.org/bpf/20200218171023.844439-12-jakub@cloudflare.com
This commit is contained in:
parent
11318ba8ca
commit
44d28be2b8
1496
tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
Normal file
1496
tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
Normal file
File diff suppressed because it is too large
Load Diff
98
tools/testing/selftests/bpf/progs/test_sockmap_listen.c
Normal file
98
tools/testing/selftests/bpf/progs/test_sockmap_listen.c
Normal file
@ -0,0 +1,98 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2020 Cloudflare
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <linux/bpf.h>
|
||||
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_SOCKMAP);
|
||||
__uint(max_entries, 2);
|
||||
__type(key, __u32);
|
||||
__type(value, __u64);
|
||||
} sock_map SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_SOCKHASH);
|
||||
__uint(max_entries, 2);
|
||||
__type(key, __u32);
|
||||
__type(value, __u64);
|
||||
} sock_hash SEC(".maps");
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 2);
|
||||
__type(key, int);
|
||||
__type(value, unsigned int);
|
||||
} verdict_map SEC(".maps");
|
||||
|
||||
static volatile bool test_sockmap; /* toggled by user-space */
|
||||
|
||||
SEC("sk_skb/stream_parser")
|
||||
int prog_skb_parser(struct __sk_buff *skb)
|
||||
{
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
SEC("sk_skb/stream_verdict")
|
||||
int prog_skb_verdict(struct __sk_buff *skb)
|
||||
{
|
||||
unsigned int *count;
|
||||
__u32 zero = 0;
|
||||
int verdict;
|
||||
|
||||
if (test_sockmap)
|
||||
verdict = bpf_sk_redirect_map(skb, &sock_map, zero, 0);
|
||||
else
|
||||
verdict = bpf_sk_redirect_hash(skb, &sock_hash, &zero, 0);
|
||||
|
||||
count = bpf_map_lookup_elem(&verdict_map, &verdict);
|
||||
if (count)
|
||||
(*count)++;
|
||||
|
||||
return verdict;
|
||||
}
|
||||
|
||||
SEC("sk_msg")
|
||||
int prog_msg_verdict(struct sk_msg_md *msg)
|
||||
{
|
||||
unsigned int *count;
|
||||
__u32 zero = 0;
|
||||
int verdict;
|
||||
|
||||
if (test_sockmap)
|
||||
verdict = bpf_msg_redirect_map(msg, &sock_map, zero, 0);
|
||||
else
|
||||
verdict = bpf_msg_redirect_hash(msg, &sock_hash, &zero, 0);
|
||||
|
||||
count = bpf_map_lookup_elem(&verdict_map, &verdict);
|
||||
if (count)
|
||||
(*count)++;
|
||||
|
||||
return verdict;
|
||||
}
|
||||
|
||||
SEC("sk_reuseport")
|
||||
int prog_reuseport(struct sk_reuseport_md *reuse)
|
||||
{
|
||||
unsigned int *count;
|
||||
int err, verdict;
|
||||
__u32 zero = 0;
|
||||
|
||||
if (test_sockmap)
|
||||
err = bpf_sk_select_reuseport(reuse, &sock_map, &zero, 0);
|
||||
else
|
||||
err = bpf_sk_select_reuseport(reuse, &sock_hash, &zero, 0);
|
||||
verdict = err ? SK_DROP : SK_PASS;
|
||||
|
||||
count = bpf_map_lookup_elem(&verdict_map, &verdict);
|
||||
if (count)
|
||||
(*count)++;
|
||||
|
||||
return verdict;
|
||||
}
|
||||
|
||||
int _version SEC("version") = 1;
|
||||
char _license[] SEC("license") = "GPL";
|
Loading…
Reference in New Issue
Block a user