From patchwork Mon Oct 23 16:24:05 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829395 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="W78yId8G"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMF83hCkz9tX8 for ; Tue, 24 Oct 2017 03:25:00 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751576AbdJWQY6 (ORCPT ); Mon, 23 Oct 2017 12:24:58 -0400 Received: from mail-pf0-f195.google.com ([209.85.192.195]:48568 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751514AbdJWQY4 (ORCPT ); Mon, 23 Oct 2017 12:24:56 -0400 Received: by mail-pf0-f195.google.com with SMTP id b79so17490205pfk.5 for ; Mon, 23 Oct 2017 09:24:55 -0700 (PDT) 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=sUyFJdjkYH3x23cHqrtlcTPukB1Cx61AvfN/69MgUg4=; b=W78yId8GjcnBxVFzVObMO21Hhs0sxxB9bvTcte2ZCzszy2iTHjIL8aeSJsI4NYmV3S 8pM/SszU0ivha8w7vZke+BcK+Wxvhth7K62H4zxw31JPdsWbca9js/1R2N4HAkbbj4ba oX2vWb7T51fCO+BGbyotzK/snCFHXJsOxwj/taxF90wjnOAeMqdQebMRyhJvKCC7TyAF DL36DuGSOBZpo2lik82CAbY3If/OAbOwQZ31+SJ6gFkf7OaFaVyS01pUHxH1WIXQAxj/ 4h6lBTSpIr4YTjB40Aau0q2GZefmxKFPlH1jCfXgI0tO5X6kg1VGpX40fA+d3FmWwmlX lopA== 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=sUyFJdjkYH3x23cHqrtlcTPukB1Cx61AvfN/69MgUg4=; b=ld0g+jk2CHyXBX+vasfpKXvy1TgVo/HZnzUIZHdtFqtH1N81QkO6D70DUGXYRYykjW PgQmI0W0ZNPATdIHSs897c21VUkY6gA5enB6yA3jhBkTI5zUgPkHjChV6z77oRoSphSd 46FYJpwQ874GKZf8G7zaQOJTIHvTvQEF2KPShxesqFta2RL7IWwbrAEqyAhivi3cCQAY 1sOH0ymJLHCl1fIMty4UnF22l/K4SzbI2JYC4KkaML2w5vxtxBLMFXbp/rGpMTETWiOE eysg7LpyqZM8Lvug94O92rSv772fmwnEMuNs1U8B3MZxFSC1mq1xgxbY5v/K0mJQHVJG hLlg== X-Gm-Message-State: AMCzsaVT1/CkccW+B2sWFInon+VHoGU6Ks1d3TR0eSUtc5dg9G0l7HdR 8BXW108o4OkvhrnxYh9hlNOyU4nT X-Google-Smtp-Source: ABhQp+SD+9S6XY0TNf5Cddz0oFWUjPUogaf0pthyc0ud95FaNXMEQgPI2gxkBJiVAqF+cWGuq7+CJQ== X-Received: by 10.101.74.4 with SMTP id s4mr12055269pgq.259.1508775895250; Mon, 23 Oct 2017 09:24:55 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.24.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:24:54 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 01/12] tools: bpftool: copy JSON writer from iproute2 repository Date: Mon, 23 Oct 2017 09:24:05 -0700 Message-Id: <20171023162416.32753-2-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet In prevision of following commits, supposed to add JSON output to the tool, two files are copied from the iproute2 repository (taken at commit 268a9eee985f): lib/json_writer.c and include/json_writer.h. Signed-off-by: Quentin Monnet Acked-by: Daniel Borkmann Acked-by: Stephen Hemminger --- tools/bpf/bpftool/json_writer.c | 348 ++++++++++++++++++++++++++++++++++++++++ tools/bpf/bpftool/json_writer.h | 70 ++++++++ 2 files changed, 418 insertions(+) create mode 100644 tools/bpf/bpftool/json_writer.c create mode 100644 tools/bpf/bpftool/json_writer.h diff --git a/tools/bpf/bpftool/json_writer.c b/tools/bpf/bpftool/json_writer.c new file mode 100644 index 000000000000..6b77d288cce2 --- /dev/null +++ b/tools/bpf/bpftool/json_writer.c @@ -0,0 +1,348 @@ +/* + * Simple streaming JSON writer + * + * This takes care of the annoying bits of JSON syntax like the commas + * after elements + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Stephen Hemminger + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "json_writer.h" + +struct json_writer { + FILE *out; /* output file */ + unsigned depth; /* nesting */ + bool pretty; /* optional whitepace */ + char sep; /* either nul or comma */ +}; + +/* indentation for pretty print */ +static void jsonw_indent(json_writer_t *self) +{ + unsigned i; + for (i = 0; i < self->depth; ++i) + fputs(" ", self->out); +} + +/* end current line and indent if pretty printing */ +static void jsonw_eol(json_writer_t *self) +{ + if (!self->pretty) + return; + + putc('\n', self->out); + jsonw_indent(self); +} + +/* If current object is not empty print a comma */ +static void jsonw_eor(json_writer_t *self) +{ + if (self->sep != '\0') + putc(self->sep, self->out); + self->sep = ','; +} + + +/* Output JSON encoded string */ +/* Handles C escapes, does not do Unicode */ +static void jsonw_puts(json_writer_t *self, const char *str) +{ + putc('"', self->out); + for (; *str; ++str) + switch (*str) { + case '\t': + fputs("\\t", self->out); + break; + case '\n': + fputs("\\n", self->out); + break; + case '\r': + fputs("\\r", self->out); + break; + case '\f': + fputs("\\f", self->out); + break; + case '\b': + fputs("\\b", self->out); + break; + case '\\': + fputs("\\n", self->out); + break; + case '"': + fputs("\\\"", self->out); + break; + case '\'': + fputs("\\\'", self->out); + break; + default: + putc(*str, self->out); + } + putc('"', self->out); +} + +/* Create a new JSON stream */ +json_writer_t *jsonw_new(FILE *f) +{ + json_writer_t *self = malloc(sizeof(*self)); + if (self) { + self->out = f; + self->depth = 0; + self->pretty = false; + self->sep = '\0'; + } + return self; +} + +/* End output to JSON stream */ +void jsonw_destroy(json_writer_t **self_p) +{ + json_writer_t *self = *self_p; + + assert(self->depth == 0); + fputs("\n", self->out); + fflush(self->out); + free(self); + *self_p = NULL; +} + +void jsonw_pretty(json_writer_t *self, bool on) +{ + self->pretty = on; +} + +/* Basic blocks */ +static void jsonw_begin(json_writer_t *self, int c) +{ + jsonw_eor(self); + putc(c, self->out); + ++self->depth; + self->sep = '\0'; +} + +static void jsonw_end(json_writer_t *self, int c) +{ + assert(self->depth > 0); + + --self->depth; + if (self->sep != '\0') + jsonw_eol(self); + putc(c, self->out); + self->sep = ','; +} + + +/* Add a JSON property name */ +void jsonw_name(json_writer_t *self, const char *name) +{ + jsonw_eor(self); + jsonw_eol(self); + self->sep = '\0'; + jsonw_puts(self, name); + putc(':', self->out); + if (self->pretty) + putc(' ', self->out); +} + +void jsonw_printf(json_writer_t *self, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + jsonw_eor(self); + vfprintf(self->out, fmt, ap); + va_end(ap); +} + +/* Collections */ +void jsonw_start_object(json_writer_t *self) +{ + jsonw_begin(self, '{'); +} + +void jsonw_end_object(json_writer_t *self) +{ + jsonw_end(self, '}'); +} + +void jsonw_start_array(json_writer_t *self) +{ + jsonw_begin(self, '['); +} + +void jsonw_end_array(json_writer_t *self) +{ + jsonw_end(self, ']'); +} + +/* JSON value types */ +void jsonw_string(json_writer_t *self, const char *value) +{ + jsonw_eor(self); + jsonw_puts(self, value); +} + +void jsonw_bool(json_writer_t *self, bool val) +{ + jsonw_printf(self, "%s", val ? "true" : "false"); +} + +void jsonw_null(json_writer_t *self) +{ + jsonw_printf(self, "null"); +} + +void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num) +{ + jsonw_printf(self, fmt, num); +} + +#ifdef notused +void jsonw_float(json_writer_t *self, double num) +{ + jsonw_printf(self, "%g", num); +} +#endif + +void jsonw_hu(json_writer_t *self, unsigned short num) +{ + jsonw_printf(self, "%hu", num); +} + +void jsonw_uint(json_writer_t *self, uint64_t num) +{ + jsonw_printf(self, "%"PRIu64, num); +} + +void jsonw_lluint(json_writer_t *self, unsigned long long int num) +{ + jsonw_printf(self, "%llu", num); +} + +void jsonw_int(json_writer_t *self, int64_t num) +{ + jsonw_printf(self, "%"PRId64, num); +} + +/* Basic name/value objects */ +void jsonw_string_field(json_writer_t *self, const char *prop, const char *val) +{ + jsonw_name(self, prop); + jsonw_string(self, val); +} + +void jsonw_bool_field(json_writer_t *self, const char *prop, bool val) +{ + jsonw_name(self, prop); + jsonw_bool(self, val); +} + +#ifdef notused +void jsonw_float_field(json_writer_t *self, const char *prop, double val) +{ + jsonw_name(self, prop); + jsonw_float(self, val); +} +#endif + +void jsonw_float_field_fmt(json_writer_t *self, + const char *prop, + const char *fmt, + double val) +{ + jsonw_name(self, prop); + jsonw_float_fmt(self, fmt, val); +} + +void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num) +{ + jsonw_name(self, prop); + jsonw_uint(self, num); +} + +void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num) +{ + jsonw_name(self, prop); + jsonw_hu(self, num); +} + +void jsonw_lluint_field(json_writer_t *self, + const char *prop, + unsigned long long int num) +{ + jsonw_name(self, prop); + jsonw_lluint(self, num); +} + +void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num) +{ + jsonw_name(self, prop); + jsonw_int(self, num); +} + +void jsonw_null_field(json_writer_t *self, const char *prop) +{ + jsonw_name(self, prop); + jsonw_null(self); +} + +#ifdef TEST +int main(int argc, char **argv) +{ + json_writer_t *wr = jsonw_new(stdout); + + jsonw_start_object(wr); + jsonw_pretty(wr, true); + jsonw_name(wr, "Vyatta"); + jsonw_start_object(wr); + jsonw_string_field(wr, "url", "http://vyatta.com"); + jsonw_uint_field(wr, "downloads", 2000000ul); + jsonw_float_field(wr, "stock", 8.16); + + jsonw_name(wr, "ARGV"); + jsonw_start_array(wr); + while (--argc) + jsonw_string(wr, *++argv); + jsonw_end_array(wr); + + jsonw_name(wr, "empty"); + jsonw_start_array(wr); + jsonw_end_array(wr); + + jsonw_name(wr, "NIL"); + jsonw_start_object(wr); + jsonw_end_object(wr); + + jsonw_null_field(wr, "my_null"); + + jsonw_name(wr, "special chars"); + jsonw_start_array(wr); + jsonw_string_field(wr, "slash", "/"); + jsonw_string_field(wr, "newline", "\n"); + jsonw_string_field(wr, "tab", "\t"); + jsonw_string_field(wr, "ff", "\f"); + jsonw_string_field(wr, "quote", "\""); + jsonw_string_field(wr, "tick", "\'"); + jsonw_string_field(wr, "backslash", "\\"); + jsonw_end_array(wr); + + jsonw_end_object(wr); + + jsonw_end_object(wr); + jsonw_destroy(&wr); + return 0; +} + +#endif diff --git a/tools/bpf/bpftool/json_writer.h b/tools/bpf/bpftool/json_writer.h new file mode 100644 index 000000000000..1516aafba59d --- /dev/null +++ b/tools/bpf/bpftool/json_writer.h @@ -0,0 +1,70 @@ +/* + * Simple streaming JSON writer + * + * This takes care of the annoying bits of JSON syntax like the commas + * after elements + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Stephen Hemminger + */ + +#ifndef _JSON_WRITER_H_ +#define _JSON_WRITER_H_ + +#include +#include + +/* Opaque class structure */ +typedef struct json_writer json_writer_t; + +/* Create a new JSON stream */ +json_writer_t *jsonw_new(FILE *f); +/* End output to JSON stream */ +void jsonw_destroy(json_writer_t **self_p); + +/* Cause output to have pretty whitespace */ +void jsonw_pretty(json_writer_t *self, bool on); + +/* Add property name */ +void jsonw_name(json_writer_t *self, const char *name); + +/* Add value */ +void jsonw_printf(json_writer_t *self, const char *fmt, ...); +void jsonw_string(json_writer_t *self, const char *value); +void jsonw_bool(json_writer_t *self, bool value); +void jsonw_float(json_writer_t *self, double number); +void jsonw_float_fmt(json_writer_t *self, const char *fmt, double num); +void jsonw_uint(json_writer_t *self, uint64_t number); +void jsonw_hu(json_writer_t *self, unsigned short number); +void jsonw_int(json_writer_t *self, int64_t number); +void jsonw_null(json_writer_t *self); +void jsonw_lluint(json_writer_t *self, unsigned long long int num); + +/* Useful Combinations of name and value */ +void jsonw_string_field(json_writer_t *self, const char *prop, const char *val); +void jsonw_bool_field(json_writer_t *self, const char *prop, bool value); +void jsonw_float_field(json_writer_t *self, const char *prop, double num); +void jsonw_uint_field(json_writer_t *self, const char *prop, uint64_t num); +void jsonw_hu_field(json_writer_t *self, const char *prop, unsigned short num); +void jsonw_int_field(json_writer_t *self, const char *prop, int64_t num); +void jsonw_null_field(json_writer_t *self, const char *prop); +void jsonw_lluint_field(json_writer_t *self, const char *prop, + unsigned long long int num); +void jsonw_float_field_fmt(json_writer_t *self, const char *prop, + const char *fmt, double val); + +/* Collections */ +void jsonw_start_object(json_writer_t *self); +void jsonw_end_object(json_writer_t *self); + +void jsonw_start_array(json_writer_t *self); +void jsonw_end_array(json_writer_t *self); + +/* Override default exception handling */ +typedef void (jsonw_err_handler_fn)(const char *); + +#endif /* _JSON_WRITER_H_ */ From patchwork Mon Oct 23 16:24:06 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829396 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="DqoMf9nS"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMFC1t5vz9t5s for ; Tue, 24 Oct 2017 03:25:02 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751603AbdJWQY7 (ORCPT ); Mon, 23 Oct 2017 12:24:59 -0400 Received: from mail-pf0-f193.google.com ([209.85.192.193]:57083 "EHLO mail-pf0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751277AbdJWQY4 (ORCPT ); Mon, 23 Oct 2017 12:24:56 -0400 Received: by mail-pf0-f193.google.com with SMTP id b85so17461152pfj.13 for ; Mon, 23 Oct 2017 09:24:56 -0700 (PDT) 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=eiMZDHzIMJapC+QsdqcHC1xLL/SaeFPbtcPSgVK38kk=; b=DqoMf9nSJnNjXvUCu5Q5ApsMHtgOWuERVLMgdc2U57vbSP4g2BgT60r4wZ6lNgASw5 bq3Bbzq0qIUC9VFosBvfVxg44i4gv0TroIokv4wsna4zK8Saj+3ny+h+zkmNacGT9zLT 1RmdMbpnVeNxhRvuME0meRhxD8fqrW4q0VqGkBzjBDXbNrg7piPgqooEsu7UA4/AZ3IR /fsAx+88pGC+PyQTXMTBbtpVHl0xWc6jITNJwBybZfGMgGboS+gImLLt3NiHcxczaZxG kZff9VspXpoBTJuCLMLcUOOZtJ04YWHR/MKV2ufFzzBStm53XaZyKiQIvt89VQCb6XiP E//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=eiMZDHzIMJapC+QsdqcHC1xLL/SaeFPbtcPSgVK38kk=; b=iYiWN+W5pWYl2UK7tzGoArf79C/XuZK9/+WV7c141AJMsZbkLR3Zc294N7FYSXRs6k 5aTJ7LkbVgTRrUOpBgHrELDYNiiVycVfDiZZfFBe3EoFudpsuqv1U3LHNh/ymqLn6+On r1Q4h+coMg9jCcZvnTKJqI1Lttcvc2Q4pr3wd6TpwA2Of247IEdveJ/dw2dvdjhoKuDm bnJs3ShXVoPm1JNTminr6sItsH9zL/rOWkXDNgjZfIOgI6OlQWDEugNIjLemdHm7hL2T m3p3+w3g4lv4Dn2uAUQ/OXyYQFHwvTYu+v7f/5Y3LbRDJtmzg0YZLJBK6EUMQuUlxSrn iSKg== X-Gm-Message-State: AMCzsaX9SApqtzXmEqKoByznSY7qInuBN2dsWsIdi3tjsKYub+Tw/t3k CPsWItXnvF2IPnPJKZzXU/t/3LYU X-Google-Smtp-Source: ABhQp+RXIl5wwBKN858gSBQnDDPKa/ZjK7F0QstZ9oKUYTxD2xYv5kteM+x5u3uG/facT3lp2g6/fQ== X-Received: by 10.99.178.77 with SMTP id t13mr12418147pgo.219.1508775896143; Mon, 23 Oct 2017 09:24:56 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.24.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:24:55 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 02/12] tools: bpftool: add option parsing to bpftool, --help and --version Date: Mon, 23 Oct 2017 09:24:06 -0700 Message-Id: <20171023162416.32753-3-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet Add an option parsing facility to bpftool, in prevision of future options for demanding JSON output. Currently, two options are added: --help and --version, that act the same as the respective commands `help` and `version`. Signed-off-by: Quentin Monnet Acked-by: Daniel Borkmann --- tools/bpf/bpftool/Documentation/bpftool-map.rst | 8 +++++++ tools/bpf/bpftool/Documentation/bpftool-prog.rst | 8 +++++++ tools/bpf/bpftool/Documentation/bpftool.rst | 8 +++++++ tools/bpf/bpftool/main.c | 27 +++++++++++++++++++++++- 4 files changed, 50 insertions(+), 1 deletion(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst index ff63e89e4b6c..5210c4fab356 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-map.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst @@ -68,6 +68,14 @@ DESCRIPTION **bpftool map 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**). + EXAMPLES ======== **# bpftool map show** diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst index 69b3770370c8..6620a81d9dc9 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst @@ -50,6 +50,14 @@ DESCRIPTION **bpftool prog 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**). + EXAMPLES ======== **# bpftool prog show** diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst index 45ad8baf1915..9c04cd6677bd 100644 --- a/tools/bpf/bpftool/Documentation/bpftool.rst +++ b/tools/bpf/bpftool/Documentation/bpftool.rst @@ -31,6 +31,14 @@ DESCRIPTION Note that format of the output of all tools is not guaranteed to be stable and should not be depended upon. +OPTIONS +======= + -h, --help + Print short help message (similar to **bpftool help**). + + -v, --version + Print version number (similar to **bpftool version**). + SEE ALSO ======== **bpftool-map**\ (8), **bpftool-prog**\ (8) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 814d19e1b53f..613e3c75f78a 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -215,8 +216,32 @@ static int do_batch(int argc, char **argv) int main(int argc, char **argv) { + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { 0 } + }; + int opt; + + last_do_help = do_help; bin_name = argv[0]; - NEXT_ARG(); + + while ((opt = getopt_long(argc, argv, "Vh", + options, NULL)) >= 0) { + switch (opt) { + case 'V': + return do_version(argc, argv); + case 'h': + return do_help(argc, argv); + default: + usage(); + } + } + + argc -= optind; + argv += optind; + if (argc < 0) + usage(); bfd_init(); From patchwork Mon Oct 23 16:24:07 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829407 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="L50I4NLq"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMGG5GVWz9t5s for ; Tue, 24 Oct 2017 03:25:58 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751795AbdJWQZz (ORCPT ); Mon, 23 Oct 2017 12:25:55 -0400 Received: from mail-pf0-f193.google.com ([209.85.192.193]:49645 "EHLO mail-pf0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751548AbdJWQY5 (ORCPT ); Mon, 23 Oct 2017 12:24:57 -0400 Received: by mail-pf0-f193.google.com with SMTP id i5so17476716pfe.6 for ; Mon, 23 Oct 2017 09:24:57 -0700 (PDT) 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=d1DKR2dk53psgkvlwufq64za3/+AOn+hc2HXDddND0M=; b=L50I4NLq3maZHAqMoW5NV+I1Vdt/WBMOQfvlZDiOJOD+DA6IqwFg2YdGZ1QkRp2MdW ArndTlsKHFyhzuy9bFH74InkOFKL+hgQKqkkXIJXCfVOOhEMfQ11mVw1P5ir99K9VA+D /6HT5urSAaJGi/SEg3m42061/5AzLikzWhTowsIh2rIwVNnUHi5rUGBMB03LlJqD77K/ RK0HqlmTE2FpbFwCi2qGmUJ9FHE81/P82dqCDi5Beiydmou/O0LHplnpzHzo16UlENGV bUq0K79cQBplnrCnRHoJnliKmkR/bL1k3fEAwPPle17M+5EGzn9DUCT9S2rgToCBn8N2 3oXg== 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=d1DKR2dk53psgkvlwufq64za3/+AOn+hc2HXDddND0M=; b=JM74GXZJZtC8IuYWtCCAi4Zwbb3kNOapicRcQERpHuHJD7pbthfrzpGmHK4wOE8vr0 Y1PNR4VUo7Le1zH2voo2h0psqFE9NWeaUxEIo/24uD7oKldESmRafEVawZvQZ0Tp2r8P ONn6ckoHYJF21KM1UxYymvVel5vtRP3VmVvbkF4UYf6DTFh658585sMHXy7mVUO5WmsB +AE5tSS6zpTFq6B2ZjZYado9bRJwwGIf/DAnmb9iMMMOnDJLAT4NjTeGNE7ZCwC89i9B cxZPKU9bGKIwG9exXmHJ3MzfcWjLh3gCotj6wqvcaMpZ73RsFUFgA4Vk01iPhO7/P8H/ bN/w== X-Gm-Message-State: AMCzsaX05nQYNuWs6sQiP/Q75RfQe9iu2f3LyP0DlB6COxUnEzhQlkpa r0FjGv9EidIVUDZyFdpsc6gsnPlB X-Google-Smtp-Source: ABhQp+TstJWRuT6huzglpMsCNT57hvTnPVtUwrY7BD16omB9kyd9zQbWD/qoHR73lKr+TRLyPmSOQg== X-Received: by 10.99.106.67 with SMTP id f64mr12660033pgc.101.1508775897102; Mon, 23 Oct 2017 09:24:57 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.24.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:24:56 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 03/12] tools: bpftool: introduce --json and --pretty options Date: Mon, 23 Oct 2017 09:24:07 -0700 Message-Id: <20171023162416.32753-4-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet These two options can be used to ask for a JSON output (--j or -json), and to make this JSON human-readable (-p or --pretty). A json_writer object is created when JSON is required, and will be used in follow-up commits to produce JSON output. Note that --pretty implies --json. Update for the manual pages and interactive help messages comes in a later patch of the series. Signed-off-by: Quentin Monnet Acked-by: Daniel Borkmann --- tools/bpf/bpftool/main.c | 33 ++++++++++++++++++++++++++++++--- tools/bpf/bpftool/main.h | 5 +++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 613e3c75f78a..14bfc17cd4de 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -51,6 +51,9 @@ const char *bin_name; static int last_argc; static char **last_argv; static int (*last_do_help)(int argc, char **argv); +json_writer_t *json_wtr; +bool pretty_output; +bool json_output; void usage(void) { @@ -217,22 +220,32 @@ static int do_batch(int argc, char **argv) int main(int argc, char **argv) { static const struct option options[] = { + { "json", no_argument, NULL, 'j' }, { "help", no_argument, NULL, 'h' }, + { "pretty", no_argument, NULL, 'p' }, { "version", no_argument, NULL, 'V' }, { 0 } }; - int opt; + int opt, ret; last_do_help = do_help; + pretty_output = false; + json_output = false; bin_name = argv[0]; - while ((opt = getopt_long(argc, argv, "Vh", + while ((opt = getopt_long(argc, argv, "Vhpj", options, NULL)) >= 0) { switch (opt) { case 'V': return do_version(argc, argv); case 'h': return do_help(argc, argv); + case 'p': + pretty_output = true; + /* fall through */ + case 'j': + json_output = true; + break; default: usage(); } @@ -243,7 +256,21 @@ int main(int argc, char **argv) if (argc < 0) usage(); + if (json_output) { + json_wtr = jsonw_new(stdout); + if (!json_wtr) { + err("failed to create JSON writer\n"); + return -1; + } + jsonw_pretty(json_wtr, pretty_output); + } + bfd_init(); - return cmd_select(cmds, argc, argv, do_help); + ret = cmd_select(cmds, argc, argv, do_help); + + if (json_output) + jsonw_destroy(&json_wtr); + + return ret; } diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 41e6c7d3fcad..15927fc9fb31 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -43,6 +43,8 @@ #include #include +#include "json_writer.h" + #define err(msg...) fprintf(stderr, "Error: " msg) #define warn(msg...) fprintf(stderr, "Warning: " msg) #define info(msg...) fprintf(stderr, msg) @@ -66,6 +68,9 @@ enum bpf_obj_type { extern const char *bin_name; +extern json_writer_t *json_wtr; +extern bool json_output; + bool is_prefix(const char *pfx, const char *str); void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep); void usage(void) __attribute__((noreturn)); From patchwork Mon Oct 23 16:24:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829406 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="WsUq40Ty"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMG46W1Mz9tXC for ; Tue, 24 Oct 2017 03:25:48 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751779AbdJWQZr (ORCPT ); Mon, 23 Oct 2017 12:25:47 -0400 Received: from mail-pg0-f67.google.com ([74.125.83.67]:49637 "EHLO mail-pg0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751514AbdJWQY6 (ORCPT ); Mon, 23 Oct 2017 12:24:58 -0400 Received: by mail-pg0-f67.google.com with SMTP id g6so12169439pgn.6 for ; Mon, 23 Oct 2017 09:24:58 -0700 (PDT) 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=4MWIBpwYJ5IXPrsRZtpWdRkRlTLnkrpCaf75wZSi6ZI=; b=WsUq40TyHjhNWhTgffWHA4i4CGgVLGxdrWrCmSfs3pcjg8A25zKJcv/YVi7RX/TIpR OcYM20Fca6NbQISKh8Vsj2hMzFudUWcbHYmgJkHbES/dkm3DRhoSnmezlRbZ3zmnnGkD S/xYKPDvqGaSbgQzieAzNV2v98PqQtqelqqAOwUZgX9wQE9KsPghQ1JzF7Tu37QZQ5kT su7UddxEyDyewZMo6kZWCkHTHhgpu0XYe+bPtBKZEUHbXPG2oh4Z84qSGwyA5H7D+wf/ ZmlbxiLHPHxE4cxVy25nziL+dceauqNp1IJMTMABNX5ivelDPzNPRBTSahOSSrxHd8tw Ahxg== 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=4MWIBpwYJ5IXPrsRZtpWdRkRlTLnkrpCaf75wZSi6ZI=; b=kz9dZSxJU7cw96Op4Wwq9ShMJ/iCHO0yV6Y+ZTKVYm2UNaRHp0LqUlY+sdJaYbIkvv fNESgUyMgs6798kiMfu/RI1dfHxgLlreLTJeOQI/m+4hHx5P5t4qnR+w3jBPu6pPEsKO wKjqfvjravGlQ6u2CBC3QZCc80SgQs2ZIb7VjEJyuR6FrjT3drxycROHJ7noXIOGp3D1 Un8Uv5zUf7TtWhet7VFf26ijyLk6Laoap17payh5g2zq49SrjftQu456yUwDtvdoEInL 3t4/EC1IPibPinKUExqMXXIB4ZWdAJHH3aCnQNU2lV0KFvES2/r3D3qsb5k1Hbx3HTZK uG3g== X-Gm-Message-State: AMCzsaWFwWt4gi1CH4RV+QjS6etyWwmUzkl0+U8mayqHZ2fUkUEAZYzf gOUqlByLDNvI3i7aWjvUr337pI0n X-Google-Smtp-Source: ABhQp+QJqg51iX22SoW1CcBtTCFeLPnQt4BkQD+KypB6dyUrlzW4OgHK+K4EeKzv0pOrwysV+As88A== X-Received: by 10.159.255.1 with SMTP id bi1mr10641222plb.300.1508775897888; Mon, 23 Oct 2017 09:24:57 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.24.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:24:57 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 04/12] tools: bpftool: add JSON output for `bpftool prog show *` command Date: Mon, 23 Oct 2017 09:24:08 -0700 Message-Id: <20171023162416.32753-5-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet Reuse the json_writer API introduced in an earlier commit to make bpftool able to generate JSON output on `bpftool prog show *` commands. For readability, the code from show_prog() has been split into two functions, one for plain output, one for JSON. Outputs from sample programs have been successfully tested against a JSON validator. Signed-off-by: Quentin Monnet Acked-by: Daniel Borkmann --- tools/bpf/bpftool/prog.c | 139 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 107 insertions(+), 32 deletions(-) diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 7838206a455b..f373f2baef5a 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -195,51 +195,100 @@ static void show_prog_maps(int fd, u32 num_maps) if (err || !info.nr_map_ids) return; - printf(" map_ids "); - for (i = 0; i < info.nr_map_ids; i++) - printf("%u%s", map_ids[i], - i == info.nr_map_ids - 1 ? "" : ","); + if (json_output) { + jsonw_name(json_wtr, "map_ids"); + jsonw_start_array(json_wtr); + for (i = 0; i < info.nr_map_ids; i++) + jsonw_uint(json_wtr, map_ids[i]); + jsonw_end_array(json_wtr); + } else { + printf(" map_ids "); + for (i = 0; i < info.nr_map_ids; i++) + printf("%u%s", map_ids[i], + i == info.nr_map_ids - 1 ? "" : ","); + } } -static int show_prog(int fd) +static void print_prog_json(struct bpf_prog_info *info, int fd) { - struct bpf_prog_info info = {}; - __u32 len = sizeof(info); char *memlock; - int err; - err = bpf_obj_get_info_by_fd(fd, &info, &len); - if (err) { - err("can't get prog info: %s\n", strerror(errno)); - return -1; + jsonw_start_object(json_wtr); + jsonw_uint_field(json_wtr, "id", info->id); + if (info->type < ARRAY_SIZE(prog_type_name)) + jsonw_string_field(json_wtr, "type", + prog_type_name[info->type]); + else + jsonw_uint_field(json_wtr, "type", info->type); + + if (*info->name) + jsonw_string_field(json_wtr, "name", info->name); + + jsonw_name(json_wtr, "tag"); + jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", + info->tag[0], info->tag[1], info->tag[2], info->tag[3], + info->tag[4], info->tag[5], info->tag[6], info->tag[7]); + + if (info->load_time) { + char buf[32]; + + print_boot_time(info->load_time, buf, sizeof(buf)); + + /* Piggy back on load_time, since 0 uid is a valid one */ + jsonw_string_field(json_wtr, "loaded_at", buf); + jsonw_uint_field(json_wtr, "uid", info->created_by_uid); } - printf("%u: ", info.id); - if (info.type < ARRAY_SIZE(prog_type_name)) - printf("%s ", prog_type_name[info.type]); + jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); + + if (info->jited_prog_len) { + jsonw_bool_field(json_wtr, "jited", true); + jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); + } else { + jsonw_bool_field(json_wtr, "jited", false); + } + + memlock = get_fdinfo(fd, "memlock"); + if (memlock) + jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); + free(memlock); + + if (info->nr_map_ids) + show_prog_maps(fd, info->nr_map_ids); + + jsonw_end_object(json_wtr); +} + +static void print_prog_plain(struct bpf_prog_info *info, int fd) +{ + char *memlock; + + printf("%u: ", info->id); + if (info->type < ARRAY_SIZE(prog_type_name)) + printf("%s ", prog_type_name[info->type]); else - printf("type %u ", info.type); + printf("type %u ", info->type); - if (*info.name) - printf("name %s ", info.name); + if (*info->name) + printf("name %s ", info->name); printf("tag "); - fprint_hex(stdout, info.tag, BPF_TAG_SIZE, ""); + fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); printf("\n"); - if (info.load_time) { + if (info->load_time) { char buf[32]; - print_boot_time(info.load_time, buf, sizeof(buf)); + print_boot_time(info->load_time, buf, sizeof(buf)); /* Piggy back on load_time, since 0 uid is a valid one */ - printf("\tloaded_at %s uid %u\n", buf, info.created_by_uid); + printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); } - printf("\txlated %uB", info.xlated_prog_len); + printf("\txlated %uB", info->xlated_prog_len); - if (info.jited_prog_len) - printf(" jited %uB", info.jited_prog_len); + if (info->jited_prog_len) + printf(" jited %uB", info->jited_prog_len); else printf(" not jited"); @@ -248,16 +297,35 @@ static int show_prog(int fd) printf(" memlock %sB", memlock); free(memlock); - if (info.nr_map_ids) - show_prog_maps(fd, info.nr_map_ids); + if (info->nr_map_ids) + show_prog_maps(fd, info->nr_map_ids); printf("\n"); +} + +static int show_prog(int fd) +{ + struct bpf_prog_info info = {}; + __u32 len = sizeof(info); + int err; + + err = bpf_obj_get_info_by_fd(fd, &info, &len); + if (err) { + err("can't get prog info: %s\n", strerror(errno)); + return -1; + } + + if (json_output) + print_prog_json(&info, fd); + else + print_prog_plain(&info, fd); return 0; } static int do_show(int argc, char **argv) -{ __u32 id = 0; +{ + __u32 id = 0; int err; int fd; @@ -272,6 +340,8 @@ static int do_show(int argc, char **argv) if (argc) return BAD_ARG(); + if (json_output) + jsonw_start_array(json_wtr); while (true) { err = bpf_prog_get_next_id(id, &id); if (err) { @@ -282,23 +352,28 @@ static int do_show(int argc, char **argv) err("can't get next program: %s\n", strerror(errno)); if (errno == EINVAL) err("kernel too old?\n"); - return -1; + err = -1; + break; } fd = bpf_prog_get_fd_by_id(id); if (fd < 0) { err("can't get prog by id (%u): %s\n", id, strerror(errno)); - return -1; + err = -1; + break; } err = show_prog(fd); close(fd); if (err) - return err; + break; } - return 0; + if (json_output) + jsonw_end_array(json_wtr); + + return err; } static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...) From patchwork Mon Oct 23 16:24:09 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829397 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="r3wGz36M"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMFG4Gh6z9t5s for ; Tue, 24 Oct 2017 03:25:06 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751632AbdJWQZE (ORCPT ); Mon, 23 Oct 2017 12:25:04 -0400 Received: from mail-pf0-f195.google.com ([209.85.192.195]:43350 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751587AbdJWQY7 (ORCPT ); Mon, 23 Oct 2017 12:24:59 -0400 Received: by mail-pf0-f195.google.com with SMTP id a8so17478939pfc.0 for ; Mon, 23 Oct 2017 09:24:59 -0700 (PDT) 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=qqhXsyJg2C4E/HS5p6xl0naruxfU5b8HVKuBpX/1kb4=; b=r3wGz36MMh/QkCru51YX00Ix0VD201k1hefKSb5C8elZWT//76s9RUSc1usNxhM2uR 6m8opANnfjNwkJx6/XY2ahuFq15LHoiwpSpalvk6UncsZXsRiZrTKs02AQ18YVIEXNOA 5ZnqPJYNFh60T/mXNLKRPJrRa9OSnW2km6ZJK9vIjebmyXDI9w8z2HRCf9Wnb5G7qKLe r3+iNguJyr1PXen2Q1kBB1M/tJ1tf1GOkOQTajnE/Xs1Ja94iz6EpirxcU4qW4x/jZiC vFu7EJKC2yAKYEIfP0s7aOipowXEs3E5W29vWJCgpydU7c1DziAsECkRwjoHlG5Lsudp xgMg== 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=qqhXsyJg2C4E/HS5p6xl0naruxfU5b8HVKuBpX/1kb4=; b=mZ2XJ/76utrksFESLb3COnEFr8h6Yy50WL7mPbb26skobSNT9V0eesL97DmB7eT7j6 CwHEceiMBb+FuJyG8+DeSpKHx7HTKtKpkbDLci064SJbEaRaf26R4q+Yj45EPUaiUWiS py5J3Z3xkp6bsaavmeU2Jhv0BwJDyTTwOvlVtrgjF3+tqfN/gP+6jMnEoyFwnr4YNZB2 VMZTi+5h7Oz9gFFzmBFvCWOVsXkLEkDfMaVmMudTf9rNMqE4n50Jropc2Hn1vFT06Hcm nJBnn6pEQNR2rmPa2R/4ykBxVby9/Vs5IdF6nW8Azvk7mD89DI+MMC6rAgV1A51bKVyL cZxw== X-Gm-Message-State: AMCzsaVYSdvxH9pEjk+CPKhyPtdsf0N0a2Wr74dmu6Jex4lqvMuCq8FM juhj3P4ClC26+JqGedfZpwSTozWU X-Google-Smtp-Source: ABhQp+SDcD38rcTvo1dMYB9NKjJICGgoEoe5TUmQD5uqZ5SVhxWaezK7qxpS6lLqMZKZRz60u+vv/A== X-Received: by 10.84.148.203 with SMTP id y11mr10679114plg.198.1508775899055; Mon, 23 Oct 2017 09:24:59 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.24.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:24:58 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 05/12] tools: bpftool: add JSON output for `bpftool prog dump jited *` command Date: Mon, 23 Oct 2017 09:24:09 -0700 Message-Id: <20171023162416.32753-6-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet Reuse the json_writer API introduced in an earlier commit to make bpftool able to generate JSON output on `bpftool prog show *` commands. A new printing function is created to be passed as an argument to the disassembler. Similarly to plain output, opcodes are printed on request. Outputs from sample programs have been successfully tested against a JSON validator. Signed-off-by: Quentin Monnet Acked-by: Daniel Borkmann --- tools/bpf/bpftool/jit_disasm.c | 86 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/tools/bpf/bpftool/jit_disasm.c b/tools/bpf/bpftool/jit_disasm.c index 70e480b59e9d..5937e134e408 100644 --- a/tools/bpf/bpftool/jit_disasm.c +++ b/tools/bpf/bpftool/jit_disasm.c @@ -10,6 +10,7 @@ * Licensed under the GNU General Public License, version 2.0 (GPLv2) */ +#include #include #include #include @@ -21,6 +22,9 @@ #include #include +#include "json_writer.h" +#include "main.h" + static void get_exec_path(char *tpath, size_t size) { ssize_t len; @@ -39,6 +43,38 @@ static void get_exec_path(char *tpath, size_t size) free(path); } +static int oper_count; +static int fprintf_json(void *out, const char *fmt, ...) +{ + va_list ap; + char *s; + + va_start(ap, fmt); + if (!oper_count) { + int i; + + s = va_arg(ap, char *); + + /* Strip trailing spaces */ + i = strlen(s) - 1; + while (s[i] == ' ') + s[i--] = '\0'; + + jsonw_string_field(json_wtr, "operation", s); + jsonw_name(json_wtr, "operands"); + jsonw_start_array(json_wtr); + oper_count++; + } else if (!strcmp(fmt, ",")) { + /* Skip */ + } else { + s = va_arg(ap, char *); + jsonw_string(json_wtr, s); + oper_count++; + } + va_end(ap); + return 0; +} + void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes) { disassembler_ftype disassemble; @@ -57,7 +93,12 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes) assert(bfdf); assert(bfd_check_format(bfdf, bfd_object)); - init_disassemble_info(&info, stdout, (fprintf_ftype) fprintf); + if (json_output) + init_disassemble_info(&info, stdout, + (fprintf_ftype) fprintf_json); + else + init_disassemble_info(&info, stdout, + (fprintf_ftype) fprintf); info.arch = bfd_get_arch(bfdf); info.mach = bfd_get_mach(bfdf); info.buffer = image; @@ -68,20 +109,53 @@ void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes) disassemble = disassembler(bfdf); assert(disassemble); + if (json_output) + jsonw_start_array(json_wtr); do { - printf("%4x:\t", pc); + if (json_output) { + jsonw_start_object(json_wtr); + oper_count = 0; + jsonw_name(json_wtr, "pc"); + jsonw_printf(json_wtr, "\"0x%x\"", pc); + } else { + printf("%4x:\t", pc); + } count = disassemble(pc, &info); + if (json_output) { + /* Operand array, was started in fprintf_json. Before + * that, make sure we have a _null_ value if no operand + * other than operation code was present. + */ + if (oper_count == 1) + jsonw_null(json_wtr); + jsonw_end_array(json_wtr); + } if (opcodes) { - printf("\n\t"); - for (i = 0; i < count; ++i) - printf("%02x ", (uint8_t) image[pc + i]); + if (json_output) { + jsonw_name(json_wtr, "opcodes"); + jsonw_start_array(json_wtr); + for (i = 0; i < count; ++i) + jsonw_printf(json_wtr, "\"0x%02hhx\"", + (uint8_t)image[pc + i]); + jsonw_end_array(json_wtr); + } else { + printf("\n\t"); + for (i = 0; i < count; ++i) + printf("%02x ", + (uint8_t)image[pc + i]); + } } - printf("\n"); + if (json_output) + jsonw_end_object(json_wtr); + else + printf("\n"); pc += count; } while (count > 0 && pc < len); + if (json_output) + jsonw_end_array(json_wtr); bfd_close(bfdf); } From patchwork Mon Oct 23 16:24:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829401 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="AwfE1wZf"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMFh4BRtz9t5s for ; Tue, 24 Oct 2017 03:25:28 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751735AbdJWQZ0 (ORCPT ); Mon, 23 Oct 2017 12:25:26 -0400 Received: from mail-pf0-f193.google.com ([209.85.192.193]:45742 "EHLO mail-pf0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751608AbdJWQZB (ORCPT ); Mon, 23 Oct 2017 12:25:01 -0400 Received: by mail-pf0-f193.google.com with SMTP id d28so17482330pfe.2 for ; Mon, 23 Oct 2017 09:25:00 -0700 (PDT) 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=2thUwJrMrUWwcxusl6RPFDkkDLgPn2ufAPmNVdWhXZI=; b=AwfE1wZfn6zQBHxc+C5rqzvOODHYJ74h/bI6NCCax1Y9naMMTE0yoKkOmYeiL1QMmR fwzabAnuOP7L5nWuRyGTo5vAxH5d3iSoi7bDG2uURZgKwgEbN6azxYuZzfJX39os0p4x 91dNai1x5xDuYFXcvxAKprRn1uoc9GckjUlAaSRYM4hkBNVc6gapwbZ7vxSwYbOWeccF f2Ep+GpbRoOJTp7e9PNJ0wJRu6ZWQclYpHzrNW/aqhXiv7HSYJc7QiY7obO2xBVvQ7s1 OS1v3rWGwq5Hh2YdhYLG8cNVFcncdv8oYKKSciQwTzdJZIkz0vdIpkTGM6XoaiaUKTNF J5GQ== 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=2thUwJrMrUWwcxusl6RPFDkkDLgPn2ufAPmNVdWhXZI=; b=OoRWSP/q6f0B+0fhGvOdPDDMzilIOvRzKvDk/mQ9o5Nm8ihiGHqQoAXYNmDQgMrtba ZzaNM7UekuoNxwS4WY3XbOQVmhWh26KWQWf99NQJtaOJEOWYzeIFusAFBb32OFCyGEzC gdYYdORHS0n+9Qu5JgXt5GD3+xjUgUR75Er+irIaCzYADZFuJ3bAlS6tsEE1E6XUhD78 uQ7UFQdr0zcZRh+JbjbB3HGmY5SB1qnjhHgMR0QkD2JU5ltJzQyIcOFbGG9ohyEkkMoR ca2wcNz5JJL88FXw00qN2vfBvrTpneuJ0XdiZw4+tATtpP/DBkjoCuoE+MvqEgeFPRK1 gPQQ== X-Gm-Message-State: AMCzsaVX855XQczOJfz7yFPgGbTXRrEaYop31PpUWKlydGaqIKBcaxB0 aarj/lXcFZtniYwsI5S/XO89WLDH X-Google-Smtp-Source: ABhQp+R/EuH8pnuUyMhCJvZBDJSiCQGAmZklKn33Bd5zlH3SiBuLcCGFKsyY6+uEcODwO7ZuKZKszw== X-Received: by 10.101.82.8 with SMTP id o8mr12447690pgp.422.1508775899952; Mon, 23 Oct 2017 09:24:59 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.24.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:24:59 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 06/12] tools: bpftool: add JSON output for `bpftool prog dump xlated *` command Date: Mon, 23 Oct 2017 09:24:10 -0700 Message-Id: <20171023162416.32753-7-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet Add a new printing function to dump translated eBPF instructions as JSON. As for plain output, opcodes are printed only on request (when `opcodes` is provided on the command line). The disassembled output is generated by the same code that is used by the kernel verifier. Example output: $ bpftool --json --pretty prog dump xlated id 1 [{ "disasm": "(bf) r6 = r1" },{ "disasm": "(61) r7 = *(u32 *)(r6 +16)" },{ "disasm": "(95) exit" } ] $ bpftool --json --pretty prog dump xlated id 1 opcodes [{ "disasm": "(bf) r6 = r1", "opcodes": { "code": "0xbf", "src_reg": "0x1", "dst_reg": "0x6", "off": ["0x00","0x00" ], "imm": ["0x00","0x00","0x00","0x00" ] } },{ "disasm": "(61) r7 = *(u32 *)(r6 +16)", "opcodes": { "code": "0x61", "src_reg": "0x6", "dst_reg": "0x7", "off": ["0x10","0x00" ], "imm": ["0x00","0x00","0x00","0x00" ] } },{ "disasm": "(95) exit", "opcodes": { "code": "0x95", "src_reg": "0x0", "dst_reg": "0x0", "off": ["0x00","0x00" ], "imm": ["0x00","0x00","0x00","0x00" ] } } ] Signed-off-by: Quentin Monnet Acked-by: Daniel Borkmann --- tools/bpf/bpftool/common.c | 10 ++++++ tools/bpf/bpftool/json_writer.c | 8 +++++ tools/bpf/bpftool/json_writer.h | 2 ++ tools/bpf/bpftool/main.h | 1 + tools/bpf/bpftool/prog.c | 70 +++++++++++++++++++++++++++++++++++++++-- 5 files changed, 89 insertions(+), 2 deletions(-) diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c index df8396a0c400..e7a756b8ee21 100644 --- a/tools/bpf/bpftool/common.c +++ b/tools/bpf/bpftool/common.c @@ -214,3 +214,13 @@ char *get_fdinfo(int fd, const char *key) fclose(fdi); return NULL; } + +void print_hex_data_json(uint8_t *data, size_t len) +{ + unsigned int i; + + jsonw_start_array(json_wtr); + for (i = 0; i < len; i++) + jsonw_printf(json_wtr, "\"0x%02hhx\"", data[i]); + jsonw_end_array(json_wtr); +} diff --git a/tools/bpf/bpftool/json_writer.c b/tools/bpf/bpftool/json_writer.c index 6b77d288cce2..c6eef76322ae 100644 --- a/tools/bpf/bpftool/json_writer.c +++ b/tools/bpf/bpftool/json_writer.c @@ -156,6 +156,14 @@ void jsonw_name(json_writer_t *self, const char *name) putc(' ', self->out); } +void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap) +{ + jsonw_eor(self); + putc('"', self->out); + vfprintf(self->out, fmt, ap); + putc('"', self->out); +} + void jsonw_printf(json_writer_t *self, const char *fmt, ...) { va_list ap; diff --git a/tools/bpf/bpftool/json_writer.h b/tools/bpf/bpftool/json_writer.h index 1516aafba59d..0fa2fb1b6351 100644 --- a/tools/bpf/bpftool/json_writer.h +++ b/tools/bpf/bpftool/json_writer.h @@ -17,6 +17,7 @@ #include #include +#include /* Opaque class structure */ typedef struct json_writer json_writer_t; @@ -33,6 +34,7 @@ void jsonw_pretty(json_writer_t *self, bool on); void jsonw_name(json_writer_t *self, const char *name); /* Add value */ +void jsonw_vprintf_enquote(json_writer_t *self, const char *fmt, va_list ap); void jsonw_printf(json_writer_t *self, const char *fmt, ...); void jsonw_string(json_writer_t *self, const char *value); void jsonw_bool(json_writer_t *self, bool value); diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 15927fc9fb31..693fc9710be1 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -95,5 +95,6 @@ int do_map(int argc, char **arg); int prog_parse_fd(int *argc, char ***argv); void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes); +void print_hex_data_json(uint8_t *data, size_t len); #endif diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index f373f2baef5a..43e49799a624 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -385,7 +385,7 @@ static void print_insn(struct bpf_verifier_env *env, const char *fmt, ...) va_end(args); } -static void dump_xlated(void *buf, unsigned int len, bool opcodes) +static void dump_xlated_plain(void *buf, unsigned int len, bool opcodes) { struct bpf_insn *insn = buf; bool double_insn = false; @@ -414,6 +414,69 @@ static void dump_xlated(void *buf, unsigned int len, bool opcodes) } } +static void print_insn_json(struct bpf_verifier_env *env, const char *fmt, ...) +{ + unsigned int l = strlen(fmt); + char chomped_fmt[l]; + va_list args; + + va_start(args, fmt); + if (l > 0) { + strncpy(chomped_fmt, fmt, l - 1); + chomped_fmt[l - 1] = '\0'; + } + jsonw_vprintf_enquote(json_wtr, chomped_fmt, args); + va_end(args); +} + +static void dump_xlated_json(void *buf, unsigned int len, bool opcodes) +{ + struct bpf_insn *insn = buf; + bool double_insn = false; + unsigned int i; + + jsonw_start_array(json_wtr); + for (i = 0; i < len / sizeof(*insn); i++) { + if (double_insn) { + double_insn = false; + continue; + } + double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW); + + jsonw_start_object(json_wtr); + jsonw_name(json_wtr, "disasm"); + print_bpf_insn(print_insn_json, NULL, insn + i, true); + + if (opcodes) { + jsonw_name(json_wtr, "opcodes"); + jsonw_start_object(json_wtr); + + jsonw_name(json_wtr, "code"); + jsonw_printf(json_wtr, "\"0x%02hhx\"", insn[i].code); + + jsonw_name(json_wtr, "src_reg"); + jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].src_reg); + + jsonw_name(json_wtr, "dst_reg"); + jsonw_printf(json_wtr, "\"0x%hhx\"", insn[i].dst_reg); + + jsonw_name(json_wtr, "off"); + print_hex_data_json((uint8_t *)(&insn[i].off), 2); + + jsonw_name(json_wtr, "imm"); + if (double_insn && i < len - 1) + print_hex_data_json((uint8_t *)(&insn[i].imm), + 12); + else + print_hex_data_json((uint8_t *)(&insn[i].imm), + 4); + jsonw_end_object(json_wtr); + } + jsonw_end_object(json_wtr); + } + jsonw_end_array(json_wtr); +} + static int do_dump(int argc, char **argv) { struct bpf_prog_info info = {}; @@ -523,7 +586,10 @@ static int do_dump(int argc, char **argv) if (member_len == &info.jited_prog_len) disasm_print_insn(buf, *member_len, opcodes); else - dump_xlated(buf, *member_len, opcodes); + if (json_output) + dump_xlated_json(buf, *member_len, opcodes); + else + dump_xlated_plain(buf, *member_len, opcodes); } free(buf); From patchwork Mon Oct 23 16:24:11 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829402 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="U8Y5VIlK"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMFm5ytpz9tX8 for ; Tue, 24 Oct 2017 03:25:32 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751731AbdJWQZ0 (ORCPT ); Mon, 23 Oct 2017 12:25:26 -0400 Received: from mail-pg0-f65.google.com ([74.125.83.65]:49101 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751609AbdJWQZB (ORCPT ); Mon, 23 Oct 2017 12:25:01 -0400 Received: by mail-pg0-f65.google.com with SMTP id v78so12162033pgb.5 for ; Mon, 23 Oct 2017 09:25:01 -0700 (PDT) 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=YSFBxLvGRC2o/PZB0DIercIh6RtKcm+XPzFGVMRqACU=; b=U8Y5VIlK5XgZTOQrKN22Ix5HuB64dD+u/svSt9RxF33C4JK+Z/cXY75AUVnFOtgpMt K4Om09r/rUOZNGQ9BiLmIMhi+kyhohyLaHqoB3HoKJ2tEzP2W3bKHcps3BwVzLJVZDeS ttChKGhfOOByQ9L5fx5bjuFzMyJgvrQ6lzbb1EQTnbwf2rOukn2aKqNkrmSwHkswNKcg 72E4zVJ4rmGO+589h5hohUkLk31wLbU+KHzy4+1QjFvpWSpIW9Xsd7Cm7crUmKW+iO1r SUshuhuW5W4atJaTwgwvRPAXiZvC2gSakopRQmbI66Z2wZUbIT1pDYQZgVOnYAoIq5h0 Yn5w== 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=YSFBxLvGRC2o/PZB0DIercIh6RtKcm+XPzFGVMRqACU=; b=pJO9Heu8BpNGrHP3b7kH5iPx4Fr8ddM4HcW0y+O6Lz0i/2owvlyIqabXwcYOTdzMf+ MWN7x9cMq3rdotssjWD1rKouXfCjxk+NTy2CEqA+C+tZsbEjl3ij4SFAK8PxoVKWbN8v TtHqvTumpvn043e5akxCsZZP8XT9wk3Df+OChylqNyicL5AkQ26Jdjf18zZ5dKLjxLn/ Aowu8DSyGwb1BpXA0Pb/Ao/a2uuXO4nU+1vvHTMgD0SKcQXMhU6Eca3hspd125HKu6uQ TEfen77a5dY0mSX0gW5XAnW5RJVz7yEr/8oREZItd+q4s/98KEZSnR7MZVRB7V3kpSYb gHYg== X-Gm-Message-State: AMCzsaV3RSL1N3cd0wghEWr+eAevGfRNDMwmm9BcvHnJMuCXlWUnN8js ms7MwiBOhZQaxFmrsBHufgKneGag X-Google-Smtp-Source: ABhQp+Qa6UayZnaA3OrFXKPysARNS7EWmo0C8+kvRCHz4ek24gi/j4CgcLXrdlvmdcJQcsJpzAbO7A== X-Received: by 10.84.176.131 with SMTP id v3mr10725100plb.208.1508775900827; Mon, 23 Oct 2017 09:25:00 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.24.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:25:00 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 07/12] tools: bpftool: add JSON output for `bpftool map *` commands Date: Mon, 23 Oct 2017 09:24:11 -0700 Message-Id: <20171023162416.32753-8-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet Reuse the json_writer API introduced in an earlier commit to make bpftool able to generate JSON output on `bpftool map { show | dump | lookup | getnext }` commands. Remaining commands produce no output. Some functions have been spit into plain-output and JSON versions in order to remain readable. Outputs for sample maps have been successfully tested against a JSON validator. Signed-off-by: Quentin Monnet Acked-by: Daniel Borkmann --- tools/bpf/bpftool/map.c | 149 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 129 insertions(+), 20 deletions(-) diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index e1004d825392..14d89bfabc66 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -205,8 +205,45 @@ map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len) return fd; } -static void print_entry(struct bpf_map_info *info, unsigned char *key, - unsigned char *value) +static void print_entry_json(struct bpf_map_info *info, unsigned char *key, + unsigned char *value) +{ + jsonw_start_object(json_wtr); + + if (!map_is_per_cpu(info->type)) { + jsonw_name(json_wtr, "key"); + print_hex_data_json(key, info->key_size); + jsonw_name(json_wtr, "value"); + print_hex_data_json(value, info->value_size); + } else { + unsigned int i, n; + + n = get_possible_cpus(); + + jsonw_name(json_wtr, "key"); + print_hex_data_json(key, info->key_size); + + jsonw_name(json_wtr, "values"); + jsonw_start_array(json_wtr); + for (i = 0; i < n; i++) { + jsonw_start_object(json_wtr); + + jsonw_int_field(json_wtr, "cpu", i); + + jsonw_name(json_wtr, "value"); + print_hex_data_json(value + i * info->value_size, + info->value_size); + + jsonw_end_object(json_wtr); + } + jsonw_end_array(json_wtr); + } + + jsonw_end_object(json_wtr); +} + +static void print_entry_plain(struct bpf_map_info *info, unsigned char *key, + unsigned char *value) { if (!map_is_per_cpu(info->type)) { bool single_line, break_names; @@ -370,7 +407,41 @@ static int parse_elem(char **argv, struct bpf_map_info *info, return -1; } -static int show_map_close(int fd, struct bpf_map_info *info) +static int show_map_close_json(int fd, struct bpf_map_info *info) +{ + char *memlock; + + memlock = get_fdinfo(fd, "memlock"); + close(fd); + + jsonw_start_object(json_wtr); + + jsonw_uint_field(json_wtr, "id", info->id); + if (info->type < ARRAY_SIZE(map_type_name)) + jsonw_string_field(json_wtr, "type", + map_type_name[info->type]); + else + jsonw_uint_field(json_wtr, "type", info->type); + + if (*info->name) + jsonw_string_field(json_wtr, "name", info->name); + + jsonw_name(json_wtr, "flags"); + jsonw_printf(json_wtr, "%#x", info->map_flags); + jsonw_uint_field(json_wtr, "bytes_key", info->key_size); + jsonw_uint_field(json_wtr, "bytes_value", info->value_size); + jsonw_uint_field(json_wtr, "max_entries", info->max_entries); + + if (memlock) + jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); + free(memlock); + + jsonw_end_object(json_wtr); + + return 0; +} + +static int show_map_close_plain(int fd, struct bpf_map_info *info) { char *memlock; @@ -412,12 +483,17 @@ static int do_show(int argc, char **argv) if (fd < 0) return -1; - return show_map_close(fd, &info); + if (json_output) + return show_map_close_json(fd, &info); + else + return show_map_close_plain(fd, &info); } if (argc) return BAD_ARG(); + if (json_output) + jsonw_start_array(json_wtr); while (true) { err = bpf_map_get_next_id(id, &id); if (err) { @@ -443,8 +519,13 @@ static int do_show(int argc, char **argv) return -1; } - show_map_close(fd, &info); + if (json_output) + show_map_close_json(fd, &info); + else + show_map_close_plain(fd, &info); } + if (json_output) + jsonw_end_array(json_wtr); return errno == ENOENT ? 0 : -1; } @@ -480,6 +561,8 @@ static int do_dump(int argc, char **argv) } prev_key = NULL; + if (json_output) + jsonw_start_array(json_wtr); while (true) { err = bpf_map_get_next_key(fd, prev_key, key); if (err) { @@ -489,7 +572,10 @@ static int do_dump(int argc, char **argv) } if (!bpf_map_lookup_elem(fd, key, value)) { - print_entry(&info, key, value); + if (json_output) + print_entry_json(&info, key, value); + else + print_entry_plain(&info, key, value); } else { info("can't lookup element with key: "); fprint_hex(stderr, key, info.key_size, " "); @@ -500,7 +586,11 @@ static int do_dump(int argc, char **argv) num_elems++; } - printf("Found %u element%s\n", num_elems, num_elems != 1 ? "s" : ""); + if (json_output) + jsonw_end_array(json_wtr); + else + printf("Found %u element%s\n", num_elems, + num_elems != 1 ? "s" : ""); exit_free: free(key); @@ -584,11 +674,18 @@ static int do_lookup(int argc, char **argv) err = bpf_map_lookup_elem(fd, key, value); if (!err) { - print_entry(&info, key, value); + if (json_output) + print_entry_json(&info, key, value); + else + print_entry_plain(&info, key, value); } else if (errno == ENOENT) { - printf("key:\n"); - fprint_hex(stdout, key, info.key_size, " "); - printf("\n\nNot found\n"); + if (json_output) { + jsonw_null(json_wtr); + } else { + printf("key:\n"); + fprint_hex(stdout, key, info.key_size, " "); + printf("\n\nNot found\n"); + } } else { err("lookup failed: %s\n", strerror(errno)); } @@ -640,18 +737,30 @@ static int do_getnext(int argc, char **argv) goto exit_free; } - if (key) { - printf("key:\n"); - fprint_hex(stdout, key, info.key_size, " "); - printf("\n"); + if (json_output) { + jsonw_start_object(json_wtr); + if (key) { + jsonw_name(json_wtr, "key"); + print_hex_data_json(key, info.key_size); + } else { + jsonw_null_field(json_wtr, "key"); + } + jsonw_name(json_wtr, "next_key"); + print_hex_data_json(nextkey, info.key_size); + jsonw_end_object(json_wtr); } else { - printf("key: None\n"); + if (key) { + printf("key:\n"); + fprint_hex(stdout, key, info.key_size, " "); + printf("\n"); + } else { + printf("key: None\n"); + } + printf("next key:\n"); + fprint_hex(stdout, nextkey, info.key_size, " "); + printf("\n"); } - printf("next key:\n"); - fprint_hex(stdout, nextkey, info.key_size, " "); - printf("\n"); - exit_free: free(nextkey); free(key); From patchwork Mon Oct 23 16:24:12 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829403 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="0qnTuMfu"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMFs2Xc1z9t5s for ; Tue, 24 Oct 2017 03:25:37 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751725AbdJWQZZ (ORCPT ); Mon, 23 Oct 2017 12:25:25 -0400 Received: from mail-pg0-f66.google.com ([74.125.83.66]:44744 "EHLO mail-pg0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751612AbdJWQZC (ORCPT ); Mon, 23 Oct 2017 12:25:02 -0400 Received: by mail-pg0-f66.google.com with SMTP id j3so12171108pga.1 for ; Mon, 23 Oct 2017 09:25:02 -0700 (PDT) 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=6wuT6S31NPu1gwBuJRxr1DSCwJvcGRUP/43Cgro4IG8=; b=0qnTuMfu+eKXaGKhmttVFQi5aIRAdPI0ZoPyUKj89lD71Bxodykqb4KlmopjeQh/vX kC84zqFa/eM/f1TqSQPVU+XjlFDCNGBtN7gJ/m5z5m1khNkRntup3lZyvt75CNDS4QSD Bq9i0brUp6OOqHJMsCRxlD2rDIWqojOS098FBLYFWRVOfzUUpzcAwzpAQBI0d+R7PCcd Cpk5X8qpM7zLpzynQ0AatPB2iTfsq4zhnN9plkWvrPnxSWR81zy8w2y4QD1jMf8y2pWm hXbIjLhdX+jT2wkUgDfXixAU0zSYhZp2VIOTZ2VVnDs32u26hK4go6ge6xmw9oTqYi3S jiLQ== 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=6wuT6S31NPu1gwBuJRxr1DSCwJvcGRUP/43Cgro4IG8=; b=Q7xWzFYB2syDkg2wfGtKTa7uDs1Gff/C+TPN2SkfuBinYxnCG4fYa2rvjMzyhxAo46 SK0MBHUUWFcSaWOKKSGNH9BnOat3bXqHk0HaHKjf9SJUgmv+zOsEIRYzPj/oYxpbCS6k zkB6IZGCnOGhlGfGTeiI0hDKdZ505ebXuoIC5Ycn3GzKmc4G9ddswUjurtaNO7Y0H6J8 fBr1Ik/Cqkjs2t4FI0Og+V5uxuRezj/Ac+zZ9jyy7PZa7H6nYitTxqCpO0D2wL8QQhGK DWwhDOKevWFOdLKDMyCVJ6Z3ccT56jp/By8WIrGzrqgNci3uqiX5ZooRRgLVwnD6Qnhp N2+Q== X-Gm-Message-State: AMCzsaVu6iNts0oXJOEahmPjmCyOFT6HjikFh3e6YXBhcMA35Y/eHPlo Te5wfpljM65dBXoo0V2KqUOrOQJJ X-Google-Smtp-Source: ABhQp+Rg3L6JMWQIfthFqeo9wn/qrJxsUOPSN/yWlcobVWDTKk08ISqRX+HCNqiyHL4lkIA/Z0vg1Q== X-Received: by 10.159.194.204 with SMTP id u12mr10582654plz.401.1508775901858; Mon, 23 Oct 2017 09:25:01 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.25.00 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:25:01 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 08/12] tools: bpftool: add JSON output for `bpftool batch file FILE` command Date: Mon, 23 Oct 2017 09:24:12 -0700 Message-Id: <20171023162416.32753-9-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet `bpftool batch file FILE` takes FILE as an argument and executes all the bpftool commands it finds inside (or stops if an error occurs). To obtain a consistent JSON output, create a root JSON array, then for each command create a new object containing two fields: one with the command arguments, the other with the output (which is the JSON object that the command would have produced, if called on its own). Signed-off-by: Quentin Monnet Acked-by: Daniel Borkmann --- tools/bpf/bpftool/main.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 14bfc17cd4de..71b01bf73912 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -155,6 +155,7 @@ static int do_batch(int argc, char **argv) int n_argc; FILE *fp; int err; + int i; if (argc < 2) { err("too few parameters for batch\n"); @@ -174,6 +175,8 @@ static int do_batch(int argc, char **argv) return -1; } + if (json_output) + jsonw_start_array(json_wtr); while (fgets(buf, sizeof(buf), fp)) { if (strlen(buf) == sizeof(buf) - 1) { errno = E2BIG; @@ -197,7 +200,21 @@ static int do_batch(int argc, char **argv) if (!n_argc) continue; + if (json_output) { + jsonw_start_object(json_wtr); + jsonw_name(json_wtr, "command"); + jsonw_start_array(json_wtr); + for (i = 0; i < n_argc; i++) + jsonw_string(json_wtr, n_argv[i]); + jsonw_end_array(json_wtr); + jsonw_name(json_wtr, "output"); + } + err = cmd_select(cmds, n_argc, n_argv, do_help); + + if (json_output) + jsonw_end_object(json_wtr); + if (err) goto err_close; @@ -214,6 +231,9 @@ static int do_batch(int argc, char **argv) err_close: fclose(fp); + if (json_output) + jsonw_end_array(json_wtr); + return err; } From patchwork Mon Oct 23 16:24:13 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829404 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="YJDF0oTH"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMFw5JvMz9t5s for ; Tue, 24 Oct 2017 03:25:40 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751720AbdJWQZY (ORCPT ); Mon, 23 Oct 2017 12:25:24 -0400 Received: from mail-pf0-f195.google.com ([209.85.192.195]:46422 "EHLO mail-pf0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751619AbdJWQZD (ORCPT ); Mon, 23 Oct 2017 12:25:03 -0400 Received: by mail-pf0-f195.google.com with SMTP id p87so17473258pfj.3 for ; Mon, 23 Oct 2017 09:25:03 -0700 (PDT) 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=jmvJYt3XXDCyLfIuAP4d+LfAUKmn9iwMjgC0p8Jry/U=; b=YJDF0oTHb9dXOa1Lz1FWovJfwCfBOXvCq0kW5JYSnfrAmJCdghEnfVdLuRkouQleJj k3g6+QZkawHZDXbPmLpE/1uJNDGg9/zZUam08WkIVmQTA4M3wGpiu1LsGpi9hA1+Srer ZjapQkmup/5PSbbRGJ4u/88OHqbB3Id7P7KwB5Wr+NMfdu1rot1wSQ/MOYz42Er1Pc4W 9Qy1LSktXIGm49+rEHfrj2LJzPrilXeUL6xjhXTtWbqpUOZUziF37ujlAXBYbYC2+iRU U7ENkjiphqFTaw59MhNhu1Z2rLER4YC0kUz7UHGy1oav65cBhp5qMlUYotBQoL52c2jO 5vJQ== 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=jmvJYt3XXDCyLfIuAP4d+LfAUKmn9iwMjgC0p8Jry/U=; b=VFKgVc6RR5p5ezrvI9Ce9q7PBUJNs1Q2Z2XLzYueLzNhfFEU5cJpysmifwKnmn/Oj8 jyL5jsCLQVcT4LDOc3PlqyuPJzO5l0IWEWsUENfDQM9QymHh/aFXuRlrZP8NrgmPbNn1 A/Q0hF5MqzNZ7bGmDPouG67AaJcG75dHIHszjQrMMH6JqGTSAAV2ycsr4/JC/MLXeUlY vbyACqO7ECX82OBgXo3kyjGp5eJE6bQx5nHkuEMMxMLYJMXTfb2qzY0g390JDJ/OUyWT IOg+L8t8lvWG8DJz87CNRzg+jdgB4PXlZq5IQ9/ax+eeKFPq6MF1Bio8JTVZShP8bXNt Ly+A== X-Gm-Message-State: AMCzsaUdqpsRJybERLo0VP2e3njxWLJAoQIs6E8WRFVClCwMXthg9YPk JFKfOR9b8rtxKhm4B4ZQRcz2c7ZH X-Google-Smtp-Source: ABhQp+RmIP3Q8bof8aFiZKHgvo2MEcDzq8tHla2GR/m28b0iDRuz1wHJap+JLj8KqDA6jai3M2QRLQ== X-Received: by 10.84.173.195 with SMTP id p61mr892107plb.138.1508775902674; Mon, 23 Oct 2017 09:25:02 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.25.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:25:02 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 09/12] tools: bpftool: turn err() and info() macros into functions Date: Mon, 23 Oct 2017 09:24:13 -0700 Message-Id: <20171023162416.32753-10-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet Turn err() and info() macros into functions. In order to avoid naming conflicts with variables in the code, rename them as p_err() and p_info() respectively. The behavior of these functions is similar to the one of the macros for plain output. However, when JSON output is requested, these macros return a JSON-formatted "error" object instead of printing a message to stderr. To handle error messages correctly with JSON, a modification was brought to their behavior nonetheless: the functions now append a end-of-line character at the end of the message. This way, we can remove end-of-line characters at the end of the argument strings, and not have them in the JSON output. All error messages are formatted to hold in a single call to p_err(), in order to produce a single JSON field. Signed-off-by: Quentin Monnet Acked-by: Jakub Kicinski Acked-by: Daniel Borkmann --- tools/bpf/bpftool/common.c | 26 +++++++------- tools/bpf/bpftool/main.c | 16 ++++----- tools/bpf/bpftool/main.h | 37 +++++++++++++++++--- tools/bpf/bpftool/map.c | 87 +++++++++++++++++++++++++--------------------- tools/bpf/bpftool/prog.c | 51 +++++++++++++-------------- 5 files changed, 126 insertions(+), 91 deletions(-) diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c index e7a756b8ee21..b2533f1cae3e 100644 --- a/tools/bpf/bpftool/common.c +++ b/tools/bpf/bpftool/common.c @@ -66,8 +66,8 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type) fd = bpf_obj_get(path); if (fd < 0) { - err("bpf obj get (%s): %s\n", path, - errno == EACCES && !is_bpffs(dirname(path)) ? + p_err("bpf obj get (%s): %s", path, + errno == EACCES && !is_bpffs(dirname(path)) ? "directory not in bpf file system (bpffs)" : strerror(errno)); return -1; @@ -79,7 +79,7 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type) return type; } if (type != exp_type) { - err("incorrect object type: %s\n", get_fd_type_name(type)); + p_err("incorrect object type: %s", get_fd_type_name(type)); close(fd); return -1; } @@ -95,14 +95,14 @@ int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32)) int fd; if (!is_prefix(*argv, "id")) { - err("expected 'id' got %s\n", *argv); + p_err("expected 'id' got %s", *argv); return -1; } NEXT_ARG(); id = strtoul(*argv, &endptr, 0); if (*endptr) { - err("can't parse %s as ID\n", *argv); + p_err("can't parse %s as ID", *argv); return -1; } NEXT_ARG(); @@ -112,15 +112,15 @@ int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32)) fd = get_fd_by_id(id); if (fd < 0) { - err("can't get prog by id (%u): %s\n", id, strerror(errno)); + p_err("can't get prog by id (%u): %s", id, strerror(errno)); return -1; } err = bpf_obj_pin(fd, *argv); close(fd); if (err) { - err("can't pin the object (%s): %s\n", *argv, - errno == EACCES && !is_bpffs(dirname(*argv)) ? + p_err("can't pin the object (%s): %s", *argv, + errno == EACCES && !is_bpffs(dirname(*argv)) ? "directory not in bpf file system (bpffs)" : strerror(errno)); return -1; @@ -153,11 +153,11 @@ int get_fd_type(int fd) n = readlink(path, buf, sizeof(buf)); if (n < 0) { - err("can't read link type: %s\n", strerror(errno)); + p_err("can't read link type: %s", strerror(errno)); return -1; } if (n == sizeof(path)) { - err("can't read link type: path too long!\n"); + p_err("can't read link type: path too long!"); return -1; } @@ -181,7 +181,7 @@ char *get_fdinfo(int fd, const char *key) fdi = fopen(path, "r"); if (!fdi) { - err("can't open fdinfo: %s\n", strerror(errno)); + p_err("can't open fdinfo: %s", strerror(errno)); return NULL; } @@ -196,7 +196,7 @@ char *get_fdinfo(int fd, const char *key) value = strchr(line, '\t'); if (!value || !value[1]) { - err("malformed fdinfo!?\n"); + p_err("malformed fdinfo!?"); free(line); return NULL; } @@ -209,7 +209,7 @@ char *get_fdinfo(int fd, const char *key) return line; } - err("key '%s' not found in fdinfo\n", key); + p_err("key '%s' not found in fdinfo", key); free(line); fclose(fdi); return NULL; diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 71b01bf73912..9989a77fdc4a 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -158,20 +158,20 @@ static int do_batch(int argc, char **argv) int i; if (argc < 2) { - err("too few parameters for batch\n"); + p_err("too few parameters for batch"); return -1; } else if (!is_prefix(*argv, "file")) { - err("expected 'file', got: %s\n", *argv); + p_err("expected 'file', got: %s", *argv); return -1; } else if (argc > 2) { - err("too many parameters for batch\n"); + p_err("too many parameters for batch"); return -1; } NEXT_ARG(); fp = fopen(*argv, "r"); if (!fp) { - err("Can't open file (%s): %s\n", *argv, strerror(errno)); + p_err("Can't open file (%s): %s", *argv, strerror(errno)); return -1; } @@ -189,8 +189,8 @@ static int do_batch(int argc, char **argv) while (n_argv[n_argc]) { n_argc++; if (n_argc == ARRAY_SIZE(n_argv)) { - err("line %d has too many arguments, skip\n", - lines); + p_err("line %d has too many arguments, skip", + lines); n_argc = 0; break; } @@ -225,7 +225,7 @@ static int do_batch(int argc, char **argv) perror("reading batch file failed"); err = -1; } else { - info("processed %d lines\n", lines); + p_info("processed %d lines", lines); err = 0; } err_close: @@ -279,7 +279,7 @@ int main(int argc, char **argv) if (json_output) { json_wtr = jsonw_new(stdout); if (!json_wtr) { - err("failed to create JSON writer\n"); + p_err("failed to create JSON writer"); return -1; } jsonw_pretty(json_wtr, pretty_output); diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 693fc9710be1..04c88b55d8c7 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -45,15 +45,11 @@ #include "json_writer.h" -#define err(msg...) fprintf(stderr, "Error: " msg) -#define warn(msg...) fprintf(stderr, "Warning: " msg) -#define info(msg...) fprintf(stderr, msg) - #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr)) #define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); }) #define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); }) -#define BAD_ARG() ({ err("what is '%s'?\n", *argv); -1; }) +#define BAD_ARG() ({ p_err("what is '%s'?\n", *argv); -1; }) #define BPF_TAG_FMT "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" @@ -97,4 +93,35 @@ int prog_parse_fd(int *argc, char ***argv); void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes); void print_hex_data_json(uint8_t *data, size_t len); +static inline void p_err(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (json_output) { + jsonw_start_object(json_wtr); + jsonw_name(json_wtr, "error"); + jsonw_vprintf_enquote(json_wtr, fmt, ap); + jsonw_end_object(json_wtr); + } else { + fprintf(stderr, "Error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } + va_end(ap); +} + +static inline void p_info(const char *fmt, ...) +{ + va_list ap; + + if (json_output) + return; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + #endif diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index 14d89bfabc66..86c128c433ba 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -81,19 +81,19 @@ static unsigned int get_possible_cpus(void) fd = open("/sys/devices/system/cpu/possible", O_RDONLY); if (fd < 0) { - err("can't open sysfs possible cpus\n"); + p_err("can't open sysfs possible cpus"); exit(-1); } n = read(fd, buf, sizeof(buf)); if (n < 2) { - err("can't read sysfs possible cpus\n"); + p_err("can't read sysfs possible cpus"); exit(-1); } close(fd); if (n == sizeof(buf)) { - err("read sysfs possible cpus overflow\n"); + p_err("read sysfs possible cpus overflow"); exit(-1); } @@ -161,14 +161,14 @@ static int map_parse_fd(int *argc, char ***argv) id = strtoul(**argv, &endptr, 0); if (*endptr) { - err("can't parse %s as ID\n", **argv); + p_err("can't parse %s as ID", **argv); return -1; } NEXT_ARGP(); fd = bpf_map_get_fd_by_id(id); if (fd < 0) - err("get map by id (%u): %s\n", id, strerror(errno)); + p_err("get map by id (%u): %s", id, strerror(errno)); return fd; } else if (is_prefix(**argv, "pinned")) { char *path; @@ -181,7 +181,7 @@ static int map_parse_fd(int *argc, char ***argv) return open_obj_pinned_any(path, BPF_OBJ_MAP); } - err("expected 'id' or 'pinned', got: '%s'?\n", **argv); + p_err("expected 'id' or 'pinned', got: '%s'?", **argv); return -1; } @@ -197,7 +197,7 @@ map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len) err = bpf_obj_get_info_by_fd(fd, info, info_len); if (err) { - err("can't get map info: %s\n", strerror(errno)); + p_err("can't get map info: %s", strerror(errno)); close(fd); return err; } @@ -288,14 +288,14 @@ static char **parse_bytes(char **argv, const char *name, unsigned char *val, while (i < n && argv[i]) { val[i] = strtoul(argv[i], &endptr, 0); if (*endptr) { - err("error parsing byte: %s\n", argv[i]); + p_err("error parsing byte: %s", argv[i]); return NULL; } i++; } if (i != n) { - err("%s expected %d bytes got %d\n", name, n, i); + p_err("%s expected %d bytes got %d", name, n, i); return NULL; } @@ -309,16 +309,16 @@ static int parse_elem(char **argv, struct bpf_map_info *info, if (!*argv) { if (!key && !value) return 0; - err("did not find %s\n", key ? "key" : "value"); + p_err("did not find %s", key ? "key" : "value"); return -1; } if (is_prefix(*argv, "key")) { if (!key) { if (key_size) - err("duplicate key\n"); + p_err("duplicate key"); else - err("unnecessary key\n"); + p_err("unnecessary key"); return -1; } @@ -333,9 +333,9 @@ static int parse_elem(char **argv, struct bpf_map_info *info, if (!value) { if (value_size) - err("duplicate value\n"); + p_err("duplicate value"); else - err("unnecessary value\n"); + p_err("unnecessary value"); return -1; } @@ -345,11 +345,11 @@ static int parse_elem(char **argv, struct bpf_map_info *info, int argc = 2; if (value_size != 4) { - err("value smaller than 4B for map in map?\n"); + p_err("value smaller than 4B for map in map?"); return -1; } if (!argv[0] || !argv[1]) { - err("not enough value arguments for map in map\n"); + p_err("not enough value arguments for map in map"); return -1; } @@ -363,11 +363,11 @@ static int parse_elem(char **argv, struct bpf_map_info *info, int argc = 2; if (value_size != 4) { - err("value smaller than 4B for map of progs?\n"); + p_err("value smaller than 4B for map of progs?"); return -1; } if (!argv[0] || !argv[1]) { - err("not enough value arguments for map of progs\n"); + p_err("not enough value arguments for map of progs"); return -1; } @@ -388,7 +388,7 @@ static int parse_elem(char **argv, struct bpf_map_info *info, } else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") || is_prefix(*argv, "exist")) { if (!flags) { - err("flags specified multiple times: %s\n", *argv); + p_err("flags specified multiple times: %s", *argv); return -1; } @@ -403,7 +403,7 @@ static int parse_elem(char **argv, struct bpf_map_info *info, value_size, NULL, value_fd); } - err("expected key or value, got: %s\n", *argv); + p_err("expected key or value, got: %s", *argv); return -1; } @@ -499,22 +499,21 @@ static int do_show(int argc, char **argv) if (err) { if (errno == ENOENT) break; - err("can't get next map: %s\n", strerror(errno)); - if (errno == EINVAL) - err("kernel too old?\n"); + p_err("can't get next map: %s%s", strerror(errno), + errno == EINVAL ? " -- kernel too old?" : ""); return -1; } fd = bpf_map_get_fd_by_id(id); if (fd < 0) { - err("can't get map by id (%u): %s\n", - id, strerror(errno)); + p_err("can't get map by id (%u): %s", + id, strerror(errno)); return -1; } err = bpf_obj_get_info_by_fd(fd, &info, &len); if (err) { - err("can't get map info: %s\n", strerror(errno)); + p_err("can't get map info: %s", strerror(errno)); close(fd); return -1; } @@ -547,7 +546,7 @@ static int do_dump(int argc, char **argv) return -1; if (map_is_map_of_maps(info.type) || map_is_map_of_progs(info.type)) { - err("Dumping maps of maps and program maps not supported\n"); + p_err("Dumping maps of maps and program maps not supported"); close(fd); return -1; } @@ -555,7 +554,7 @@ static int do_dump(int argc, char **argv) key = malloc(info.key_size); value = alloc_value(&info); if (!key || !value) { - err("mem alloc failed\n"); + p_err("mem alloc failed"); err = -1; goto exit_free; } @@ -577,9 +576,19 @@ static int do_dump(int argc, char **argv) else print_entry_plain(&info, key, value); } else { - info("can't lookup element with key: "); - fprint_hex(stderr, key, info.key_size, " "); - fprintf(stderr, "\n"); + if (json_output) { + jsonw_name(json_wtr, "key"); + print_hex_data_json(key, info.key_size); + jsonw_name(json_wtr, "value"); + jsonw_start_object(json_wtr); + jsonw_string_field(json_wtr, "error", + "can't lookup element"); + jsonw_end_object(json_wtr); + } else { + p_info("can't lookup element with key: "); + fprint_hex(stderr, key, info.key_size, " "); + fprintf(stderr, "\n"); + } } prev_key = key; @@ -619,7 +628,7 @@ static int do_update(int argc, char **argv) key = malloc(info.key_size); value = alloc_value(&info); if (!key || !value) { - err("mem alloc failed"); + p_err("mem alloc failed"); err = -1; goto exit_free; } @@ -631,7 +640,7 @@ static int do_update(int argc, char **argv) err = bpf_map_update_elem(fd, key, value, flags); if (err) { - err("update failed: %s\n", strerror(errno)); + p_err("update failed: %s", strerror(errno)); goto exit_free; } @@ -663,7 +672,7 @@ static int do_lookup(int argc, char **argv) key = malloc(info.key_size); value = alloc_value(&info); if (!key || !value) { - err("mem alloc failed"); + p_err("mem alloc failed"); err = -1; goto exit_free; } @@ -687,7 +696,7 @@ static int do_lookup(int argc, char **argv) printf("\n\nNot found\n"); } } else { - err("lookup failed: %s\n", strerror(errno)); + p_err("lookup failed: %s", strerror(errno)); } exit_free: @@ -716,7 +725,7 @@ static int do_getnext(int argc, char **argv) key = malloc(info.key_size); nextkey = malloc(info.key_size); if (!key || !nextkey) { - err("mem alloc failed"); + p_err("mem alloc failed"); err = -1; goto exit_free; } @@ -733,7 +742,7 @@ static int do_getnext(int argc, char **argv) err = bpf_map_get_next_key(fd, key, nextkey); if (err) { - err("can't get next key: %s\n", strerror(errno)); + p_err("can't get next key: %s", strerror(errno)); goto exit_free; } @@ -786,7 +795,7 @@ static int do_delete(int argc, char **argv) key = malloc(info.key_size); if (!key) { - err("mem alloc failed"); + p_err("mem alloc failed"); err = -1; goto exit_free; } @@ -797,7 +806,7 @@ static int do_delete(int argc, char **argv) err = bpf_map_delete_elem(fd, key); if (err) - err("delete failed: %s\n", strerror(errno)); + p_err("delete failed: %s", strerror(errno)); exit_free: free(key); diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 43e49799a624..41bd5390b4fc 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -104,21 +104,21 @@ static int prog_fd_by_tag(unsigned char *tag) while (true) { err = bpf_prog_get_next_id(id, &id); if (err) { - err("%s\n", strerror(errno)); + p_err("%s", strerror(errno)); return -1; } fd = bpf_prog_get_fd_by_id(id); if (fd < 0) { - err("can't get prog by id (%u): %s\n", - id, strerror(errno)); + p_err("can't get prog by id (%u): %s", + id, strerror(errno)); return -1; } err = bpf_obj_get_info_by_fd(fd, &info, &len); if (err) { - err("can't get prog info (%u): %s\n", - id, strerror(errno)); + p_err("can't get prog info (%u): %s", + id, strerror(errno)); close(fd); return -1; } @@ -142,14 +142,14 @@ int prog_parse_fd(int *argc, char ***argv) id = strtoul(**argv, &endptr, 0); if (*endptr) { - err("can't parse %s as ID\n", **argv); + p_err("can't parse %s as ID", **argv); return -1; } NEXT_ARGP(); fd = bpf_prog_get_fd_by_id(id); if (fd < 0) - err("get by id (%u): %s\n", id, strerror(errno)); + p_err("get by id (%u): %s", id, strerror(errno)); return fd; } else if (is_prefix(**argv, "tag")) { unsigned char tag[BPF_TAG_SIZE]; @@ -159,7 +159,7 @@ int prog_parse_fd(int *argc, char ***argv) if (sscanf(**argv, BPF_TAG_FMT, tag, tag + 1, tag + 2, tag + 3, tag + 4, tag + 5, tag + 6, tag + 7) != BPF_TAG_SIZE) { - err("can't parse tag\n"); + p_err("can't parse tag"); return -1; } NEXT_ARGP(); @@ -176,7 +176,7 @@ int prog_parse_fd(int *argc, char ***argv) return open_obj_pinned_any(path, BPF_OBJ_PROG); } - err("expected 'id', 'tag' or 'pinned', got: '%s'?\n", **argv); + p_err("expected 'id', 'tag' or 'pinned', got: '%s'?", **argv); return -1; } @@ -311,7 +311,7 @@ static int show_prog(int fd) err = bpf_obj_get_info_by_fd(fd, &info, &len); if (err) { - err("can't get prog info: %s\n", strerror(errno)); + p_err("can't get prog info: %s", strerror(errno)); return -1; } @@ -349,17 +349,16 @@ static int do_show(int argc, char **argv) err = 0; break; } - err("can't get next program: %s\n", strerror(errno)); - if (errno == EINVAL) - err("kernel too old?\n"); + p_err("can't get next program: %s%s", strerror(errno), + errno == EINVAL ? " -- kernel too old?" : ""); err = -1; break; } fd = bpf_prog_get_fd_by_id(id); if (fd < 0) { - err("can't get prog by id (%u): %s\n", - id, strerror(errno)); + p_err("can't get prog by id (%u): %s", + id, strerror(errno)); err = -1; break; } @@ -498,7 +497,7 @@ static int do_dump(int argc, char **argv) member_len = &info.xlated_prog_len; member_ptr = &info.xlated_prog_insns; } else { - err("expected 'xlated' or 'jited', got: %s\n", *argv); + p_err("expected 'xlated' or 'jited', got: %s", *argv); return -1; } NEXT_ARG(); @@ -513,7 +512,7 @@ static int do_dump(int argc, char **argv) if (is_prefix(*argv, "file")) { NEXT_ARG(); if (!argc) { - err("expected file path\n"); + p_err("expected file path"); return -1; } @@ -531,12 +530,12 @@ static int do_dump(int argc, char **argv) err = bpf_obj_get_info_by_fd(fd, &info, &len); if (err) { - err("can't get prog info: %s\n", strerror(errno)); + p_err("can't get prog info: %s", strerror(errno)); return -1; } if (!*member_len) { - info("no instructions returned\n"); + p_info("no instructions returned"); close(fd); return 0; } @@ -545,7 +544,7 @@ static int do_dump(int argc, char **argv) buf = malloc(buf_size); if (!buf) { - err("mem alloc failed\n"); + p_err("mem alloc failed"); close(fd); return -1; } @@ -558,28 +557,28 @@ static int do_dump(int argc, char **argv) err = bpf_obj_get_info_by_fd(fd, &info, &len); close(fd); if (err) { - err("can't get prog info: %s\n", strerror(errno)); + p_err("can't get prog info: %s", strerror(errno)); goto err_free; } if (*member_len > buf_size) { - err("too many instructions returned\n"); + p_err("too many instructions returned"); goto err_free; } if (filepath) { fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); if (fd < 0) { - err("can't open file %s: %s\n", filepath, - strerror(errno)); + p_err("can't open file %s: %s", filepath, + strerror(errno)); goto err_free; } n = write(fd, buf, *member_len); close(fd); if (n != *member_len) { - err("error writing output file: %s\n", - n < 0 ? strerror(errno) : "short write"); + p_err("error writing output file: %s", + n < 0 ? strerror(errno) : "short write"); goto err_free; } } else { From patchwork Mon Oct 23 16:24:14 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829399 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="rsPsX5pj"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMFL67lqz9t5s for ; Tue, 24 Oct 2017 03:25:10 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751662AbdJWQZJ (ORCPT ); Mon, 23 Oct 2017 12:25:09 -0400 Received: from mail-pf0-f196.google.com ([209.85.192.196]:50504 "EHLO mail-pf0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751636AbdJWQZE (ORCPT ); Mon, 23 Oct 2017 12:25:04 -0400 Received: by mail-pf0-f196.google.com with SMTP id b6so17475979pfh.7 for ; Mon, 23 Oct 2017 09:25:04 -0700 (PDT) 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=QGBaqGCebRJkxst1kabqguVidbTLre/NQKrsZfBupoI=; b=rsPsX5pjyQRrQWlUjeR9KGDWi9nW12udvH3GX8IuXhj70Cojzk9t7Tgp5VPeD2l5t0 ++PisrHawEJ5TmALMOKADog1QxkNqn/QgmojSzAVBsHEuqUxNEkdF4Otq+HuE8mLjPIj 4Ge9K9D7h1i2MCeJ3m9YFX+m6QsjS/Vl8JtUOaCtWYX0BvfsAF9AyqsrEfBBxN2kplsb /RVIN+pkzkX0plTtJmN6C7kLD15cYOOdgifKgbMS0MD6BeM20UjFyVfObX7UF3EuXczg WQyLIDkWDiHsNliYE3a08vArC/JomWnbJ1gWnN9eHMvN6e3kEsWPdmF7Tc3QtQ1w9kfk F7Yw== 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=QGBaqGCebRJkxst1kabqguVidbTLre/NQKrsZfBupoI=; b=s+SS2MFfWXJrFcnHG8Zf/F1XHJMIfl/9hSNvST8FkyqdGKdTSeWpHYAWSGN9r/RcQ+ F36F/39bU2vOp80j41lZQ0Q1zQ+MHGny+6rjhwH/78Hl/cK8b3O+6EF9cVXVyx/HU3tt scXkXokwrEWy1UZp00Tkrh+f15YyyLjaH2MVHBy3eFdGrRhL/J7xdLY3L5qE++5yURSp RM2LEdmZ4BsO0XXPGTFbwCoD0RYyBvO3EzuDksLENw3ULPWJDFjrOrLkb2H1wwJe3x7+ KI6rCy7jcveg8cxCVNinR1bCrQxrXSK3w0a9x3AMjdtXd8TkXTqMM8VJLCyJrtYo4Wz3 Aqzw== X-Gm-Message-State: AMCzsaXGx+XYNjo+9OStArz2+CrEjB4D0ZZqDlQ9HVbITPhuUB9jD4ic iIub/STmHpINKL5ls0EG4OvtDn2B X-Google-Smtp-Source: ABhQp+SNsaYs0M6vSg30VL+dvCcf/A3eOcVJo9Jk3mD3A7fjMDPIaCACRk0xSHaojV9cZUnowb34Yg== X-Received: by 10.84.244.2 with SMTP id g2mr10908544pll.400.1508775903943; Mon, 23 Oct 2017 09:25:03 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.25.02 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:25:03 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 10/12] tools: bpftool: provide JSON output for all possible commands Date: Mon, 23 Oct 2017 09:24:14 -0700 Message-Id: <20171023162416.32753-11-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet As all commands can now return JSON output (possibly just a "null" value), output of `bpftool --json batch file FILE` should also be fully JSON compliant. Signed-off-by: Quentin Monnet Acked-by: Daniel Borkmann --- tools/bpf/bpftool/main.c | 25 +++++++++++++++++++++---- tools/bpf/bpftool/map.c | 16 +++++++++++++++- tools/bpf/bpftool/prog.c | 12 +++++++++++- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 9989a77fdc4a..55ba0a04c102 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -64,6 +64,11 @@ void usage(void) static int do_help(int argc, char **argv) { + if (json_output) { + jsonw_null(json_wtr); + return 0; + } + fprintf(stderr, "Usage: %s OBJECT { COMMAND | help }\n" " %s batch file FILE\n" @@ -77,10 +82,22 @@ static int do_help(int argc, char **argv) static int do_version(int argc, char **argv) { - printf("%s v%d.%d.%d\n", bin_name, - LINUX_VERSION_CODE >> 16, - LINUX_VERSION_CODE >> 8 & 0xf, - LINUX_VERSION_CODE & 0xf); + unsigned int version[3]; + + version[0] = LINUX_VERSION_CODE >> 16; + version[1] = LINUX_VERSION_CODE >> 8 & 0xf; + version[2] = LINUX_VERSION_CODE & 0xf; + + if (json_output) { + jsonw_start_object(json_wtr); + jsonw_name(json_wtr, "version"); + jsonw_printf(json_wtr, "\"%u.%u.%u\"", + version[0], version[1], version[2]); + jsonw_end_object(json_wtr); + } else { + printf("%s v%u.%u.%u\n", bin_name, + version[0], version[1], version[2]); + } return 0; } diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index 86c128c433ba..a611f31f574f 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -651,6 +651,8 @@ static int do_update(int argc, char **argv) free(value); close(fd); + if (!err && json_output) + jsonw_null(json_wtr); return err; } @@ -812,16 +814,28 @@ static int do_delete(int argc, char **argv) free(key); close(fd); + if (!err && json_output) + jsonw_null(json_wtr); return err; } static int do_pin(int argc, char **argv) { - return do_pin_any(argc, argv, bpf_map_get_fd_by_id); + int err; + + err = do_pin_any(argc, argv, bpf_map_get_fd_by_id); + if (!err && json_output) + jsonw_null(json_wtr); + return err; } static int do_help(int argc, char **argv) { + if (json_output) { + jsonw_null(json_wtr); + return 0; + } + fprintf(stderr, "Usage: %s %s show [MAP]\n" " %s %s dump MAP\n" diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 41bd5390b4fc..e07f35ff80d1 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -602,11 +602,21 @@ static int do_dump(int argc, char **argv) static int do_pin(int argc, char **argv) { - return do_pin_any(argc, argv, bpf_prog_get_fd_by_id); + int err; + + err = do_pin_any(argc, argv, bpf_prog_get_fd_by_id); + if (!err && json_output) + jsonw_null(json_wtr); + return err; } static int do_help(int argc, char **argv) { + if (json_output) { + jsonw_null(json_wtr); + return 0; + } + fprintf(stderr, "Usage: %s %s show [PROG]\n" " %s %s dump xlated PROG [{ file FILE | opcodes }]\n" From patchwork Mon Oct 23 16:24:15 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829398 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="Qit4gXLW"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMFK4WS5z9t5s for ; Tue, 24 Oct 2017 03:25:09 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751658AbdJWQZH (ORCPT ); Mon, 23 Oct 2017 12:25:07 -0400 Received: from mail-pg0-f68.google.com ([74.125.83.68]:46811 "EHLO mail-pg0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751587AbdJWQZF (ORCPT ); Mon, 23 Oct 2017 12:25:05 -0400 Received: by mail-pg0-f68.google.com with SMTP id k7so12171591pga.3 for ; Mon, 23 Oct 2017 09:25:05 -0700 (PDT) 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=tb3ikPMV8JHpXc7n3/iC76uA3HgmviKSSSyAowL+HAE=; b=Qit4gXLW1lS6iFtdsEvdLlZXrC9O8C9KnhGIsVevEllO6aDHCfK8UZa93gY9A12wgo F9ZdydVZyWiXFGqcwVRqq5rXPxWUklceLztPDNIYsQh0cw3NYiYNyr6Axb4Sm2aF2nMo +NuGsmYn1pjSMgSwjEA+aSQOt7H9hs63K4QhIxQNDtRhDkPaHvIFS4RnPOe4w8zwCV6c zGbh3dWAaSYIxdV7DvmyqWS9ih4BNfL68v1pftqGhBwhKiD/sk3ikGEyio/egqX17XHN d+Q7FtQJbaqxs9kiD6EfqLAKKAPszJIfy3U1oF0WId93A9rz84DcgZaDyYbXd2KgWoIG 9TVw== 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=tb3ikPMV8JHpXc7n3/iC76uA3HgmviKSSSyAowL+HAE=; b=eTf6Bnyw8BG8inqW9JwHchyk/umWdDLLNgKUyEZT32vMuuYwQNZahH8wN7Pxz3UMxn 5tgoPFWfbA8+9CZ4BzRAa6WFiXw6Nt4kJrsPgwfaFPEI1zXbJWFLRYrDo5oiZhL9Ci/2 Bv8Ou8br3RzmHfWDfjmAsVq2jpn8f5M/ZoqQjUZDrNmfuk0Sihzl9WaJ5i3U6aktWgHM /tz5L3ilXCOsMuCxuu3l33UHWadNdcvT3G7gQzCB3n98nT/7LmfnOYVLtA7OdzU+pV5G p7fvHHYJ1TmHxqa1ka9PSCBAtBdodiIHmz/vstIEufIHdx4j5NBQaSUWySocJz6hyUOP sXbw== X-Gm-Message-State: AMCzsaVSFtCsAfyuRliC/1M5FcTO3CAkpArL/dxsxDjgcIvMHEtIhXDx 4UgKQB9+HOXX1kRXV7xRLegJHgmg X-Google-Smtp-Source: ABhQp+Q63cPXa49KXV5848ePYgvtz7xws/aylxgdvRQeZYdGc42sqMzCSIZFlZcy/58by0+i40NWug== X-Received: by 10.84.238.1 with SMTP id u1mr2401428plk.396.1508775904819; Mon, 23 Oct 2017 09:25:04 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.25.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:25:04 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 11/12] tools: bpftool: add cosmetic changes for the manual pages Date: Mon, 23 Oct 2017 09:24:15 -0700 Message-Id: <20171023162416.32753-12-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet Make the look-and-feel of the manual pages somewhat closer to other manual pages, such as the ones from the utilities from iproute2, by highlighting more keywords. Signed-off-by: Quentin Monnet Acked-by: Jakub Kicinski Acked-by: Daniel Borkmann --- tools/bpf/bpftool/Documentation/bpftool-map.rst | 25 ++++++++++++------------ tools/bpf/bpftool/Documentation/bpftool-prog.rst | 12 ++++++------ tools/bpf/bpftool/Documentation/bpftool.rst | 12 +++++++----- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst index 5210c4fab356..3954b3ea4f26 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-map.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst @@ -13,23 +13,24 @@ SYNOPSIS **bpftool** **map** *COMMAND* *COMMANDS* := - { show | dump | update | lookup | getnext | delete | pin | help } + { **show** | **dump** | **update** | **lookup** | **getnext** | **delete** + | **pin** | **help** } MAP COMMANDS ============= -| **bpftool** map show [*MAP*] -| **bpftool** map dump *MAP* -| **bpftool** map update *MAP* key *BYTES* value *VALUE* [*UPDATE_FLAGS*] -| **bpftool** map lookup *MAP* key *BYTES* -| **bpftool** map getnext *MAP* [key *BYTES*] -| **bpftool** map delete *MAP* key *BYTES* -| **bpftool** map pin *MAP* *FILE* -| **bpftool** map help +| **bpftool** **map show** [*MAP*] +| **bpftool** **map dump** *MAP* +| **bpftool** **map update** *MAP* **key** *BYTES* **value** *VALUE* [*UPDATE_FLAGS*] +| **bpftool** **map lookup** *MAP* **key** *BYTES* +| **bpftool** **map getnext** *MAP* [**key** *BYTES*] +| **bpftool** **map delete** *MAP* **key** *BYTES* +| **bpftool** **map pin** *MAP* *FILE* +| **bpftool** **map help** | -| *MAP* := { id MAP_ID | pinned FILE } -| *VALUE* := { BYTES | MAP | PROGRAM } -| *UPDATE_FLAGS* := { any | exist | noexist } +| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* } +| *VALUE* := { *BYTES* | *MAP* | *PROGRAM* } +| *UPDATE_FLAGS* := { **any** | **exist** | **noexist** } DESCRIPTION =========== diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst index 6620a81d9dc9..685a19e71fec 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst @@ -10,13 +10,13 @@ tool for inspection and simple manipulation of eBPF progs SYNOPSIS ======== -| **bpftool** prog show [*PROG*] -| **bpftool** prog dump xlated *PROG* [{file *FILE* | opcodes }] -| **bpftool** prog dump jited *PROG* [{file *FILE* | opcodes }] -| **bpftool** prog pin *PROG* *FILE* -| **bpftool** prog help +| **bpftool** **prog show** [*PROG*] +| **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes**}] +| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] +| **bpftool** **prog pin** *PROG* *FILE* +| **bpftool** **prog help** | -| *PROG* := { id *PROG_ID* | pinned *FILE* | tag *PROG_TAG* } +| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* } DESCRIPTION =========== diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst index 9c04cd6677bd..44e07799d54d 100644 --- a/tools/bpf/bpftool/Documentation/bpftool.rst +++ b/tools/bpf/bpftool/Documentation/bpftool.rst @@ -10,18 +10,20 @@ tool for inspection and simple manipulation of eBPF programs and maps SYNOPSIS ======== - **bpftool** *OBJECT* { *COMMAND* | help } + **bpftool** *OBJECT* { *COMMAND* | **help** } - **bpftool** batch file *FILE* + **bpftool** **batch file** *FILE* - **bpftool** version + **bpftool** **version** *OBJECT* := { **map** | **program** } *MAP-COMMANDS* := - { show | dump | update | lookup | getnext | delete | pin | help } + { **show** | **dump** | **update** | **lookup** | **getnext** | **delete** + | **pin** | **help** } - *PROG-COMMANDS* := { show | dump jited | dump xlated | pin | help } + *PROG-COMMANDS* := { **show** | **dump jited** | **dump xlated** | **pin** + | **help** } DESCRIPTION =========== From patchwork Mon Oct 23 16:24:16 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Kicinski X-Patchwork-Id: 829400 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@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; dkim=pass (2048-bit key; unprotected) header.d=netronome-com.20150623.gappssmtp.com header.i=@netronome-com.20150623.gappssmtp.com header.b="a4zFHbhS"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3yLMFW0Y8pz9t5s for ; Tue, 24 Oct 2017 03:25:19 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751691AbdJWQZR (ORCPT ); Mon, 23 Oct 2017 12:25:17 -0400 Received: from mail-pg0-f67.google.com ([74.125.83.67]:47458 "EHLO mail-pg0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751643AbdJWQZG (ORCPT ); Mon, 23 Oct 2017 12:25:06 -0400 Received: by mail-pg0-f67.google.com with SMTP id r25so12163513pgn.4 for ; Mon, 23 Oct 2017 09:25:06 -0700 (PDT) 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=rkK5iTJIXiO1Ue974oXNnYs7YuA4j1fhoKhcZRkyAXA=; b=a4zFHbhSn+2Jas680PyWHDfeldlsDs4C8UqD1JcBx97Ki+J/LMSVSg8/0nzv719nOF mzCbSjfoHuwYSGzm1WhEGNiVNhOjCxcR84K6pj41tPGLvWxKP6RgAX/OR9/+UwKxedrd 7XlJtIz19PHexdBOr3fElZuz9l8h8QQH+nKq9uyCg7Q4QL+gnq+pQLpYAkb/Pa/Mse1j L/kwAkFGSoVaqFt0RbnKjaqpzVJV2L+u/X/R2VvyWaQx7ILtlCLak7MbdDhkCRf8vWdJ YVz3o2NyHX+RTsLs8b0EPQdhIPr3HocbQcuOCFiQgJUukiUINTn+O1YFZtMLg+Y7WTIy AXDg== 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=rkK5iTJIXiO1Ue974oXNnYs7YuA4j1fhoKhcZRkyAXA=; b=NGftL+i+uEg8ukU5hqoHF7xqCsgdKY5iKrYxZeekhTAak0hPnX34Qv/a47VjZw+hkF CN2D2N7of7b47nN4CMhExpArcSvN6hLsGTEaUrl6YduS/lWlKMa5hx6Qd63vNspiwODN sHqFB+HLiwjdYnGLuvLx7VnAxCGypgx0HDLPrtSsTqT0jG4IxACVyiy0V79VysXXfmpY v68QaPMMfVJH4Myj9SRq+ut7QLeHiQDtEaElR7QI2yVQxHQo6dPsLcrzHEWkS1aTIisl h5SEr5hhcxFG47YaKERUdntww+LK2yb/WXH3GRStVHpxVCEeTwfSYTkx+E5m/48CdW5m K3DQ== X-Gm-Message-State: AMCzsaWPndly+P0A3TGEFS2jOEbCZW1IqiplyDNiUAHTAJjmyX8ZfS5b xkQr/+GcAtdg9ceo0XH0Q9Puqe92 X-Google-Smtp-Source: ABhQp+QIBbS+BzBqACltN0o5cqaeWB/zAuJKIVcXmr2Rdw2bTwVPGQGSqajJkz/CT48YiQYPGi4EGQ== X-Received: by 10.101.67.3 with SMTP id j3mr12017594pgq.278.1508775905844; Mon, 23 Oct 2017 09:25:05 -0700 (PDT) Received: from jkicinski-Precision-T1700.netronome.com ([75.53.12.129]) by smtp.gmail.com with ESMTPSA id a19sm13586540pfh.30.2017.10.23.09.25.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 23 Oct 2017 09:25:05 -0700 (PDT) From: Jakub Kicinski To: netdev@vger.kernel.org Cc: oss-drivers@netronome.com, alexei.starovoitov@gmail.com, daniel@iogearbox.net, Quentin Monnet Subject: [PATCH net-next 12/12] tools: bpftool: update documentation for --json and --pretty usage Date: Mon, 23 Oct 2017 09:24:16 -0700 Message-Id: <20171023162416.32753-13-jakub.kicinski@netronome.com> X-Mailer: git-send-email 2.14.1 In-Reply-To: <20171023162416.32753-1-jakub.kicinski@netronome.com> References: <20171023162416.32753-1-jakub.kicinski@netronome.com> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Quentin Monnet Update the documentation to provide help about JSON output generation, and add an example in bpftool-prog manual page. Also reintroduce an example that was left aside when the tool was moved from GitHub to the kernel sources, in order to show how to mount the bpffs file system (to pin programs) inside the bpftool-prog manual page. Signed-off-by: Quentin Monnet Acked-by: Daniel Borkmann --- tools/bpf/bpftool/Documentation/bpftool-map.rst | 11 ++++- tools/bpf/bpftool/Documentation/bpftool-prog.rst | 61 +++++++++++++++++++++++- tools/bpf/bpftool/Documentation/bpftool.rst | 12 ++++- tools/bpf/bpftool/main.c | 6 ++- tools/bpf/bpftool/main.h | 2 + tools/bpf/bpftool/map.c | 1 + tools/bpf/bpftool/prog.c | 1 + 7 files changed, 88 insertions(+), 6 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst index 3954b3ea4f26..abb9ee940b15 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-map.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst @@ -10,7 +10,9 @@ tool for inspection and simple manipulation of eBPF maps SYNOPSIS ======== - **bpftool** **map** *COMMAND* + **bpftool** [*OPTIONS*] **map** *COMMAND* + + *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] } *COMMANDS* := { **show** | **dump** | **update** | **lookup** | **getnext** | **delete** @@ -77,6 +79,13 @@ OPTIONS -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**. + EXAMPLES ======== **# bpftool map show** diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst index 685a19e71fec..0f25d3c39e05 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst @@ -10,6 +10,16 @@ tool for inspection and simple manipulation of eBPF progs SYNOPSIS ======== + **bpftool** [*OPTIONS*] **prog** *COMMAND* + + *OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] } + + *COMMANDS* := + { **show** | **dump xlated** | **dump jited** | **pin** | **help** } + +MAP COMMANDS +============= + | **bpftool** **prog show** [*PROG*] | **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes**}] | **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}] @@ -58,6 +68,13 @@ OPTIONS -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**. + EXAMPLES ======== **# bpftool prog show** @@ -67,13 +84,33 @@ EXAMPLES loaded_at Sep 29/20:11 uid 0 xlated 528B jited 370B memlock 4096B map_ids 10 +**# bpftool --json --pretty prog show** + +:: + + { + "programs": [{ + "id": 10, + "type": "xdp", + "tag": "005a3d2123620c8b", + "loaded_at": "Sep 29/20:11", + "uid": 0, + "bytes_xlated": 528, + "jited": true, + "bytes_jited": 370, + "bytes_memlock": 4096, + "map_ids": [10 + ] + } + ] + } + | | **# bpftool prog dump xlated id 10 file /tmp/t** | **# ls -l /tmp/t** | -rw------- 1 root root 560 Jul 22 01:42 /tmp/t -| -| **# bpftool prog dum jited pinned /sys/fs/bpf/prog** +**# bpftool prog dum jited tag 005a3d2123620c8b** :: @@ -83,6 +120,26 @@ EXAMPLES sub $0x28,%rbp mov %rbx,0x0(%rbp) +| +| **# mount -t bpf none /sys/fs/bpf/** +| **# bpftool prog pin id 10 /sys/fs/bpf/prog** +| **# ls -l /sys/fs/bpf/** +| -rw------- 1 root root 0 Jul 22 01:43 prog + +**# bpftool prog dum jited pinned /sys/fs/bpf/prog opcodes** + +:: + + push %rbp + 55 + mov %rsp,%rbp + 48 89 e5 + sub $0x228,%rsp + 48 81 ec 28 02 00 00 + sub $0x28,%rbp + 48 83 ed 28 + mov %rbx,0x0(%rbp) + 48 89 5d 00 SEE ALSO diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst index 44e07799d54d..926c03d5a8da 100644 --- a/tools/bpf/bpftool/Documentation/bpftool.rst +++ b/tools/bpf/bpftool/Documentation/bpftool.rst @@ -10,7 +10,7 @@ tool for inspection and simple manipulation of eBPF programs and maps SYNOPSIS ======== - **bpftool** *OBJECT* { *COMMAND* | **help** } + **bpftool** [*OPTIONS*] *OBJECT* { *COMMAND* | **help** } **bpftool** **batch file** *FILE* @@ -18,6 +18,9 @@ SYNOPSIS *OBJECT* := { **map** | **program** } + *OPTIONS* := { { **-V** | **--version** } | { **-h** | **--help** } + | { **-j** | **--json** } [{ **-p** | **--pretty** }] } + *MAP-COMMANDS* := { **show** | **dump** | **update** | **lookup** | **getnext** | **delete** | **pin** | **help** } @@ -41,6 +44,13 @@ OPTIONS -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 ======== **bpftool-map**\ (8), **bpftool-prog**\ (8) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 55ba0a04c102..78d9afb74ef4 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -70,11 +70,13 @@ static int do_help(int argc, char **argv) } fprintf(stderr, - "Usage: %s OBJECT { COMMAND | help }\n" + "Usage: %s [OPTIONS] OBJECT { COMMAND | help }\n" " %s batch file FILE\n" " %s version\n" "\n" - " OBJECT := { prog | map }\n", + " OBJECT := { prog | map }\n" + " " HELP_SPEC_OPTIONS "\n" + "", bin_name, bin_name, bin_name); return 0; diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 04c88b55d8c7..2f94bed03a8d 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -55,6 +55,8 @@ #define HELP_SPEC_PROGRAM \ "PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }" +#define HELP_SPEC_OPTIONS \ + "OPTIONS := { {-j|--json} [{-p|--pretty}] }" enum bpf_obj_type { BPF_OBJ_UNKNOWN, diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c index a611f31f574f..e978ab23a77f 100644 --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -850,6 +850,7 @@ static int do_help(int argc, char **argv) " " HELP_SPEC_PROGRAM "\n" " VALUE := { BYTES | MAP | PROG }\n" " UPDATE_FLAGS := { any | exist | noexist }\n" + " " HELP_SPEC_OPTIONS "\n" "", bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index e07f35ff80d1..250f80fd46aa 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -625,6 +625,7 @@ static int do_help(int argc, char **argv) " %s %s help\n" "\n" " " HELP_SPEC_PROGRAM "\n" + " " HELP_SPEC_OPTIONS "\n" "", bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);