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);