Received: by 2002:ac0:a591:0:0:0:0:0 with SMTP id m17-v6csp1887046imm; Sun, 8 Jul 2018 13:37:45 -0700 (PDT) X-Google-Smtp-Source: AAOMgpcNB/PgKaL43taPDsYAJ/BlQu3kMjyNWmG2aFNbOnQPHMwiJPQKc5fCY1hYid9RLykR1K/K X-Received: by 2002:a62:6cc7:: with SMTP id h190-v6mr18741996pfc.113.1531082264974; Sun, 08 Jul 2018 13:37:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1531082264; cv=none; d=google.com; s=arc-20160816; b=FOeUpCJ5acoQLAqMhB1jUyRBV2S+S24Y8Fh4CQzlICUzXIZPcnlBo1FWv4AbqvyXAZ iV+Qtt/691o3qNlBVfUMxQ8I21u1B0Fu3vXvkcbOgHmBMYUOxOKlPXl8iW9gOuWTP1yP 5t5C+9OKN0hYb6f3Zu8VDXvOMPjJPlBtpwQwDKuhZiJjPxvtkwzZ4ICE2KLE8t+14ZGe rLLKH1WLrflsIDAf9vVyWFlPGym9ZmEUBNalO6ZKv7a6LiLN10pG8X48M+2u3oBiBpAT y0HUsgWpa0ovPSUM9dgUPnDHL0rx1h7A516u6RJ+vm7Uj/ScAtMJRGaV0TINtKTWfCWB /K1A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-disposition:mime-version :references:subject:smtp-origin-cluster:cc:to:smtp-origin-hostname :from:smtp-origin-hostprefix:date:user-agent:message-id :dkim-signature:arc-authentication-results; bh=RHKFnIBbpd5ztKVN8+ccYiP2f7F+D3IoY0hf1y7r4GQ=; b=hj1Zvei5DWcWZEoaKLskhFi5i1VEozhfiM4INNscYV5CbiFhy7OVWdNf+Noq2xgQyQ hdt7ZWDEYYCfXAbxUZ+saXsK0pV6tXgLbPs08722qO7N3u7yq6CFZx093cK4ljjvHoma vvw/UpNE88PeZXR9Fsh+/XYGSp9RhhdIrDQTMs+mb/zYKq20aRfhs+HT3pK1vJaRIrhc vuYVpNvaxeKWbEdqFErNuMO55akXhOfZoIznnnqyfYffKQ5UuD0JqISAG0iXw7OQ+TO9 t93m70NV0F2lYKFzrKVBjpTQrLrHlj1wgDjhErkwQMOQINd2mNjs23eFRTTzPoZk8KsY XrfQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@fb.com header.s=facebook header.b=Ckb6vhFJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=fb.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id n7-v6si12186107plp.363.2018.07.08.13.37.07; Sun, 08 Jul 2018 13:37:44 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@fb.com header.s=facebook header.b=Ckb6vhFJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=fb.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754371AbeGHUgD (ORCPT + 99 others); Sun, 8 Jul 2018 16:36:03 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:56306 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754239AbeGHUgB (ORCPT ); Sun, 8 Jul 2018 16:36:01 -0400 Received: from pps.filterd (m0148461.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w68KReBQ020563 for ; Sun, 8 Jul 2018 13:36:01 -0700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=message-id : date : from : to : cc : subject : references : mime-version : content-type; s=facebook; bh=RHKFnIBbpd5ztKVN8+ccYiP2f7F+D3IoY0hf1y7r4GQ=; b=Ckb6vhFJ5jgzKLmvQNEQAo49z6YrQO86MWJ84oLqWTsES7eLxtQ9KUMXA29cz2BJADPw +gEsm65EIlJtHJxBhBlA1p64b6FCNRwsiizqcCcyFRDm3piAM88pDmuAbEwErunkjKqu DFMR+vRQYIYPiV3EOmx5m5HQX6QmI9kmqXQ= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2k2tmet765-1 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT) for ; Sun, 08 Jul 2018 13:36:01 -0700 Received: from PRN-CHUB02.TheFacebook.com (2620:10d:c081:35::11) by PRN-CHUB13.TheFacebook.com (2620:10d:c081:35::22) with Microsoft SMTP Server (TLS) id 14.3.361.1; Sun, 8 Jul 2018 13:36:00 -0700 Received: from mx-out.facebook.com (192.168.52.123) by mail.thefacebook.com (192.168.16.12) with Microsoft SMTP Server (TLS) id 14.3.361.1; Sun, 8 Jul 2018 13:35:59 -0700 Received: by dev026.lla1.facebook.com (Postfix, from userid 152872) id A1D898A4581; Sun, 8 Jul 2018 13:33:36 -0700 (PDT) Message-ID: <20180708203336.570589830@fb.com> User-Agent: quilt/0.63-1 Date: Sun, 8 Jul 2018 13:30:05 -0700 Smtp-Origin-Hostprefix: dev From: Okash Khawaja Smtp-Origin-Hostname: dev026.lla1.facebook.com To: Daniel Borkmann , Martin KaFai Lau , Alexei Starovoitov , Yonghong Song , "Quentin Monnet" , Jakub Kicinski , "David S. Miller" CC: , , Smtp-Origin-Cluster: lla1c22 Subject: [PATCH bpf-next v3 3/3] bpf: btf: print map dump and lookup with btf info References: <20180708203002.543403467@fb.com> MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Disposition: inline; filename="03-json-print-btf-info-for-map" X-FB-Internal: Safe X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:,, definitions=2018-07-08_12:,, signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch augments the output of bpftool's map dump and map lookup commands to print data along side btf info, if the correspondin btf info is available. The outputs for each of map dump and map lookup commands are augmented in two ways: 1. when neither of -j and -p are supplied, btf-ful map data is printed whose aim is human readability. This means no commitments for json- or backward- compatibility. 2. when either -j or -p are supplied, a new json object named "formatted" is added for each key-value pair. This object contains the same data as the key-value pair, but with btf info. "formatted" object promises json- and backward- compatibility. Below is a sample output. $ bpftool map dump -p id 8 [{ "key": ["0x0f","0x00","0x00","0x00" ], "value": ["0x03", "0x00", "0x00", "0x00", ... ], "formatted": { "key": 15, "value": { "int_field": 3, ... } } } ] This patch calls btf_dumper introduced in previous patch to accomplish the above. Indeed, btf-ful info is only displayed if btf data for the given map is available. Otherwise existing output is displayed as-is. Signed-off-by: Okash Khawaja --- tools/bpf/bpftool/map.c | 207 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 191 insertions(+), 16 deletions(-) --- a/tools/bpf/bpftool/map.c +++ b/tools/bpf/bpftool/map.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,8 @@ #include +#include "btf.h" +#include "json_writer.h" #include "main.h" static const char * const map_type_name[] = { @@ -148,8 +151,111 @@ int map_parse_fd_and_info(int *argc, cha return fd; } +static int do_dump_btf(const struct btf_dumper *d, + struct bpf_map_info *map_info, void *key, + void *value) +{ + int ret; + + /* start of key-value pair */ + jsonw_start_object(d->jw); + + jsonw_name(d->jw, "key"); + + ret = btf_dumper_type(d, map_info->btf_key_type_id, key); + if (ret) + goto err_end_obj; + + jsonw_name(d->jw, "value"); + + ret = btf_dumper_type(d, map_info->btf_value_type_id, value); + +err_end_obj: + /* end of key-value pair */ + jsonw_end_object(d->jw); + + return ret; +} + +static struct btf *get_btf(struct bpf_map_info *map_info) +{ + struct bpf_btf_info btf_info = { 0 }; + __u32 len = sizeof(btf_info); + struct btf *btf = NULL; + __u32 last_size; + int btf_fd; + void *ptr; + int err; + + btf_fd = bpf_btf_get_fd_by_id(map_info->btf_id); + if (btf_fd < 0) + return NULL; + + /* we won't know btf_size until we call bpf_obj_get_info_by_fd(). so + * let's start with a sane default - 4KiB here - and resize it only if + * bpf_obj_get_info_by_fd() needs a bigger buffer. + */ + btf_info.btf_size = 4096; + last_size = btf_info.btf_size; + ptr = malloc(last_size); + if (!ptr) { + p_err("unable to allocate memory for debug info"); + goto exit_free; + } + + bzero(ptr, last_size); + btf_info.btf = ptr_to_u64(ptr); + err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); + + if (!err && btf_info.btf_size > last_size) { + void *temp_ptr; + + last_size = btf_info.btf_size; + temp_ptr = realloc(ptr, last_size); + if (!temp_ptr) { + p_err("unable to re-allocate memory for debug info"); + goto exit_free; + } + ptr = temp_ptr; + bzero(ptr, last_size); + btf_info.btf = ptr_to_u64(ptr); + err = bpf_obj_get_info_by_fd(btf_fd, &btf_info, &len); + } + + if (err || btf_info.btf_size > last_size) { + p_info("can't get btf info. debug info won't be displayed. error: %s", + err ? strerror(errno) : "exceeds size retry"); + goto exit_free; + } + + btf = btf__new((__u8 *)btf_info.btf, + btf_info.btf_size, NULL); + if (IS_ERR(btf)) { + p_info("error when initialising btf: %s\n", + strerror(PTR_ERR(btf))); + btf = NULL; + } + +exit_free: + close(btf_fd); + free(ptr); + + return btf; +} + +static json_writer_t *get_btf_writer(void) +{ + json_writer_t *jw = jsonw_new(stdout); + + if (!jw) + return NULL; + jsonw_pretty(jw, true); + + return jw; +} + static void print_entry_json(struct bpf_map_info *info, unsigned char *key, - unsigned char *value) + unsigned char *value, struct btf *btf) { jsonw_start_object(json_wtr); @@ -158,6 +264,16 @@ static void print_entry_json(struct bpf_ print_hex_data_json(key, info->key_size); jsonw_name(json_wtr, "value"); print_hex_data_json(value, info->value_size); + if (btf) { + struct btf_dumper d = { + .btf = btf, + .jw = json_wtr, + .is_plain_text = false, + }; + + jsonw_name(json_wtr, "formatted"); + do_dump_btf(&d, info, key, value); + } } else { unsigned int i, n; @@ -508,10 +624,12 @@ static int do_show(int argc, char **argv static int do_dump(int argc, char **argv) { + struct bpf_map_info info = {}; void *key, *value, *prev_key; unsigned int num_elems = 0; - struct bpf_map_info info = {}; __u32 len = sizeof(info); + json_writer_t *btf_wtr; + struct btf *btf = NULL; int err; int fd; @@ -537,8 +655,22 @@ static int do_dump(int argc, char **argv } prev_key = NULL; + + btf = get_btf(&info); if (json_output) jsonw_start_array(json_wtr); + else + if (btf) { + btf_wtr = get_btf_writer(); + if (!btf_wtr) { + p_info("failed to create json writer for btf. falling back to plain output"); + btf__free(btf); + btf = NULL; + } else { + jsonw_start_array(btf_wtr); + } + } + while (true) { err = bpf_map_get_next_key(fd, prev_key, key); if (err) { @@ -549,9 +681,18 @@ static int do_dump(int argc, char **argv if (!bpf_map_lookup_elem(fd, key, value)) { if (json_output) - print_entry_json(&info, key, value); + print_entry_json(&info, key, value, btf); else - print_entry_plain(&info, key, value); + if (btf) { + struct btf_dumper d = { + .btf = btf, + .jw = btf_wtr, + .is_plain_text = true, + }; + do_dump_btf(&d, &info, key, value); + } else { + print_entry_plain(&info, key, value); + } } else { if (json_output) { jsonw_name(json_wtr, "key"); @@ -574,14 +715,19 @@ static int do_dump(int argc, char **argv if (json_output) jsonw_end_array(json_wtr); - else + else if (btf) { + jsonw_end_array(btf_wtr); + jsonw_destroy(&btf_wtr); + } else { printf("Found %u element%s\n", num_elems, num_elems != 1 ? "s" : ""); + } exit_free: free(key); free(value); close(fd); + btf__free(btf); return err; } @@ -637,6 +783,8 @@ static int do_lookup(int argc, char **ar { struct bpf_map_info info = {}; __u32 len = sizeof(info); + json_writer_t *btf_wtr; + struct btf *btf = NULL; void *key, *value; int err; int fd; @@ -661,27 +809,54 @@ static int do_lookup(int argc, char **ar goto exit_free; err = bpf_map_lookup_elem(fd, key, value); - if (!err) { - if (json_output) - print_entry_json(&info, key, value); - else + if (err) { + if (errno == ENOENT) { + if (json_output) { + jsonw_null(json_wtr); + } else { + printf("key:\n"); + fprint_hex(stdout, key, info.key_size, " "); + printf("\n\nNot found\n"); + } + } else { + p_err("lookup failed: %s", strerror(errno)); + } + + goto exit_free; + } + + /* here means bpf_map_lookup_elem() succeeded */ + btf = get_btf(&info); + if (json_output) { + print_entry_json(&info, key, value, btf); + } else if (btf) { + /* if here json_wtr wouldn't have been initialised, + * so let's create separate writer for btf + */ + btf_wtr = get_btf_writer(); + if (!btf_wtr) { + p_info("failed to create json writer for btf. falling back to plain output"); + btf__free(btf); + btf = NULL; print_entry_plain(&info, key, value); - } else if (errno == ENOENT) { - if (json_output) { - jsonw_null(json_wtr); } else { - printf("key:\n"); - fprint_hex(stdout, key, info.key_size, " "); - printf("\n\nNot found\n"); + struct btf_dumper d = { + .btf = btf, + .jw = btf_wtr, + .is_plain_text = true, + }; + do_dump_btf(&d, &info, key, value); + jsonw_destroy(&btf_wtr); } } else { - p_err("lookup failed: %s", strerror(errno)); + print_entry_plain(&info, key, value); } exit_free: free(key); free(value); close(fd); + btf__free(btf); return err; }