From patchwork Wed Jan 16 14:21:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1025956 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=netronome.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="AGE+TyTd"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43fqCK6V4Dz9sBQ for ; Thu, 17 Jan 2019 01:21:49 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2404661AbfAPOVs (ORCPT ); Wed, 16 Jan 2019 09:21:48 -0500 Received: from mail-wr1-f68.google.com ([209.85.221.68]:44410 "EHLO mail-wr1-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1733125AbfAPOVq (ORCPT ); Wed, 16 Jan 2019 09:21:46 -0500 Received: by mail-wr1-f68.google.com with SMTP id z5so7076958wrt.11 for ; Wed, 16 Jan 2019 06:21:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=netronome-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=dwnqGjEd0EuiA/ZhV38iu5XrF4hKHsY6v1B5G4Ihuns=; b=AGE+TyTdsXlO1Ep6PX46CnVWlMcWUgca8PUme6xBv88TpbxKhUDsD3XNXztF3Ol6CU I2ZfDw3kpimOUtZMx9sq+Z6rA6QFp8eIBT9UrFsrX86WXEDzHysOZf1RK4tAQh4CmkFx iomsJZ4tTUKAMx9B8XJGVbtXTkIRM0/O02ObCIlaGNsxi15Zij8HNghOa1fyg+m+QWYa xOOZzhBMRZzCCcy+Xjw7NAuWcgbGZA3JDniDGOW4QSphx7NaQ7I/m0pNOJEQ85ulc8pe mtzJCjLqlNTHHZOV2K7pt0vsvHe97yapF4y3oX4d4QueK1rmHotqOoMxUutkgN7Vln7M U3mw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=dwnqGjEd0EuiA/ZhV38iu5XrF4hKHsY6v1B5G4Ihuns=; b=mcItPtV2IQ3F869Ckzv0BXAwCqBkKUdDnHB+H5KQAqln8mKYFQrgWzjAh/kTp9Ypk2 ipDOCzf0Xn4lICh6J771gZkHbytGMjvNZW29/T2MfqVyfqb7QBSixAfWYmuE9btqLs5T tJoF8IP/wj+cifL3G+G2bAxY3Mc9unwhxp4lYyL9leqJVubZZL60ChZEsXBvjgOo4dOl m3QJ5EPqjHaGHxjyslWaFtF2eQTj48zZ0KtUYvS379obAX3SqC3o51nnlroR4E6+RPyN yDz98adpw/rlS2cFxmYtm0Tw4JlkWmqyBxAst/3cvn1ewr6qrj2tVou1IoQ7Em7VgAwj W/2w== X-Gm-Message-State: AJcUuke7XdSJ/wrMCAwtyQAkZTvLghU/7aIe+7GLkIfToegZcmRwDbqh z59nAGTtpU1wwPe/0VavZ1h5QA== X-Google-Smtp-Source: ALg8bN4PZZQyh2qF8AMcyAMGbUxl0QJUpyNdcDYZxSG/6TXpQkDIuFraca8hY1LZ+yeuYkTGX88h1A== X-Received: by 2002:a05:6000:f:: with SMTP id h15mr7585097wrx.248.1547648504143; Wed, 16 Jan 2019 06:21:44 -0800 (PST) Received: from cbtest32.netronome.com ([217.38.71.146]) by smtp.gmail.com with ESMTPSA id p6sm97412602wrx.50.2019.01.16.06.21.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 16 Jan 2019 06:21:43 -0800 (PST) From: Quentin Monnet To: Alexei Starovoitov , Daniel Borkmann Cc: netdev@vger.kernel.org, oss-drivers@netronome.com, Quentin Monnet , Arnaldo Carvalho de Melo , Jesper Dangaard Brouer , Stanislav Fomichev Subject: [PATCH bpf-next v4 6/9] tools: bpftool: add probes for eBPF helper functions Date: Wed, 16 Jan 2019 14:21:16 +0000 Message-Id: <20190116142119.8358-7-quentin.monnet@netronome.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190116142119.8358-1-quentin.monnet@netronome.com> References: <20190116142119.8358-1-quentin.monnet@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Similarly to what was done for program types and map types, add a set of probes to test the availability of the different eBPF helper functions on the current system. For each known program type, all known helpers are tested, in order to establish a compatibility matrix. Output is provided as a set of lists of available helpers, one per program type. Sample output: # bpftool feature probe kernel ... Scanning eBPF helper functions... eBPF helpers supported for program type socket_filter: - bpf_map_lookup_elem - bpf_map_update_elem - bpf_map_delete_elem ... eBPF helpers supported for program type kprobe: - bpf_map_lookup_elem - bpf_map_update_elem - bpf_map_delete_elem ... # bpftool --json --pretty feature probe kernel { ... "helpers": { "socket_filter_available_helpers": ["bpf_map_lookup_elem", \ "bpf_map_update_elem","bpf_map_delete_elem", ... ], "kprobe_available_helpers": ["bpf_map_lookup_elem", \ "bpf_map_update_elem","bpf_map_delete_elem", ... ], ... } } v4: - Use "enum bpf_func_id" instead of "__u32" in bpf_probe_helper() declaration for the type of the argument used to pass the id of the helper to probe. - Undef BPF_HELPER_MAKE_ENTRY after using it. v3: - Do not pass kernel version from bpftool to libbpf probes (kernel version for testing program with kprobes is retrieved directly from libbpf). - Dump one list of available helpers per program type (instead of one list of compatible program types per helper). v2: - Move probes from bpftool to libbpf. - Test all program types for each helper, print a list of working prog types for each helper. - Fall back on include/uapi/linux/bpf.h for names and ids of helpers. - Remove C-style macros output from this patch. Signed-off-by: Quentin Monnet --- .../bpftool/Documentation/bpftool-feature.rst | 4 ++ tools/bpf/bpftool/feature.c | 51 +++++++++++++++ tools/lib/bpf/libbpf.h | 2 + tools/lib/bpf/libbpf.map | 1 + tools/lib/bpf/libbpf_probes.c | 63 +++++++++++++++++++ 5 files changed, 121 insertions(+) diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst index 40ac13c0b782..255e3b3629a0 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst @@ -30,6 +30,10 @@ DESCRIPTION Keyword **kernel** can be omitted. + Note that when probed, some eBPF helpers (e.g. + **bpf_trace_printk**\ () or **bpf_probe_write_user**\ ()) may + print warnings to kernel logs. + **bpftool feature help** Print short help message. diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index 3d53306bb66d..eb4d0500520d 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -25,6 +25,13 @@ enum probe_component { COMPONENT_KERNEL, }; +#define BPF_HELPER_MAKE_ENTRY(name) [BPF_FUNC_ ## name] = "bpf_" # name +static const char * const helper_name[] = { + __BPF_FUNC_MAPPER(BPF_HELPER_MAKE_ENTRY) +}; + +#undef BPF_HELPER_MAKE_ENTRY + /* Miscellaneous utility functions */ static bool check_procfs(void) @@ -458,6 +465,44 @@ static void probe_map_type(enum bpf_map_type map_type) print_bool_feature(feat_name, plain_desc, res); } +static void +probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type) +{ + const char *ptype_name = prog_type_name[prog_type]; + char feat_name[128]; + unsigned int id; + bool res; + + if (json_output) { + sprintf(feat_name, "%s_available_helpers", ptype_name); + jsonw_name(json_wtr, feat_name); + jsonw_start_array(json_wtr); + } else { + printf("eBPF helpers supported for program type %s:", + ptype_name); + } + + for (id = 1; id < ARRAY_SIZE(helper_name); id++) { + if (!supported_type) + res = false; + else + res = bpf_probe_helper(id, prog_type, 0); + + if (json_output) { + if (res) + jsonw_string(json_wtr, helper_name[id]); + } else { + if (res) + printf("\n\t- %s", helper_name[id]); + } + } + + if (json_output) + jsonw_end_array(json_wtr); + else + printf("\n"); +} + static int do_probe(int argc, char **argv) { enum probe_component target = COMPONENT_UNSPEC; @@ -533,6 +578,12 @@ static int do_probe(int argc, char **argv) for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++) probe_map_type(i); + print_end_then_start_section("helpers", + "Scanning eBPF helper functions..."); + + for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) + probe_helpers_for_progtype(i, supported_types[i]); + exit_close_json: if (json_output) { /* End current "section" of probes */ diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 72385f6f9415..62ae6cb93da1 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -366,6 +366,8 @@ bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo, LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex); LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex); +LIBBPF_API bool bpf_probe_helper(enum bpf_func_id id, + enum bpf_prog_type prog_type, __u32 ifindex); #ifdef __cplusplus } /* extern "C" */ diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index c08f4c726e8e..67e51b2becec 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -56,6 +56,7 @@ LIBBPF_0.0.1 { bpf_object__unpin_maps; bpf_object__unpin_programs; bpf_perf_event_read_simple; + bpf_probe_helper; bpf_probe_map_type; bpf_probe_prog_type; bpf_prog_attach; diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c index e3d57632a975..890ab9370c8d 100644 --- a/tools/lib/bpf/libbpf_probes.c +++ b/tools/lib/bpf/libbpf_probes.c @@ -2,7 +2,11 @@ /* Copyright (c) 2019 Netronome Systems, Inc. */ #include +#include +#include +#include #include +#include #include #include @@ -11,6 +15,37 @@ #include "bpf.h" #include "libbpf.h" +static bool grep(const char *buffer, const char *pattern) +{ + return !!strstr(buffer, pattern); +} + +static int get_vendor_id(int ifindex) +{ + char ifname[IF_NAMESIZE], path[64], buf[8]; + ssize_t len; + int fd; + + if (!if_indextoname(ifindex, ifname)) + return -1; + + snprintf(path, sizeof(path), "/sys/class/net/%s/device/vendor", ifname); + + fd = open(path, O_RDONLY); + if (fd < 0) + return -1; + + len = read(fd, buf, sizeof(buf)); + close(fd); + if (len < 0) + return -1; + if (len >= (ssize_t)sizeof(buf)) + return -1; + buf[len] = '\0'; + + return strtol(buf, NULL, 0); +} + static int get_kernel_version(void) { int version, subversion, patchlevel; @@ -177,3 +212,31 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex) return fd >= 0; } + +bool bpf_probe_helper(enum bpf_func_id id, enum bpf_prog_type prog_type, + __u32 ifindex) +{ + struct bpf_insn insns[2] = { + BPF_EMIT_CALL(id), + BPF_EXIT_INSN() + }; + char buf[4096] = {}; + bool res; + + prog_load(prog_type, insns, ARRAY_SIZE(insns), buf, sizeof(buf), + ifindex); + res = !grep(buf, "invalid func ") && !grep(buf, "unknown func "); + + if (ifindex) { + switch (get_vendor_id(ifindex)) { + case 0x19ee: /* Netronome specific */ + res = res && !grep(buf, "not supported by FW") && + !grep(buf, "unsupported function id"); + break; + default: + break; + } + } + + return res; +}