From patchwork Tue Aug 6 09:47:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Palethorpe X-Patchwork-Id: 1142662 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.linux.it (client-ip=213.254.12.146; helo=picard.linux.it; envelope-from=ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.com Received: from picard.linux.it (picard.linux.it [213.254.12.146]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 462qZM051Jz9s7T for ; Tue, 6 Aug 2019 19:48:10 +1000 (AEST) Received: from picard.linux.it (localhost [IPv6:::1]) by picard.linux.it (Postfix) with ESMTP id 776E63C194D for ; Tue, 6 Aug 2019 11:48:08 +0200 (CEST) X-Original-To: ltp@lists.linux.it Delivered-To: ltp@picard.linux.it Received: from in-7.smtp.seeweb.it (in-7.smtp.seeweb.it [IPv6:2001:4b78:1:20::7]) by picard.linux.it (Postfix) with ESMTP id 352653C194D for ; Tue, 6 Aug 2019 11:48:06 +0200 (CEST) Received: from mx1.suse.de (mx2.suse.de [195.135.220.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by in-7.smtp.seeweb.it (Postfix) with ESMTPS id E56D3201002 for ; Tue, 6 Aug 2019 11:48:04 +0200 (CEST) Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 2221CAFD4 for ; Tue, 6 Aug 2019 09:48:04 +0000 (UTC) From: Richard Palethorpe To: ltp@lists.linux.it Date: Tue, 6 Aug 2019 11:47:49 +0200 Message-Id: <20190806094752.9794-2-rpalethorpe@suse.com> X-Mailer: git-send-email 2.22.0 In-Reply-To: <20190806094752.9794-1-rpalethorpe@suse.com> References: <20190801092616.30553-1-chrubis@suse.cz> <20190806094752.9794-1-rpalethorpe@suse.com> MIME-Version: 1.0 X-Virus-Scanned: clamav-milter 0.99.2 at in-7.smtp.seeweb.it X-Virus-Status: Clean X-Spam-Status: No, score=0.0 required=7.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=3.4.0 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on in-7.smtp.seeweb.it Subject: [LTP] [PATCH v3 1/4] BPF: Essential headers for map creation X-BeenThere: ltp@lists.linux.it X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux Test Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Richard Palethorpe Errors-To: ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it Sender: "ltp" Signed-off-by: Richard Palethorpe --- include/lapi/bpf.h | 242 +++++++++++++++++++++++++++++++ include/lapi/syscalls/aarch64.in | 1 + include/lapi/syscalls/i386.in | 1 + include/lapi/syscalls/s390.in | 1 + include/lapi/syscalls/sparc.in | 1 + include/lapi/syscalls/x86_64.in | 1 + 6 files changed, 247 insertions(+) create mode 100644 include/lapi/bpf.h diff --git a/include/lapi/bpf.h b/include/lapi/bpf.h new file mode 100644 index 000000000..369de0175 --- /dev/null +++ b/include/lapi/bpf.h @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Richard Palethorpe + * + * Essential Extended Berkeley Packet Filter (eBPF) headers + * + * Mostly copied/adapted from linux/bpf.h and libbpf so that we can perform + * some eBPF testing without any external dependencies. + */ + +#ifndef BPF_H +# define BPF_H + +#include + +#include "lapi/syscalls.h" + +/* Start copy from linux/bpf.h */ +enum bpf_cmd { + BPF_MAP_CREATE, + BPF_MAP_LOOKUP_ELEM, + BPF_MAP_UPDATE_ELEM, + BPF_MAP_DELETE_ELEM, + BPF_MAP_GET_NEXT_KEY, + BPF_PROG_LOAD, + BPF_OBJ_PIN, + BPF_OBJ_GET, + BPF_PROG_ATTACH, + BPF_PROG_DETACH, + BPF_PROG_TEST_RUN, + BPF_PROG_GET_NEXT_ID, + BPF_MAP_GET_NEXT_ID, + BPF_PROG_GET_FD_BY_ID, + BPF_MAP_GET_FD_BY_ID, + BPF_OBJ_GET_INFO_BY_FD, + BPF_PROG_QUERY, + BPF_RAW_TRACEPOINT_OPEN, + BPF_BTF_LOAD, + BPF_BTF_GET_FD_BY_ID, + BPF_TASK_FD_QUERY, + BPF_MAP_LOOKUP_AND_DELETE_ELEM, + BPF_MAP_FREEZE, +}; + +enum bpf_map_type { + BPF_MAP_TYPE_UNSPEC, + BPF_MAP_TYPE_HASH, + BPF_MAP_TYPE_ARRAY, + BPF_MAP_TYPE_PROG_ARRAY, + BPF_MAP_TYPE_PERF_EVENT_ARRAY, + BPF_MAP_TYPE_PERCPU_HASH, + BPF_MAP_TYPE_PERCPU_ARRAY, + BPF_MAP_TYPE_STACK_TRACE, + BPF_MAP_TYPE_CGROUP_ARRAY, + BPF_MAP_TYPE_LRU_HASH, + BPF_MAP_TYPE_LRU_PERCPU_HASH, + BPF_MAP_TYPE_LPM_TRIE, + BPF_MAP_TYPE_ARRAY_OF_MAPS, + BPF_MAP_TYPE_HASH_OF_MAPS, + BPF_MAP_TYPE_DEVMAP, + BPF_MAP_TYPE_SOCKMAP, + BPF_MAP_TYPE_CPUMAP, + BPF_MAP_TYPE_XSKMAP, + BPF_MAP_TYPE_SOCKHASH, + BPF_MAP_TYPE_CGROUP_STORAGE, + BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, + BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, + BPF_MAP_TYPE_QUEUE, + BPF_MAP_TYPE_STACK, + BPF_MAP_TYPE_SK_STORAGE, +}; + +#define BPF_OBJ_NAME_LEN 16U + +#define BPF_ANY 0 /* create new element or update existing */ +#define BPF_NOEXIST 1 /* create new element if it didn't exist */ +#define BPF_EXIST 2 /* update existing element */ +#define BPF_F_LOCK 4 /* spin_lock-ed map_lookup/map_update */ + +#define aligned_uint64_t uint64_t __attribute__((aligned(8))) + +union bpf_attr { + struct { /* anonymous struct used by BPF_MAP_CREATE command */ + uint32_t map_type; /* one of enum bpf_map_type */ + uint32_t key_size; /* size of key in bytes */ + uint32_t value_size; /* size of value in bytes */ + uint32_t max_entries; /* max number of entries in a map */ + uint32_t map_flags; /* BPF_MAP_CREATE related + * flags defined above. + */ + uint32_t inner_map_fd; /* fd pointing to the inner map */ + uint32_t numa_node; /* numa node (effective only if + * BPF_F_NUMA_NODE is set). + */ + char map_name[BPF_OBJ_NAME_LEN]; + uint32_t map_ifindex; /* ifindex of netdev to create on */ + uint32_t btf_fd; /* fd pointing to a BTF type data */ + uint32_t btf_key_type_id; /* BTF type_id of the key */ + uint32_t btf_value_type_id; /* BTF type_id of the value */ + }; + + struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ + uint32_t map_fd; + aligned_uint64_t key; + union { + aligned_uint64_t value; + aligned_uint64_t next_key; + }; + uint64_t flags; + }; + + struct { /* anonymous struct used by BPF_PROG_LOAD command */ + uint32_t prog_type; /* one of enum bpf_prog_type */ + uint32_t insn_cnt; + aligned_uint64_t insns; + aligned_uint64_t license; + uint32_t log_level; /* verbosity level of verifier */ + uint32_t log_size; /* size of user buffer */ + aligned_uint64_t log_buf; /* user supplied buffer */ + uint32_t kern_version; /* not used */ + uint32_t prog_flags; + char prog_name[BPF_OBJ_NAME_LEN]; + uint32_t prog_ifindex; /* ifindex of netdev to prep for */ + /* For some prog types expected attach type must be known at + * load time to verify attach type specific parts of prog + * (context accesses, allowed helpers, etc). + */ + uint32_t expected_attach_type; + uint32_t prog_btf_fd; /* fd pointing to BTF type data */ + uint32_t func_info_rec_size; /* userspace bpf_func_info size */ + aligned_uint64_t func_info; /* func info */ + uint32_t func_info_cnt; /* number of bpf_func_info records */ + uint32_t line_info_rec_size; /* userspace bpf_line_info size */ + aligned_uint64_t line_info; /* line info */ + uint32_t line_info_cnt; /* number of bpf_line_info records */ + }; + + struct { /* anonymous struct used by BPF_OBJ_* commands */ + aligned_uint64_t pathname; + uint32_t bpf_fd; + uint32_t file_flags; + }; + + struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */ + uint32_t target_fd; /* container object to attach to */ + uint32_t attach_bpf_fd; /* eBPF program to attach */ + uint32_t attach_type; + uint32_t attach_flags; + }; + + struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */ + uint32_t prog_fd; + uint32_t retval; + uint32_t data_size_in; /* input: len of data_in */ + uint32_t data_size_out; /* input/output: len of data_out + * returns ENOSPC if data_out + * is too small. + */ + aligned_uint64_t data_in; + aligned_uint64_t data_out; + uint32_t repeat; + uint32_t duration; + uint32_t ctx_size_in; /* input: len of ctx_in */ + uint32_t ctx_size_out; /* input/output: len of ctx_out + * returns ENOSPC if ctx_out + * is too small. + */ + aligned_uint64_t ctx_in; + aligned_uint64_t ctx_out; + } test; + + struct { /* anonymous struct used by BPF_*_GET_*_ID */ + union { + uint32_t start_id; + uint32_t prog_id; + uint32_t map_id; + uint32_t btf_id; + }; + uint32_t next_id; + uint32_t open_flags; + }; + + struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */ + uint32_t bpf_fd; + uint32_t info_len; + aligned_uint64_t info; + } info; + + struct { /* anonymous struct used by BPF_PROG_QUERY command */ + uint32_t target_fd; /* container object to query */ + uint32_t attach_type; + uint32_t query_flags; + uint32_t attach_flags; + aligned_uint64_t prog_ids; + uint32_t prog_cnt; + } query; + + struct { + uint64_t name; + uint32_t prog_fd; + } raw_tracepoint; + + struct { /* anonymous struct for BPF_BTF_LOAD */ + aligned_uint64_t btf; + aligned_uint64_t btf_log_buf; + uint32_t btf_size; + uint32_t btf_log_size; + uint32_t btf_log_level; + }; + + struct { + uint32_t pid; /* input: pid */ + uint32_t fd; /* input: fd */ + uint32_t flags; /* input: flags */ + uint32_t buf_len; /* input/output: buf len */ + aligned_uint64_t buf; /* input/output: + * tp_name for tracepoint + * symbol for kprobe + * filename for uprobe + */ + uint32_t prog_id; /* output: prod_id */ + uint32_t fd_type; /* output: BPF_FD_TYPE_* */ + uint64_t probe_offset; /* output: probe_offset */ + uint64_t probe_addr; /* output: probe_addr */ + } task_fd_query; +} __attribute__((aligned(8))); + +/* End copy from linux/bpf.h */ + +/* Start copy from tools/lib/bpf */ +inline uint64_t ptr_to_u64(const void *ptr) +{ + return (uint64_t) (unsigned long) ptr; +} + +inline int bpf(enum bpf_cmd cmd, union bpf_attr *attr, unsigned int size) +{ + return tst_syscall(__NR_bpf, cmd, attr, size); +} +/* End copy from tools/lib/bpf */ + +#endif /* BPF_H */ diff --git a/include/lapi/syscalls/aarch64.in b/include/lapi/syscalls/aarch64.in index 7db6e281c..0e00641bc 100644 --- a/include/lapi/syscalls/aarch64.in +++ b/include/lapi/syscalls/aarch64.in @@ -258,6 +258,7 @@ process_vm_writev 271 kcmp 272 getrandom 278 memfd_create 279 +bpf 280 userfaultfd 282 membarrier 283 execveat 281 diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in index 02f3955ba..87ab46933 100644 --- a/include/lapi/syscalls/i386.in +++ b/include/lapi/syscalls/i386.in @@ -340,6 +340,7 @@ sched_getattr 352 renameat2 354 getrandom 355 memfd_create 356 +bpf 357 execveat 358 userfaultfd 374 membarrier 375 diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in index c304ef4b7..d3f7eb1f6 100644 --- a/include/lapi/syscalls/s390.in +++ b/include/lapi/syscalls/s390.in @@ -331,6 +331,7 @@ sched_getattr 346 renameat2 347 getrandom 349 memfd_create 350 +bpf 351 userfaultfd 355 membarrier 356 execveat 354 diff --git a/include/lapi/syscalls/sparc.in b/include/lapi/syscalls/sparc.in index ab7204663..94a672428 100644 --- a/include/lapi/syscalls/sparc.in +++ b/include/lapi/syscalls/sparc.in @@ -336,6 +336,7 @@ kcmp 341 renameat2 345 getrandom 347 memfd_create 348 +bpf 349 membarrier 351 userfaultfd 352 execveat 350 diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in index fdb414c10..b1cbd4f2f 100644 --- a/include/lapi/syscalls/x86_64.in +++ b/include/lapi/syscalls/x86_64.in @@ -307,6 +307,7 @@ sched_getattr 315 renameat2 316 getrandom 318 memfd_create 319 +bpf 321 execveat 322 userfaultfd 323 membarrier 324 From patchwork Tue Aug 6 09:47:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Palethorpe X-Patchwork-Id: 1142665 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.linux.it (client-ip=2001:1418:10:5::2; helo=picard.linux.it; envelope-from=ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.com Received: from picard.linux.it (picard.linux.it [IPv6:2001:1418:10:5::2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 462qZm6LWGz9s7T for ; Tue, 6 Aug 2019 19:48:32 +1000 (AEST) Received: from picard.linux.it (localhost [IPv6:::1]) by picard.linux.it (Postfix) with ESMTP id 27D453C1D8F for ; Tue, 6 Aug 2019 11:48:30 +0200 (CEST) X-Original-To: ltp@lists.linux.it Delivered-To: ltp@picard.linux.it Received: from in-5.smtp.seeweb.it (in-5.smtp.seeweb.it [217.194.8.5]) by picard.linux.it (Postfix) with ESMTP id 54FAB3C1C81 for ; Tue, 6 Aug 2019 11:48:06 +0200 (CEST) Received: from mx1.suse.de (mx2.suse.de [195.135.220.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by in-5.smtp.seeweb.it (Postfix) with ESMTPS id 6CCF4600BA1 for ; Tue, 6 Aug 2019 11:48:07 +0200 (CEST) Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 2FEA1AFEF for ; Tue, 6 Aug 2019 09:48:04 +0000 (UTC) From: Richard Palethorpe To: ltp@lists.linux.it Date: Tue, 6 Aug 2019 11:47:50 +0200 Message-Id: <20190806094752.9794-3-rpalethorpe@suse.com> X-Mailer: git-send-email 2.22.0 In-Reply-To: <20190806094752.9794-1-rpalethorpe@suse.com> References: <20190801092616.30553-1-chrubis@suse.cz> <20190806094752.9794-1-rpalethorpe@suse.com> MIME-Version: 1.0 X-Virus-Scanned: clamav-milter 0.99.2 at in-5.smtp.seeweb.it X-Virus-Status: Clean X-Spam-Status: No, score=0.0 required=7.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=3.4.0 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on in-5.smtp.seeweb.it Subject: [LTP] [PATCH v3 2/4] BPF: Sanity check creating and updating maps X-BeenThere: ltp@lists.linux.it X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux Test Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Richard Palethorpe Errors-To: ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it Sender: "ltp" Signed-off-by: Richard Palethorpe --- runtest/syscalls | 2 + testcases/kernel/syscalls/bpf/.gitignore | 1 + testcases/kernel/syscalls/bpf/Makefile | 10 ++ testcases/kernel/syscalls/bpf/bpf_map01.c | 140 ++++++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 testcases/kernel/syscalls/bpf/.gitignore create mode 100644 testcases/kernel/syscalls/bpf/Makefile create mode 100644 testcases/kernel/syscalls/bpf/bpf_map01.c diff --git a/runtest/syscalls b/runtest/syscalls index a68a4c9d0..9d48285b8 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -32,6 +32,8 @@ bind01 bind01 bind02 bind02 bind03 bind03 +bpf_map01 bpf_map01 + brk01 brk01 capget01 capget01 diff --git a/testcases/kernel/syscalls/bpf/.gitignore b/testcases/kernel/syscalls/bpf/.gitignore new file mode 100644 index 000000000..f33532484 --- /dev/null +++ b/testcases/kernel/syscalls/bpf/.gitignore @@ -0,0 +1 @@ +bpf_map01 diff --git a/testcases/kernel/syscalls/bpf/Makefile b/testcases/kernel/syscalls/bpf/Makefile new file mode 100644 index 000000000..990c8c83c --- /dev/null +++ b/testcases/kernel/syscalls/bpf/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2019 Linux Test Project + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +CFLAGS += -D_GNU_SOURCE + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/bpf/bpf_map01.c b/testcases/kernel/syscalls/bpf/bpf_map01.c new file mode 100644 index 000000000..c5ddd8aad --- /dev/null +++ b/testcases/kernel/syscalls/bpf/bpf_map01.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Richard Palethorpe + * + * Trivial Extended Berkeley Packet Filter (eBPF) test. + * + * Sanity check creating and updating maps. + */ + +#include +#include + +#include "config.h" +#include "tst_test.h" +#include "lapi/bpf.h" + +#define KEY_SZ 8 +#define VAL_SZ 1024 + +struct map_type { + uint32_t id; + char *name; +}; + +static const struct map_type map_types[] = { + {BPF_MAP_TYPE_HASH, "hash"}, + {BPF_MAP_TYPE_ARRAY, "array"} +}; + +static void *key; +static void *val0; +static void *val1; +static union bpf_attr *attr; + +void run(unsigned int n) +{ + int fd, i; + + memset(attr, 0, sizeof(*attr)); + attr->map_type = map_types[n].id; + attr->key_size = n == 0 ? KEY_SZ : 4; + attr->value_size = VAL_SZ; + attr->max_entries = 1; + + TEST(bpf(BPF_MAP_CREATE, attr, sizeof(*attr))); + if (TST_RET == -1) { + if (TST_ERR == EPERM) { + tst_brk(TCONF | TTERRNO, + "bpf() requires CAP_SYS_ADMIN on this system"); + } else { + tst_brk(TFAIL | TTERRNO, "Failed to create %s map", + map_types[n].name); + } + } + tst_res(TPASS, "Created %s map", map_types[n].name); + fd = TST_RET; + + if (n == 0) + memcpy(key, "12345678", KEY_SZ); + else + memset(key, 0, 4); + + memset(attr, 0, sizeof(*attr)); + attr->map_fd = fd; + attr->key = ptr_to_u64(key); + attr->value = ptr_to_u64(val1); + + TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr))); + if (n == 0) { + if (TST_RET != -1 || TST_ERR != ENOENT) { + tst_res(TFAIL | TTERRNO, + "Empty hash map lookup should fail with ENOENT"); + } else { + tst_res(TPASS | TTERRNO, "Empty hash map lookup"); + } + } else if (TST_RET != -1) { + for (i = 0;;) { + if (*(char *) val1 != 0) { + tst_res(TFAIL, + "Preallocated array map val not zero"); + } else if (++i >= VAL_SZ) { + tst_res(TPASS, + "Preallocated array map lookup"); + break; + } + } + } else { + tst_res(TFAIL | TERRNO, "Prellocated array map lookup"); + } + + memset(attr, 0, sizeof(*attr)); + attr->map_fd = fd; + attr->key = ptr_to_u64(key); + attr->value = ptr_to_u64(val0); + attr->flags = BPF_ANY; + + TEST(bpf(BPF_MAP_UPDATE_ELEM, attr, sizeof(*attr))); + if (TST_RET == -1) { + tst_brk(TFAIL | TTERRNO, + "Update %s map element", + map_types[n].name); + } else { + tst_res(TPASS, + "Update %s map element", + map_types[n].name); + } + + memset(attr, 0, sizeof(*attr)); + attr->map_fd = fd; + attr->key = ptr_to_u64(key); + attr->value = ptr_to_u64(val1); + + TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr))); + if (TST_RET == -1) { + tst_res(TFAIL | TTERRNO, + "%s map lookup missing", + map_types[n].name); + } else if (memcmp(val0, val1, (size_t) VAL_SZ)) { + tst_res(TFAIL, + "%s map lookup returned different value", + map_types[n].name); + } else { + tst_res(TPASS, "%s map lookup", map_types[n].name); + } + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tcnt = 2, + .test = run, + .min_kver = "3.18", + .bufs = (struct tst_buffers []) { + {&key, .size = KEY_SZ}, + {&val0, .size = VAL_SZ}, + {&val1, .size = VAL_SZ}, + {&attr, .size = sizeof(*attr)}, + {NULL}, + }, +}; From patchwork Tue Aug 6 09:47:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Palethorpe X-Patchwork-Id: 1142664 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.linux.it (client-ip=213.254.12.146; helo=picard.linux.it; envelope-from=ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.com Received: from picard.linux.it (picard.linux.it [213.254.12.146]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 462qZd6CwYz9s7T for ; Tue, 6 Aug 2019 19:48:25 +1000 (AEST) Received: from picard.linux.it (localhost [IPv6:::1]) by picard.linux.it (Postfix) with ESMTP id 41D583C1DA5 for ; Tue, 6 Aug 2019 11:48:23 +0200 (CEST) X-Original-To: ltp@lists.linux.it Delivered-To: ltp@picard.linux.it Received: from in-3.smtp.seeweb.it (in-3.smtp.seeweb.it [217.194.8.3]) by picard.linux.it (Postfix) with ESMTP id 418A63C1A4E for ; Tue, 6 Aug 2019 11:48:06 +0200 (CEST) Received: from mx1.suse.de (mx2.suse.de [195.135.220.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by in-3.smtp.seeweb.it (Postfix) with ESMTPS id E5C321A00F01 for ; Tue, 6 Aug 2019 11:48:04 +0200 (CEST) Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 3E9AEAFF2 for ; Tue, 6 Aug 2019 09:48:04 +0000 (UTC) From: Richard Palethorpe To: ltp@lists.linux.it Date: Tue, 6 Aug 2019 11:47:51 +0200 Message-Id: <20190806094752.9794-4-rpalethorpe@suse.com> X-Mailer: git-send-email 2.22.0 In-Reply-To: <20190806094752.9794-1-rpalethorpe@suse.com> References: <20190801092616.30553-1-chrubis@suse.cz> <20190806094752.9794-1-rpalethorpe@suse.com> MIME-Version: 1.0 X-Virus-Scanned: clamav-milter 0.99.2 at in-3.smtp.seeweb.it X-Virus-Status: Clean X-Spam-Status: No, score=0.0 required=7.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=3.4.0 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on in-3.smtp.seeweb.it Subject: [LTP] [PATCH v3 3/4] BPF: Essential headers for a basic program X-BeenThere: ltp@lists.linux.it X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux Test Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Richard Palethorpe Errors-To: ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it Sender: "ltp" Signed-off-by: Richard Palethorpe --- include/lapi/bpf.h | 286 +++++++++++++++++++++++++++++++++++++++++- include/lapi/socket.h | 4 + 2 files changed, 289 insertions(+), 1 deletion(-) diff --git a/include/lapi/bpf.h b/include/lapi/bpf.h index 369de0175..122eb5469 100644 --- a/include/lapi/bpf.h +++ b/include/lapi/bpf.h @@ -15,7 +15,57 @@ #include "lapi/syscalls.h" -/* Start copy from linux/bpf.h */ +/* Start copy from linux/bpf_(common).h */ +#define BPF_CLASS(code) ((code) & 0x07) +#define BPF_LD 0x00 +#define BPF_ST 0x02 +#define BPF_JMP 0x05 + +#define BPF_SIZE(code) ((code) & 0x18) +#define BPF_DW 0x18 /* double word (64-bit) */ + +#define BPF_MODE(code) ((code) & 0xe0) +#define BPF_IMM 0x00 +#define BPF_MEM 0x60 + +#define BPF_OP(code) ((code) & 0xf0) +#define BPF_ADD 0x00 + +#define BPF_JEQ 0x10 + +#define BPF_SRC(code) ((code) & 0x08) +#define BPF_K 0x00 +#define BPF_X 0x08 + +#define BPF_ALU64 0x07 /* alu mode in double word width */ +#define BPF_MOV 0xb0 /* mov reg to reg */ +#define BPF_CALL 0x80 /* function call */ +#define BPF_EXIT 0x90 /* function return */ + +/* Register numbers */ +enum { + BPF_REG_0 = 0, + BPF_REG_1, + BPF_REG_2, + BPF_REG_3, + BPF_REG_4, + BPF_REG_5, + BPF_REG_6, + BPF_REG_7, + BPF_REG_8, + BPF_REG_9, + BPF_REG_10, + MAX_BPF_REG, +}; + +struct bpf_insn { + uint8_t code; /* opcode */ + uint8_t dst_reg:4; /* dest register */ + uint8_t src_reg:4; /* source register */ + int16_t off; /* signed offset */ + int32_t imm; /* signed immediate constant */ +}; + enum bpf_cmd { BPF_MAP_CREATE, BPF_MAP_LOOKUP_ELEM, @@ -70,6 +120,37 @@ enum bpf_map_type { BPF_MAP_TYPE_SK_STORAGE, }; +enum bpf_prog_type { + BPF_PROG_TYPE_UNSPEC, + BPF_PROG_TYPE_SOCKET_FILTER, + BPF_PROG_TYPE_KPROBE, + BPF_PROG_TYPE_SCHED_CLS, + BPF_PROG_TYPE_SCHED_ACT, + BPF_PROG_TYPE_TRACEPOINT, + BPF_PROG_TYPE_XDP, + BPF_PROG_TYPE_PERF_EVENT, + BPF_PROG_TYPE_CGROUP_SKB, + BPF_PROG_TYPE_CGROUP_SOCK, + BPF_PROG_TYPE_LWT_IN, + BPF_PROG_TYPE_LWT_OUT, + BPF_PROG_TYPE_LWT_XMIT, + BPF_PROG_TYPE_SOCK_OPS, + BPF_PROG_TYPE_SK_SKB, + BPF_PROG_TYPE_CGROUP_DEVICE, + BPF_PROG_TYPE_SK_MSG, + BPF_PROG_TYPE_RAW_TRACEPOINT, + BPF_PROG_TYPE_CGROUP_SOCK_ADDR, + BPF_PROG_TYPE_LWT_SEG6LOCAL, + BPF_PROG_TYPE_LIRC_MODE2, + BPF_PROG_TYPE_SK_REUSEPORT, + BPF_PROG_TYPE_FLOW_DISSECTOR, + BPF_PROG_TYPE_CGROUP_SYSCTL, + BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, + BPF_PROG_TYPE_CGROUP_SOCKOPT, +}; + +#define BPF_PSEUDO_MAP_FD 1 + #define BPF_OBJ_NAME_LEN 16U #define BPF_ANY 0 /* create new element or update existing */ @@ -225,8 +306,211 @@ union bpf_attr { } task_fd_query; } __attribute__((aligned(8))); +#define __BPF_FUNC_MAPPER(FN) \ + FN(unspec), \ + FN(map_lookup_elem), \ + FN(map_update_elem), \ + FN(map_delete_elem), \ + FN(probe_read), \ + FN(ktime_get_ns), \ + FN(trace_printk), \ + FN(get_prandom_u32), \ + FN(get_smp_processor_id), \ + FN(skb_store_bytes), \ + FN(l3_csum_replace), \ + FN(l4_csum_replace), \ + FN(tail_call), \ + FN(clone_redirect), \ + FN(get_current_pid_tgid), \ + FN(get_current_uid_gid), \ + FN(get_current_comm), \ + FN(get_cgroup_classid), \ + FN(skb_vlan_push), \ + FN(skb_vlan_pop), \ + FN(skb_get_tunnel_key), \ + FN(skb_set_tunnel_key), \ + FN(perf_event_read), \ + FN(redirect), \ + FN(get_route_realm), \ + FN(perf_event_output), \ + FN(skb_load_bytes), \ + FN(get_stackid), \ + FN(csum_diff), \ + FN(skb_get_tunnel_opt), \ + FN(skb_set_tunnel_opt), \ + FN(skb_change_proto), \ + FN(skb_change_type), \ + FN(skb_under_cgroup), \ + FN(get_hash_recalc), \ + FN(get_current_task), \ + FN(probe_write_user), \ + FN(current_task_under_cgroup), \ + FN(skb_change_tail), \ + FN(skb_pull_data), \ + FN(csum_update), \ + FN(set_hash_invalid), \ + FN(get_numa_node_id), \ + FN(skb_change_head), \ + FN(xdp_adjust_head), \ + FN(probe_read_str), \ + FN(get_socket_cookie), \ + FN(get_socket_uid), \ + FN(set_hash), \ + FN(setsockopt), \ + FN(skb_adjust_room), \ + FN(redirect_map), \ + FN(sk_redirect_map), \ + FN(sock_map_update), \ + FN(xdp_adjust_meta), \ + FN(perf_event_read_value), \ + FN(perf_prog_read_value), \ + FN(getsockopt), \ + FN(override_return), \ + FN(sock_ops_cb_flags_set), \ + FN(msg_redirect_map), \ + FN(msg_apply_bytes), \ + FN(msg_cork_bytes), \ + FN(msg_pull_data), \ + FN(bind), \ + FN(xdp_adjust_tail), \ + FN(skb_get_xfrm_state), \ + FN(get_stack), \ + FN(skb_load_bytes_relative), \ + FN(fib_lookup), \ + FN(sock_hash_update), \ + FN(msg_redirect_hash), \ + FN(sk_redirect_hash), \ + FN(lwt_push_encap), \ + FN(lwt_seg6_store_bytes), \ + FN(lwt_seg6_adjust_srh), \ + FN(lwt_seg6_action), \ + FN(rc_repeat), \ + FN(rc_keydown), \ + FN(skb_cgroup_id), \ + FN(get_current_cgroup_id), \ + FN(get_local_storage), \ + FN(sk_select_reuseport), \ + FN(skb_ancestor_cgroup_id), \ + FN(sk_lookup_tcp), \ + FN(sk_lookup_udp), \ + FN(sk_release), \ + FN(map_push_elem), \ + FN(map_pop_elem), \ + FN(map_peek_elem), \ + FN(msg_push_data), \ + FN(msg_pop_data), \ + FN(rc_pointer_rel), \ + FN(spin_lock), \ + FN(spin_unlock), \ + FN(sk_fullsock), \ + FN(tcp_sock), \ + FN(skb_ecn_set_ce), \ + FN(get_listener_sock), \ + FN(skc_lookup_tcp), \ + FN(tcp_check_syncookie), \ + FN(sysctl_get_name), \ + FN(sysctl_get_current_value), \ + FN(sysctl_get_new_value), \ + FN(sysctl_set_new_value), \ + FN(strtol), \ + FN(strtoul), \ + FN(sk_storage_get), \ + FN(sk_storage_delete), \ + FN(send_signal), + +/* integer value in 'imm' field of BPF_CALL instruction selects which helper + * function eBPF program intends to call + */ +#define __BPF_ENUM_FN(x) BPF_FUNC_ ## x +enum bpf_func_id { + __BPF_FUNC_MAPPER(__BPF_ENUM_FN) + __BPF_FUNC_MAX_ID, +}; +#undef __BPF_ENUM_FN + /* End copy from linux/bpf.h */ +/* Start copy from tools/include/filter.h */ + +#define BPF_ALU64_IMM(OP, DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + +#define BPF_MOV64_REG(DST, SRC) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_X, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = 0 }) + +#define BPF_LD_IMM64(DST, IMM) \ + BPF_LD_IMM64_RAW(DST, 0, IMM) + +#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_LD | BPF_DW | BPF_IMM, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = 0, \ + .imm = (uint32_t) (IMM) }), \ + ((struct bpf_insn) { \ + .code = 0, /* zero is reserved opcode */ \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = ((uint64_t) (IMM)) >> 32 }) + +/* pseudo BPF_LD_IMM64 insn used to refer to process-local map_fd */ +#define BPF_LD_MAP_FD(DST, MAP_FD) \ + BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD) + +#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = OFF, \ + .imm = IMM }) + +#define BPF_JMP_IMM(OP, DST, IMM, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = OFF, \ + .imm = IMM }) + +#define BPF_MOV64_IMM(DST, IMM) \ + ((struct bpf_insn) { \ + .code = BPF_ALU64 | BPF_MOV | BPF_K, \ + .dst_reg = DST, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) + +#define BPF_EMIT_CALL(FUNC) \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_CALL, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = ((FUNC) - BPF_FUNC_unspec) }) + +#define BPF_EXIT_INSN() \ + ((struct bpf_insn) { \ + .code = BPF_JMP | BPF_EXIT, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = 0 }) + +/* End copy from tools/include/filter.h */ + /* Start copy from tools/lib/bpf */ inline uint64_t ptr_to_u64(const void *ptr) { diff --git a/include/lapi/socket.h b/include/lapi/socket.h index 6d9e9fe30..f32782fed 100644 --- a/include/lapi/socket.h +++ b/include/lapi/socket.h @@ -38,6 +38,10 @@ # define SO_BUSY_POLL 46 #endif +#ifndef SO_ATTACH_BPF +# define SO_ATTACH_BPF 50 +#endif + #ifndef SO_ZEROCOPY # define SO_ZEROCOPY 60 #endif From patchwork Tue Aug 6 09:47:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Palethorpe X-Patchwork-Id: 1142666 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=lists.linux.it (client-ip=2001:1418:10:5::2; helo=picard.linux.it; envelope-from=ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.com Received: from picard.linux.it (picard.linux.it [IPv6:2001:1418:10:5::2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 462qZw2gtBz9s7T for ; Tue, 6 Aug 2019 19:48:40 +1000 (AEST) Received: from picard.linux.it (localhost [IPv6:::1]) by picard.linux.it (Postfix) with ESMTP id B07D53C1C9A for ; Tue, 6 Aug 2019 11:48:37 +0200 (CEST) X-Original-To: ltp@lists.linux.it Delivered-To: ltp@picard.linux.it Received: from in-3.smtp.seeweb.it (in-3.smtp.seeweb.it [IPv6:2001:4b78:1:20::3]) by picard.linux.it (Postfix) with ESMTP id 771C33C194D for ; Tue, 6 Aug 2019 11:48:06 +0200 (CEST) Received: from mx1.suse.de (mx2.suse.de [195.135.220.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by in-3.smtp.seeweb.it (Postfix) with ESMTPS id E6B371A00F17 for ; Tue, 6 Aug 2019 11:48:04 +0200 (CEST) Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 45583AFF8 for ; Tue, 6 Aug 2019 09:48:04 +0000 (UTC) From: Richard Palethorpe To: ltp@lists.linux.it Date: Tue, 6 Aug 2019 11:47:52 +0200 Message-Id: <20190806094752.9794-5-rpalethorpe@suse.com> X-Mailer: git-send-email 2.22.0 In-Reply-To: <20190806094752.9794-1-rpalethorpe@suse.com> References: <20190801092616.30553-1-chrubis@suse.cz> <20190806094752.9794-1-rpalethorpe@suse.com> MIME-Version: 1.0 X-Virus-Scanned: clamav-milter 0.99.2 at in-3.smtp.seeweb.it X-Virus-Status: Clean X-Spam-Status: No, score=0.0 required=7.0 tests=SPF_HELO_NONE,SPF_PASS autolearn=disabled version=3.4.0 X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on in-3.smtp.seeweb.it Subject: [LTP] [PATCH v3 4/4] BPF: Sanity check creating a program X-BeenThere: ltp@lists.linux.it X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux Test Project List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Richard Palethorpe Errors-To: ltp-bounces+incoming=patchwork.ozlabs.org@lists.linux.it Sender: "ltp" Signed-off-by: Richard Palethorpe --- runtest/syscalls | 1 + testcases/kernel/syscalls/bpf/.gitignore | 1 + testcases/kernel/syscalls/bpf/bpf_prog01.c | 161 +++++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 testcases/kernel/syscalls/bpf/bpf_prog01.c diff --git a/runtest/syscalls b/runtest/syscalls index 9d48285b8..c0c325c92 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -33,6 +33,7 @@ bind02 bind02 bind03 bind03 bpf_map01 bpf_map01 +bpf_prog01 bpf_prog01 brk01 brk01 diff --git a/testcases/kernel/syscalls/bpf/.gitignore b/testcases/kernel/syscalls/bpf/.gitignore index f33532484..7eb5f7c92 100644 --- a/testcases/kernel/syscalls/bpf/.gitignore +++ b/testcases/kernel/syscalls/bpf/.gitignore @@ -1 +1,2 @@ bpf_map01 +bpf_prog01 diff --git a/testcases/kernel/syscalls/bpf/bpf_prog01.c b/testcases/kernel/syscalls/bpf/bpf_prog01.c new file mode 100644 index 000000000..9cb2a0c86 --- /dev/null +++ b/testcases/kernel/syscalls/bpf/bpf_prog01.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2019 Richard Palethorpe + * + * Trivial Extended Berkeley Packet Filter (eBPF) test. + * + * Sanity check loading and running bytecode. + * + * Test flow: + * 1. Create array map + * 2. Load eBPF program + * 3. Attach program to socket + * 4. Send packet on socket + * 5. This should trigger eBPF program which writes to array map + * 6. Verify array map was written to + */ + +#include +#include +#include + +#include "config.h" +#include "tst_test.h" +#include "lapi/socket.h" +#include "lapi/bpf.h" + +const char MSG[] = "Ahoj!"; +static char *msg; + +/* + * The following is a byte code template. We copy it to a guarded buffer and + * substitute the runtime value of our map file descriptor. + * + * r0 - r10 = registers 0 to 10 + * r0 = return code + * r1 - r5 = scratch registers, used for function arguments + * r6 - r9 = registers preserved across function calls + * fp/r10 = stack frame pointer + */ +const struct bpf_insn PROG[] = { + /* Load the map FD into r1 (place holder) */ + BPF_LD_MAP_FD(BPF_REG_1, 0), + /* Put (key = 0) on stack and key ptr into r2 */ + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), /* r2 = fp */ + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), /* r2 = r2 - 8 */ + BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0), /* *r2 = 0 */ + /* r0 = bpf_map_lookup_elem(r1, r2) */ + BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem), + /* if r0 == 0 goto exit */ + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3), + /* Set map[0] = 1 */ + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), /* r1 = r0 */ + BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 1), /* *r1 = 1 */ + BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */ + BPF_EXIT_INSN(), /* return r0 */ +}; +static struct bpf_insn *prog; +static char *log; +static union bpf_attr *attr; + +int load_prog(int fd) +{ + prog[0] = BPF_LD_MAP_FD(BPF_REG_1, fd); + + memset(attr, 0, sizeof(*attr)); + attr->prog_type = BPF_PROG_TYPE_SOCKET_FILTER; + attr->insns = ptr_to_u64(prog); + attr->insn_cnt = ARRAY_SIZE(PROG); + attr->license = ptr_to_u64("GPL"); + attr->log_buf = ptr_to_u64(log); + attr->log_size = BUFSIZ; + attr->log_level = 1; + + TEST(bpf(BPF_PROG_LOAD, attr, sizeof(*attr))); + if (TST_RET == -1) { + if (log[0] != 0) { + tst_brk(TFAIL | TTERRNO, + "Failed verification: %s", + log); + } else { + tst_brk(TFAIL | TTERRNO, "Failed to load program"); + } + } else { + tst_res(TPASS, "Loaded program"); + } + + return TST_RET; +} + +void setup(void) +{ + memcpy(prog, PROG, sizeof(PROG)); + memcpy(msg, MSG, sizeof(MSG)); +} + +void run(void) +{ + int map_fd, prog_fd; + int sk[2]; + uint32_t key = 0; + uint64_t val; + + memset(attr, 0, sizeof(*attr)); + attr->map_type = BPF_MAP_TYPE_ARRAY; + attr->key_size = 4; + attr->value_size = 8; + attr->max_entries = 1; + + TEST(bpf(BPF_MAP_CREATE, attr, sizeof(*attr))); + if (TST_RET == -1) { + if (TST_ERR == EPERM) { + tst_brk(TCONF | TTERRNO, + "bpf() requires CAP_SYS_ADMIN on this system"); + } else { + tst_brk(TBROK | TTERRNO, "Failed to create array map"); + } + } + map_fd = TST_RET; + + prog_fd = load_prog(map_fd); + + SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sk); + SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF, + &prog_fd, sizeof(prog_fd)); + + SAFE_WRITE(1, sk[0], msg, sizeof(MSG)); + + memset(attr, 0, sizeof(*attr)); + attr->map_fd = map_fd; + attr->key = ptr_to_u64(&key); + attr->value = ptr_to_u64(&val); + + TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr))); + if (TST_RET == -1) { + tst_res(TFAIL | TTERRNO, "array map lookup"); + } else if (val != 1) { + tst_res(TFAIL, + "val = %lu, but should be val = 1", + val); + } else { + tst_res(TPASS, "val = 1"); + } + + SAFE_CLOSE(prog_fd); + SAFE_CLOSE(map_fd); + SAFE_CLOSE(sk[0]); + SAFE_CLOSE(sk[1]); +} + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .min_kver = "3.18", + .bufs = (struct tst_buffers []) { + {&log, .size = BUFSIZ}, + {&prog, .size = sizeof(PROG)}, + {&attr, .size = sizeof(*attr)}, + {&msg, .size = sizeof(MSG)}, + {NULL}, + } +};