1
0
Fork 0

Merge git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf

Alexei Starovoitov says:

====================
pull-request: bpf 2020-06-12

The following pull-request contains BPF updates for your *net* tree.

We've added 26 non-merge commits during the last 10 day(s) which contain
a total of 27 files changed, 348 insertions(+), 93 deletions(-).

The main changes are:

1) sock_hash accounting fix, from Andrey.

2) libbpf fix and probe_mem sanitizing, from Andrii.

3) sock_hash fixes, from Jakub.

4) devmap_val fix, from Jesper.

5) load_bytes_relative fix, from YiFei.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
alistair/sunxi64-5.8
David S. Miller 2020-06-13 15:28:08 -07:00
commit fa7566a0d6
27 changed files with 348 additions and 93 deletions

View File

@ -3761,6 +3761,19 @@ struct xdp_md {
__u32 egress_ifindex; /* txq->dev->ifindex */
};
/* DEVMAP map-value layout
*
* The struct data-layout of map-value is a configuration interface.
* New members can only be added to the end of this structure.
*/
struct bpf_devmap_val {
__u32 ifindex; /* device index */
union {
int fd; /* prog fd on map write */
__u32 id; /* prog id on map read */
} bpf_prog;
};
enum sk_action {
SK_DROP = 0,
SK_PASS,

View File

@ -378,7 +378,7 @@ static struct bpf_prog_list *find_attach_entry(struct list_head *progs,
}
list_for_each_entry(pl, progs, node) {
if (prog && pl->prog == prog)
if (prog && pl->prog == prog && prog != replace_prog)
/* disallow attaching the same prog twice */
return ERR_PTR(-EINVAL);
if (link && pl->link == link)

View File

@ -60,15 +60,6 @@ struct xdp_dev_bulk_queue {
unsigned int count;
};
/* DEVMAP values */
struct bpf_devmap_val {
u32 ifindex; /* device index */
union {
int fd; /* prog fd on map write */
u32 id; /* prog id on map read */
} bpf_prog;
};
struct bpf_dtab_netdev {
struct net_device *dev; /* must be first member, due to tracepoint */
struct hlist_node index_hlist;
@ -479,6 +470,7 @@ static struct xdp_buff *dev_map_run_prog(struct net_device *dev,
struct xdp_txq_info txq = { .dev = dev };
u32 act;
xdp_set_data_meta_invalid(xdp);
xdp->txq = &txq;
act = bpf_prog_run_xdp(xdp_prog, xdp);
@ -618,7 +610,7 @@ static struct bpf_dtab_netdev *__dev_map_alloc_node(struct net *net,
if (!dev->dev)
goto err_out;
if (val->bpf_prog.fd >= 0) {
if (val->bpf_prog.fd > 0) {
prog = bpf_prog_get_type_dev(val->bpf_prog.fd,
BPF_PROG_TYPE_XDP, false);
if (IS_ERR(prog))
@ -652,8 +644,8 @@ static int __dev_map_update_elem(struct net *net, struct bpf_map *map,
void *key, void *value, u64 map_flags)
{
struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
struct bpf_devmap_val val = { .bpf_prog.fd = -1 };
struct bpf_dtab_netdev *dev, *old_dev;
struct bpf_devmap_val val = {};
u32 i = *(u32 *)key;
if (unlikely(map_flags > BPF_EXIST))
@ -669,7 +661,7 @@ static int __dev_map_update_elem(struct net *net, struct bpf_map *map,
if (!val.ifindex) {
dev = NULL;
/* can not specify fd if ifindex is 0 */
if (val.bpf_prog.fd != -1)
if (val.bpf_prog.fd > 0)
return -EINVAL;
} else {
dev = __dev_map_alloc_node(net, dtab, &val, i);
@ -699,8 +691,8 @@ static int __dev_map_hash_update_elem(struct net *net, struct bpf_map *map,
void *key, void *value, u64 map_flags)
{
struct bpf_dtab *dtab = container_of(map, struct bpf_dtab, map);
struct bpf_devmap_val val = { .bpf_prog.fd = -1 };
struct bpf_dtab_netdev *dev, *old_dev;
struct bpf_devmap_val val = {};
u32 idx = *(u32 *)key;
unsigned long flags;
int err = -EEXIST;

View File

@ -3158,6 +3158,7 @@ static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog)
struct bpf_insn *insns;
u32 off, type;
u64 imm;
u8 code;
int i;
insns = kmemdup(prog->insnsi, bpf_prog_insn_size(prog),
@ -3166,21 +3167,27 @@ static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog)
return insns;
for (i = 0; i < prog->len; i++) {
if (insns[i].code == (BPF_JMP | BPF_TAIL_CALL)) {
code = insns[i].code;
if (code == (BPF_JMP | BPF_TAIL_CALL)) {
insns[i].code = BPF_JMP | BPF_CALL;
insns[i].imm = BPF_FUNC_tail_call;
/* fall-through */
}
if (insns[i].code == (BPF_JMP | BPF_CALL) ||
insns[i].code == (BPF_JMP | BPF_CALL_ARGS)) {
if (insns[i].code == (BPF_JMP | BPF_CALL_ARGS))
if (code == (BPF_JMP | BPF_CALL) ||
code == (BPF_JMP | BPF_CALL_ARGS)) {
if (code == (BPF_JMP | BPF_CALL_ARGS))
insns[i].code = BPF_JMP | BPF_CALL;
if (!bpf_dump_raw_ok())
insns[i].imm = 0;
continue;
}
if (BPF_CLASS(code) == BPF_LDX && BPF_MODE(code) == BPF_PROBE_MEM) {
insns[i].code = BPF_LDX | BPF_SIZE(code) | BPF_MEM;
continue;
}
if (insns[i].code != (BPF_LD | BPF_IMM | BPF_DW))
if (code != (BPF_LD | BPF_IMM | BPF_DW))
continue;
imm = ((u64)insns[i + 1].imm << 32) | (u32)insns[i].imm;

View File

@ -7552,7 +7552,7 @@ static int check_btf_func(struct bpf_verifier_env *env,
const struct btf *btf;
void __user *urecord;
u32 prev_offset = 0;
int ret = 0;
int ret = -ENOMEM;
nfuncs = attr->func_info_cnt;
if (!nfuncs)

View File

@ -1629,7 +1629,7 @@ int bpf_get_kprobe_info(const struct perf_event *event, u32 *fd_type,
if (perf_type_tracepoint)
tk = find_trace_kprobe(pevent, group);
else
tk = event->tp_event->data;
tk = trace_kprobe_primary_from_call(event->tp_event);
if (!tk)
return -EINVAL;

View File

@ -1412,7 +1412,7 @@ int bpf_get_uprobe_info(const struct perf_event *event, u32 *fd_type,
if (perf_type_tracepoint)
tu = find_probe_event(pevent, group);
else
tu = event->tp_event->data;
tu = trace_uprobe_primary_from_call(event->tp_event);
if (!tu)
return -EINVAL;

View File

@ -1755,25 +1755,27 @@ BPF_CALL_5(bpf_skb_load_bytes_relative, const struct sk_buff *, skb,
u32, offset, void *, to, u32, len, u32, start_header)
{
u8 *end = skb_tail_pointer(skb);
u8 *net = skb_network_header(skb);
u8 *mac = skb_mac_header(skb);
u8 *ptr;
u8 *start, *ptr;
if (unlikely(offset > 0xffff || len > (end - mac)))
if (unlikely(offset > 0xffff))
goto err_clear;
switch (start_header) {
case BPF_HDR_START_MAC:
ptr = mac + offset;
if (unlikely(!skb_mac_header_was_set(skb)))
goto err_clear;
start = skb_mac_header(skb);
break;
case BPF_HDR_START_NET:
ptr = net + offset;
start = skb_network_header(skb);
break;
default:
goto err_clear;
}
if (likely(ptr >= mac && ptr + len <= end)) {
ptr = start + offset;
if (likely(ptr + len <= end)) {
memcpy(to, ptr, len);
return 0;
}
@ -4340,8 +4342,6 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname,
}
break;
case SO_BINDTODEVICE:
ret = -ENOPROTOOPT;
#ifdef CONFIG_NETDEVICES
optlen = min_t(long, optlen, IFNAMSIZ - 1);
strncpy(devname, optval, optlen);
devname[optlen] = 0;
@ -4360,7 +4360,6 @@ static int _bpf_setsockopt(struct sock *sk, int level, int optname,
dev_put(dev);
}
ret = sock_bindtoindex(sk, ifindex, false);
#endif
break;
default:
ret = -EINVAL;

View File

@ -424,10 +424,7 @@ static int sock_map_get_next_key(struct bpf_map *map, void *key, void *next)
return 0;
}
static bool sock_map_redirect_allowed(const struct sock *sk)
{
return sk->sk_state != TCP_LISTEN;
}
static bool sock_map_redirect_allowed(const struct sock *sk);
static int sock_map_update_common(struct bpf_map *map, u32 idx,
struct sock *sk, u64 flags)
@ -508,6 +505,11 @@ static bool sk_is_udp(const struct sock *sk)
sk->sk_protocol == IPPROTO_UDP;
}
static bool sock_map_redirect_allowed(const struct sock *sk)
{
return sk_is_tcp(sk) && sk->sk_state != TCP_LISTEN;
}
static bool sock_map_sk_is_suitable(const struct sock *sk)
{
return sk_is_tcp(sk) || sk_is_udp(sk);
@ -989,11 +991,15 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr)
err = -EINVAL;
goto free_htab;
}
err = bpf_map_charge_init(&htab->map.memory, cost);
if (err)
goto free_htab;
htab->buckets = bpf_map_area_alloc(htab->buckets_num *
sizeof(struct bpf_htab_bucket),
htab->map.numa_node);
if (!htab->buckets) {
bpf_map_charge_finish(&htab->map.memory);
err = -ENOMEM;
goto free_htab;
}
@ -1013,6 +1019,7 @@ static void sock_hash_free(struct bpf_map *map)
{
struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
struct bpf_htab_bucket *bucket;
struct hlist_head unlink_list;
struct bpf_htab_elem *elem;
struct hlist_node *node;
int i;
@ -1024,13 +1031,32 @@ static void sock_hash_free(struct bpf_map *map)
synchronize_rcu();
for (i = 0; i < htab->buckets_num; i++) {
bucket = sock_hash_select_bucket(htab, i);
hlist_for_each_entry_safe(elem, node, &bucket->head, node) {
hlist_del_rcu(&elem->node);
/* We are racing with sock_hash_delete_from_link to
* enter the spin-lock critical section. Every socket on
* the list is still linked to sockhash. Since link
* exists, psock exists and holds a ref to socket. That
* lets us to grab a socket ref too.
*/
raw_spin_lock_bh(&bucket->lock);
hlist_for_each_entry(elem, &bucket->head, node)
sock_hold(elem->sk);
hlist_move_list(&bucket->head, &unlink_list);
raw_spin_unlock_bh(&bucket->lock);
/* Process removed entries out of atomic context to
* block for socket lock before deleting the psock's
* link to sockhash.
*/
hlist_for_each_entry_safe(elem, node, &unlink_list, node) {
hlist_del(&elem->node);
lock_sock(elem->sk);
rcu_read_lock();
sock_map_unref(elem->sk, elem);
rcu_read_unlock();
release_sock(elem->sk);
sock_put(elem->sk);
sock_hash_free_elem(htab, elem);
}
}

View File

@ -64,6 +64,9 @@ int __tcp_bpf_recvmsg(struct sock *sk, struct sk_psock *psock,
} while (i != msg_rx->sg.end);
if (unlikely(peek)) {
if (msg_rx == list_last_entry(&psock->ingress_msg,
struct sk_msg, list))
break;
msg_rx = list_next_entry(msg_rx, list);
continue;
}
@ -242,6 +245,9 @@ static int tcp_bpf_wait_data(struct sock *sk, struct sk_psock *psock,
DEFINE_WAIT_FUNC(wait, woken_wake_function);
int ret = 0;
if (sk->sk_shutdown & RCV_SHUTDOWN)
return 1;
if (!timeo)
return ret;

View File

@ -352,10 +352,8 @@ static int xsk_generic_xmit(struct sock *sk)
len = desc.len;
skb = sock_alloc_send_skb(sk, len, 1, &err);
if (unlikely(!skb)) {
err = -EAGAIN;
if (unlikely(!skb))
goto out;
}
skb_put(skb, len);
addr = desc.addr;

View File

@ -143,8 +143,8 @@ gen_btf()
fi
pahole_ver=$(${PAHOLE} --version | sed -E 's/v([0-9]+)\.([0-9]+)/\1\2/')
if [ "${pahole_ver}" -lt "113" ]; then
echo >&2 "BTF: ${1}: pahole version $(${PAHOLE} --version) is too old, need at least v1.13"
if [ "${pahole_ver}" -lt "116" ]; then
echo >&2 "BTF: ${1}: pahole version $(${PAHOLE} --version) is too old, need at least v1.16"
return 1
fi

View File

@ -3,7 +3,6 @@ include ../scripts/Makefile.include
prefix ?= /usr/local
CC = gcc
LEX = flex
YACC = bison
MAKE = make

View File

@ -200,7 +200,7 @@ out:
return err;
}
static int codegen(const char *template, ...)
static void codegen(const char *template, ...)
{
const char *src, *end;
int skip_tabs = 0, n;
@ -211,7 +211,7 @@ static int codegen(const char *template, ...)
n = strlen(template);
s = malloc(n + 1);
if (!s)
return -ENOMEM;
exit(-1);
src = template;
dst = s;
@ -224,7 +224,8 @@ static int codegen(const char *template, ...)
} else {
p_err("unrecognized character at pos %td in template '%s'",
src - template - 1, template);
return -EINVAL;
free(s);
exit(-1);
}
}
@ -234,7 +235,8 @@ static int codegen(const char *template, ...)
if (*src != '\t') {
p_err("not enough tabs at pos %td in template '%s'",
src - template - 1, template);
return -EINVAL;
free(s);
exit(-1);
}
}
/* trim trailing whitespace */
@ -255,7 +257,6 @@ static int codegen(const char *template, ...)
va_end(args);
free(s);
return n;
}
static int do_skeleton(int argc, char **argv)

View File

@ -3761,6 +3761,19 @@ struct xdp_md {
__u32 egress_ifindex; /* txq->dev->ifindex */
};
/* DEVMAP map-value layout
*
* The struct data-layout of map-value is a configuration interface.
* New members can only be added to the end of this structure.
*/
struct bpf_devmap_val {
__u32 ifindex; /* device index */
union {
int fd; /* prog fd on map write */
__u32 id; /* prog id on map read */
} bpf_prog;
};
enum sk_action {
SK_DROP = 0,
SK_PASS,

View File

@ -1137,6 +1137,20 @@ static void btf_dump_emit_mods(struct btf_dump *d, struct id_stack *decl_stack)
}
}
static void btf_dump_drop_mods(struct btf_dump *d, struct id_stack *decl_stack)
{
const struct btf_type *t;
__u32 id;
while (decl_stack->cnt) {
id = decl_stack->ids[decl_stack->cnt - 1];
t = btf__type_by_id(d->btf, id);
if (!btf_is_mod(t))
return;
decl_stack->cnt--;
}
}
static void btf_dump_emit_name(const struct btf_dump *d,
const char *name, bool last_was_ptr)
{
@ -1235,14 +1249,7 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
* a const/volatile modifier for array, so we are
* going to silently skip them here.
*/
while (decls->cnt) {
next_id = decls->ids[decls->cnt - 1];
next_t = btf__type_by_id(d->btf, next_id);
if (btf_is_mod(next_t))
decls->cnt--;
else
break;
}
btf_dump_drop_mods(d, decls);
if (decls->cnt == 0) {
btf_dump_emit_name(d, fname, last_was_ptr);
@ -1270,7 +1277,15 @@ static void btf_dump_emit_type_chain(struct btf_dump *d,
__u16 vlen = btf_vlen(t);
int i;
btf_dump_emit_mods(d, decls);
/*
* GCC emits extra volatile qualifier for
* __attribute__((noreturn)) function pointers. Clang
* doesn't do it. It's a GCC quirk for backwards
* compatibility with code written for GCC <2.5. So,
* similarly to extra qualifiers for array, just drop
* them, instead of handling them.
*/
btf_dump_drop_mods(d, decls);
if (decls->cnt) {
btf_dump_printf(d, " (");
btf_dump_emit_type_chain(d, decls, fname, lvl);

View File

@ -10,10 +10,9 @@
#include <stdbool.h>
#include <stddef.h>
#ifdef __GLIBC__
#include <bits/wordsize.h>
#else
#include <bits/reg.h>
#include <limits.h>
#ifndef __WORDSIZE
#define __WORDSIZE (__SIZEOF_LONG__ * 8)
#endif
static inline size_t hash_bits(size_t h, int bits)

View File

@ -3564,10 +3564,6 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map)
char *cp, errmsg[STRERR_BUFSIZE];
int err, zero = 0;
/* kernel already zero-initializes .bss map. */
if (map_type == LIBBPF_MAP_BSS)
return 0;
err = bpf_map_update_elem(map->fd, &zero, map->mmaped, 0);
if (err) {
err = -errno;

View File

@ -230,6 +230,13 @@ void test_cgroup_attach_multi(void)
"prog_replace", "errno=%d\n", errno))
goto err;
/* replace program with itself */
attach_opts.replace_prog_fd = allow_prog[6];
if (CHECK(bpf_prog_attach_xattr(allow_prog[6], cg1,
BPF_CGROUP_INET_EGRESS, &attach_opts),
"prog_replace", "errno=%d\n", errno))
goto err;
value = 0;
CHECK_FAIL(bpf_map_update_elem(map_fd, &key, &value, 0));
CHECK_FAIL(system(PING_CMD));

View File

@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2020 Google LLC.
*/
#include <test_progs.h>
#include <network_helpers.h>
void test_load_bytes_relative(void)
{
int server_fd, cgroup_fd, prog_fd, map_fd, client_fd;
int err;
struct bpf_object *obj;
struct bpf_program *prog;
struct bpf_map *test_result;
__u32 duration = 0;
__u32 map_key = 0;
__u32 map_value = 0;
cgroup_fd = test__join_cgroup("/load_bytes_relative");
if (CHECK_FAIL(cgroup_fd < 0))
return;
server_fd = start_server(AF_INET, SOCK_STREAM);
if (CHECK_FAIL(server_fd < 0))
goto close_cgroup_fd;
err = bpf_prog_load("./load_bytes_relative.o", BPF_PROG_TYPE_CGROUP_SKB,
&obj, &prog_fd);
if (CHECK_FAIL(err))
goto close_server_fd;
test_result = bpf_object__find_map_by_name(obj, "test_result");
if (CHECK_FAIL(!test_result))
goto close_bpf_object;
map_fd = bpf_map__fd(test_result);
if (map_fd < 0)
goto close_bpf_object;
prog = bpf_object__find_program_by_name(obj, "load_bytes_relative");
if (CHECK_FAIL(!prog))
goto close_bpf_object;
err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_INET_EGRESS,
BPF_F_ALLOW_MULTI);
if (CHECK_FAIL(err))
goto close_bpf_object;
client_fd = connect_to_fd(AF_INET, SOCK_STREAM, server_fd);
if (CHECK_FAIL(client_fd < 0))
goto close_bpf_object;
close(client_fd);
err = bpf_map_lookup_elem(map_fd, &map_key, &map_value);
if (CHECK_FAIL(err))
goto close_bpf_object;
CHECK(map_value != 1, "bpf", "bpf program returned failure");
close_bpf_object:
bpf_object__close(obj);
close_server_fd:
close(server_fd);
close_cgroup_fd:
close(cgroup_fd);
}

View File

@ -25,13 +25,23 @@ struct sample {
char comm[16];
};
static volatile int sample_cnt;
static int sample_cnt;
static void atomic_inc(int *cnt)
{
__atomic_add_fetch(cnt, 1, __ATOMIC_SEQ_CST);
}
static int atomic_xchg(int *cnt, int val)
{
return __atomic_exchange_n(cnt, val, __ATOMIC_SEQ_CST);
}
static int process_sample(void *ctx, void *data, size_t len)
{
struct sample *s = data;
sample_cnt++;
atomic_inc(&sample_cnt);
switch (s->seq) {
case 0:
@ -76,7 +86,7 @@ void test_ringbuf(void)
const size_t rec_sz = BPF_RINGBUF_HDR_SZ + sizeof(struct sample);
pthread_t thread;
long bg_ret = -1;
int err;
int err, cnt;
skel = test_ringbuf__open_and_load();
if (CHECK(!skel, "skel_open_load", "skeleton open&load failed\n"))
@ -116,11 +126,15 @@ void test_ringbuf(void)
/* -EDONE is used as an indicator that we are done */
if (CHECK(err != -EDONE, "err_done", "done err: %d\n", err))
goto cleanup;
cnt = atomic_xchg(&sample_cnt, 0);
CHECK(cnt != 2, "cnt", "exp %d samples, got %d\n", 2, cnt);
/* we expect extra polling to return nothing */
err = ring_buffer__poll(ringbuf, 0);
if (CHECK(err != 0, "extra_samples", "poll result: %d\n", err))
goto cleanup;
cnt = atomic_xchg(&sample_cnt, 0);
CHECK(cnt != 0, "cnt", "exp %d samples, got %d\n", 0, cnt);
CHECK(skel->bss->dropped != 0, "err_dropped", "exp %ld, got %ld\n",
0L, skel->bss->dropped);
@ -136,6 +150,8 @@ void test_ringbuf(void)
3L * rec_sz, skel->bss->cons_pos);
err = ring_buffer__poll(ringbuf, -1);
CHECK(err <= 0, "poll_err", "err %d\n", err);
cnt = atomic_xchg(&sample_cnt, 0);
CHECK(cnt != 2, "cnt", "exp %d samples, got %d\n", 2, cnt);
/* start poll in background w/ long timeout */
err = pthread_create(&thread, NULL, poll_thread, (void *)(long)10000);
@ -164,6 +180,8 @@ void test_ringbuf(void)
2L, skel->bss->total);
CHECK(skel->bss->discarded != 1, "err_discarded", "exp %ld, got %ld\n",
1L, skel->bss->discarded);
cnt = atomic_xchg(&sample_cnt, 0);
CHECK(cnt != 0, "cnt", "exp %d samples, got %d\n", 0, cnt);
/* clear flags to return to "adaptive" notification mode */
skel->bss->flags = 0;
@ -178,10 +196,20 @@ void test_ringbuf(void)
if (CHECK(err != EBUSY, "try_join", "err %d\n", err))
goto cleanup;
/* still no samples, because consumer is behind */
cnt = atomic_xchg(&sample_cnt, 0);
CHECK(cnt != 0, "cnt", "exp %d samples, got %d\n", 0, cnt);
skel->bss->dropped = 0;
skel->bss->total = 0;
skel->bss->discarded = 0;
skel->bss->value = 333;
syscall(__NR_getpgid);
/* now force notifications */
skel->bss->flags = BPF_RB_FORCE_WAKEUP;
sample_cnt = 0;
trigger_samples();
skel->bss->value = 777;
syscall(__NR_getpgid);
/* now we should get a pending notification */
usleep(50000);
@ -193,8 +221,8 @@ void test_ringbuf(void)
goto cleanup;
/* 3 rounds, 2 samples each */
CHECK(sample_cnt != 6, "wrong_sample_cnt",
"expected to see %d samples, got %d\n", 6, sample_cnt);
cnt = atomic_xchg(&sample_cnt, 0);
CHECK(cnt != 6, "cnt", "exp %d samples, got %d\n", 6, cnt);
/* BPF side did everything right */
CHECK(skel->bss->dropped != 0, "err_dropped", "exp %ld, got %ld\n",

View File

@ -15,6 +15,8 @@ void test_skeleton(void)
int duration = 0, err;
struct test_skeleton* skel;
struct test_skeleton__bss *bss;
struct test_skeleton__data *data;
struct test_skeleton__rodata *rodata;
struct test_skeleton__kconfig *kcfg;
skel = test_skeleton__open();
@ -24,13 +26,45 @@ void test_skeleton(void)
if (CHECK(skel->kconfig, "skel_kconfig", "kconfig is mmaped()!\n"))
goto cleanup;
bss = skel->bss;
data = skel->data;
rodata = skel->rodata;
/* validate values are pre-initialized correctly */
CHECK(data->in1 != -1, "in1", "got %d != exp %d\n", data->in1, -1);
CHECK(data->out1 != -1, "out1", "got %d != exp %d\n", data->out1, -1);
CHECK(data->in2 != -1, "in2", "got %lld != exp %lld\n", data->in2, -1LL);
CHECK(data->out2 != -1, "out2", "got %lld != exp %lld\n", data->out2, -1LL);
CHECK(bss->in3 != 0, "in3", "got %d != exp %d\n", bss->in3, 0);
CHECK(bss->out3 != 0, "out3", "got %d != exp %d\n", bss->out3, 0);
CHECK(bss->in4 != 0, "in4", "got %lld != exp %lld\n", bss->in4, 0LL);
CHECK(bss->out4 != 0, "out4", "got %lld != exp %lld\n", bss->out4, 0LL);
CHECK(rodata->in6 != 0, "in6", "got %d != exp %d\n", rodata->in6, 0);
CHECK(bss->out6 != 0, "out6", "got %d != exp %d\n", bss->out6, 0);
/* validate we can pre-setup global variables, even in .bss */
data->in1 = 10;
data->in2 = 11;
bss->in3 = 12;
bss->in4 = 13;
rodata->in6 = 14;
err = test_skeleton__load(skel);
if (CHECK(err, "skel_load", "failed to load skeleton: %d\n", err))
goto cleanup;
bss = skel->bss;
bss->in1 = 1;
bss->in2 = 2;
/* validate pre-setup values are still there */
CHECK(data->in1 != 10, "in1", "got %d != exp %d\n", data->in1, 10);
CHECK(data->in2 != 11, "in2", "got %lld != exp %lld\n", data->in2, 11LL);
CHECK(bss->in3 != 12, "in3", "got %d != exp %d\n", bss->in3, 12);
CHECK(bss->in4 != 13, "in4", "got %lld != exp %lld\n", bss->in4, 13LL);
CHECK(rodata->in6 != 14, "in6", "got %d != exp %d\n", rodata->in6, 14);
/* now set new values and attach to get them into outX variables */
data->in1 = 1;
data->in2 = 2;
bss->in3 = 3;
bss->in4 = 4;
bss->in5.a = 5;
@ -44,14 +78,15 @@ void test_skeleton(void)
/* trigger tracepoint */
usleep(1);
CHECK(bss->out1 != 1, "res1", "got %d != exp %d\n", bss->out1, 1);
CHECK(bss->out2 != 2, "res2", "got %lld != exp %d\n", bss->out2, 2);
CHECK(data->out1 != 1, "res1", "got %d != exp %d\n", data->out1, 1);
CHECK(data->out2 != 2, "res2", "got %lld != exp %d\n", data->out2, 2);
CHECK(bss->out3 != 3, "res3", "got %d != exp %d\n", (int)bss->out3, 3);
CHECK(bss->out4 != 4, "res4", "got %lld != exp %d\n", bss->out4, 4);
CHECK(bss->handler_out5.a != 5, "res5", "got %d != exp %d\n",
bss->handler_out5.a, 5);
CHECK(bss->handler_out5.b != 6, "res6", "got %lld != exp %d\n",
bss->handler_out5.b, 6);
CHECK(bss->out6 != 14, "res7", "got %d != exp %d\n", bss->out6, 14);
CHECK(bss->bpf_syscall != kcfg->CONFIG_BPF_SYSCALL, "ext1",
"got %d != exp %d\n", bss->bpf_syscall, kcfg->CONFIG_BPF_SYSCALL);

View File

@ -8,14 +8,6 @@
#define IFINDEX_LO 1
struct bpf_devmap_val {
u32 ifindex; /* device index */
union {
int fd; /* prog fd on map write */
u32 id; /* prog id on map read */
} bpf_prog;
};
void test_xdp_with_devmap_helpers(void)
{
struct test_xdp_with_devmap_helpers *skel;

View File

@ -0,0 +1,48 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2020 Google LLC.
*/
#include <errno.h>
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <bpf/bpf_helpers.h>
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, 1);
__type(key, __u32);
__type(value, __u32);
} test_result SEC(".maps");
SEC("cgroup_skb/egress")
int load_bytes_relative(struct __sk_buff *skb)
{
struct ethhdr eth;
struct iphdr iph;
__u32 map_key = 0;
__u32 test_passed = 0;
/* MAC header is not set by the time cgroup_skb/egress triggers */
if (bpf_skb_load_bytes_relative(skb, 0, &eth, sizeof(eth),
BPF_HDR_START_MAC) != -EFAULT)
goto fail;
if (bpf_skb_load_bytes_relative(skb, 0, &iph, sizeof(iph),
BPF_HDR_START_NET))
goto fail;
if (bpf_skb_load_bytes_relative(skb, 0xffff, &iph, sizeof(iph),
BPF_HDR_START_NET) != -EFAULT)
goto fail;
test_passed = 1;
fail:
bpf_map_update_elem(&test_result, &map_key, &test_passed, BPF_ANY);
return 1;
}

View File

@ -10,16 +10,26 @@ struct s {
long long b;
} __attribute__((packed));
int in1 = 0;
long long in2 = 0;
/* .data section */
int in1 = -1;
long long in2 = -1;
/* .bss section */
char in3 = '\0';
long long in4 __attribute__((aligned(64))) = 0;
struct s in5 = {};
long long out2 = 0;
/* .rodata section */
const volatile int in6 = 0;
/* .data section */
int out1 = -1;
long long out2 = -1;
/* .bss section */
char out3 = 0;
long long out4 = 0;
int out1 = 0;
int out6 = 0;
extern bool CONFIG_BPF_SYSCALL __kconfig;
extern int LINUX_KERNEL_VERSION __kconfig;
@ -36,6 +46,7 @@ int handler(const void *ctx)
out3 = in3;
out4 = in4;
out5 = in5;
out6 = in6;
bpf_syscall = CONFIG_BPF_SYSCALL;
kern_ver = LINUX_KERNEL_VERSION;

View File

@ -2,7 +2,7 @@
/* fails to load without expected_attach_type = BPF_XDP_DEVMAP
* because of access to egress_ifindex
*/
#include "vmlinux.h"
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
SEC("xdp_dm_log")

View File

@ -1,6 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
#include "vmlinux.h"
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
struct {