From patchwork Wed Sep 9 18:24:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stanislav Fomichev X-Patchwork-Id: 261227 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.5 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D2E54C43461 for ; Wed, 9 Sep 2020 18:25:06 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 858C421D40 for ; Wed, 9 Sep 2020 18:25:06 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="afXZik5c" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729741AbgIISY6 (ORCPT ); Wed, 9 Sep 2020 14:24:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46406 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727075AbgIISYP (ORCPT ); Wed, 9 Sep 2020 14:24:15 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BBBCAC061786 for ; Wed, 9 Sep 2020 11:24:14 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id s3so3065146ybi.18 for ; Wed, 09 Sep 2020 11:24:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=Kp0FBrpofhNJI+kmmwHfi2Nq63x0XIfSCSb00FSkJPA=; b=afXZik5cfyiAAg4USSINaxi07eTcXvUFDvmzMlaDDJ69cxoQ8TqAy8YUwqmzPn5Zrc MvInKeEjqhq7jyCwSZO9Dw7xolMNyyZTyZ3abQn0/InrVHnEiUAUgP7fDMlvCCu7EWsb O0L0jdU4aZyxJlWV0x808jRMdGYpTdOLk7j1fQF8KQ4O+gdVfn9KpUOOH2HQFKIe/nZ+ D2nruda2SA8Vd3tNw4+6S/OZCHZmTSutViGTiO3uRn13XeB6RlR7bjH4Y79FL33CoLDA 5i6xQx5R/95i4uKxajUD57/M/pd1Qu6/oANb6K8uvXnXYeGH4UQXedigrbEctBSWXeV8 o3Zg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=Kp0FBrpofhNJI+kmmwHfi2Nq63x0XIfSCSb00FSkJPA=; b=ZECSzpqQMRIDYbVN/Y+QQxbUg8e0rtq1T2mfS3YAzfC/PdEW8mEuXtgNSN1g+1Eupd nnn3ZufG1LSxBWmkZSvTcGZe67uCTggLYQaCOGxFahI4n9sqNrNCPC/iM9O5u47VLht7 yN1BFqm+GuqyyYUN0D/s/M+FxEW+xzYN8PySTuCO2bE2M7uxEApelMTa1WezwL+Dic3J L63V0gbfoJjDL1ynWPXmLUOUUPViD35cP22u68S57t4e5jjmDHlwNG0HpVl88KusisET 3s/Q4rCO/psm30RGQHbou2DEtoA6VWmMOf+ziq1s2MnK3MqOhTr+W4dItdolFOy+Uq0I tmqw== X-Gm-Message-State: AOAM530vvL/Q3fySP/R0cPlnvI5qmVo4MyXZxH4sINS+v6OItj5fVLv2 jHlGhcCK+XC4AIi1+KXf8s0b0Vgr/6n7ZxtEhv+BaqvUe8wxy7lE99iDGue2Er/NEcqS6aajnzP z2Gzqd2iqNkliGjiMMEVZpkjQrs57H8ldD4PIfLhmnVgM+UtnmzcqBA== X-Google-Smtp-Source: ABdhPJzdQl/DtmvRdisK6Z1bgExtHgErmst9kwdRUu1Taswo9nYt99YEmvxDUscE5M+j96/rOv1cMh0= X-Received: from sdf2.svl.corp.google.com ([2620:15c:2c4:1:7220:84ff:fe09:7732]) (user=sdf job=sendgmr) by 2002:a25:d348:: with SMTP id e69mr7964941ybf.273.1599675853854; Wed, 09 Sep 2020 11:24:13 -0700 (PDT) Date: Wed, 9 Sep 2020 11:24:04 -0700 In-Reply-To: <20200909182406.3147878-1-sdf@google.com> Message-Id: <20200909182406.3147878-4-sdf@google.com> Mime-Version: 1.0 References: <20200909182406.3147878-1-sdf@google.com> X-Mailer: git-send-email 2.28.0.526.ge36021eeef-goog Subject: [PATCH bpf-next v4 3/5] libbpf: Add BPF_PROG_BIND_MAP syscall and use it on .metadata section From: Stanislav Fomichev To: netdev@vger.kernel.org, bpf@vger.kernel.org Cc: davem@davemloft.net, ast@kernel.org, daniel@iogearbox.net, YiFei Zhu , YiFei Zhu , Stanislav Fomichev Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: YiFei Zhu The patch adds a simple wrapper bpf_prog_bind_map around the syscall. When the libbpf tries to load a program, it will probe the kernel for the support of this syscall and unconditionally bind .rodata section to the program. Cc: YiFei Zhu Signed-off-by: YiFei Zhu Signed-off-by: Stanislav Fomichev --- tools/lib/bpf/bpf.c | 13 ++++++ tools/lib/bpf/bpf.h | 8 ++++ tools/lib/bpf/libbpf.c | 94 ++++++++++++++++++++++++++++++++-------- tools/lib/bpf/libbpf.map | 1 + 4 files changed, 98 insertions(+), 18 deletions(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 82b983ff6569..5f6c5676cc45 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -872,3 +872,16 @@ int bpf_enable_stats(enum bpf_stats_type type) return sys_bpf(BPF_ENABLE_STATS, &attr, sizeof(attr)); } + +int bpf_prog_bind_map(int prog_fd, int map_fd, + const struct bpf_prog_bind_opts *opts) +{ + union bpf_attr attr; + + memset(&attr, 0, sizeof(attr)); + attr.prog_bind_map.prog_fd = prog_fd; + attr.prog_bind_map.map_fd = map_fd; + attr.prog_bind_map.flags = OPTS_GET(opts, flags, 0); + + return sys_bpf(BPF_PROG_BIND_MAP, &attr, sizeof(attr)); +} diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h index 015d13f25fcc..8c1ac4b42f90 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -243,6 +243,14 @@ LIBBPF_API int bpf_task_fd_query(int pid, int fd, __u32 flags, char *buf, enum bpf_stats_type; /* defined in up-to-date linux/bpf.h */ LIBBPF_API int bpf_enable_stats(enum bpf_stats_type type); +struct bpf_prog_bind_opts { + size_t sz; /* size of this struct for forward/backward compatibility */ + __u32 flags; +}; +#define bpf_prog_bind_opts__last_field flags + +LIBBPF_API int bpf_prog_bind_map(int prog_fd, int map_fd, + const struct bpf_prog_bind_opts *opts); #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 550950eb1860..f500ae7e9126 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -174,6 +174,8 @@ enum kern_feature_id { FEAT_EXP_ATTACH_TYPE, /* bpf_probe_read_{kernel,user}[_str] helpers */ FEAT_PROBE_READ_KERN, + /* BPF_PROG_BIND_MAP is supported */ + FEAT_PROG_BIND_MAP, __FEAT_CNT, }; @@ -409,6 +411,7 @@ struct bpf_object { struct extern_desc *externs; int nr_extern; int kconfig_map_idx; + int rodata_map_idx; bool loaded; bool has_subcalls; @@ -1070,6 +1073,7 @@ static struct bpf_object *bpf_object__new(const char *path, obj->efile.bss_shndx = -1; obj->efile.st_ops_shndx = -1; obj->kconfig_map_idx = -1; + obj->rodata_map_idx = -1; obj->kern_version = get_kernel_version(); obj->loaded = false; @@ -1428,6 +1432,8 @@ static int bpf_object__init_global_data_maps(struct bpf_object *obj) obj->efile.rodata->d_size); if (err) return err; + + obj->rodata_map_idx = obj->nr_maps - 1; } if (obj->efile.bss_shndx >= 0) { err = bpf_object__init_internal_map(obj, LIBBPF_MAP_BSS, @@ -3729,18 +3735,13 @@ static int probe_kern_prog_name(void) return probe_fd(ret); } -static int probe_kern_global_data(void) +static void probe_create_global_data(int *prog, int *map, + struct bpf_insn *insns, size_t insns_cnt) { struct bpf_load_program_attr prg_attr; struct bpf_create_map_attr map_attr; char *cp, errmsg[STRERR_BUFSIZE]; - struct bpf_insn insns[] = { - BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16), - BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42), - BPF_MOV64_IMM(BPF_REG_0, 0), - BPF_EXIT_INSN(), - }; - int ret, map; + int err; memset(&map_attr, 0, sizeof(map_attr)); map_attr.map_type = BPF_MAP_TYPE_ARRAY; @@ -3748,26 +3749,40 @@ static int probe_kern_global_data(void) map_attr.value_size = 32; map_attr.max_entries = 1; - map = bpf_create_map_xattr(&map_attr); - if (map < 0) { - ret = -errno; - cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); + *map = bpf_create_map_xattr(&map_attr); + if (*map < 0) { + err = errno; + cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg)); pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", - __func__, cp, -ret); - return ret; + __func__, cp, -err); + return; } - insns[0].imm = map; + insns[0].imm = *map; memset(&prg_attr, 0, sizeof(prg_attr)); prg_attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; prg_attr.insns = insns; - prg_attr.insns_cnt = ARRAY_SIZE(insns); + prg_attr.insns_cnt = insns_cnt; prg_attr.license = "GPL"; - ret = bpf_load_program_xattr(&prg_attr, NULL, 0); + *prog = bpf_load_program_xattr(&prg_attr, NULL, 0); +} + +static int probe_kern_global_data(void) +{ + struct bpf_insn insns[] = { + BPF_LD_MAP_VALUE(BPF_REG_1, 0, 16), + BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 42), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + int prog = -1, map = -1; + + probe_create_global_data(&prog, &map, insns, ARRAY_SIZE(insns)); + close(map); - return probe_fd(ret); + return probe_fd(prog); } static int probe_kern_btf(void) @@ -3894,6 +3909,32 @@ static int probe_kern_probe_read_kernel(void) return probe_fd(bpf_load_program_xattr(&attr, NULL, 0)); } +static int probe_prog_bind_map(void) +{ + struct bpf_insn insns[] = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + int prog = -1, map = -1, ret = 0; + + if (!kernel_supports(FEAT_GLOBAL_DATA)) + return 0; + + probe_create_global_data(&prog, &map, insns, ARRAY_SIZE(insns)); + + if (map >= 0 && prog < 0) { + close(map); + return 0; + } + + if (!bpf_prog_bind_map(prog, map, NULL)) + ret = 1; + + close(map); + close(prog); + return ret; +} + enum kern_feature_result { FEAT_UNKNOWN = 0, FEAT_SUPPORTED = 1, @@ -3934,6 +3975,9 @@ static struct kern_feature_desc { }, [FEAT_PROBE_READ_KERN] = { "bpf_probe_read_kernel() helper", probe_kern_probe_read_kernel, + }, + [FEAT_PROG_BIND_MAP] = { + "BPF_PROG_BIND_MAP support", probe_prog_bind_map, } }; @@ -6468,6 +6512,20 @@ load_program(struct bpf_program *prog, struct bpf_insn *insns, int insns_cnt, if (ret >= 0) { if (log_buf && load_attr.log_level) pr_debug("verifier log:\n%s", log_buf); + + if (prog->obj->rodata_map_idx >= 0 && + kernel_supports(FEAT_PROG_BIND_MAP)) { + struct bpf_map *rodata_map = + &prog->obj->maps[prog->obj->rodata_map_idx]; + + if (bpf_prog_bind_map(ret, bpf_map__fd(rodata_map), NULL)) { + cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); + pr_warn("prog '%s': failed to bind .rodata map: %s\n", + prog->name, cp); + /* Don't fail hard if can't bind rodata. */ + } + } + *pfd = ret; ret = 0; goto out; diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index 92ceb48a5ca2..0b7830f4ff8b 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -308,4 +308,5 @@ LIBBPF_0.2.0 { perf_buffer__epoll_fd; perf_buffer__consume_buffer; xsk_socket__create_shared; + bpf_prog_bind_map; } LIBBPF_0.1.0; From patchwork Wed Sep 9 18:24:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stanislav Fomichev X-Patchwork-Id: 261228 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-12.5 required=3.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_INVALID, DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 818C6C433E2 for ; Wed, 9 Sep 2020 18:24:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3733C21941 for ; Wed, 9 Sep 2020 18:24:39 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="T1fjKqny" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729622AbgIISYe (ORCPT ); Wed, 9 Sep 2020 14:24:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46394 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728264AbgIISYW (ORCPT ); Wed, 9 Sep 2020 14:24:22 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 90E87C061796 for ; Wed, 9 Sep 2020 11:24:16 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id t127so3050873ybf.16 for ; Wed, 09 Sep 2020 11:24:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=b0qCV0C2cjdPMv4ejLiY/AMfUzUSAd07vJk0w5XDbZE=; b=T1fjKqnynJhcVChZR80gQuP+D+tCnKgekk2pvC+8d8lezX9nqtC4Pfi1V7EsmB1QaN aKZBdm1t/eGzrpRGrgv9iDYvFkQE1W4B/Jdc/b1J/TFXBF0GVrZQI4Ugl6MEnWxm7JRn AaToExAzcF23Ox76hH+yTAGyauJX7Y0mVZ56jIuFIyGXDhNiDFnFrVvqe6FnHiddLt0x /1TMbfwZZDz5V5UVP3KHs78F3+h3VrQKkvJWyYbcOeSPZocb/AUMAovBJsiM1KuW3zj4 RnEAkbEMAPO4/O7N/dXkmZVxREe9gEiL5kWKYS94OTSXY7utkf3eF48UzrkGEthlR/8g dDQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=b0qCV0C2cjdPMv4ejLiY/AMfUzUSAd07vJk0w5XDbZE=; b=lYpPURAtsHJBgc68aIKqedE1qAPs8l6hLW/ZHgTNWaJMwmuSy394nZVxjf+CjGjDNY MO7Q8lvb3ofv26fag+pm05WE4whUCV2Fa0fKCcZ2PNmMMUtWhry63e6T8Q1Kc4uMlnS/ G1NT2uTSgqd8irCNf5HomkZrjSXU9Y3qYRfGe3RvDWz7YG/GDAnf94i3val0XWWuOmMH l5tz7xuVUwYo5VgmMFHdiSTmwJJllZn9z3jwJULpP+9qUUdOfTM+OmEiqwt3mxtysHJc Nzh5AV1FFLAEl261f13UVY87jJIl4tZUKiWXNLsZFjHFJru59AfPn8gblDONVRMFbGhs hF+g== X-Gm-Message-State: AOAM533aXgZ6XiB9oh7UtwS2H6ISGuPvS7SNOSVejHaAQ4X9h+4zdRoz dVc0OSba9u1hzZIX7tvdnl3cNtEIvGt614QuxkPpInebVzQ4YavqWVS6WsYtqvyQeFiDygqpVv4 2ykyo+jlALePPZvdR1M+Jbv/oQXPtUPYwNgIdNQZlJCvPtyC+lC557w== X-Google-Smtp-Source: ABdhPJy7KgmqOZMSgq+Dbb9B/W9oXpEERO9XLv8Oj6xqefNb3AHWo9v0NhRCQ7thZWLQ3NAqhLVIzAA= X-Received: from sdf2.svl.corp.google.com ([2620:15c:2c4:1:7220:84ff:fe09:7732]) (user=sdf job=sendgmr) by 2002:a05:6902:4e3:: with SMTP id w3mr8272813ybs.172.1599675855681; Wed, 09 Sep 2020 11:24:15 -0700 (PDT) Date: Wed, 9 Sep 2020 11:24:05 -0700 In-Reply-To: <20200909182406.3147878-1-sdf@google.com> Message-Id: <20200909182406.3147878-5-sdf@google.com> Mime-Version: 1.0 References: <20200909182406.3147878-1-sdf@google.com> X-Mailer: git-send-email 2.28.0.526.ge36021eeef-goog Subject: [PATCH bpf-next v4 4/5] bpftool: support dumping metadata From: Stanislav Fomichev To: netdev@vger.kernel.org, bpf@vger.kernel.org Cc: davem@davemloft.net, ast@kernel.org, daniel@iogearbox.net, YiFei Zhu , YiFei Zhu , Stanislav Fomichev Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: YiFei Zhu Dump metadata in the 'bpftool prog' list if it's present. For some formatting some BTF code is put directly in the metadata dumping. Sanity checks on the map and the kind of the btf_type to make sure we are actually dumping what we are expecting. A helper jsonw_reset is added to json writer so we can reuse the same json writer without having extraneous commas. Sample output: $ bpftool prog 6: cgroup_skb name prog tag bcf7977d3b93787c gpl [...] btf_id 4 metadata: a = "foo" b = 1 $ bpftool prog --json --pretty [{ "id": 6, [...] "btf_id": 4, "metadata": { "a": "foo", "b": 1 } } ] Cc: YiFei Zhu Signed-off-by: YiFei Zhu Signed-off-by: Stanislav Fomichev --- tools/bpf/bpftool/json_writer.c | 6 + tools/bpf/bpftool/json_writer.h | 3 + tools/bpf/bpftool/prog.c | 222 ++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+) diff --git a/tools/bpf/bpftool/json_writer.c b/tools/bpf/bpftool/json_writer.c index 86501cd3c763..7fea83bedf48 100644 --- a/tools/bpf/bpftool/json_writer.c +++ b/tools/bpf/bpftool/json_writer.c @@ -119,6 +119,12 @@ void jsonw_pretty(json_writer_t *self, bool on) self->pretty = on; } +void jsonw_reset(json_writer_t *self) +{ + assert(self->depth == 0); + self->sep = '\0'; +} + /* Basic blocks */ static void jsonw_begin(json_writer_t *self, int c) { diff --git a/tools/bpf/bpftool/json_writer.h b/tools/bpf/bpftool/json_writer.h index 35cf1f00f96c..8ace65cdb92f 100644 --- a/tools/bpf/bpftool/json_writer.h +++ b/tools/bpf/bpftool/json_writer.h @@ -27,6 +27,9 @@ void jsonw_destroy(json_writer_t **self_p); /* Cause output to have pretty whitespace */ void jsonw_pretty(json_writer_t *self, bool on); +/* Reset separator to create new JSON */ +void jsonw_reset(json_writer_t *self); + /* Add property name */ void jsonw_name(json_writer_t *self, const char *name); diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index f7923414a052..ca264dc22434 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -29,6 +29,9 @@ #include "main.h" #include "xlated_dumper.h" +#define BPF_METADATA_PREFIX "bpf_metadata_" +#define BPF_METADATA_PREFIX_LEN strlen(BPF_METADATA_PREFIX) + const char * const prog_type_name[] = { [BPF_PROG_TYPE_UNSPEC] = "unspec", [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", @@ -151,6 +154,221 @@ static void show_prog_maps(int fd, __u32 num_maps) } } +static int bpf_prog_find_metadata(int prog_fd, int *map_id) +{ + struct bpf_prog_info prog_info = {}; + struct bpf_map_info map_info; + __u32 prog_info_len; + __u32 map_info_len; + int saved_errno; + __u32 *map_ids; + int nr_maps; + int map_fd; + int ret; + __u32 i; + + prog_info_len = sizeof(prog_info); + + ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); + if (ret) + return ret; + + if (!prog_info.nr_map_ids) { + errno = ENOENT; + return -1; + } + + map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32)); + if (!map_ids) { + errno = ENOMEM; + return -1; + } + + nr_maps = prog_info.nr_map_ids; + memset(&prog_info, 0, sizeof(prog_info)); + prog_info.nr_map_ids = nr_maps; + prog_info.map_ids = ptr_to_u64(map_ids); + prog_info_len = sizeof(prog_info); + + ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); + if (ret) + goto free_map_ids; + + for (i = 0; i < prog_info.nr_map_ids; i++) { + map_fd = bpf_map_get_fd_by_id(map_ids[i]); + if (map_fd < 0) { + ret = -1; + goto free_map_ids; + } + + memset(&map_info, 0, sizeof(map_info)); + map_info_len = sizeof(map_info); + ret = bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len); + + saved_errno = errno; + close(map_fd); + errno = saved_errno; + if (ret) + goto free_map_ids; + + if (map_info.type != BPF_MAP_TYPE_ARRAY) + continue; + if (map_info.key_size != sizeof(int)) + continue; + if (map_info.max_entries != 1) + continue; + if (!map_info.btf_value_type_id) + continue; + if (!strstr(map_info.name, ".rodata")) + continue; + + *map_id = map_ids[i]; + goto free_map_ids; + } + + ret = -1; + errno = ENOENT; + +free_map_ids: + saved_errno = errno; + free(map_ids); + errno = saved_errno; + return ret; +} + +static bool has_metadata_prefix(const char *s) +{ + return strstr(s, BPF_METADATA_PREFIX) == s; +} + +static void show_prog_metadata(int fd, __u32 num_maps) +{ + const struct btf_type *t_datasec, *t_var; + struct bpf_map_info map_info = {}; + struct btf_var_secinfo *vsi; + bool printed_header = false; + struct btf *btf = NULL; + unsigned int i, vlen; + __u32 map_info_len; + void *value = NULL; + const char *name; + int map_id = 0; + int key = 0; + int map_fd; + int err; + + if (!num_maps) + return; + + err = bpf_prog_find_metadata(fd, &map_id); + if (err < 0) + return; + + map_fd = bpf_map_get_fd_by_id(map_id); + if (map_fd < 0) + return; + + map_info_len = sizeof(map_info); + err = bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len); + if (err) + goto out_close; + + value = malloc(map_info.value_size); + if (!value) + goto out_close; + + if (bpf_map_lookup_elem(map_fd, &key, value)) + goto out_free; + + err = btf__get_from_id(map_info.btf_id, &btf); + if (err || !btf) + goto out_free; + + t_datasec = btf__type_by_id(btf, map_info.btf_value_type_id); + if (!btf_is_datasec(t_datasec)) + goto out_free; + + vlen = btf_vlen(t_datasec); + vsi = btf_var_secinfos(t_datasec); + + /* We don't proceed to check the kinds of the elements of the DATASEC. + * The verifier enforces them to be BTF_KIND_VAR. + */ + + if (json_output) { + struct btf_dumper d = { + .btf = btf, + .jw = json_wtr, + .is_plain_text = false, + }; + + for (i = 0; i < vlen; i++, vsi++) { + t_var = btf__type_by_id(btf, vsi->type); + name = btf__name_by_offset(btf, t_var->name_off); + + if (!has_metadata_prefix(name)) + continue; + + if (!printed_header) { + jsonw_name(json_wtr, "metadata"); + jsonw_start_object(json_wtr); + printed_header = true; + } + + jsonw_name(json_wtr, name + BPF_METADATA_PREFIX_LEN); + err = btf_dumper_type(&d, t_var->type, value + vsi->offset); + if (err) { + p_err("btf dump failed: %d", err); + break; + } + } + if (printed_header) + jsonw_end_object(json_wtr); + } else { + json_writer_t *btf_wtr = jsonw_new(stdout); + struct btf_dumper d = { + .btf = btf, + .jw = btf_wtr, + .is_plain_text = true, + }; + if (!btf_wtr) { + p_err("jsonw alloc failed"); + goto out_free; + } + + for (i = 0; i < vlen; i++, vsi++) { + t_var = btf__type_by_id(btf, vsi->type); + name = btf__name_by_offset(btf, t_var->name_off); + + if (!has_metadata_prefix(name)) + continue; + + if (!printed_header) { + printf("\tmetadata:"); + printed_header = true; + } + + printf("\n\t\t%s = ", name + BPF_METADATA_PREFIX_LEN); + + jsonw_reset(btf_wtr); + err = btf_dumper_type(&d, t_var->type, value + vsi->offset); + if (err) { + p_err("btf dump failed: %d", err); + break; + } + } + if (printed_header) + jsonw_destroy(&btf_wtr); + } + +out_free: + btf__free(btf); + free(value); + +out_close: + close(map_fd); +} + static void print_prog_header_json(struct bpf_prog_info *info) { jsonw_uint_field(json_wtr, "id", info->id); @@ -228,6 +446,8 @@ static void print_prog_json(struct bpf_prog_info *info, int fd) emit_obj_refs_json(&refs_table, info->id, json_wtr); + show_prog_metadata(fd, info->nr_map_ids); + jsonw_end_object(json_wtr); } @@ -297,6 +517,8 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd) emit_obj_refs_plain(&refs_table, info->id, "\n\tpids "); printf("\n"); + + show_prog_metadata(fd, info->nr_map_ids); } static int show_prog(int fd)