From patchwork Thu Jan 3 14:02:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1020314 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="0hByk4+Q"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43VqPc72Krz9s55 for ; Fri, 4 Jan 2019 01:03:00 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731824AbfACOC7 (ORCPT ); Thu, 3 Jan 2019 09:02:59 -0500 Received: from mail-wm1-f65.google.com ([209.85.128.65]:55030 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731776AbfACOC5 (ORCPT ); Thu, 3 Jan 2019 09:02:57 -0500 Received: by mail-wm1-f65.google.com with SMTP id a62so29381443wmh.4 for ; Thu, 03 Jan 2019 06:02:55 -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=/3TdyciFqEPgGa9QYyEsucDc3F0ipIQgQNI2zoWeEvI=; b=0hByk4+QgaNt1ShCHMPdwsU/Jq27ALEyvM4Vmtrh3MIREps7LK0daO9SqB0O8V1c0G MQdi0+JfnfLaWmELeUdZodkAQu5ihBrGRvaPDnrVt5rHlCj0Kyj7t3GrZwyFL/Io0GiZ 9gXmwnOEP0675WvSdpIyrcCPSnsL6w31+dO80BP2kQgqu5+ArTTPJhumGxu7aeNriDmq B4YHyN2XlARBRoSKmsRUo4YQfvRY8XmRCxAzB5x4KFnMd4vSwJpi3zElId0VPvB9q+jW hhVrDOvCyyoOZdwVAiHrlGQXmfqC2Um9UA6Z0nkrcJh1pTvliLje7LORd2mCYqe5JCXu RDiA== 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=/3TdyciFqEPgGa9QYyEsucDc3F0ipIQgQNI2zoWeEvI=; b=ZmbionYS0RVHuch4SyYuiw/y81RCnPD5RUHIh5Wn9bSrpZ0DxiNDy74UgaADmZF4bC UQhFx4sVxcaKgdOnDRjC84zJVaJazSvIAYCj9lcsjJW2YRN6hzUrcp14pVcdPYvrRtet hhyzhBuzPpD35EVjuwpTSBeHXfKgf4q/h5u/PbRlYgMl3/LukthAmsfxnGMN8od847e+ 4BEveFOPCDwrXXIUUVz/3S1iI6rM79uXoIC+1z9/U8V1lmFOkA/Z9O6rP0RdmUQHX4R1 hJ0+0LSGK/AkX25ENreX/YD0vwKgnuL5X07mV++3GGBfG/CRtJ13a2A60l4XQmngruit yKjQ== X-Gm-Message-State: AJcUukfmnW+PYTPmdeSap+h78xpuELCUBsaGc+VI8ovRvi07KUpVVP58 42Bolevk0yqwijDsb3AwMvlQgA== X-Google-Smtp-Source: ALg8bN5Ow/kjAeFf7wDdpfJ0B9D5eBLKosFJL5TuVaXr6phCbx0urWUY8vIHjz1TC3nXBbuAEmqKmQ== X-Received: by 2002:a1c:2007:: with SMTP id g7mr37040891wmg.79.1546524174341; Thu, 03 Jan 2019 06:02:54 -0800 (PST) Received: from cbtest32.netronome.com ([217.38.71.146]) by smtp.gmail.com with ESMTPSA id 10sm44854771wmy.40.2019.01.03.06.02.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 03 Jan 2019 06:02:53 -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: [RFC bpf-next v3 1/9] tools: bpftool: add basic probe capability, probe syscall availability Date: Thu, 3 Jan 2019 14:02:31 +0000 Message-Id: <20190103140239.23548-2-quentin.monnet@netronome.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190103140239.23548-1-quentin.monnet@netronome.com> References: <20190103140239.23548-1-quentin.monnet@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add a new component and command for bpftool, in order to probe the system to dump a set of eBPF-related parameters so that users can know what features are available on the system. Parameters are dumped in plain or JSON output (with -j/-p options). The current patch introduces probing of one simple parameter: availability of the bpf() system call. Later commits will add other probes. Sample output: # bpftool feature probe kernel Scanning system call availability... bpf() syscall is available # bpftool --json --pretty feature probe kernel { "syscall_config": { "have_bpf_syscall": true } } The optional "kernel" keyword enforces probing of the current system, which is the only possible behaviour at this stage. It can be safely omitted. The feature comes with the relevant man page, but bash completion will come in a dedicated commit. v3: - Do not probe kernel version. Contrarily to what is written below for v2, we can have the kernel version retrieved in libbpf instead of bpftool (in the patch adding probing for program types). v2: - Remove C-style macros output from this patch. - Even though kernel version is no longer needed for testing kprobes availability, note that we still collect it in this patch so that bpftool gets able to probe (in next patches) older kernels as well. Signed-off-by: Quentin Monnet Reviewed-by: Jakub Kicinski --- .../bpftool/Documentation/bpftool-cgroup.rst | 1 + .../bpftool/Documentation/bpftool-feature.rst | 60 ++++++++ .../bpf/bpftool/Documentation/bpftool-map.rst | 1 + .../bpf/bpftool/Documentation/bpftool-net.rst | 1 + .../bpftool/Documentation/bpftool-perf.rst | 1 + .../bpftool/Documentation/bpftool-prog.rst | 1 + tools/bpf/bpftool/Documentation/bpftool.rst | 1 + tools/bpf/bpftool/feature.c | 131 ++++++++++++++++++ tools/bpf/bpftool/main.c | 3 +- tools/bpf/bpftool/main.h | 1 + 10 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 tools/bpf/bpftool/Documentation/bpftool-feature.rst create mode 100644 tools/bpf/bpftool/feature.c diff --git a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst index d07ccf8a23f7..d43fce568ef7 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst @@ -142,5 +142,6 @@ SEE ALSO **bpftool**\ (8), **bpftool-prog**\ (8), **bpftool-map**\ (8), + **bpftool-feature**\ (8), **bpftool-net**\ (8), **bpftool-perf**\ (8) diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst new file mode 100644 index 000000000000..40ac13c0b782 --- /dev/null +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst @@ -0,0 +1,60 @@ +=============== +bpftool-feature +=============== +------------------------------------------------------------------------------- +tool for inspection of eBPF-related parameters for Linux kernel or net device +------------------------------------------------------------------------------- + +:Manual section: 8 + +SYNOPSIS +======== + + **bpftool** [*OPTIONS*] **feature** *COMMAND* + + *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] } + + *COMMANDS* := { **probe** | **help** } + +MAP COMMANDS +============= + +| **bpftool** **feature probe** [**kernel**] +| **bpftool** **feature help** + +DESCRIPTION +=========== + **bpftool feature probe** [**kernel**] + Probe the running kernel and dump a number of eBPF-related + parameters, such as availability of the **bpf()** system call. + + Keyword **kernel** can be omitted. + + **bpftool feature help** + Print short help message. + +OPTIONS +======= + -h, --help + Print short generic help message (similar to **bpftool help**). + + -v, --version + Print version number (similar to **bpftool version**). + + -j, --json + Generate JSON output. For commands that cannot produce JSON, this + option has no effect. + + -p, --pretty + Generate human-readable JSON output. Implies **-j**. + +SEE ALSO +======== + **bpf**\ (2), + **bpf-helpers**\ (7), + **bpftool**\ (8), + **bpftool-prog**\ (8), + **bpftool-map**\ (8), + **bpftool-cgroup**\ (8), + **bpftool-net**\ (8), + **bpftool-perf**\ (8) diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst index 64b001b4f777..eafdc9f76694 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-map.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst @@ -236,5 +236,6 @@ SEE ALSO **bpftool**\ (8), **bpftool-prog**\ (8), **bpftool-cgroup**\ (8), + **bpftool-feature**\ (8), **bpftool-net**\ (8), **bpftool-perf**\ (8) diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst b/tools/bpf/bpftool/Documentation/bpftool-net.rst index ed87c9b619ad..779dab3650ee 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-net.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst @@ -142,4 +142,5 @@ SEE ALSO **bpftool-prog**\ (8), **bpftool-map**\ (8), **bpftool-cgroup**\ (8), + **bpftool-feature**\ (8), **bpftool-perf**\ (8) diff --git a/tools/bpf/bpftool/Documentation/bpftool-perf.rst b/tools/bpf/bpftool/Documentation/bpftool-perf.rst index f4c5e5538bb8..bca5590a80d0 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-perf.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-perf.rst @@ -84,4 +84,5 @@ SEE ALSO **bpftool-prog**\ (8), **bpftool-map**\ (8), **bpftool-cgroup**\ (8), + **bpftool-feature**\ (8), **bpftool-net**\ (8) diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst index 58c8369b77dd..13b56102f528 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst @@ -258,5 +258,6 @@ SEE ALSO **bpftool**\ (8), **bpftool-map**\ (8), **bpftool-cgroup**\ (8), + **bpftool-feature**\ (8), **bpftool-net**\ (8), **bpftool-perf**\ (8) diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst index e1677e81ed59..27153bb816ac 100644 --- a/tools/bpf/bpftool/Documentation/bpftool.rst +++ b/tools/bpf/bpftool/Documentation/bpftool.rst @@ -72,5 +72,6 @@ SEE ALSO **bpftool-prog**\ (8), **bpftool-map**\ (8), **bpftool-cgroup**\ (8), + **bpftool-feature**\ (8), **bpftool-net**\ (8), **bpftool-perf**\ (8) diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c new file mode 100644 index 000000000000..954fb12a5228 --- /dev/null +++ b/tools/bpf/bpftool/feature.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright (c) 2019 Netronome Systems, Inc. */ + +#include +#include +#include +#include + +#include +#include + +#include + +#include "main.h" + +enum probe_component { + COMPONENT_UNSPEC, + COMPONENT_KERNEL, +}; + +/* Printing utility functions */ + +static void +print_bool_feature(const char *feat_name, const char *plain_name, bool res) +{ + if (json_output) + jsonw_bool_field(json_wtr, feat_name, res); + else + printf("%s is %savailable\n", plain_name, res ? "" : "NOT "); +} + +static void +print_start_section(const char *json_title, const char *plain_title) +{ + if (json_output) { + jsonw_name(json_wtr, json_title); + jsonw_start_object(json_wtr); + } else { + printf("%s\n", plain_title); + } +} + +/* Probing functions */ + +static bool probe_bpf_syscall(void) +{ + bool res; + + bpf_load_program(BPF_PROG_TYPE_UNSPEC, NULL, 0, NULL, 0, NULL, 0); + res = (errno != ENOSYS); + + print_bool_feature("have_bpf_syscall", + "bpf() syscall", + res); + + return res; +} + +static int do_probe(int argc, char **argv) +{ + enum probe_component target = COMPONENT_UNSPEC; + + /* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN). + * Let's approximate, and restrict usage to root user only. + */ + if (geteuid()) { + p_err("please run this command as root user"); + return -1; + } + + set_max_rlimit(); + + while (argc) { + if (is_prefix(*argv, "kernel")) { + if (target != COMPONENT_UNSPEC) { + p_err("component to probe already specified"); + return -1; + } + target = COMPONENT_KERNEL; + NEXT_ARG(); + } else { + p_err("expected no more arguments, 'kernel', got: '%s'?", + *argv); + return -1; + } + } + + if (json_output) + jsonw_start_object(json_wtr); + + print_start_section("syscall_config", + "Scanning system call availability..."); + + probe_bpf_syscall(); + + if (json_output) { + /* End current "section" of probes */ + jsonw_end_object(json_wtr); + /* End root object */ + jsonw_end_object(json_wtr); + } + + return 0; +} + +static int do_help(int argc, char **argv) +{ + if (json_output) { + jsonw_null(json_wtr); + return 0; + } + + fprintf(stderr, + "Usage: %s %s probe [kernel]\n" + " %s %s help\n" + "", + bin_name, argv[-2], bin_name, argv[-2]); + + return 0; +} + +static const struct cmd cmds[] = { + { "help", do_help }, + { "probe", do_probe }, + { 0 } +}; + +int do_feature(int argc, char **argv) +{ + return cmd_select(cmds, argc, argv, do_help); +} diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index f44a1c2c4ea0..a9d5e9e6a732 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -56,7 +56,7 @@ static int do_help(int argc, char **argv) " %s batch file FILE\n" " %s version\n" "\n" - " OBJECT := { prog | map | cgroup | perf | net }\n" + " OBJECT := { prog | map | cgroup | perf | net | feature }\n" " " HELP_SPEC_OPTIONS "\n" "", bin_name, bin_name, bin_name); @@ -187,6 +187,7 @@ static const struct cmd cmds[] = { { "cgroup", do_cgroup }, { "perf", do_perf }, { "net", do_net }, + { "feature", do_feature }, { "version", do_version }, { 0 } }; diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 052c91d4dc55..5cfc6601de9b 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -145,6 +145,7 @@ int do_cgroup(int argc, char **arg); int do_perf(int argc, char **arg); int do_net(int argc, char **arg); int do_tracelog(int argc, char **arg); +int do_feature(int argc, char **argv); int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what); int prog_parse_fd(int *argc, char ***argv); From patchwork Thu Jan 3 14:02:32 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1020313 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="tLeKxg74"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43VqPc0dSsz9sBn for ; Fri, 4 Jan 2019 01:03:00 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731819AbfACOC7 (ORCPT ); Thu, 3 Jan 2019 09:02:59 -0500 Received: from mail-wm1-f67.google.com ([209.85.128.67]:39321 "EHLO mail-wm1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730652AbfACOC5 (ORCPT ); Thu, 3 Jan 2019 09:02:57 -0500 Received: by mail-wm1-f67.google.com with SMTP id f81so30333150wmd.4 for ; Thu, 03 Jan 2019 06:02:56 -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=mcGRJ66eudZr7kfR7DbS4j/o9iI472SjYfLYt8nsp5o=; b=tLeKxg74IQhj7bgrFiyQNT5q5UvK3OIteGjZzgJfd/IcFNvqp+buBNvQAMivtaEsSz +DVsLOnYrNbwVU+ko05q4wESOvilFWvxzZlxfP46T7sEf/bPd/jgkekc60Sf7GbafdGQ yqpW4aVG7RJtYGLrx4ecl37/vqFu5V3pcNginkhaVbainJdtimEsZaWzhWFhDNgHN6W6 CfRBCZIeVDVN2Jei204BOc064iYxKZk8GmZcyAhMDoARb1oZ5OqBYQYkJ0syq9YvFKi5 50sY6vvIzj73xoky6uwTcJWZxNE9fB/JycyioiVS/Y/zIwC4PGIwJo+n0Xpu1LrUOuAO Bawg== 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=mcGRJ66eudZr7kfR7DbS4j/o9iI472SjYfLYt8nsp5o=; b=OjHO09nFrS1on3Tq/ccoFA7u6a5TTtGDNRKgqz0QrUULuQYA3EAaJp6FplzDEU28+i L1u2ub6xMl9uE/wuCkb6ay3v5c+1hAK7QdmRJP7X0TnNBi0Zwx8f4k4aGBu1p+yTB9jP 5ZLGAPDR3ulj6B0+RSIHpXy+YGYyH+Ap74/kxjfmDCWglQzJca08j5WiqcCAzRSm6jDu UH52TIZ+61IJQsOFwUYlygENnrNFIEGMMBrnkDsZlutb5fjyc5QriS9tcBPn78NkSEIK Hq5g7XMQUfKq7jTH4a5Yyix/Y30Bb+OnqD0rePQV4CFo50QlOUdmlkmFH5VCNkceJdUh W7ZQ== X-Gm-Message-State: AA+aEWa4DSvoz2TeP3bi8FVb4vtDpiG2+WesNsJDvf1qxupS6nFo4RNw IbWWz2cuyETM7HCFBERLTeC5Pg== X-Google-Smtp-Source: ALg8bN5E2YOiZgWKTOxAeXOIDBwj3aMaJgL1bGrFvct7jGAjDwYkXSLeWp3TLjssA1nnzRpkELsrYQ== X-Received: by 2002:a1c:8095:: with SMTP id b143mr37128575wmd.63.1546524175844; Thu, 03 Jan 2019 06:02:55 -0800 (PST) Received: from cbtest32.netronome.com ([217.38.71.146]) by smtp.gmail.com with ESMTPSA id 10sm44854771wmy.40.2019.01.03.06.02.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 03 Jan 2019 06:02:55 -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: [RFC bpf-next v3 2/9] tools: bpftool: add probes for /proc/ eBPF parameters Date: Thu, 3 Jan 2019 14:02:32 +0000 Message-Id: <20190103140239.23548-3-quentin.monnet@netronome.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190103140239.23548-1-quentin.monnet@netronome.com> References: <20190103140239.23548-1-quentin.monnet@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add a set of probes to dump the eBPF-related parameters available from /proc/: availability of bpf() syscall for unprivileged users, JIT compiler status and hardening status, kallsyms exports status. Sample output: # bpftool feature probe kernel Scanning system configuration... bpf() syscall for unprivileged users is enabled JIT compiler is disabled JIT compiler hardening is disabled JIT compiler kallsyms exports are disabled ... # bpftool --json --pretty feature probe kernel { "system_config": { "unprivileged_bpf_disabled": 0, "bpf_jit_enable": 0, "bpf_jit_harden": 0, "bpf_jit_kallsyms": 0 }, ... } These probes are skipped if procfs is not mounted. v2: - Remove C-style macros output from this patch. Signed-off-by: Quentin Monnet Reviewed-by: Jakub Kicinski --- tools/bpf/bpftool/feature.c | 168 ++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index 954fb12a5228..37fe79f59015 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -13,11 +14,29 @@ #include "main.h" +#ifndef PROC_SUPER_MAGIC +# define PROC_SUPER_MAGIC 0x9fa0 +#endif + enum probe_component { COMPONENT_UNSPEC, COMPONENT_KERNEL, }; +/* Miscellaneous utility functions */ + +static bool check_procfs(void) +{ + struct statfs st_fs; + + if (statfs("/proc", &st_fs) < 0) + return false; + if ((unsigned long)st_fs.f_type != PROC_SUPER_MAGIC) + return false; + + return true; +} + /* Printing utility functions */ static void @@ -42,6 +61,135 @@ print_start_section(const char *json_title, const char *plain_title) /* Probing functions */ +static int read_procfs(const char *path) +{ + char *endptr, *line = NULL; + size_t len = 0; + FILE *fd; + int res; + + fd = fopen(path, "r"); + if (!fd) + return -1; + + res = getline(&line, &len, fd); + fclose(fd); + if (res < 0) + return -1; + + errno = 0; + res = strtol(line, &endptr, 10); + if (errno || *line == '\0' || *endptr != '\n') + res = -1; + free(line); + + return res; +} + +static void probe_unprivileged_disabled(void) +{ + int res; + + res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled"); + if (json_output) { + jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res); + } else { + switch (res) { + case 0: + printf("bpf() syscall for unprivileged users is enabled\n"); + break; + case 1: + printf("bpf() syscall restricted to privileged users\n"); + break; + case -1: + printf("Unable to retrieve required privileges for bpf() syscall\n"); + break; + default: + printf("bpf() syscall restriction has unknown value %d\n", res); + } + } +} + +static void probe_jit_enable(void) +{ + int res; + + res = read_procfs("/proc/sys/net/core/bpf_jit_enable"); + if (json_output) { + jsonw_int_field(json_wtr, "bpf_jit_enable", res); + } else { + switch (res) { + case 0: + printf("JIT compiler is disabled\n"); + break; + case 1: + printf("JIT compiler is enabled\n"); + break; + case 2: + printf("JIT compiler is enabled with debugging traces in kernel logs\n"); + break; + case -1: + printf("Unable to retrieve JIT-compiler status\n"); + break; + default: + printf("JIT-compiler status has unknown value %d\n", + res); + } + } +} + +static void probe_jit_harden(void) +{ + int res; + + res = read_procfs("/proc/sys/net/core/bpf_jit_harden"); + if (json_output) { + jsonw_int_field(json_wtr, "bpf_jit_harden", res); + } else { + switch (res) { + case 0: + printf("JIT compiler hardening is disabled\n"); + break; + case 1: + printf("JIT compiler hardening is enabled for unprivileged users\n"); + break; + case 2: + printf("JIT compiler hardening is enabled for all users\n"); + break; + case -1: + printf("Unable to retrieve JIT hardening status\n"); + break; + default: + printf("JIT hardening status has unknown value %d\n", + res); + } + } +} + +static void probe_jit_kallsyms(void) +{ + int res; + + res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms"); + if (json_output) { + jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res); + } else { + switch (res) { + case 0: + printf("JIT compiler kallsyms exports are disabled\n"); + break; + case 1: + printf("JIT compiler kallsyms exports are enabled for root\n"); + break; + case -1: + printf("Unable to retrieve JIT kallsyms export status\n"); + break; + default: + printf("JIT kallsyms exports status has unknown value %d\n", res); + } + } +} + static bool probe_bpf_syscall(void) { bool res; @@ -88,6 +236,26 @@ static int do_probe(int argc, char **argv) if (json_output) jsonw_start_object(json_wtr); + switch (target) { + case COMPONENT_KERNEL: + case COMPONENT_UNSPEC: + print_start_section("system_config", + "Scanning system configuration..."); + if (check_procfs()) { + probe_unprivileged_disabled(); + probe_jit_enable(); + probe_jit_harden(); + probe_jit_kallsyms(); + } else { + p_info("/* procfs not mounted, skipping related probes */"); + } + if (json_output) + jsonw_end_object(json_wtr); + else + printf("\n"); + break; + } + print_start_section("syscall_config", "Scanning system call availability..."); From patchwork Thu Jan 3 14:02:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1020320 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="ZoljGVBJ"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43VqPv6g1sz9s9h for ; Fri, 4 Jan 2019 01:03:15 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731829AbfACODB (ORCPT ); Thu, 3 Jan 2019 09:03:01 -0500 Received: from mail-wr1-f67.google.com ([209.85.221.67]:41094 "EHLO mail-wr1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731762AbfACOC7 (ORCPT ); Thu, 3 Jan 2019 09:02:59 -0500 Received: by mail-wr1-f67.google.com with SMTP id x10so33639465wrs.8 for ; Thu, 03 Jan 2019 06:02:58 -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=202PP8Dy4PW6VGwSHicEq9RzeblpF1cBAogkBo9KcvI=; b=ZoljGVBJ6glzO0AdqhxLIQaykOJg4vg9x9nsoMkyfuNVn90ouj3brFWbhjUCmBUb6s Lsitj+hMYGndkA/hl+Eniq1U4hvJNPWAVZgg4Nt06k7fNuP/qynDTtvBU+XY/HvWEOrJ yGlG7Lf1Zy+i3DNUuQ81h3ouOMn2cfJyvNUjsNwPtbqwN8/vdoPr1U97Yjm5g5SPamxb tKX5T1ypXJvhYybld8l+ddLV33L1MYszm0bebuElLenJLwxMuaMl7hiF5bndYXumWhz2 GOBuPuC7yOI+OJIb1PK63Q8xqQlxAFQ1iydvDzd+2FG9wqjxzaxN5j2YeIGEGQFkiO6F c3GQ== 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=202PP8Dy4PW6VGwSHicEq9RzeblpF1cBAogkBo9KcvI=; b=UfYo3y14U0Q9q9dHoIw/ybd0Dx3IhypxMHBLvXQK7lZOzKj9rlRR+adqOfZk4y3VDz ttbzndi0HsILruFC7GeXgxk2rQYhCO/qdBsYaZXbUul/4Cp37mn7D6evXejGtnHTQSwD 8OSaMOI3yP3wk4On4/jt2czdxwwup0o3FCtBzZ9ZeA/zVC0yO7b8tGbZ+17dWZoAPqMt iNU6LfYlHfkQWutiO/Oh6HO92rnyRIkccN0Lz7KRdsZ1cWWhTb8XXbddyV8Xq90Kqy5T NGBv4d21J5EUQP0dfb7nfHLQOgPYXVfQ8IKf6Mhcb0IETGvcSqAR96njdB3jwkYV1GDz NTnw== X-Gm-Message-State: AJcUukfE5EYsoLp9d6qPmgF6MzLKkJRHWRBw0aA//iQL0JwX9AOK5wB6 n0Qlb4kikZg6NktzA1TH8DOVQjhNXoXmnw== X-Google-Smtp-Source: ALg8bN6R8oq1JZMZCF0PhY0/ehqzGEUMW/4LMrRjYlHUhSFs7OUqMyLokK37IlwD1Zadiu+6HRpCcw== X-Received: by 2002:adf:84e4:: with SMTP id 91mr40667833wrg.237.1546524177270; Thu, 03 Jan 2019 06:02:57 -0800 (PST) Received: from cbtest32.netronome.com ([217.38.71.146]) by smtp.gmail.com with ESMTPSA id 10sm44854771wmy.40.2019.01.03.06.02.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 03 Jan 2019 06:02:56 -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: [RFC bpf-next v3 3/9] tools: bpftool: add probes for kernel configuration options Date: Thu, 3 Jan 2019 14:02:33 +0000 Message-Id: <20190103140239.23548-4-quentin.monnet@netronome.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190103140239.23548-1-quentin.monnet@netronome.com> References: <20190103140239.23548-1-quentin.monnet@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add probes to dump a number of options set (or not set) for compiling the kernel image. These parameters provide information about what BPF components should be available on the system. A number of them are not directly related to eBPF, but are in fact used in the kernel as conditions on which to compile, or not to compile, some of the eBPF helper functions. Sample output: # bpftool feature probe kernel Scanning system configuration... ... CONFIG_BPF is set to y CONFIG_BPF_SYSCALL is set to y CONFIG_HAVE_EBPF_JIT is set to y ... # bpftool --pretty --json feature probe kernel { "system_config": { ... "CONFIG_BPF": "y", "CONFIG_BPF_SYSCALL": "y", "CONFIG_HAVE_EBPF_JIT": "y", ... } } v3: - Add a comment about /proc/config.gz not being supported as a path for the config file at this time. - Use p_info() instead of p_err() on failure to get options from config file, as bpftool keeps probing other parameters and that would possibly create duplicate "error" entries for JSON. v2: - Remove C-style macros output from this patch. - NOT addressed: grouping of those config options into subsections (I don't see an easy way of grouping them at the moment, please see also the discussion on v1 thread). Signed-off-by: Quentin Monnet Reviewed-by: Jakub Kicinski --- tools/bpf/bpftool/feature.c | 142 ++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index 37fe79f59015..05c16fe67005 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -48,6 +48,30 @@ print_bool_feature(const char *feat_name, const char *plain_name, bool res) printf("%s is %savailable\n", plain_name, res ? "" : "NOT "); } +static void print_kernel_option(const char *name, const char *value) +{ + char *endptr; + int res; + + if (json_output) { + if (!value) { + jsonw_null_field(json_wtr, name); + return; + } + errno = 0; + res = strtol(value, &endptr, 0); + if (!errno && *endptr == '\n') + jsonw_int_field(json_wtr, name, res); + else + jsonw_string_field(json_wtr, name, value); + } else { + if (value) + printf("%s is set to %s\n", name, value); + else + printf("%s is not set\n", name); + } +} + static void print_start_section(const char *json_title, const char *plain_title) { @@ -190,6 +214,123 @@ static void probe_jit_kallsyms(void) } } +static char *get_kernel_config_option(FILE *fd, const char *option) +{ + size_t line_n = 0, optlen = strlen(option); + char *res, *strval, *line = NULL; + ssize_t n; + + rewind(fd); + while ((n = getline(&line, &line_n, fd)) > 0) { + if (strncmp(line, option, optlen)) + continue; + /* Check we have at least '=', value, and '\n' */ + if (strlen(line) < optlen + 3) + continue; + if (*(line + optlen) != '=') + continue; + + /* Trim ending '\n' */ + line[strlen(line) - 1] = '\0'; + + /* Copy and return config option value */ + strval = line + optlen + 1; + res = strdup(strval); + free(line); + return res; + } + free(line); + + return NULL; +} + +static void probe_kernel_image_config(void) +{ + const char * const options[] = { + "CONFIG_BPF", + "CONFIG_BPF_SYSCALL", + "CONFIG_HAVE_EBPF_JIT", + "CONFIG_BPF_JIT", + "CONFIG_BPF_JIT_ALWAYS_ON", + "CONFIG_NET", + "CONFIG_XDP_SOCKETS", + "CONFIG_CGROUPS", + "CONFIG_CGROUP_BPF", + "CONFIG_CGROUP_NET_CLASSID", + "CONFIG_BPF_EVENTS", + "CONFIG_LWTUNNEL_BPF", + "CONFIG_NET_ACT_BPF", + "CONFIG_NET_CLS_ACT", + "CONFIG_NET_CLS_BPF", + "CONFIG_NET_SCH_INGRESS", + "CONFIG_XFRM", + "CONFIG_SOCK_CGROUP_DATA", + "CONFIG_IP_ROUTE_CLASSID", + "CONFIG_IPV6_SEG6_BPF", + "CONFIG_FUNCTION_ERROR_INJECTION", + "CONFIG_BPF_KPROBE_OVERRIDE", + "CONFIG_BPF_LIRC_MODE2", + "CONFIG_NETFILTER_XT_MATCH_BPF", + "CONFIG_TEST_BPF", + "CONFIG_BPFILTER", + "CONFIG_BPFILTER_UMH", + "CONFIG_BPF_STREAM_PARSER", + }; + char *value, *buf = NULL; + struct utsname utsn; + char path[PATH_MAX]; + size_t i, n; + ssize_t ret; + FILE *fd; + + if (uname(&utsn)) + goto no_config; + + snprintf(path, sizeof(path), "/boot/config-%s", utsn.release); + + fd = fopen(path, "r"); + if (!fd && errno == ENOENT) { + /* Some distributions put the config file at /proc/config, give + * it a try. + * Sometimes it is also at /proc/config.gz but we do not try + * this one for now, it would require linking against libz. + */ + fd = fopen("/proc/config", "r"); + } + if (!fd) { + p_info("skipping kernel config, can't open file: %s", + strerror(errno)); + goto no_config; + } + /* Sanity checks */ + ret = getline(&buf, &n, fd); + ret = getline(&buf, &n, fd); + if (!buf || !ret) { + p_info("skipping kernel config, can't read from file: %s", + strerror(errno)); + free(buf); + goto no_config; + } + if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) { + p_info("skipping kernel config, can't find correct file"); + free(buf); + goto no_config; + } + free(buf); + + for (i = 0; i < ARRAY_SIZE(options); i++) { + value = get_kernel_config_option(fd, options[i]); + print_kernel_option(options[i], value); + free(value); + } + fclose(fd); + return; + +no_config: + for (i = 0; i < ARRAY_SIZE(options); i++) + print_kernel_option(options[i], NULL); +} + static bool probe_bpf_syscall(void) { bool res; @@ -249,6 +390,7 @@ static int do_probe(int argc, char **argv) } else { p_info("/* procfs not mounted, skipping related probes */"); } + probe_kernel_image_config(); if (json_output) jsonw_end_object(json_wtr); else From patchwork Thu Jan 3 14:02:34 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1020315 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="Koy58eoy"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43VqPh5Rt5z9s55 for ; Fri, 4 Jan 2019 01:03:04 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731832AbfACODC (ORCPT ); Thu, 3 Jan 2019 09:03:02 -0500 Received: from mail-wr1-f65.google.com ([209.85.221.65]:39765 "EHLO mail-wr1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731820AbfACODA (ORCPT ); Thu, 3 Jan 2019 09:03:00 -0500 Received: by mail-wr1-f65.google.com with SMTP id t27so33665837wra.6 for ; Thu, 03 Jan 2019 06:02:59 -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=5IdQZn6hdy4qzC+usGbTLw420RRyfQCasXqzy9XTt5g=; b=Koy58eoyxPmhi7phLs3mFRR5Dy4ccxpvyrfCz+EBvyysLF0LpGK9mF5Q6S7K1iKIu5 5S3JZeA83EmrwO57ZHSGUp/UNkwQeF2GpkMtdpcMGGY0n4QEvlwSIs28cezJ7TYpFPdB oby4mMpcnQci/GkwkkeTfM4NlmvmT2qA56DqWhIv0QNsXp50hoHSOzF0ei/IoDPQ6Tf6 fUEWYkuSZ8ruWCI6HwvKucMjaSxfyxzqueDWYnlDw8kzc7ZCCmod75e/c93xKIN+fZr3 KYUp0SyEshIuSDICH15qTW8D+ew/ilCx6lfMM3WWUs3nJNpKsj4kab5ushW7tYjBnwyZ WAPQ== 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=5IdQZn6hdy4qzC+usGbTLw420RRyfQCasXqzy9XTt5g=; b=Z9C4g+uLcqJ+R1kUVYcHxG49Iws25MQhtolp1LItJd/Ak4ZZmIla1JwW/oMmlV8p9D VG7Hg7fP7M8kakM6NdcY+kU+4Bc0H+cyLVtZ4WBG2NB5ecRTdjvkHvA4yNbmCzbB47dj tKOBKGhODC6KQzbjLk2wM1QrJA7MztlN6W8GU7HKkLvsybM1u0fwBB+mlcwSjKkS2Z7P hoSg7U1+kAxxvcYjrVjvwKfB8BpIw07U6a6amTiWQjSr3DIcYiIb1L+Yhgt4RGDxcmtK IHCFVyoZwZ8tottr91EwMXoRCPrJwGdDO8SydFSRIclwwtHWYvIzwCDWTtudQOQaDq2u G6qQ== X-Gm-Message-State: AJcUukewcMEBRlBuEf9J8cLcXvhT5gHi+BPFrV12BkzwFsoZz03q73nm +HRCiS/Ue267DsdV8UzMd78Udg== X-Google-Smtp-Source: ALg8bN7nYbvnfjTdHiD7cgYC/AVCellnX0x6fS+qsLmX0C6aMpBdA2OxzSjasmUX+JrqezcRil3msA== X-Received: by 2002:adf:f052:: with SMTP id t18mr44072401wro.112.1546524178309; Thu, 03 Jan 2019 06:02:58 -0800 (PST) Received: from cbtest32.netronome.com ([217.38.71.146]) by smtp.gmail.com with ESMTPSA id 10sm44854771wmy.40.2019.01.03.06.02.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 03 Jan 2019 06:02:57 -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: [RFC bpf-next v3 4/9] tools: bpftool: add probes for eBPF program types Date: Thu, 3 Jan 2019 14:02:34 +0000 Message-Id: <20190103140239.23548-5-quentin.monnet@netronome.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190103140239.23548-1-quentin.monnet@netronome.com> References: <20190103140239.23548-1-quentin.monnet@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Introduce probes for supported BPF program types in libbpf, and call it from bpftool to test what types are available on the system. The probe simply consists in loading a very basic program of that type and see if the verifier complains or not. Sample output: # bpftool feature probe kernel ... Scanning eBPF program types... eBPF program_type socket_filter is available eBPF program_type kprobe is available eBPF program_type sched_cls is available ... # bpftool --json --pretty feature probe kernel { ... "program_types": { "have_socket_filter_prog_type": true, "have_kprobe_prog_type": true, "have_sched_cls_prog_type": true, ... } } v3: - Get kernel version for checking kprobes availability from libbpf instead of from bpftool. Do not pass kernel_version as an argument when calling libbpf probes. - Use a switch with all enum values for setting specific program parameters just before probing, so that gcc complains at compile time (-Wswitch-enum) if new prog types were added to the kernel but libbpf was not updated. - Add a comment in libbpf.h about setrlimit() usage to allow many consecutive probe attempts. v2: - Move probes from bpftool to libbpf. - Remove C-style macros output from this patch. Signed-off-by: Quentin Monnet --- tools/bpf/bpftool/feature.c | 48 +++++++++++++++++- tools/lib/bpf/Build | 2 +- tools/lib/bpf/libbpf.h | 11 ++++ tools/lib/bpf/libbpf.map | 1 + tools/lib/bpf/libbpf_probes.c | 95 +++++++++++++++++++++++++++++++++++ 5 files changed, 155 insertions(+), 2 deletions(-) create mode 100644 tools/lib/bpf/libbpf_probes.c diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index 05c16fe67005..8b9e00867000 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) /* Copyright (c) 2019 Netronome Systems, Inc. */ +#include #include #include #include @@ -11,6 +12,7 @@ #include #include +#include #include "main.h" @@ -83,6 +85,17 @@ print_start_section(const char *json_title, const char *plain_title) } } +static void +print_end_then_start_section(const char *json_title, const char *plain_title) +{ + if (json_output) + jsonw_end_object(json_wtr); + else + printf("\n"); + + print_start_section(json_title, plain_title); +} + /* Probing functions */ static int read_procfs(const char *path) @@ -345,9 +358,33 @@ static bool probe_bpf_syscall(void) return res; } +static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types) +{ + const char *plain_comment = "eBPF program_type "; + char feat_name[128], plain_desc[128]; + size_t maxlen; + bool res; + + res = bpf_probe_prog_type(prog_type, 0); + + supported_types[prog_type] |= res; + + maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1; + if (strlen(prog_type_name[prog_type]) > maxlen) { + p_info("program type name too long"); + return; + } + + sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]); + sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]); + print_bool_feature(feat_name, plain_desc, res); +} + static int do_probe(int argc, char **argv) { enum probe_component target = COMPONENT_UNSPEC; + bool supported_types[128] = {}; + unsigned int i; /* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN). * Let's approximate, and restrict usage to root user only. @@ -401,8 +438,17 @@ static int do_probe(int argc, char **argv) print_start_section("syscall_config", "Scanning system call availability..."); - probe_bpf_syscall(); + if (!probe_bpf_syscall()) + /* bpf() syscall unavailable, don't probe other BPF features */ + goto exit_close_json; + + print_end_then_start_section("program_types", + "Scanning eBPF program types..."); + + for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) + probe_prog_type(i, supported_types); +exit_close_json: if (json_output) { /* End current "section" of probes */ jsonw_end_object(json_wtr); diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build index 197b40f5b5c6..bfd9bfc82c3b 100644 --- a/tools/lib/bpf/Build +++ b/tools/lib/bpf/Build @@ -1 +1 @@ -libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o bpf_prog_linfo.o +libbpf-y := libbpf.o bpf.o nlattr.o btf.o libbpf_errno.o str_error.o netlink.o bpf_prog_linfo.o libbpf_probes.o diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 5f68d7b75215..8e63821109ab 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -355,6 +355,17 @@ LIBBPF_API const struct bpf_line_info * bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo, __u32 insn_off, __u32 nr_skip); +/* + * Probe for supported system features + * + * Note that running many of these probes in a short amount of time can cause + * the kernel to reach the maximal size of lockable memory allowed for the + * user, causing subsequent probes to fail. In this case, the caller may want + * to adjust that limit with setrlimit(). + */ +LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type, + __u32 ifindex); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index cd02cd4e2cc3..6355e4c80a86 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_prog_type; bpf_prog_attach; bpf_prog_detach; bpf_prog_detach2; diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c new file mode 100644 index 000000000000..f08c33fa8dc9 --- /dev/null +++ b/tools/lib/bpf/libbpf_probes.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +/* Copyright (c) 2019 Netronome Systems, Inc. */ + +#include +#include +#include + +#include +#include + +#include "bpf.h" +#include "libbpf.h" + +static int get_kernel_version(void) +{ + int version, subversion, patchlevel; + struct utsname utsn; + + /* Return 0 on failure, and attempt to probe with empty kversion */ + if (uname(&utsn)) + return 0; + + if (sscanf(utsn.release, "%d.%d.%d", + &version, &subversion, &patchlevel) != 3) + return 0; + + return (version << 16) + (subversion << 8) + patchlevel; +} + +static void +prog_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns, + size_t insns_cnt, char *buf, size_t buf_len, __u32 ifindex) +{ + struct bpf_load_program_attr xattr = {}; + int fd; + + switch (prog_type) { + case BPF_PROG_TYPE_CGROUP_SOCK_ADDR: + xattr.expected_attach_type = BPF_CGROUP_INET4_CONNECT; + break; + case BPF_PROG_TYPE_KPROBE: + xattr.kern_version = get_kernel_version(); + break; + case BPF_PROG_TYPE_UNSPEC: + case BPF_PROG_TYPE_SOCKET_FILTER: + case BPF_PROG_TYPE_SCHED_CLS: + case BPF_PROG_TYPE_SCHED_ACT: + case BPF_PROG_TYPE_TRACEPOINT: + case BPF_PROG_TYPE_XDP: + case BPF_PROG_TYPE_PERF_EVENT: + case BPF_PROG_TYPE_CGROUP_SKB: + case BPF_PROG_TYPE_CGROUP_SOCK: + case BPF_PROG_TYPE_LWT_IN: + case BPF_PROG_TYPE_LWT_OUT: + case BPF_PROG_TYPE_LWT_XMIT: + case BPF_PROG_TYPE_SOCK_OPS: + case BPF_PROG_TYPE_SK_SKB: + case BPF_PROG_TYPE_CGROUP_DEVICE: + case BPF_PROG_TYPE_SK_MSG: + case BPF_PROG_TYPE_RAW_TRACEPOINT: + case BPF_PROG_TYPE_LWT_SEG6LOCAL: + case BPF_PROG_TYPE_LIRC_MODE2: + case BPF_PROG_TYPE_SK_REUSEPORT: + case BPF_PROG_TYPE_FLOW_DISSECTOR: + default: + break; + } + + xattr.prog_type = prog_type; + xattr.insns = insns; + xattr.insns_cnt = insns_cnt; + xattr.license = "GPL"; + xattr.prog_ifindex = ifindex; + + fd = bpf_load_program_xattr(&xattr, buf, buf_len); + if (fd >= 0) + close(fd); +} + +bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex) +{ + struct bpf_insn insns[2] = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN() + }; + + if (ifindex && prog_type == BPF_PROG_TYPE_SCHED_CLS) + /* nfp returns -EINVAL on exit(0) with TC offload */ + insns[0].imm = 2; + + errno = 0; + prog_load(prog_type, insns, ARRAY_SIZE(insns), NULL, 0, ifindex); + + return errno != EINVAL && errno != EOPNOTSUPP; +} From patchwork Thu Jan 3 14:02:35 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1020321 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="oK3hgEYO"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43VqQ106tKz9s9h for ; Fri, 4 Jan 2019 01:03:21 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731851AbfACODR (ORCPT ); Thu, 3 Jan 2019 09:03:17 -0500 Received: from mail-wm1-f67.google.com ([209.85.128.67]:40637 "EHLO mail-wm1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731776AbfACODC (ORCPT ); Thu, 3 Jan 2019 09:03:02 -0500 Received: by mail-wm1-f67.google.com with SMTP id f188so30351562wmf.5 for ; Thu, 03 Jan 2019 06:03:00 -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=auRs7jGZERO6MUB/NYQuAsu23hMIOced/3H+BX/le8k=; b=oK3hgEYOVoUX9TRS8m8bvRVG+oBU2xwoTbl8wHkh9t272SegtWp9Sr8UpmiJAbksWv kFFlNwyuTd3veB8V4KeEi/QkcOXx5f0c5jD2Zb34afWGbdJf7QegWQVGlmFR1SES1EWj 0Kp9n/BZQH85tYQTO8uUwNDW270b6e9+oNxQ4Zj5v8R09SpcyyCPOZrLLCazYGao0swA yP4BdtB7jam2Ak8iu+PfcZdAoqzjESCLO622HOiDPxb7Wo8SXcurNEbaWb/SdY6qQ2/g RwdyXqpfvg8lNZ4iL6TohUsa+77+5rYEbwAPHSQGaFKY5IrUiKW7CJQT+RBh1mN8OfMz gwhQ== 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=auRs7jGZERO6MUB/NYQuAsu23hMIOced/3H+BX/le8k=; b=Fi3N6TFqdMk2o38GwWsuDuXd/5CZ7m33X28M5W2oZxFDAIU5ttTVLadm2Z+46Z6nix L1DMGFAYxaitbGrNShF7wYKTmXvPocuj3AxKTEgw75tgjH3+L8ednrw4+46VsM1TYJ7o BTW4VL4FGikUBznriuxrdrE4KsRh22GKWjbit8hkk/GyGYSYG3ImGDGPMdW1ZI/W8GdS zRzyYsNDfj7iQ8VZzOmjNnlOUaLlCalCbEB/8RMl4myTU72oMkWbfW0BB1NHujCCHs/L ZnVLg7gWFV6QIgcJkR5GzJWiCCzRtlmGsVsSv8ykGkB3LdBZFV4OZZQKtxOziuQhf9/3 02sw== X-Gm-Message-State: AJcUukdaMnl8hE8r3ZpECWamB7x+lsHEosCcjcgRF7fnnReAhaGAHdP9 8kp9ejSQMnR/+VISshqNAdMLWA== X-Google-Smtp-Source: ALg8bN7vMAwwNjIF9dR7MVgbWrJu4olC0ONVXFllEZUKhzAAe0f9SvnjPqZfkPd1V0DT9leXJ6U1ZA== X-Received: by 2002:a1c:f319:: with SMTP id q25mr26781895wmq.151.1546524179578; Thu, 03 Jan 2019 06:02:59 -0800 (PST) Received: from cbtest32.netronome.com ([217.38.71.146]) by smtp.gmail.com with ESMTPSA id 10sm44854771wmy.40.2019.01.03.06.02.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 03 Jan 2019 06:02:58 -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: [RFC bpf-next v3 5/9] tools: bpftool: add probes for eBPF map types Date: Thu, 3 Jan 2019 14:02:35 +0000 Message-Id: <20190103140239.23548-6-quentin.monnet@netronome.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190103140239.23548-1-quentin.monnet@netronome.com> References: <20190103140239.23548-1-quentin.monnet@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add new probes for eBPF map types, to detect what are the ones available on the system. Try creating one map of each type, and see if the kernel complains. Sample output: # bpftool feature probe kernel ... Scanning eBPF map types... eBPF map_type hash is available eBPF map_type array is available eBPF map_type prog_array is available ... # bpftool --json --pretty feature probe kernel { ... "map_types": { "have_hash_map_type": true, "have_array_map_type": true, "have_prog_array_map_type": true, ... } } v3: - Use a switch with all enum values for setting specific map parameters, so that gcc complains at compile time (-Wswitch-enum) if new map types were added to the kernel but libbpf was not updated. v2: - Move probes from bpftool to libbpf. - Remove C-style macros output from this patch. Signed-off-by: Quentin Monnet --- tools/bpf/bpftool/feature.c | 26 +++++++++++ tools/bpf/bpftool/main.h | 3 ++ tools/bpf/bpftool/map.c | 4 +- tools/lib/bpf/libbpf.h | 1 + tools/lib/bpf/libbpf.map | 1 + tools/lib/bpf/libbpf_probes.c | 84 +++++++++++++++++++++++++++++++++++ 6 files changed, 118 insertions(+), 1 deletion(-) diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index 8b9e00867000..6a4ff402854c 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -380,6 +380,26 @@ static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types) print_bool_feature(feat_name, plain_desc, res); } +static void probe_map_type(enum bpf_map_type map_type) +{ + const char *plain_comment = "eBPF map_type "; + char feat_name[128], plain_desc[128]; + size_t maxlen; + bool res; + + res = bpf_probe_map_type(map_type, 0); + + maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1; + if (strlen(map_type_name[map_type]) > maxlen) { + p_info("map type name too long"); + return; + } + + sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]); + sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]); + print_bool_feature(feat_name, plain_desc, res); +} + static int do_probe(int argc, char **argv) { enum probe_component target = COMPONENT_UNSPEC; @@ -448,6 +468,12 @@ static int do_probe(int argc, char **argv) for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) probe_prog_type(i, supported_types); + print_end_then_start_section("map_types", + "Scanning eBPF map types..."); + + for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++) + probe_map_type(i); + exit_close_json: if (json_output) { /* End current "section" of probes */ diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 5cfc6601de9b..d7dd84d3c660 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -75,6 +75,9 @@ static const char * const prog_type_name[] = { [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector", }; +extern const char * const map_type_name[]; +extern const size_t map_type_name_size; + enum bpf_obj_type { BPF_OBJ_UNKNOWN, BPF_OBJ_PROG, diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index 2037e3dc864b..b73985589929 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -21,7 +21,7 @@ #include "json_writer.h" #include "main.h" -static const char * const map_type_name[] = { +const char * const map_type_name[] = { [BPF_MAP_TYPE_UNSPEC] = "unspec", [BPF_MAP_TYPE_HASH] = "hash", [BPF_MAP_TYPE_ARRAY] = "array", @@ -48,6 +48,8 @@ static const char * const map_type_name[] = { [BPF_MAP_TYPE_STACK] = "stack", }; +const size_t map_type_name_size = ARRAY_SIZE(map_type_name); + static bool map_is_per_cpu(__u32 type) { return type == BPF_MAP_TYPE_PERCPU_HASH || diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 8e63821109ab..72385f6f9415 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -365,6 +365,7 @@ 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); #ifdef __cplusplus } /* extern "C" */ diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 6355e4c80a86..c08f4c726e8e 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_map_type; bpf_probe_prog_type; bpf_prog_attach; bpf_prog_detach; diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c index f08c33fa8dc9..e3d57632a975 100644 --- a/tools/lib/bpf/libbpf_probes.c +++ b/tools/lib/bpf/libbpf_probes.c @@ -93,3 +93,87 @@ bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex) return errno != EINVAL && errno != EOPNOTSUPP; } + +bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex) +{ + int key_size, value_size, max_entries, map_flags; + struct bpf_create_map_attr attr = {}; + int fd = -1, fd_inner; + + key_size = sizeof(__u32); + value_size = sizeof(__u32); + max_entries = 1; + map_flags = 0; + + switch (map_type) { + case BPF_MAP_TYPE_STACK_TRACE: + value_size = sizeof(__u64); + break; + case BPF_MAP_TYPE_LPM_TRIE: + key_size = sizeof(__u64); + value_size = sizeof(__u64); + map_flags = BPF_F_NO_PREALLOC; + break; + case BPF_MAP_TYPE_CGROUP_STORAGE: + case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE: + key_size = sizeof(struct bpf_cgroup_storage_key); + value_size = sizeof(__u64); + max_entries = 0; + break; + case BPF_MAP_TYPE_QUEUE: + case BPF_MAP_TYPE_STACK: + key_size = 0; + break; + case BPF_MAP_TYPE_UNSPEC: + case BPF_MAP_TYPE_HASH: + case BPF_MAP_TYPE_ARRAY: + case BPF_MAP_TYPE_PROG_ARRAY: + case BPF_MAP_TYPE_PERF_EVENT_ARRAY: + case BPF_MAP_TYPE_PERCPU_HASH: + case BPF_MAP_TYPE_PERCPU_ARRAY: + case BPF_MAP_TYPE_CGROUP_ARRAY: + case BPF_MAP_TYPE_LRU_HASH: + case BPF_MAP_TYPE_LRU_PERCPU_HASH: + case BPF_MAP_TYPE_ARRAY_OF_MAPS: + case BPF_MAP_TYPE_HASH_OF_MAPS: + case BPF_MAP_TYPE_DEVMAP: + case BPF_MAP_TYPE_SOCKMAP: + case BPF_MAP_TYPE_CPUMAP: + case BPF_MAP_TYPE_XSKMAP: + case BPF_MAP_TYPE_SOCKHASH: + case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY: + default: + break; + } + + if (map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS || + map_type == BPF_MAP_TYPE_HASH_OF_MAPS) { + /* TODO: probe for device, once libbpf has a function to create + * map-in-map for offload + */ + if (ifindex) + return false; + + fd_inner = bpf_create_map(BPF_MAP_TYPE_HASH, + sizeof(__u32), sizeof(__u32), 1, 0); + if (fd_inner < 0) + return false; + fd = bpf_create_map_in_map(map_type, NULL, sizeof(__u32), + fd_inner, 1, 0); + close(fd_inner); + } else { + /* Note: No other restriction on map type probes for offload */ + attr.map_type = map_type; + attr.key_size = key_size; + attr.value_size = value_size; + attr.max_entries = max_entries; + attr.map_flags = map_flags; + attr.map_ifindex = ifindex; + + fd = bpf_create_map_xattr(&attr); + } + if (fd >= 0) + close(fd); + + return fd >= 0; +} From patchwork Thu Jan 3 14:02:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1020316 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="sOPhSg/q"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43VqPl30S5z9s55 for ; Fri, 4 Jan 2019 01:03:07 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731837AbfACODG (ORCPT ); Thu, 3 Jan 2019 09:03:06 -0500 Received: from mail-wm1-f67.google.com ([209.85.128.67]:55808 "EHLO mail-wm1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731826AbfACODC (ORCPT ); Thu, 3 Jan 2019 09:03:02 -0500 Received: by mail-wm1-f67.google.com with SMTP id y139so29192612wmc.5 for ; Thu, 03 Jan 2019 06:03:01 -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=QcG/4Hi9JUIQcu0hOi7SF65vqOg7JqwukB4lPxGVsKQ=; b=sOPhSg/qZYkeLWI+k13yi3BLBcGKpcZz5ESidCCYqW3EQzsla/o6+RXQtcmU4xtXZ1 Z0L5LAjBO2+Xc1nPsAPkcWWz3pWiQWNPqRHMMLW1gjA3U73t2kDnJOt3hPfFGzsf9dhq 5C11K5kdfkkXdELJbGuYou+UioHP8YqsWMt953wt3YtNPBG0qShAD3z6s/a1xuLlt1WP 7roggy7MeWpziMk3lNQXPz+16CG4g1ODHb+p0j6Y99dbBOO5AcyKgPZsTPOGOQ07Cwdf mc5SLUXJBqi/et7blWM/RAEJl2aMXGtXG6nQ8zb0aVJsNJacM4oez8uKM+D44gSQJcrr EUbA== 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=QcG/4Hi9JUIQcu0hOi7SF65vqOg7JqwukB4lPxGVsKQ=; b=IqODCrqCLuuXGVVUnI7SKABQA6PoP3VdUNLbKXd9Ia4IFnYhcNXJho/2FwlGw5frdZ P5LjfuIsnwHi9n7yPidkezHamPOkJhQ8N6bd/dxBqDykquEUxMF5upc9bLrY2AhFzpVm lOC0MEH7m7v9JOUj2jNCv7ONW7Qf0ij9UotmGxHWfeNcTL4/RSWKzyuvLlUV7fjQ9OUv 0HAafKD7xH+yFfaR4jzkgHBjWexbJXiZw1vbGZnNotgPXMTNEGvuOx7v+qIlt6vfFVI3 5ta0k0FK3iio6UTjm2sXFrumFnIB5a7R7lFTMz9n8K+JwxevNb3UpdlKkTglyKp0Bk5p 2low== X-Gm-Message-State: AJcUukdwJQ1iFgEvREJ4K1rJ7zn2xRAYE1U0+o4+4z2JQjMB6do9HpNb xGUnV3+294mSVYXosfBra8gVkQ== X-Google-Smtp-Source: AFSGD/W0O/hnZofNtZJ/7TnHmmBPeZlaQh6Z6qbSYGPEXJ/HAh1i8jw3r3/6Lz5xP7R2yr8E/muV8Q== X-Received: by 2002:a1c:2457:: with SMTP id k84mr38148820wmk.139.1546524180645; Thu, 03 Jan 2019 06:03:00 -0800 (PST) Received: from cbtest32.netronome.com ([217.38.71.146]) by smtp.gmail.com with ESMTPSA id 10sm44854771wmy.40.2019.01.03.06.02.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 03 Jan 2019 06:02:59 -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: [RFC bpf-next v3 6/9] tools: bpftool: add probes for eBPF helper functions Date: Thu, 3 Jan 2019 14:02:36 +0000 Message-Id: <20190103140239.23548-7-quentin.monnet@netronome.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190103140239.23548-1-quentin.monnet@netronome.com> References: <20190103140239.23548-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", ... ], ... } } 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 | 49 +++++++++++++++ tools/lib/bpf/libbpf.h | 2 + tools/lib/bpf/libbpf.map | 1 + tools/lib/bpf/libbpf_probes.c | 62 +++++++++++++++++++ 5 files changed, 118 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 6a4ff402854c..133cdfda00d4 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -25,6 +25,11 @@ 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) +}; + /* Miscellaneous utility functions */ static bool check_procfs(void) @@ -400,6 +405,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; @@ -474,6 +517,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..6ab275933d2e 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(__u32 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..1b325142bca4 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,30 @@ bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex) return fd >= 0; } + +bool bpf_probe_helper(__u32 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; +} From patchwork Thu Jan 3 14:02:37 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1020317 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="PJVhiiOO"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43VqPn34Tgz9s55 for ; Fri, 4 Jan 2019 01:03:09 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731840AbfACODH (ORCPT ); Thu, 3 Jan 2019 09:03:07 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:50310 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731833AbfACODF (ORCPT ); Thu, 3 Jan 2019 09:03:05 -0500 Received: by mail-wm1-f66.google.com with SMTP id n190so29390025wmd.0 for ; Thu, 03 Jan 2019 06:03:02 -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=XkpOBcJOV5YpP5iADO82DllFpqAPEJ5NPg7npo4EoUc=; b=PJVhiiOOyqLGM7stParM3Ki4Ejrh/y5ai92z1zW6c4uDdimqSQfpKNAz3dXoZ9yCqG 1NrhU9OgiMOiN6G5cbKvUqX6iXFO7pqOudgjo12ks6/tq6b7eNynbc5Tak2a42rDDsLw CpM2hWxSs32bTGpt6rZCBohyfNwt07SVfu4Ztm/UElMW6kRzmQDavLReOqDOCYSMB4Ff fReTDjclerNIzDtjbnEZ+0wGqHMvN6ydEXWFSezDtoh8LlEWpfyQKZzFtoGGw/XwjjQU oza9KL1dWB3kEqK38IW6Moks3PsPju+T59B18m1UtMTw4IRxONmYp6VAYb1ox4roNVSb 5L/A== 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=XkpOBcJOV5YpP5iADO82DllFpqAPEJ5NPg7npo4EoUc=; b=uB943+Kf/UPDTpQjJhEXoTjIT3YWx64HPN94s0eauvKW6Zqg/euK3fNYa5ciUFUl51 cdj+C0z+ynzvF0U17Eoj39RRDQWiRqK90ss12THUIptE4rI6qZfEGkzqG726marYnJNM zoT8qFY07WHk5cOzkVlD63gWr/k7vliKnDdXHH+wK8s7pOYj9UhWClSI9QNP0vAGnK2G +epRV2TYyYTjhMxzFhcZMcgocXqsFXr0SMENXKbnbxLv8GFGtOBJqzuJ9ZmgSi6hn2Od WkW2u0nnE1l4rw3LgRpOeH/yjoaFSIfV1u0ZRr7hM7pnBlt65k0o1b0mowNZ1BZ01oG3 BhCg== X-Gm-Message-State: AJcUukcFIBfQhbLVHEj24FUk/16ZC7JjP0q+44/MrmwAAiGPDxreDlNT lTxhs7zNNIokmXF9LvjPnqVe5g== X-Google-Smtp-Source: ALg8bN79Cna+MtmMlQwRmYYE1IEPsI5Dxz6Lc0bIVoBXtSaDtdJMaESGmMiVYYcyZjuLhIs6YTZwMw== X-Received: by 2002:a7b:ce8e:: with SMTP id q14mr40441003wmj.10.1546524182013; Thu, 03 Jan 2019 06:03:02 -0800 (PST) Received: from cbtest32.netronome.com ([217.38.71.146]) by smtp.gmail.com with ESMTPSA id 10sm44854771wmy.40.2019.01.03.06.03.00 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 03 Jan 2019 06:03:01 -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: [RFC bpf-next v3 7/9] tools: bpftool: add C-style "#define" output for probes Date: Thu, 3 Jan 2019 14:02:37 +0000 Message-Id: <20190103140239.23548-8-quentin.monnet@netronome.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190103140239.23548-1-quentin.monnet@netronome.com> References: <20190103140239.23548-1-quentin.monnet@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Make bpftool able to dump a subset of the parameters collected by probing the system as a listing of C-style #define macros, so that external projects can reuse the result of this probing and build BPF-based project in accordance with the features available on the system. The new "macros" keyword is used to select this output. An additional "prefix" keyword is added so that users can select a custom prefix for macro names, in order to avoid any namespace conflict. Sample output: # bpftool feature probe kernel macros prefix FOO_ /*** System call availability ***/ #define FOO_HAVE_BPF_SYSCALL /*** eBPF program types ***/ #define FOO_HAVE_SOCKET_FILTER_PROG_TYPE #define FOO_HAVE_KPROBE_PROG_TYPE #define FOO_HAVE_SCHED_CLS_PROG_TYPE ... /*** eBPF map types ***/ #define FOO_HAVE_HASH_MAP_TYPE #define FOO_HAVE_ARRAY_MAP_TYPE #define FOO_HAVE_PROG_ARRAY_MAP_TYPE ... /*** eBPF helper functions ***/ /* * Use FOO_HAVE_PROG_TYPE_HELPER(prog_type_name, helper_name) * to determine if is available for , * e.g. * #if FOO_HAVE_PROG_TYPE_HELPER(xdp, bpf_redirect) * // do stuff with this helper * #elif * // use a workaround * #endif */ #define FOO_HAVE_PROG_TYPE_HELPER(prog_type, helper) \ FOO_BPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper ... #define FOO_BPF__PROG_TYPE_socket_filter__HELPER_bpf_probe_read 0 #define FOO_BPF__PROG_TYPE_socket_filter__HELPER_bpf_ktime_get_ns 1 #define FOO_BPF__PROG_TYPE_socket_filter__HELPER_bpf_trace_printk 1 ... v3: - Change output for helpers again: add a HAVE_PROG_TYPE_HELPER(type, helper) macro that can be used to tell if is available for program . v2: - #define-based output added as a distinct patch. - "HAVE_" prefix appended to macro names. - Output limited to bpf() syscall availability, BPF prog and map types, helper functions. In this version kernel config options, procfs parameter or kernel version are intentionally left aside. - Following the change on helper probes, format for helper probes in this output style has changed (now a list of compatible program types). Signed-off-by: Quentin Monnet --- .../bpftool/Documentation/bpftool-feature.rst | 13 +- tools/bpf/bpftool/feature.c | 148 ++++++++++++++---- 2 files changed, 131 insertions(+), 30 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst index 255e3b3629a0..53092995f46b 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst @@ -19,15 +19,24 @@ SYNOPSIS MAP COMMANDS ============= -| **bpftool** **feature probe** [**kernel**] +| **bpftool** **feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]] | **bpftool** **feature help** DESCRIPTION =========== - **bpftool feature probe** [**kernel**] + **bpftool feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]] Probe the running kernel and dump a number of eBPF-related parameters, such as availability of the **bpf()** system call. + If the **macros** keyword (but not the **-j** option) is + passed, a subset of the output is dumped as a list of + **#define** macros that are ready to be included in a C + header file, for example. If, additionally, **prefix** is + used to define a *PREFIX*, the provided string will be used + as a prefix to the names of the macros: this can be used to + avoid conflicts on macro names when including the output of + this command as a header file. + Keyword **kernel** can be omitted. Note that when probed, some eBPF helpers (e.g. diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index 133cdfda00d4..a97913b0df6c 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -44,13 +44,25 @@ static bool check_procfs(void) return true; } +static void uppercase(char *str, size_t len) +{ + size_t i; + + for (i = 0; i < len && str[i] != '\0'; i++) + str[i] = toupper(str[i]); +} + /* Printing utility functions */ static void -print_bool_feature(const char *feat_name, const char *plain_name, bool res) +print_bool_feature(const char *feat_name, const char *plain_name, + const char *define_name, bool res, const char *define_prefix) { if (json_output) jsonw_bool_field(json_wtr, feat_name, res); + else if (define_prefix) + printf("#define %s%sHAVE_%s\n", define_prefix, + res ? "" : "NO_", define_name); else printf("%s is %savailable\n", plain_name, res ? "" : "NOT "); } @@ -60,6 +72,8 @@ static void print_kernel_option(const char *name, const char *value) char *endptr; int res; + /* No support for C-style ouptut */ + if (json_output) { if (!value) { jsonw_null_field(json_wtr, name); @@ -80,25 +94,31 @@ static void print_kernel_option(const char *name, const char *value) } static void -print_start_section(const char *json_title, const char *plain_title) +print_start_section(const char *json_title, const char *plain_title, + const char *define_comment, const char *define_prefix) { if (json_output) { jsonw_name(json_wtr, json_title); jsonw_start_object(json_wtr); + } else if (define_prefix) { + printf("%s\n", define_comment); } else { printf("%s\n", plain_title); } } static void -print_end_then_start_section(const char *json_title, const char *plain_title) +print_end_then_start_section(const char *json_title, const char *plain_title, + const char *define_comment, + const char *define_prefix) { if (json_output) jsonw_end_object(json_wtr); else printf("\n"); - print_start_section(json_title, plain_title); + print_start_section(json_title, plain_title, define_comment, + define_prefix); } /* Probing functions */ @@ -132,6 +152,8 @@ static void probe_unprivileged_disabled(void) { int res; + /* No support for C-style ouptut */ + res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled"); if (json_output) { jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res); @@ -156,6 +178,8 @@ static void probe_jit_enable(void) { int res; + /* No support for C-style ouptut */ + res = read_procfs("/proc/sys/net/core/bpf_jit_enable"); if (json_output) { jsonw_int_field(json_wtr, "bpf_jit_enable", res); @@ -184,6 +208,8 @@ static void probe_jit_harden(void) { int res; + /* No support for C-style ouptut */ + res = read_procfs("/proc/sys/net/core/bpf_jit_harden"); if (json_output) { jsonw_int_field(json_wtr, "bpf_jit_harden", res); @@ -212,6 +238,8 @@ static void probe_jit_kallsyms(void) { int res; + /* No support for C-style ouptut */ + res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms"); if (json_output) { jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res); @@ -349,7 +377,7 @@ static void probe_kernel_image_config(void) print_kernel_option(options[i], NULL); } -static bool probe_bpf_syscall(void) +static bool probe_bpf_syscall(const char *define_prefix) { bool res; @@ -358,15 +386,18 @@ static bool probe_bpf_syscall(void) print_bool_feature("have_bpf_syscall", "bpf() syscall", - res); + "BPF_SYSCALL", + res, define_prefix); return res; } -static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types) +static void +probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types, + const char *define_prefix) { + char feat_name[128], plain_desc[128], define_name[128]; const char *plain_comment = "eBPF program_type "; - char feat_name[128], plain_desc[128]; size_t maxlen; bool res; @@ -381,14 +412,18 @@ static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types) } sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]); + sprintf(define_name, "%s_prog_type", prog_type_name[prog_type]); + uppercase(define_name, sizeof(define_name)); sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]); - print_bool_feature(feat_name, plain_desc, res); + print_bool_feature(feat_name, plain_desc, define_name, res, + define_prefix); } -static void probe_map_type(enum bpf_map_type map_type) +static void +probe_map_type(enum bpf_map_type map_type, const char *define_prefix) { + char feat_name[128], plain_desc[128], define_name[128]; const char *plain_comment = "eBPF map_type "; - char feat_name[128], plain_desc[128]; size_t maxlen; bool res; @@ -401,12 +436,16 @@ static void probe_map_type(enum bpf_map_type map_type) } sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]); + sprintf(define_name, "%s_map_type", map_type_name[map_type]); + uppercase(define_name, sizeof(define_name)); sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]); - print_bool_feature(feat_name, plain_desc, res); + print_bool_feature(feat_name, plain_desc, define_name, res, + define_prefix); } static void -probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type) +probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type, + const char *define_prefix) { const char *ptype_name = prog_type_name[prog_type]; char feat_name[128]; @@ -417,7 +456,7 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type) sprintf(feat_name, "%s_available_helpers", ptype_name); jsonw_name(json_wtr, feat_name); jsonw_start_array(json_wtr); - } else { + } else if (!define_prefix) { printf("eBPF helpers supported for program type %s:", ptype_name); } @@ -431,6 +470,10 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type) if (json_output) { if (res) jsonw_string(json_wtr, helper_name[id]); + } else if (define_prefix) { + printf("#define %sBPF__PROG_TYPE_%s__HELPER_%s %s\n", + define_prefix, ptype_name, helper_name[id], + res ? "1" : "0"); } else { if (res) printf("\n\t- %s", helper_name[id]); @@ -439,13 +482,14 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type) if (json_output) jsonw_end_array(json_wtr); - else + else if (!define_prefix) printf("\n"); } static int do_probe(int argc, char **argv) { enum probe_component target = COMPONENT_UNSPEC; + const char *define_prefix = NULL; bool supported_types[128] = {}; unsigned int i; @@ -467,21 +511,45 @@ static int do_probe(int argc, char **argv) } target = COMPONENT_KERNEL; NEXT_ARG(); + } else if (is_prefix(*argv, "macros") && !define_prefix) { + define_prefix = ""; + NEXT_ARG(); + } else if (is_prefix(*argv, "prefix")) { + if (!define_prefix) { + p_err("'prefix' argument can only be use after 'macros'"); + return -1; + } + if (strcmp(define_prefix, "")) { + p_err("'prefix' already defined"); + return -1; + } + NEXT_ARG(); + + if (!REQ_ARGS(1)) + return -1; + define_prefix = GET_ARG(); } else { - p_err("expected no more arguments, 'kernel', got: '%s'?", + p_err("expected no more arguments, 'kernel', 'macros' or 'prefix', got: '%s'?", *argv); return -1; } } - if (json_output) + if (json_output) { + define_prefix = NULL; jsonw_start_object(json_wtr); + } switch (target) { case COMPONENT_KERNEL: case COMPONENT_UNSPEC: + if (define_prefix) + break; + print_start_section("system_config", - "Scanning system configuration..."); + "Scanning system configuration...", + NULL, /* define_comment never used here */ + NULL); /* define_prefix always NULL here */ if (check_procfs()) { probe_unprivileged_disabled(); probe_jit_enable(); @@ -499,29 +567,53 @@ static int do_probe(int argc, char **argv) } print_start_section("syscall_config", - "Scanning system call availability..."); + "Scanning system call availability...", + "/*** System call availability ***/", + define_prefix); - if (!probe_bpf_syscall()) + if (!probe_bpf_syscall(define_prefix)) /* bpf() syscall unavailable, don't probe other BPF features */ goto exit_close_json; print_end_then_start_section("program_types", - "Scanning eBPF program types..."); + "Scanning eBPF program types...", + "/*** eBPF program types ***/", + define_prefix); for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) - probe_prog_type(i, supported_types); + probe_prog_type(i, supported_types, define_prefix); print_end_then_start_section("map_types", - "Scanning eBPF map types..."); + "Scanning eBPF map types...", + "/*** eBPF map types ***/", + define_prefix); for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++) - probe_map_type(i); + probe_map_type(i, define_prefix); print_end_then_start_section("helpers", - "Scanning eBPF helper functions..."); - + "Scanning eBPF helper functions...", + "/*** eBPF helper functions ***/", + define_prefix); + + if (define_prefix) + printf("/*\n" + " * Use %sHAVE_PROG_TYPE_HELPER(prog_type_name, helper_name)\n" + " * to determine if is available for ,\n" + " * e.g.\n" + " * #if %sHAVE_PROG_TYPE_HELPER(xdp, bpf_redirect)\n" + " * // do stuff with this helper\n" + " * #elif\n" + " * // use a workaround\n" + " * #endif\n" + " */\n" + "#define %sHAVE_PROG_TYPE_HELPER(prog_type, helper) \\\n" + " %sBPF__PROG_TYPE_ ## prog_type ## __HELPER_ ## helper\n", + define_prefix, define_prefix, define_prefix, + define_prefix); for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) - probe_helpers_for_progtype(i, supported_types[i]); + probe_helpers_for_progtype(i, supported_types[i], + define_prefix); exit_close_json: if (json_output) { @@ -542,7 +634,7 @@ static int do_help(int argc, char **argv) } fprintf(stderr, - "Usage: %s %s probe [kernel]\n" + "Usage: %s %s probe [kernel] [macros [prefix PREFIX]]\n" " %s %s help\n" "", bin_name, argv[-2], bin_name, argv[-2]); From patchwork Thu Jan 3 14:02:38 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1020319 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="PGRzzGKQ"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43VqPt4lP9z9s55 for ; Fri, 4 Jan 2019 01:03:14 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731847AbfACODN (ORCPT ); Thu, 3 Jan 2019 09:03:13 -0500 Received: from mail-wm1-f66.google.com ([209.85.128.66]:40639 "EHLO mail-wm1-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730603AbfACODF (ORCPT ); Thu, 3 Jan 2019 09:03:05 -0500 Received: by mail-wm1-f66.google.com with SMTP id f188so30351718wmf.5 for ; Thu, 03 Jan 2019 06:03:03 -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=4N5UOHzSt5fIw/mccW3rIiKPDnLgkupsvZY0mcf+2Vg=; b=PGRzzGKQX0My9A7XpdSod47fS7tulPaMipEkmD1eQLaXHwpXhJ8hy7izXsv5HPh6Cc IeDBgXRqS0qkn9dm9uB424P86hASBdNpKda2jq3D1a8ZnUrM0bUi9Vf7IRPvTxIK9yGm iETyyqHnKfM8YIUzRsXbYBRrcDvNYQlcc/i2FYJnk/AiSJhRfH5KZTKEPR8x2L98uvUy I2LsX7Fctdd6X1WGELg3miwG5g5dnnZGZCo9mAvy/zhCUWRZViaL1z14BfwFjD4Lf3fg +fQ66R7G1cTxcZqDsnX/ziDNPs6diNhGt/h/k08ZuX0fjgxNq+bYzfI2jv1rRXlIZTAb +eYg== 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=4N5UOHzSt5fIw/mccW3rIiKPDnLgkupsvZY0mcf+2Vg=; b=eQfXC1J/OS54pSCNDeedYKvYzmktHvIK2wFV0TbEtPoRU9zvrwqLpytfvDSkST6NFs yE6O92G3L0JU/itPQFY6EEcATROGmTzN0mdedaANdtRS2HxnNk/GSyb8F5xhJuLxmaje 6Sep14EiZa0tktq6zj0JH+vlHfDEOb8yr4kPuuHGz0Hg2EGv1XC2JgfTJSmcmfq/xlia JUNX9md5rjSiMNuImPUaDY7auUUXr9JI9F7PMa+n2hy+gztztH4xF7NeitH/mTOaQae/ 2lA0fycP34kyv8S6j8cR30qG/cvKEkW3h5Rtzj6O5cZwEo41nHVYZO4XToruj5YpregK QuVw== X-Gm-Message-State: AJcUukcO40dE/5/N6xE/mcW5MlzxzaGl3HUDa+XVREpphOg8mIY5kiA/ uJWLgK+isvYJ8Rse8VonKzQ1aA== X-Google-Smtp-Source: ALg8bN69BGo3uCvXsRFAacWhU9XlwXaW5p3DNSuOuW01ag39gQA4kfM62P9DdWoQ9QlS4zcrO7kQYw== X-Received: by 2002:a1c:dd04:: with SMTP id u4mr37732972wmg.84.1546524182814; Thu, 03 Jan 2019 06:03:02 -0800 (PST) Received: from cbtest32.netronome.com ([217.38.71.146]) by smtp.gmail.com with ESMTPSA id 10sm44854771wmy.40.2019.01.03.06.03.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 03 Jan 2019 06:03:02 -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: [RFC bpf-next v3 8/9] tools: bpftool: add probes for a network device Date: Thu, 3 Jan 2019 14:02:38 +0000 Message-Id: <20190103140239.23548-9-quentin.monnet@netronome.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190103140239.23548-1-quentin.monnet@netronome.com> References: <20190103140239.23548-1-quentin.monnet@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org bpftool gained support for probing the current system in order to see what program and map types, and what helpers are available on that system. This patch adds the possibility to pass an interface index to libbpf (and hence to the kernel) when trying to load the programs or to create the maps, in order to see what items a given network device can support. A new keyword "dev " can be used as an alternative to "kernel" to indicate that the given device should be tested. If no target ("dev" or "kernel") is specified bpftool defaults to probing the kernel. Sample output: # bpftool -p feature probe dev lo { "syscall_config": { "have_bpf_syscall": true }, "program_types": { "have_sched_cls_prog_type": false, "have_xdp_prog_type": false }, ... } As the target is a network device, /proc/ parameters and kernel configuration are NOT dumped. Availability of the bpf() syscall is still probed, so we can return early if that syscall is not usable (since there is no point in attempting the remaining probes in this case). Among the program types, only the ones that can be offloaded are probed. All map types are probed, as there is no specific rule telling which one could or could not be supported by a device in the future. All helpers are probed (but only for offload-able program types). Caveat: as bpftool does not attempt to attach programs to the device at the moment, probes do not entirely reflect what the device accepts: typically, for Netronome's nfp, results will announce that TC cls offload is available even if support has been deactivated (with e.g. ethtool -K eth1 hw-tc-offload off). v2: - All helpers are probed, whereas previous version would only probe the ones compatible with an offload-able program type. This is because we do not keep a default compatible program type for each helper anymore. Signed-off-by: Quentin Monnet Reviewed-by: Jakub Kicinski --- .../bpftool/Documentation/bpftool-feature.rst | 18 ++++- tools/bpf/bpftool/feature.c | 69 ++++++++++++++++--- 2 files changed, 73 insertions(+), 14 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst index 53092995f46b..8d489a26e3c9 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst @@ -19,14 +19,18 @@ SYNOPSIS MAP COMMANDS ============= -| **bpftool** **feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]] +| **bpftool** **feature probe** [*COMPONENT*] [**macros** [**prefix** *PREFIX*]] | **bpftool** **feature help** +| +| *COMPONENT* := { **kernel** | **dev** *NAME* } DESCRIPTION =========== **bpftool feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]] Probe the running kernel and dump a number of eBPF-related - parameters, such as availability of the **bpf()** system call. + parameters, such as availability of the **bpf()** system call, + JIT status, eBPF program types availability, eBPF helper + functions availability, and more. If the **macros** keyword (but not the **-j** option) is passed, a subset of the output is dumped as a list of @@ -37,12 +41,20 @@ DESCRIPTION avoid conflicts on macro names when including the output of this command as a header file. - Keyword **kernel** can be omitted. + Keyword **kernel** can be omitted. If no probe target is + specified, probing the kernel is the default behaviour. 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 probe dev** *NAME* [**macros** [**prefix** *PREFIX*]] + Probe network device for supported eBPF features and dump + results to the console. + + The two keywords **macros** and **prefix** have the same + role as when probing the kernel. + **bpftool feature help** Print short help message. diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index a97913b0df6c..c1bba37287a3 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,7 @@ enum probe_component { COMPONENT_UNSPEC, COMPONENT_KERNEL, + COMPONENT_DEVICE, }; #define BPF_HELPER_MAKE_ENTRY(name) [BPF_FUNC_ ## name] = "bpf_" # name @@ -394,14 +396,24 @@ static bool probe_bpf_syscall(const char *define_prefix) static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types, - const char *define_prefix) + const char *define_prefix, __u32 ifindex) { char feat_name[128], plain_desc[128], define_name[128]; const char *plain_comment = "eBPF program_type "; size_t maxlen; bool res; - res = bpf_probe_prog_type(prog_type, 0); + if (ifindex) + /* Only test offload-able program types */ + switch (prog_type) { + case BPF_PROG_TYPE_SCHED_CLS: + case BPF_PROG_TYPE_XDP: + break; + default: + return; + } + + res = bpf_probe_prog_type(prog_type, ifindex); supported_types[prog_type] |= res; @@ -420,14 +432,15 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types, } static void -probe_map_type(enum bpf_map_type map_type, const char *define_prefix) +probe_map_type(enum bpf_map_type map_type, const char *define_prefix, + __u32 ifindex) { char feat_name[128], plain_desc[128], define_name[128]; const char *plain_comment = "eBPF map_type "; size_t maxlen; bool res; - res = bpf_probe_map_type(map_type, 0); + res = bpf_probe_map_type(map_type, ifindex); maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1; if (strlen(map_type_name[map_type]) > maxlen) { @@ -445,13 +458,23 @@ probe_map_type(enum bpf_map_type map_type, const char *define_prefix) static void probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type, - const char *define_prefix) + const char *define_prefix, __u32 ifindex) { const char *ptype_name = prog_type_name[prog_type]; char feat_name[128]; unsigned int id; bool res; + if (ifindex) + /* Only test helpers for offload-able program types */ + switch (prog_type) { + case BPF_PROG_TYPE_SCHED_CLS: + case BPF_PROG_TYPE_XDP: + break; + default: + return; + } + if (json_output) { sprintf(feat_name, "%s_available_helpers", ptype_name); jsonw_name(json_wtr, feat_name); @@ -465,7 +488,7 @@ probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type, if (!supported_type) res = false; else - res = bpf_probe_helper(id, prog_type, 0); + res = bpf_probe_helper(id, prog_type, ifindex); if (json_output) { if (res) @@ -491,7 +514,9 @@ static int do_probe(int argc, char **argv) enum probe_component target = COMPONENT_UNSPEC; const char *define_prefix = NULL; bool supported_types[128] = {}; + __u32 ifindex = 0; unsigned int i; + char *ifname; /* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN). * Let's approximate, and restrict usage to root user only. @@ -511,6 +536,24 @@ static int do_probe(int argc, char **argv) } target = COMPONENT_KERNEL; NEXT_ARG(); + } else if (is_prefix(*argv, "dev")) { + NEXT_ARG(); + + if (target != COMPONENT_UNSPEC || ifindex) { + p_err("component to probe already specified"); + return -1; + } + if (!REQ_ARGS(1)) + return -1; + + target = COMPONENT_DEVICE; + ifname = GET_ARG(); + ifindex = if_nametoindex(ifname); + if (!ifindex) { + p_err("unrecognized netdevice '%s': %s", ifname, + strerror(errno)); + return -1; + } } else if (is_prefix(*argv, "macros") && !define_prefix) { define_prefix = ""; NEXT_ARG(); @@ -529,7 +572,7 @@ static int do_probe(int argc, char **argv) return -1; define_prefix = GET_ARG(); } else { - p_err("expected no more arguments, 'kernel', 'macros' or 'prefix', got: '%s'?", + p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?", *argv); return -1; } @@ -564,6 +607,8 @@ static int do_probe(int argc, char **argv) else printf("\n"); break; + default: + break; } print_start_section("syscall_config", @@ -581,7 +626,7 @@ static int do_probe(int argc, char **argv) define_prefix); for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) - probe_prog_type(i, supported_types, define_prefix); + probe_prog_type(i, supported_types, define_prefix, ifindex); print_end_then_start_section("map_types", "Scanning eBPF map types...", @@ -589,7 +634,7 @@ static int do_probe(int argc, char **argv) define_prefix); for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++) - probe_map_type(i, define_prefix); + probe_map_type(i, define_prefix, ifindex); print_end_then_start_section("helpers", "Scanning eBPF helper functions...", @@ -613,7 +658,7 @@ static int do_probe(int argc, char **argv) define_prefix); for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) probe_helpers_for_progtype(i, supported_types[i], - define_prefix); + define_prefix, ifindex); exit_close_json: if (json_output) { @@ -634,8 +679,10 @@ static int do_help(int argc, char **argv) } fprintf(stderr, - "Usage: %s %s probe [kernel] [macros [prefix PREFIX]]\n" + "Usage: %s %s probe [COMPONENT] [macros [prefix PREFIX]]\n" " %s %s help\n" + "\n" + " COMPONENT := { kernel | dev NAME }\n" "", bin_name, argv[-2], bin_name, argv[-2]); From patchwork Thu Jan 3 14:02:39 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1020318 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="iYnS3T0o"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 43VqPr1DSKz9s55 for ; Fri, 4 Jan 2019 01:03:12 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731843AbfACODK (ORCPT ); Thu, 3 Jan 2019 09:03:10 -0500 Received: from mail-wm1-f65.google.com ([209.85.128.65]:50311 "EHLO mail-wm1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731820AbfACODF (ORCPT ); Thu, 3 Jan 2019 09:03:05 -0500 Received: by mail-wm1-f65.google.com with SMTP id n190so29390080wmd.0 for ; Thu, 03 Jan 2019 06:03:04 -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=IPWWSPA2OA0xbOf/zkTRqL2C89+NvKzrHgDC5zhi5pw=; b=iYnS3T0oph3Ki5r0VqMawZfvGVRb17oecxLHjPyhTDH4SFPUonLX7J5WwYFmV0mIrC uG67c8hfxQb+HjR/jXSlVpwMdokIOYp8+8T9d8Atu3m8/EXtp36TYGzba+NlPaunKkAV WWmwLY5g5Ng37YOScVLMl2VX7durXkLs0IPcHoR9BJUwSOThVZflxiXsZ8NwXxsFbKJr ppaBUXUjvdAbngq5eNyzGJmuqHuYArCLzWA0wzaTs3GrKiehgHM85Jekzzm9CZ9WPesg iS3cP03/j3mKKgCpUBwC9tK5JtI/74lDbFd2YZ0ZgXHgviVnRNMIFLadonxA8oyS7/md VmDg== 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=IPWWSPA2OA0xbOf/zkTRqL2C89+NvKzrHgDC5zhi5pw=; b=iWeMkL0u4JkP3eeEA4K+CuWHxK8SepbuwkFVn5w+9JJ74yIKJCRdakv6v7rZxJU65M f9uq+vRDG8aSZq89fZUkoce/6GR5cUZ1gx5wEfrb4mbkeq9EbJ+zHfYRPibI+2k5L2f2 ED408yAsYttyrYAOOdWU/T4eTJbRszcoSykCtuGUaAEAvKXaQm3AtKDmIWkjxbAqZGJd kxixxsgWc7OtPfU3pZFHBLn0AG1d0lSkRb6L3PhKQg0/4ophJv6E9EdUP4d6exfhAvBQ qKsfFvuwSsvH4155EiBytlwvNmDODDMCjMr5znQUrxjHsKJfn/3o2ngP+Chr2t6MaweX ewYg== X-Gm-Message-State: AJcUukejrso0o/bSajga4Mjg6s/x3oKLS7dfRt/oIYWqbrTX8rUHuN8C GgO3Z6VHVAAAwNEMSOHhXy5Xxw== X-Google-Smtp-Source: ALg8bN7zyzUVt+ZIbCmsfzF0I934xgBVY+e5kqME8waxdM9DDtBrtbsTOQmkvCJvK49lKj6Sy5yBBQ== X-Received: by 2002:a1c:4955:: with SMTP id w82mr40135826wma.33.1546524183671; Thu, 03 Jan 2019 06:03:03 -0800 (PST) Received: from cbtest32.netronome.com ([217.38.71.146]) by smtp.gmail.com with ESMTPSA id 10sm44854771wmy.40.2019.01.03.06.03.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 03 Jan 2019 06:03:03 -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: [RFC bpf-next v3 9/9] tools: bpftool: add bash completion for bpftool probes Date: Thu, 3 Jan 2019 14:02:39 +0000 Message-Id: <20190103140239.23548-10-quentin.monnet@netronome.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190103140239.23548-1-quentin.monnet@netronome.com> References: <20190103140239.23548-1-quentin.monnet@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add the bash completion related to the newly introduced "bpftool feature probe" command. Signed-off-by: Quentin Monnet Reviewed-by: Jakub Kicinski --- tools/bpf/bpftool/bash-completion/bpftool | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index e4e4fab1b8c7..21d5295936ed 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -624,6 +624,25 @@ _bpftool() ;; esac ;; + feature) + case $command in + probe) + [[ $prev == "dev" ]] && _sysfs_get_netdevs && return 0 + [[ $prev == "prefix" ]] && return 0 + if _bpftool_search_list 'macros'; then + COMPREPLY+=( $( compgen -W 'prefix' -- "$cur" ) ) + else + COMPREPLY+=( $( compgen -W 'macros' -- "$cur" ) ) + fi + _bpftool_one_of_list 'kernel dev' + return 0 + ;; + *) + [[ $prev == $object ]] && \ + COMPREPLY=( $( compgen -W 'help probe' -- "$cur" ) ) + ;; + esac + ;; esac } && complete -F _bpftool bpftool