From patchwork Thu Aug 20 09:42:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: YiFei Zhu X-Patchwork-Id: 1348261 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: incoming-bpf@patchwork.ozlabs.org Delivered-To: patchwork-incoming-bpf@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=bpf-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=tBshSWyo; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BXKT76pnjz9sR4 for ; Thu, 20 Aug 2020 19:43:07 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729224AbgHTJmx (ORCPT ); Thu, 20 Aug 2020 05:42:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58716 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729147AbgHTJmR (ORCPT ); Thu, 20 Aug 2020 05:42:17 -0400 Received: from mail-il1-x143.google.com (mail-il1-x143.google.com [IPv6:2607:f8b0:4864:20::143]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0D683C061383 for ; Thu, 20 Aug 2020 02:42:16 -0700 (PDT) Received: by mail-il1-x143.google.com with SMTP id t13so1073658ile.9 for ; Thu, 20 Aug 2020 02:42:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=1rlIyE7c4KLlxD5gCyeY6MsqamG9FBghZ8kzijQ88sA=; b=tBshSWyoA0N+bBpWnAjAML9ZxB867uOitrL8sJlvnJQHtpnENzIScjXAjSD3+u2qpI xk5y/IH8Ahf+7AZqL8UHj01e2xY9v/2mKKgNnSOg6SHUeTkI42L4O23z+8inKSI2PZu/ sJj3Sy6Im9B99NXo71LFBd9erPGwIJZzg5Gm3cchmSvLl2nM8xZMSBj5l3jSdty+y5nd X/CUIEyfLIEEf141fjpY5Y+Kv34pvNiQ0d6xHW6rYKI1EWo9zpnkdIRZCEQxfZk+G0gu 7LfZaITG3SaFoykt6FOv/2MMfqpHveRHWsWcIltybFszsIjXYw7/Ul/wUcnwDci604p9 bSsw== 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:mime-version:content-transfer-encoding; bh=1rlIyE7c4KLlxD5gCyeY6MsqamG9FBghZ8kzijQ88sA=; b=oKu0U7n0dQLIhmJN7B4fbZS7L2aLF063vspkbdweargUbGI4YfNNI4fOYxYNvivv8t 5ZlAA+3HfBEUAfhEBXpqAl8dzLEswklcYT8L8h3N2beV+qBx47PBqzSyqYzCOZXYaSWz e78STLzj1viSXbNriwGysRJQP+k97OuSg/zA6r3GEoTU9bd6saaDcishgNax2Arkw1Xd AxR7sL8olk5TK2kR3EgiI6/dpuA/ymv3+MQiwob8u5JURUtNTNO0uV18ecIpUwNDVO65 F11WTJTGOB+koqesU6TpBe4P0/rwyVzY9km/NpfRBu5mSOXpD8VB4gUxM0wXWZrh+M1x cYvA== X-Gm-Message-State: AOAM532OdW8L//SgH7pa21pOkDBK4T8IcuSuegnM/6CuV1pKHVMy5xy3 vPc1F1ZGZDbE3Xb36Y/4P98ZRe9DODylIXPM X-Google-Smtp-Source: ABdhPJwM+Le0kpsS4XAe70Q255qS58KMTRAe6lo4CuhMNc+0TbQ8nSyxul9/zb9qmvzshG1yN2INYA== X-Received: by 2002:a92:b106:: with SMTP id t6mr1831630ilh.122.1597916535962; Thu, 20 Aug 2020 02:42:15 -0700 (PDT) Received: from localhost.localdomain (host-173-230-99-219.tnkngak.clients.pavlovmedia.com. [173.230.99.219]) by smtp.gmail.com with ESMTPSA id r3sm1145597iov.22.2020.08.20.02.42.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2020 02:42:15 -0700 (PDT) From: YiFei Zhu To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , Stanislav Fomichev , Mahesh Bandewar , YiFei Zhu Subject: [PATCH bpf-next 1/5] bpf: Mutex protect used_maps array and count Date: Thu, 20 Aug 2020 04:42:07 -0500 Message-Id: X-Mailer: git-send-email 2.28.0 In-Reply-To: References: MIME-Version: 1.0 Sender: bpf-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org From: YiFei Zhu To support modifying the used_maps array, we use a mutex to protect the use of the counter and the array. The mutex is initialized right after the prog aux is allocated, and destroyed right before prog aux is freed. This way we guarantee it's initialized for both cBPF and eBPF. Signed-off-by: YiFei Zhu Acked-by: Yonghong Song --- .../net/ethernet/netronome/nfp/bpf/offload.c | 18 ++++++++++++------ include/linux/bpf.h | 1 + kernel/bpf/core.c | 15 +++++++++++---- kernel/bpf/syscall.c | 16 ++++++++++++---- net/core/dev.c | 11 ++++++++--- 5 files changed, 44 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/netronome/nfp/bpf/offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c index ac02369174a9..53851853562c 100644 --- a/drivers/net/ethernet/netronome/nfp/bpf/offload.c +++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c @@ -111,7 +111,9 @@ static int nfp_map_ptrs_record(struct nfp_app_bpf *bpf, struct nfp_prog *nfp_prog, struct bpf_prog *prog) { - int i, cnt, err; + int i, cnt, err = 0; + + mutex_lock(&prog->aux->used_maps_mutex); /* Quickly count the maps we will have to remember */ cnt = 0; @@ -119,13 +121,15 @@ nfp_map_ptrs_record(struct nfp_app_bpf *bpf, struct nfp_prog *nfp_prog, if (bpf_map_offload_neutral(prog->aux->used_maps[i])) cnt++; if (!cnt) - return 0; + goto out; nfp_prog->map_records = kmalloc_array(cnt, sizeof(nfp_prog->map_records[0]), GFP_KERNEL); - if (!nfp_prog->map_records) - return -ENOMEM; + if (!nfp_prog->map_records) { + err = -ENOMEM; + goto out; + } for (i = 0; i < prog->aux->used_map_cnt; i++) if (bpf_map_offload_neutral(prog->aux->used_maps[i])) { @@ -133,12 +137,14 @@ nfp_map_ptrs_record(struct nfp_app_bpf *bpf, struct nfp_prog *nfp_prog, prog->aux->used_maps[i]); if (err) { nfp_map_ptrs_forget(bpf, nfp_prog); - return err; + goto out; } } WARN_ON(cnt != nfp_prog->map_records_cnt); - return 0; +out: + mutex_unlock(&prog->aux->used_maps_mutex); + return err; } static int diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 55f694b63164..abbdde104cea 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -723,6 +723,7 @@ struct bpf_prog_aux { struct bpf_ksym ksym; const struct bpf_prog_ops *ops; struct bpf_map **used_maps; + struct mutex used_maps_mutex; /* mutex for used_maps and used_map_cnt */ struct bpf_prog *prog; struct user_struct *user; u64 load_time; /* ns since boottime */ diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index ed0b3578867c..2a20c2833996 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -98,6 +98,7 @@ struct bpf_prog *bpf_prog_alloc_no_stats(unsigned int size, gfp_t gfp_extra_flag fp->jit_requested = ebpf_jit_enabled(); INIT_LIST_HEAD_RCU(&fp->aux->ksym.lnode); + mutex_init(&fp->aux->used_maps_mutex); return fp; } @@ -253,6 +254,7 @@ struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size, void __bpf_prog_free(struct bpf_prog *fp) { if (fp->aux) { + mutex_destroy(&fp->aux->used_maps_mutex); free_percpu(fp->aux->stats); kfree(fp->aux->poke_tab); kfree(fp->aux); @@ -1747,8 +1749,9 @@ bool bpf_prog_array_compatible(struct bpf_array *array, static int bpf_check_tail_call(const struct bpf_prog *fp) { struct bpf_prog_aux *aux = fp->aux; - int i; + int i, ret = 0; + mutex_lock(&aux->used_maps_mutex); for (i = 0; i < aux->used_map_cnt; i++) { struct bpf_map *map = aux->used_maps[i]; struct bpf_array *array; @@ -1757,11 +1760,15 @@ static int bpf_check_tail_call(const struct bpf_prog *fp) continue; array = container_of(map, struct bpf_array, map); - if (!bpf_prog_array_compatible(array, fp)) - return -EINVAL; + if (!bpf_prog_array_compatible(array, fp)) { + ret = -EINVAL; + goto out; + } } - return 0; +out: + mutex_unlock(&aux->used_maps_mutex); + return ret; } static void bpf_prog_select_func(struct bpf_prog *fp) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 86299a292214..f49fd709ccd5 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -3152,21 +3152,25 @@ static const struct bpf_map *bpf_map_from_imm(const struct bpf_prog *prog, const struct bpf_map *map; int i; + mutex_lock(&prog->aux->used_maps_mutex); for (i = 0, *off = 0; i < prog->aux->used_map_cnt; i++) { map = prog->aux->used_maps[i]; if (map == (void *)addr) { *type = BPF_PSEUDO_MAP_FD; - return map; + goto out; } if (!map->ops->map_direct_value_meta) continue; if (!map->ops->map_direct_value_meta(map, addr, off)) { *type = BPF_PSEUDO_MAP_VALUE; - return map; + goto out; } } + map = NULL; - return NULL; +out: + mutex_unlock(&prog->aux->used_maps_mutex); + return map; } static struct bpf_insn *bpf_insn_prepare_dump(const struct bpf_prog *prog, @@ -3284,6 +3288,7 @@ static int bpf_prog_get_info_by_fd(struct file *file, memcpy(info.tag, prog->tag, sizeof(prog->tag)); memcpy(info.name, prog->aux->name, sizeof(prog->aux->name)); + mutex_lock(&prog->aux->used_maps_mutex); ulen = info.nr_map_ids; info.nr_map_ids = prog->aux->used_map_cnt; ulen = min_t(u32, info.nr_map_ids, ulen); @@ -3293,9 +3298,12 @@ static int bpf_prog_get_info_by_fd(struct file *file, for (i = 0; i < ulen; i++) if (put_user(prog->aux->used_maps[i]->id, - &user_map_ids[i])) + &user_map_ids[i])) { + mutex_unlock(&prog->aux->used_maps_mutex); return -EFAULT; + } } + mutex_unlock(&prog->aux->used_maps_mutex); err = set_info_rec_size(&info); if (err) diff --git a/net/core/dev.c b/net/core/dev.c index b5d1129d8310..6957b31127d9 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5441,15 +5441,20 @@ static int generic_xdp_install(struct net_device *dev, struct netdev_bpf *xdp) if (new) { u32 i; + mutex_lock(&new->aux->used_maps_mutex); + /* generic XDP does not work with DEVMAPs that can * have a bpf_prog installed on an entry */ for (i = 0; i < new->aux->used_map_cnt; i++) { - if (dev_map_can_have_prog(new->aux->used_maps[i])) - return -EINVAL; - if (cpu_map_prog_allowed(new->aux->used_maps[i])) + if (dev_map_can_have_prog(new->aux->used_maps[i]) || + cpu_map_prog_allowed(new->aux->used_maps[i])) { + mutex_unlock(&new->aux->used_maps_mutex); return -EINVAL; + } } + + mutex_unlock(&new->aux->used_maps_mutex); } switch (xdp->command) { From patchwork Thu Aug 20 09:42:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: YiFei Zhu X-Patchwork-Id: 1348364 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: incoming-bpf@patchwork.ozlabs.org Delivered-To: patchwork-incoming-bpf@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=bpf-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=HtiWPmUC; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BXPkt0GVKz9sTN for ; Thu, 20 Aug 2020 22:55:18 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729147AbgHTJnL (ORCPT ); Thu, 20 Aug 2020 05:43:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58718 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729148AbgHTJmS (ORCPT ); Thu, 20 Aug 2020 05:42:18 -0400 Received: from mail-il1-x144.google.com (mail-il1-x144.google.com [IPv6:2607:f8b0:4864:20::144]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 98723C061384 for ; Thu, 20 Aug 2020 02:42:17 -0700 (PDT) Received: by mail-il1-x144.google.com with SMTP id t13so1073683ile.9 for ; Thu, 20 Aug 2020 02:42:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=0XhET/ai5wSKKXh3cFzu4ZBlJaRyJ/PNOqZCslgOEFw=; b=HtiWPmUCe0pxTJB/SOJ8cYs8y5/GIENAlUIeUZG44yjlJyVfD01zNgG/y8IgVK7K4U no8LZjHw/TNpvvJFTVSg+cDynz6LYs6W+gzzbJFfxOMGbcBBRwmavCCiXukvy+fpWcyb 7thtA8gYe0kRnvhIxNty4TI42hXDT7IKV8KH0LJEMaDg2l7om3qluNwHBBmJ/A8alHAz 1FnND/Xhaw0d8/EXL+BQ6BqqBd81VnuUPJWvJfiWPcu05/S20vu16CuUNpdNyoNI/TYx X/o6aAkh3O8x+4b3hhzqcnvXSEqz3kHoXV9GYBMox0UNeqy1zMwtD1EEZzBnK6GB2GaT Kr3Q== 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:mime-version:content-transfer-encoding; bh=0XhET/ai5wSKKXh3cFzu4ZBlJaRyJ/PNOqZCslgOEFw=; b=OKnH5wqDJ7KZOrYI0vSZEhyG0aD8GmwQF36fGY7zJNcSQ5wfIqc8HTaw0eX69oy7P7 JHKbTwmt630IGmK856Uj1qCjZ9l+8+G9fUF4xXrlGuEMTYr5VJnRMcudmFUko6P35DaK +3GkCXZa//OD/UBTY3YVkyWxhR9VZmjrro0oNRDkhTVqe9V0SONxWVDsl7dILpK5UO2o 4gs+pne7YBj1loPszIgwnFzqn2rOBqBa14Y5tHBT+lrXibzshNnQtnGdtyK2MJpulS2z OB0De2xM/5HXCMKp77PbIoONVb7/W/23QJjq1qewduJBsFu9JPWpZWoF8gMc0f3ATRGO AqTA== X-Gm-Message-State: AOAM531vfbSPGPgO81Up2PaGcKjAf9llWXeX4yHbJO3E5bzbKsPttXLI ZVX0ZNwJBpXzNbZXFklSSg53l9lVoL/505Ab X-Google-Smtp-Source: ABdhPJzlW1wNoimvbaCEZdGRnn9H3TvPmLjkgZah6zWsh7xhCqwyNKsacrk5t5Evm2v4MtpCfSIqxA== X-Received: by 2002:a05:6e02:13ec:: with SMTP id w12mr2012048ilj.196.1597916536763; Thu, 20 Aug 2020 02:42:16 -0700 (PDT) Received: from localhost.localdomain (host-173-230-99-219.tnkngak.clients.pavlovmedia.com. [173.230.99.219]) by smtp.gmail.com with ESMTPSA id r3sm1145597iov.22.2020.08.20.02.42.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2020 02:42:16 -0700 (PDT) From: YiFei Zhu To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , Stanislav Fomichev , Mahesh Bandewar , YiFei Zhu Subject: [PATCH bpf-next 2/5] bpf: Add BPF_PROG_BIND_MAP syscall Date: Thu, 20 Aug 2020 04:42:08 -0500 Message-Id: <8ef54583bd3e57af53f3e4f16198907465f7c3c8.1597915265.git.zhuyifei@google.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: References: MIME-Version: 1.0 Sender: bpf-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org From: YiFei Zhu This syscall binds a map to a program. -EEXIST if the map is already bound to the program. Signed-off-by: YiFei Zhu Acked-by: Yonghong Song --- include/uapi/linux/bpf.h | 7 ++++ kernel/bpf/syscall.c | 65 ++++++++++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 7 ++++ 3 files changed, 79 insertions(+) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 0480f893facd..d11b2ee62148 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -124,6 +124,7 @@ enum bpf_cmd { BPF_ENABLE_STATS, BPF_ITER_CREATE, BPF_LINK_DETACH, + BPF_PROG_BIND_MAP, }; enum bpf_map_type { @@ -649,6 +650,12 @@ union bpf_attr { __u32 flags; } iter_create; + struct { /* struct used by BPF_PROG_BIND_MAP command */ + __u32 prog_fd; + __u32 map_fd; + __u32 flags; /* extra flags */ + } prog_bind_map; + } __attribute__((aligned(8))); /* The description below is an attempt at providing documentation to eBPF diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index f49fd709ccd5..f3e0457819a0 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -4141,6 +4141,68 @@ static int bpf_iter_create(union bpf_attr *attr) return err; } +#define BPF_PROG_BIND_MAP_LAST_FIELD prog_bind_map.flags + +static int bpf_prog_bind_map(union bpf_attr *attr) +{ + struct bpf_prog *prog; + struct bpf_map *map; + struct bpf_map **used_maps_old, **used_maps_new; + int i, ret = 0; + + if (CHECK_ATTR(BPF_PROG_BIND_MAP)) + return -EINVAL; + + if (attr->prog_bind_map.flags) + return -EINVAL; + + prog = bpf_prog_get(attr->prog_bind_map.prog_fd); + if (IS_ERR(prog)) + return PTR_ERR(prog); + + map = bpf_map_get(attr->prog_bind_map.map_fd); + if (IS_ERR(map)) { + ret = PTR_ERR(map); + goto out_prog_put; + } + + mutex_lock(&prog->aux->used_maps_mutex); + + used_maps_old = prog->aux->used_maps; + + for (i = 0; i < prog->aux->used_map_cnt; i++) + if (used_maps_old[i] == map) { + ret = -EEXIST; + goto out_unlock; + } + + used_maps_new = kmalloc_array(prog->aux->used_map_cnt + 1, + sizeof(used_maps_new[0]), + GFP_KERNEL); + if (!used_maps_new) { + ret = -ENOMEM; + goto out_unlock; + } + + memcpy(used_maps_new, used_maps_old, + sizeof(used_maps_old[0]) * prog->aux->used_map_cnt); + used_maps_new[prog->aux->used_map_cnt] = map; + + prog->aux->used_map_cnt++; + prog->aux->used_maps = used_maps_new; + + kfree(used_maps_old); + +out_unlock: + mutex_unlock(&prog->aux->used_maps_mutex); + + if (ret) + bpf_map_put(map); +out_prog_put: + bpf_prog_put(prog); + return ret; +} + SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, size) { union bpf_attr attr; @@ -4274,6 +4336,9 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz case BPF_LINK_DETACH: err = link_detach(&attr); break; + case BPF_PROG_BIND_MAP: + err = bpf_prog_bind_map(&attr); + break; default: err = -EINVAL; break; diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 0480f893facd..d11b2ee62148 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -124,6 +124,7 @@ enum bpf_cmd { BPF_ENABLE_STATS, BPF_ITER_CREATE, BPF_LINK_DETACH, + BPF_PROG_BIND_MAP, }; enum bpf_map_type { @@ -649,6 +650,12 @@ union bpf_attr { __u32 flags; } iter_create; + struct { /* struct used by BPF_PROG_BIND_MAP command */ + __u32 prog_fd; + __u32 map_fd; + __u32 flags; /* extra flags */ + } prog_bind_map; + } __attribute__((aligned(8))); /* The description below is an attempt at providing documentation to eBPF From patchwork Thu Aug 20 09:42:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: YiFei Zhu X-Patchwork-Id: 1348263 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: incoming-bpf@patchwork.ozlabs.org Delivered-To: patchwork-incoming-bpf@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=bpf-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=mFpMIvb7; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BXKTG665nz9sTN for ; Thu, 20 Aug 2020 19:43:14 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729233AbgHTJnN (ORCPT ); Thu, 20 Aug 2020 05:43:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58726 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729149AbgHTJmS (ORCPT ); Thu, 20 Aug 2020 05:42:18 -0400 Received: from mail-il1-x143.google.com (mail-il1-x143.google.com [IPv6:2607:f8b0:4864:20::143]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 920F2C061386 for ; Thu, 20 Aug 2020 02:42:18 -0700 (PDT) Received: by mail-il1-x143.google.com with SMTP id t4so1115554iln.1 for ; Thu, 20 Aug 2020 02:42:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=YeDsV6ML0VVk8480/NX5VmSSMK1mBoWtNTtZqIJn+Zs=; b=mFpMIvb7p5DOTQKEUOECdemzi5bIB2qv3fsyEzyqyG3Q2YdGtWEraHMplh/yTatxD7 s8+azk0nBzvQw5xDe8XJMYOXxL2a2UXq32WFUFHpo8pyu4wZcnqoBXSDXV0lhu8f9G4b WkVlAXbLowZ4flM4FqehqfBupsuc0b/k8oLVoqyaPTzdYswkeHVAFhVssTIAmNsLFSi/ ybEXZ9cJQLRwTWIPK4TbUVdAjIkQ+/QBllKRNvjV59KPGC4ErmCDwCpT8781OadJS4e9 C87hlmWV/cw8k54W2bTgtvgNOumbe1ufZwy0EK99RX3jh23BYiZBbdbyxbwGleTw0L3G FbhA== 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:mime-version:content-transfer-encoding; bh=YeDsV6ML0VVk8480/NX5VmSSMK1mBoWtNTtZqIJn+Zs=; b=h/QhrXa09B2ioWI7rFLkp1VFe5Fb0+cxXt9eSwO2VScXtmwWfLcVIF1/L66lX53dqG kCZY2UA9Zc4hwVNsnDXqyHQOw2ecSv+Psohfr2TphJQRNd6BirjpJJBx6BGHRwTV2UZz 5/c3+Iuh93nNs3YzJcAqZzT+8sT8q7U8XwCIqIlGRJFTSImKpsarkZHyMvckaprCUGIj 6GAVfrsxM912qfVhnlvH8YUUi+Izus7+fMYY6qvEQV2hgQWyXZr3B7XxDqqAZRjRVvpL xOolPW34LS4udKLCkh2ZhaZA+HCd3g4ZWBdW+/7c6nTWxTAQI/ErDRZx0VCpGEtGzGmR pRRA== X-Gm-Message-State: AOAM533wZmlmCRP4yfpMRmW2O7m52eXWARPEqhz7c8jCYMRrMUREXmWP OHSgkY/RVH5wy1TsbdzfjcbaZehLdCHWiMk/ X-Google-Smtp-Source: ABdhPJyaVrQ1Ev83jHJeNwmjoTMDiUQQ5Mf/Hi6MSGy4JydM9dhAr20nba/yqOFPBrZTrqp9gARcPw== X-Received: by 2002:a92:295:: with SMTP id 143mr1983504ilc.240.1597916537501; Thu, 20 Aug 2020 02:42:17 -0700 (PDT) Received: from localhost.localdomain (host-173-230-99-219.tnkngak.clients.pavlovmedia.com. [173.230.99.219]) by smtp.gmail.com with ESMTPSA id r3sm1145597iov.22.2020.08.20.02.42.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2020 02:42:17 -0700 (PDT) From: YiFei Zhu To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , Stanislav Fomichev , Mahesh Bandewar , YiFei Zhu Subject: [PATCH bpf-next 3/5] libbpf: Add BPF_PROG_BIND_MAP syscall and use it on .metadata section Date: Thu, 20 Aug 2020 04:42:09 -0500 Message-Id: X-Mailer: git-send-email 2.28.0 In-Reply-To: References: MIME-Version: 1.0 Sender: bpf-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org From: YiFei Zhu The patch adds a simple wrapper bpf_prog_bind_map around the syscall. And when using libbpf to load a program, it will probe the kernel for the support of this syscall, and scan for the .metadata ELF section and load it as an internal map like a .data section. In the case that kernel supports the BPF_PROG_BIND_MAP syscall and a .metadata section exists, the map will be explicitly bound to the program via the syscall immediately after program is loaded. -EEXIST is ignored for this syscall. Signed-off-by: YiFei Zhu --- tools/lib/bpf/bpf.c | 11 +++++ tools/lib/bpf/bpf.h | 1 + tools/lib/bpf/libbpf.c | 100 ++++++++++++++++++++++++++++++++++++++- tools/lib/bpf/libbpf.map | 1 + 4 files changed, 112 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index 82b983ff6569..383b29ecb1fd 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -872,3 +872,14 @@ 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, int flags) +{ + union bpf_attr attr = {}; + + attr.prog_bind_map.prog_fd = prog_fd; + attr.prog_bind_map.map_fd = map_fd; + attr.prog_bind_map.flags = flags; + + 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..32994a4e0bf6 100644 --- a/tools/lib/bpf/bpf.h +++ b/tools/lib/bpf/bpf.h @@ -243,6 +243,7 @@ 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); +LIBBPF_API int bpf_prog_bind_map(int prog_fd, int map_fd, int flags); #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 77d420c02094..4725859099c5 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 helper */ + FEAT_PROG_BIND_MAP, __FEAT_CNT, }; @@ -283,6 +285,7 @@ struct bpf_struct_ops { #define KCONFIG_SEC ".kconfig" #define KSYMS_SEC ".ksyms" #define STRUCT_OPS_SEC ".struct_ops" +#define METADATA_SEC ".metadata" enum libbpf_map_type { LIBBPF_MAP_UNSPEC, @@ -290,6 +293,7 @@ enum libbpf_map_type { LIBBPF_MAP_BSS, LIBBPF_MAP_RODATA, LIBBPF_MAP_KCONFIG, + LIBBPF_MAP_METADATA, }; static const char * const libbpf_type_to_btf_name[] = { @@ -297,6 +301,7 @@ static const char * const libbpf_type_to_btf_name[] = { [LIBBPF_MAP_BSS] = BSS_SEC, [LIBBPF_MAP_RODATA] = RODATA_SEC, [LIBBPF_MAP_KCONFIG] = KCONFIG_SEC, + [LIBBPF_MAP_METADATA] = METADATA_SEC, }; struct bpf_map { @@ -375,6 +380,8 @@ struct bpf_object { size_t nr_maps; size_t maps_cap; + struct bpf_map *metadata_map; + char *kconfig; struct extern_desc *externs; int nr_extern; @@ -398,6 +405,7 @@ struct bpf_object { Elf_Data *rodata; Elf_Data *bss; Elf_Data *st_ops_data; + Elf_Data *metadata; size_t strtabidx; struct { GElf_Shdr shdr; @@ -413,6 +421,7 @@ struct bpf_object { int rodata_shndx; int bss_shndx; int st_ops_shndx; + int metadata_shndx; } efile; /* * All loaded bpf_object is linked in a list, which is @@ -1022,6 +1031,7 @@ static struct bpf_object *bpf_object__new(const char *path, obj->efile.obj_buf_sz = obj_buf_sz; obj->efile.maps_shndx = -1; obj->efile.btf_maps_shndx = -1; + obj->efile.metadata_shndx = -1; obj->efile.data_shndx = -1; obj->efile.rodata_shndx = -1; obj->efile.bss_shndx = -1; @@ -1387,6 +1397,9 @@ bpf_object__init_internal_map(struct bpf_object *obj, enum libbpf_map_type type, if (data) memcpy(map->mmaped, data, data_sz); + if (type == LIBBPF_MAP_METADATA) + obj->metadata_map = map; + pr_debug("map %td is \"%s\"\n", map - obj->maps, map->name); return 0; } @@ -1422,6 +1435,14 @@ static int bpf_object__init_global_data_maps(struct bpf_object *obj) if (err) return err; } + if (obj->efile.metadata_shndx >= 0) { + err = bpf_object__init_internal_map(obj, LIBBPF_MAP_METADATA, + obj->efile.metadata_shndx, + obj->efile.metadata->d_buf, + obj->efile.metadata->d_size); + if (err) + return err; + } return 0; } @@ -2698,6 +2719,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj) } else if (strcmp(name, STRUCT_OPS_SEC) == 0) { obj->efile.st_ops_data = data; obj->efile.st_ops_shndx = idx; + } else if (strcmp(name, METADATA_SEC) == 0) { + obj->efile.metadata = data; + obj->efile.metadata_shndx = idx; } else { pr_debug("skip section(%d) %s\n", idx, name); } @@ -3111,7 +3135,8 @@ static bool bpf_object__shndx_is_data(const struct bpf_object *obj, { return shndx == obj->efile.data_shndx || shndx == obj->efile.bss_shndx || - shndx == obj->efile.rodata_shndx; + shndx == obj->efile.rodata_shndx || + shndx == obj->efile.metadata_shndx; } static bool bpf_object__shndx_is_maps(const struct bpf_object *obj, @@ -3132,6 +3157,8 @@ bpf_object__section_to_libbpf_map_type(const struct bpf_object *obj, int shndx) return LIBBPF_MAP_RODATA; else if (shndx == obj->efile.symbols_shndx) return LIBBPF_MAP_KCONFIG; + else if (shndx == obj->efile.metadata_shndx) + return LIBBPF_MAP_METADATA; else return LIBBPF_MAP_UNSPEC; } @@ -3655,6 +3682,60 @@ 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_load_program_attr prog_attr; + struct bpf_create_map_attr map_attr; + char *cp, errmsg[STRERR_BUFSIZE]; + struct bpf_insn insns[] = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + int ret = 0, prog, map; + + if (!kernel_supports(FEAT_GLOBAL_DATA)) + return 0; + + memset(&map_attr, 0, sizeof(map_attr)); + map_attr.map_type = BPF_MAP_TYPE_ARRAY; + map_attr.key_size = sizeof(int); + 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)); + pr_warn("Error in %s():%s(%d). Couldn't create simple array map.\n", + __func__, cp, -ret); + return ret; + } + + memset(&prog_attr, 0, sizeof(prog_attr)); + prog_attr.prog_type = BPF_PROG_TYPE_SOCKET_FILTER; + prog_attr.insns = insns; + prog_attr.insns_cnt = ARRAY_SIZE(insns); + prog_attr.license = "GPL"; + + prog = bpf_load_program_xattr(&prog_attr, NULL, 0); + if (prog < 0) { + ret = -errno; + cp = libbpf_strerror_r(ret, errmsg, sizeof(errmsg)); + pr_warn("Error in %s():%s(%d). Couldn't create simple program.\n", + __func__, cp, -ret); + + close(map); + return ret; + } + + if (!bpf_prog_bind_map(prog, map, 0)) + ret = 1; + + close(map); + close(prog); + return ret; +} + enum kern_feature_result { FEAT_UNKNOWN = 0, FEAT_SUPPORTED = 1, @@ -3695,6 +3776,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() helper", probe_prog_bind_map, } }; @@ -5954,6 +6038,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->metadata_map && kernel_supports(FEAT_PROG_BIND_MAP)) { + if (bpf_prog_bind_map(ret, bpf_map__fd(prog->obj->metadata_map), 0) && + errno != EEXIST) { + int fd = ret; + + ret = -errno; + cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg)); + pr_warn("add metadata map failed: %s\n", cp); + close(fd); + goto out; + } + } + *pfd = ret; ret = 0; goto out; diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map index e35bd6cdbdbf..4baf18a6df69 100644 --- a/tools/lib/bpf/libbpf.map +++ b/tools/lib/bpf/libbpf.map @@ -288,6 +288,7 @@ LIBBPF_0.1.0 { bpf_map__set_value_size; bpf_map__type; bpf_map__value_size; + bpf_prog_bind_map; bpf_program__attach_xdp; bpf_program__autoload; bpf_program__is_sk_lookup; From patchwork Thu Aug 20 09:42:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: YiFei Zhu X-Patchwork-Id: 1348265 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: incoming-bpf@patchwork.ozlabs.org Delivered-To: patchwork-incoming-bpf@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=bpf-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=iDX77MiM; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BXKTj1n10z9sRN for ; Thu, 20 Aug 2020 19:43:37 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729251AbgHTJnf (ORCPT ); Thu, 20 Aug 2020 05:43:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58744 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729018AbgHTJmZ (ORCPT ); Thu, 20 Aug 2020 05:42:25 -0400 Received: from mail-il1-x12b.google.com (mail-il1-x12b.google.com [IPv6:2607:f8b0:4864:20::12b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D1ACDC061342 for ; Thu, 20 Aug 2020 02:42:21 -0700 (PDT) Received: by mail-il1-x12b.google.com with SMTP id k4so1060676ilr.12 for ; Thu, 20 Aug 2020 02:42:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=3Lj8AC0dSY26aIIm+lvhaB/Q7CIHxsMDnqhwGfm7MEo=; b=iDX77MiMQE6ho6myLRNZIrsLr5r7t/esa3pFgodG76uuGGpSYRCK85Aaea+9OPgwck BTLrld7ofq6OynQbGvPsMsWmfzkF1G9IqLz/pghOebFndsmlNADO9rzzMFa5/YdXlCzV iO/9K4fV3gEFoqptKASz+d4B4NQD7GXW72O+iHNJ3Smsxkys0RcElYwmF2PmNnqLQwll 6aWy3cYhM9jUyivRcQWmzdM+AB6iCabxN3ErzdAGxBvBbjsqwpWsxtYpusGKp3rWygbc obRcG9j3nHWcozgeAvZF3j9mT0F1HM1dKGUpgsKZgMeyQFJVFMU9VDeTlAUsVXBqKY8N 1jww== 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:mime-version:content-transfer-encoding; bh=3Lj8AC0dSY26aIIm+lvhaB/Q7CIHxsMDnqhwGfm7MEo=; b=RLvcBDo8+f1aTMjXA+DXyOCHDUzTl4evuN2pe/Z2rRaPP/q9CzordMLrwXfLk4HJWd 9aPewC0LuZxIwgL0mgjzIEHOI5Jr9BOpABOyivhAt/7q5AKSwuBJgYkw5yEIH6UPiiZP WQVLF+tf1hE59f0WVx23uzEQv6VW4G58YY+ElW5MBfX1OhEyvf+ID8/zv8JW7efUwoyO lXG9E3rLpcdd48hngsCrVjNURbdL49rQTv8/dhiU7OFnjywcJ30tK4/NWtkJ86muV80Q ABgkBQWI/J5WK3SupzHXE5JL33CNx/0P152+mllargzg0P5ocYkscbQztNy2tzsjuqx/ AHPQ== X-Gm-Message-State: AOAM531qAj2FI1Oydy/2Ob6w+nay3jXSLN59PFVTl1gvkdL0dXzC1OuH RlprBHys/70nE1QijGd0NnnPVVPAxjHrwMsH X-Google-Smtp-Source: ABdhPJwdsh75RRq6v47niVVMcp+iWvlhrnyjLstKTO5j1dUQN7ESJ7y73wj0S2bELS/rrjkpMLhC6w== X-Received: by 2002:a92:d342:: with SMTP id a2mr2025074ilh.16.1597916538196; Thu, 20 Aug 2020 02:42:18 -0700 (PDT) Received: from localhost.localdomain (host-173-230-99-219.tnkngak.clients.pavlovmedia.com. [173.230.99.219]) by smtp.gmail.com with ESMTPSA id r3sm1145597iov.22.2020.08.20.02.42.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2020 02:42:17 -0700 (PDT) From: YiFei Zhu To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , Stanislav Fomichev , Mahesh Bandewar , YiFei Zhu Subject: [PATCH bpf-next 4/5] bpftool: support dumping metadata Date: Thu, 20 Aug 2020 04:42:10 -0500 Message-Id: <9138c60f036c68f02c41dae0605ef587a8347f4c.1597915265.git.zhuyifei@google.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: References: MIME-Version: 1.0 Sender: bpf-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org From: YiFei Zhu Added a flag "--metadata" to `bpftool prog list` to dump the metadata contents. 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 --metadata 6: cgroup_skb name prog tag bcf7977d3b93787c gpl [...] btf_id 4 metadata: metadata_a = "foo" metadata_b = 1 $ bpftool prog --metadata --json --pretty [{ "id": 6, [...] "btf_id": 4, "metadata": { "metadata_a": "foo", "metadata_b": 1 } } ] Signed-off-by: YiFei Zhu --- tools/bpf/bpftool/json_writer.c | 6 ++ tools/bpf/bpftool/json_writer.h | 3 + tools/bpf/bpftool/main.c | 10 +++ tools/bpf/bpftool/main.h | 1 + tools/bpf/bpftool/prog.c | 135 ++++++++++++++++++++++++++++++++ 5 files changed, 155 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/main.c b/tools/bpf/bpftool/main.c index 4a191fcbeb82..a681d568cfa7 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -28,6 +28,7 @@ bool show_pinned; bool block_mount; bool verifier_logs; bool relaxed_maps; +bool dump_metadata; struct pinned_obj_table prog_table; struct pinned_obj_table map_table; struct pinned_obj_table link_table; @@ -351,6 +352,10 @@ static int do_batch(int argc, char **argv) return err; } +enum bpftool_longonly_opts { + OPT_METADATA = 256, +}; + int main(int argc, char **argv) { static const struct option options[] = { @@ -362,6 +367,7 @@ int main(int argc, char **argv) { "mapcompat", no_argument, NULL, 'm' }, { "nomount", no_argument, NULL, 'n' }, { "debug", no_argument, NULL, 'd' }, + { "metadata", no_argument, NULL, OPT_METADATA }, { 0 } }; int opt, ret; @@ -371,6 +377,7 @@ int main(int argc, char **argv) json_output = false; show_pinned = false; block_mount = false; + dump_metadata = false; bin_name = argv[0]; hash_init(prog_table.table); @@ -412,6 +419,9 @@ int main(int argc, char **argv) libbpf_set_print(print_all_levels); verifier_logs = true; break; + case OPT_METADATA: + dump_metadata = true; + break; default: p_err("unrecognized option '%s'", argv[optind - 1]); if (json_output) diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index c46e52137b87..8750758e9150 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -90,6 +90,7 @@ extern bool show_pids; extern bool block_mount; extern bool verifier_logs; extern bool relaxed_maps; +extern bool dump_metadata; extern struct pinned_obj_table prog_table; extern struct pinned_obj_table map_table; extern struct pinned_obj_table link_table; diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index d393eb8263a6..ee767b8d90fb 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -151,6 +151,135 @@ static void show_prog_maps(int fd, __u32 num_maps) } } +static void show_prog_metadata(int fd, __u32 num_maps) +{ + struct bpf_prog_info prog_info = {}; + struct bpf_map_info map_info = {}; + __u32 prog_info_len = sizeof(prog_info); + __u32 map_info_len = sizeof(map_info); + __u32 map_ids[num_maps]; + void *value = NULL; + struct btf *btf = NULL; + const struct btf_type *t_datasec, *t_var; + struct btf_var_secinfo *vsi; + int key = 0; + unsigned int i, vlen; + int map_fd; + int err; + + prog_info.nr_map_ids = num_maps; + prog_info.map_ids = ptr_to_u64(map_ids); + + err = bpf_obj_get_info_by_fd(fd, &prog_info, &prog_info_len); + if (err || !prog_info.nr_map_ids) + return; + + 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) + return; + + err = bpf_obj_get_info_by_fd(map_fd, &map_info, &map_info_len); + if (err) + goto out_close; + + if (map_info.type != BPF_MAP_TYPE_ARRAY) + goto next_map; + if (map_info.key_size != sizeof(int)) + goto next_map; + if (map_info.max_entries != 1) + goto next_map; + if (!map_info.btf_value_type_id) + goto next_map; + if (!strstr(map_info.name, ".metadata")) + goto next_map; + + goto found; + +next_map: + close(map_fd); + } + + return; + +found: + 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_INFO_KIND(t_datasec->info) != BTF_KIND_DATASEC) + goto out_free; + + vlen = BTF_INFO_VLEN(t_datasec->info); + vsi = (struct btf_var_secinfo *)(t_datasec + 1); + + if (json_output) { + struct btf_dumper d = { + .btf = btf, + .jw = json_wtr, + .is_plain_text = false, + }; + + jsonw_name(json_wtr, "metadata"); + + jsonw_start_object(json_wtr); + for (i = 0; i < vlen; i++) { + t_var = btf__type_by_id(btf, vsi[i].type); + + if (BTF_INFO_KIND(t_var->info) != BTF_KIND_VAR) + continue; + + jsonw_name(json_wtr, btf__name_by_offset(btf, t_var->name_off)); + err = btf_dumper_type(&d, t_var->type, value + vsi[i].offset); + if (err) + break; + } + 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) + goto out_free; + + printf("\tmetadata:"); + + for (i = 0; i < vlen; i++) { + t_var = btf__type_by_id(btf, vsi[i].type); + + if (BTF_INFO_KIND(t_var->info) != BTF_KIND_VAR) + continue; + + printf("\n\t\t%s = ", btf__name_by_offset(btf, t_var->name_off)); + + jsonw_reset(btf_wtr); + err = btf_dumper_type(&d, t_var->type, value + vsi[i].offset); + if (err) + break; + } + + 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 +357,9 @@ static void print_prog_json(struct bpf_prog_info *info, int fd) emit_obj_refs_json(&refs_table, info->id, json_wtr); + if (dump_metadata) + show_prog_metadata(fd, info->nr_map_ids); + jsonw_end_object(json_wtr); } @@ -297,6 +429,9 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd) emit_obj_refs_plain(&refs_table, info->id, "\n\tpids "); printf("\n"); + + if (dump_metadata) + show_prog_metadata(fd, info->nr_map_ids); } static int show_prog(int fd) From patchwork Thu Aug 20 09:42:11 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: YiFei Zhu X-Patchwork-Id: 1348264 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: incoming-bpf@patchwork.ozlabs.org Delivered-To: patchwork-incoming-bpf@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=bpf-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=sVZlRY07; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BXKTJ1rK4z9sTQ for ; Thu, 20 Aug 2020 19:43:16 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726989AbgHTJnO (ORCPT ); Thu, 20 Aug 2020 05:43:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58728 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729151AbgHTJmU (ORCPT ); Thu, 20 Aug 2020 05:42:20 -0400 Received: from mail-il1-x141.google.com (mail-il1-x141.google.com [IPv6:2607:f8b0:4864:20::141]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 16A85C061387 for ; Thu, 20 Aug 2020 02:42:20 -0700 (PDT) Received: by mail-il1-x141.google.com with SMTP id p18so1082606ilm.7 for ; Thu, 20 Aug 2020 02:42:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=dw9oaIsYVsMP//1WkW1HJx6Q5+EKILk45et8oS2R3QM=; b=sVZlRY07kRjb4dbSVaeWrm/fiscDnw8pwYegx05Vwxe0cbQRHClfe8YYitQLVgLTAg poSDmjrHug5HJmAWyo0+r+1cwRrfqP4AioM6V9zvR0Cj+savlCiCceQIfry6T6FGKHGm Pl71z9W29U/gX/MrO1oZyrNU0XRx6jmVKtPRC+kc+QvLxFkDnDP2Iga7jgpN8cV2/EGM ktCxbqbYDnp7gp6xUWMcMlrOw3IdamupkeV52clZH1mDY8NwaBt8qmYgC+zWzLbdr8m8 1WZpIhYPPMJW82vky3V3h0vhjqq4m4zTpFa50F5e5LdXP9T4o/Jtk6dHkf4L6+D1ZRND 5rhQ== 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:mime-version:content-transfer-encoding; bh=dw9oaIsYVsMP//1WkW1HJx6Q5+EKILk45et8oS2R3QM=; b=WG+S0O+VAplet0odjEVDohrpVD/Z4K3xiKlpgnZqHr/VMcIuLGZS5Cbxhkmak2c32n VBfw0AqNXbdQI6m2FtHyODZ3GEbTmzXBZH7mHMtky8QWRJqBHJfXpFLKtTTDmmzMYAdP dUKKAbgXCAQoWfkJDHa2B2bZSEPwtFve0S1XYNMOYjRnriu2dNWRBvF6w4fUM9D6W7Lm niytiRZ9z7QwU9GpAp0xHHEyt0urokkIP3OlHsnCsKKNWE95YelHBcNxC8gZw4qI17gg dZa22s5EFuAawJmdRPsu4VvKDRcTwep+IyPPYh/hHC7RF16/FCVCRhj0qfaV+tRhrDGS wSjA== X-Gm-Message-State: AOAM531hzYsxQhehkrW1FF7rAq/B+bmag359iJXL71zynvztPMf02FlI Ctm6aq4MfqyrZ4Pe4rhRrckqlqxnTB1lAEi8 X-Google-Smtp-Source: ABdhPJy7a2S45kGnGIY3R1X0Oas8sGCXxWlSptQ4hSfIzkBJPi2AhRzJvRFc7JS3XybrOL31XZrJwQ== X-Received: by 2002:a92:c60f:: with SMTP id p15mr624614ilm.173.1597916539146; Thu, 20 Aug 2020 02:42:19 -0700 (PDT) Received: from localhost.localdomain (host-173-230-99-219.tnkngak.clients.pavlovmedia.com. [173.230.99.219]) by smtp.gmail.com with ESMTPSA id r3sm1145597iov.22.2020.08.20.02.42.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 Aug 2020 02:42:18 -0700 (PDT) From: YiFei Zhu To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Daniel Borkmann , Stanislav Fomichev , Mahesh Bandewar , YiFei Zhu Subject: [PATCH bpf-next 5/5] selftests/bpf: Test bpftool loading and dumping metadata Date: Thu, 20 Aug 2020 04:42:11 -0500 Message-Id: <788b0e49bd5dfc292b71a57f21cbf010821a0aca.1597915265.git.zhuyifei@google.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: References: MIME-Version: 1.0 Sender: bpf-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org From: YiFei Zhu This is a simple test to check that loading and dumping metadata works, whether or not metadata contents are used by the program. Signed-off-by: YiFei Zhu --- tools/testing/selftests/bpf/Makefile | 3 +- .../selftests/bpf/progs/metadata_unused.c | 15 ++++ .../selftests/bpf/progs/metadata_used.c | 15 ++++ .../selftests/bpf/test_bpftool_metadata.sh | 82 +++++++++++++++++++ 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/progs/metadata_unused.c create mode 100644 tools/testing/selftests/bpf/progs/metadata_used.c create mode 100755 tools/testing/selftests/bpf/test_bpftool_metadata.sh diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index a83b5827532f..04e56c6843c6 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -68,7 +68,8 @@ TEST_PROGS := test_kmod.sh \ test_tc_edt.sh \ test_xdping.sh \ test_bpftool_build.sh \ - test_bpftool.sh + test_bpftool.sh \ + test_bpftool_metadata.sh \ TEST_PROGS_EXTENDED := with_addr.sh \ with_tunnels.sh \ diff --git a/tools/testing/selftests/bpf/progs/metadata_unused.c b/tools/testing/selftests/bpf/progs/metadata_unused.c new file mode 100644 index 000000000000..523b3c332426 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/metadata_unused.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include + +char metadata_a[] SEC(".metadata") = "foo"; +int metadata_b SEC(".metadata") = 1; + +SEC("cgroup_skb/egress") +int prog(struct xdp_md *ctx) +{ + return 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/progs/metadata_used.c b/tools/testing/selftests/bpf/progs/metadata_used.c new file mode 100644 index 000000000000..59785404f7bb --- /dev/null +++ b/tools/testing/selftests/bpf/progs/metadata_used.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include + +char metadata_a[] SEC(".metadata") = "bar"; +int metadata_b SEC(".metadata") = 2; + +SEC("cgroup_skb/egress") +int prog(struct xdp_md *ctx) +{ + return metadata_b ? 1 : 0; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_bpftool_metadata.sh b/tools/testing/selftests/bpf/test_bpftool_metadata.sh new file mode 100755 index 000000000000..a7515c09dc2d --- /dev/null +++ b/tools/testing/selftests/bpf/test_bpftool_metadata.sh @@ -0,0 +1,82 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +TESTNAME=bpftool_metadata +BPF_FS=$(awk '$3 == "bpf" {print $2; exit}' /proc/mounts) +BPF_DIR=$BPF_FS/test_$TESTNAME + +_cleanup() +{ + set +e + rm -rf $BPF_DIR 2> /dev/null +} + +cleanup_skip() +{ + echo "selftests: $TESTNAME [SKIP]" + _cleanup + + exit $ksft_skip +} + +cleanup() +{ + if [ "$?" = 0 ]; then + echo "selftests: $TESTNAME [PASS]" + else + echo "selftests: $TESTNAME [FAILED]" + fi + _cleanup +} + +if [ $(id -u) -ne 0 ]; then + echo "selftests: $TESTNAME [SKIP] Need root privileges" + exit $ksft_skip +fi + +if [ -z "$BPF_FS" ]; then + echo "selftests: $TESTNAME [SKIP] Could not run test without bpffs mounted" + exit $ksft_skip +fi + +if ! bpftool version > /dev/null 2>&1; then + echo "selftests: $TESTNAME [SKIP] Could not run test without bpftool" + exit $ksft_skip +fi + +set -e + +trap cleanup_skip EXIT + +mkdir $BPF_DIR + +trap cleanup EXIT + +bpftool prog load metadata_unused.o $BPF_DIR/unused + +METADATA_PLAIN="$(bpftool prog --metadata)" +echo "$METADATA_PLAIN" | grep 'metadata_a = "foo"' > /dev/null +echo "$METADATA_PLAIN" | grep 'metadata_b = 1' > /dev/null + +bpftool prog --metadata --json | grep '"metadata":{"metadata_a":"foo","metadata_b":1}' > /dev/null + +bpftool map | grep 'metada.metadata' > /dev/null + +rm $BPF_DIR/unused + +bpftool prog load metadata_used.o $BPF_DIR/used + +METADATA_PLAIN="$(bpftool prog --metadata)" +echo "$METADATA_PLAIN" | grep 'metadata_a = "bar"' > /dev/null +echo "$METADATA_PLAIN" | grep 'metadata_b = 2' > /dev/null + +bpftool prog --metadata --json | grep '"metadata":{"metadata_a":"bar","metadata_b":2}' > /dev/null + +bpftool map | grep 'metada.metadata' > /dev/null + +rm $BPF_DIR/used + +exit 0