From patchwork Mon Aug 31 22:49:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Barret Rhoden X-Patchwork-Id: 1354650 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=fail (p=reject dis=none) header.from=google.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.a=rsa-sha256 header.s=20161025 header.b=LUekSZnL; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BgQPz1d1wz9sTM for ; Tue, 1 Sep 2020 08:49:59 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727048AbgHaWty (ORCPT ); Mon, 31 Aug 2020 18:49:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39820 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726821AbgHaWtx (ORCPT ); Mon, 31 Aug 2020 18:49:53 -0400 Received: from mail-qk1-x749.google.com (mail-qk1-x749.google.com [IPv6:2607:f8b0:4864:20::749]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A7356C061573 for ; Mon, 31 Aug 2020 15:49:52 -0700 (PDT) Received: by mail-qk1-x749.google.com with SMTP id v16so7165648qka.18 for ; Mon, 31 Aug 2020 15:49:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:message-id:mime-version:subject:from:to:cc; bh=lsejbdV/YJeNxRqBDrAM85EBWsJ6w6R31JBoDDcAVKw=; b=LUekSZnLLaT2oDK9/2Rbz8Jd6nMzsh3bFAVy7rsATTCt3j5BD7m3SK8NzR4k8TzPg4 A4QruQNA71TYblk3RMNxQrbX1EyX0iEbH9KQ6Gjz1h6RvPKK3nJHba2XFy8DMSHnX3mV 66iLC9nQBKiCIQzJr0ctfzfUzagCWS0VQ2wASUhZnTvlZpL2hSaxUVgOl+gbFll99RBM 0zIqR2nkQn63dJKzdcf7WI97Ty1g33U5wrnSAaMy3T3W7vuayV6gDN1SiaoewGHzhJRA I/7juz/2TsWGACUEqPTXFbh7u+AOaD41jpRBClIP3yJhvO5eknDeNS3lsrBwLXTXnaPD FsFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:message-id:mime-version:subject:from :to:cc; bh=lsejbdV/YJeNxRqBDrAM85EBWsJ6w6R31JBoDDcAVKw=; b=HXKgP+q0Pd+2vs01oOQ9BIFQ3AB2GkxXwgcvITg9IY4rZ2v7u3NlUyKzPgs4kCBgTK Y3wOfzdO5Y567e8xeJuthsRXX+SjcFlU44LF8LI6LIH8Fk/ycukTM8hGeOrw4lgG0xEH 9zlFLiCWQkRB6SR6C+o00gK8W+/lBb1e1h028KRHH0gywxONFkOy/hlyNcAdsM6NpFeA 3zhkB36WeNl2gqVlWqnI4T+KL2a7EQCqGhAFfAJxJ4j+xr/rRMHsq6qym7xu+zu5ZjDb PP7Mjye28+NoV2HRHO8uK0WEku4rfzoGrLqHWSzg11vwTvEqnvEp8d+N0sWDLErMJ5R7 rcDA== X-Gm-Message-State: AOAM533kILQ4rNh1pUKiD5ehF4IKgcaiyX+zuTMGrTwpsQtBaD2XxHi3 gqReFI38xW7pO8a2BCP4R6pcL74/ X-Google-Smtp-Source: ABdhPJx2tAjaaQbp7takpRRLRqxo3GJGDbS49dWqYyIfWseIXB4WdFQfYMpIZlsnvs4m4RnCiQN/pefi X-Received: from gnomeregan.cam.corp.google.com ([2620:15c:6:14:1ea0:b8ff:fe76:1e48]) (user=brho job=sendgmr) by 2002:a0c:ea34:: with SMTP id t20mr3387381qvp.233.1598914189559; Mon, 31 Aug 2020 15:49:49 -0700 (PDT) Date: Mon, 31 Aug 2020 18:49:33 -0400 Message-Id: <20200831224933.2129891-1-brho@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.28.0.402.g5ffc5be6b7-goog Subject: [RFC PATCH] libbpf: Support setting map max_entries at runtime From: Barret Rhoden To: Alexei Starovoitov , Daniel Borkmann , Martin KaFai Lau , Song Liu , Yonghong Song , Andrii Nakryiko , John Fastabend , KP Singh Cc: netdev@vger.kernel.org, bpf@vger.kernel.org, linux-kernel@vger.kernel.org Sender: bpf-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org The max_entries for a BPF map may depend on runtime parameters. Currently, we need to know the maximum value at BPF compile time. For instance, if you want an array map with NR_CPUS entries, you would hard code your architecture's largest value for CONFIG_NR_CPUS. This wastes memory at runtime. For the NR_CPU case, one could use a PERCPU map type, but those maps are limited in functionality. For instance, BPF programs can only access their own PERCPU part of the map, and the maps are not mmappable. This commit allows the use of sentinel values in BPF map definitions, which libbpf patches at runtime. For starters, we support NUM_POSSIBLE_CPUS: e.g. struct { __uint(type, BPF_MAP_TYPE_ARRAY); __uint(max_entries, NUM_POSSIBLE_CPUS); __type(key, u32); __type(value, struct cpu_data); } cpu_blobs SEC(".maps"); This can be extended to other runtime dependent values, such as the maximum number of threads (/proc/sys/kernel/threads-max). Signed-off-by: Barret Rhoden --- tools/lib/bpf/bpf_helpers.h | 4 ++++ tools/lib/bpf/libbpf.c | 40 ++++++++++++++++++++++++++++++------- tools/lib/bpf/libbpf.h | 4 ++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h index f67dce2af802..38b431d85ac6 100644 --- a/tools/lib/bpf/bpf_helpers.h +++ b/tools/lib/bpf/bpf_helpers.h @@ -74,6 +74,10 @@ enum libbpf_tristate { TRI_MODULE = 2, }; +enum libbpf_max_entries { + NUM_POSSIBLE_CPUS = (unsigned int)-1, +}; + #define __kconfig __attribute__((section(".kconfig"))) #endif diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 11e4725b8b1c..7d0e9792e015 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1868,36 +1868,55 @@ resolve_func_ptr(const struct btf *btf, __u32 id, __u32 *res_id) * encodes `type => BPF_MAP_TYPE_ARRAY` key/value pair completely using BTF * type definition, while using only sizeof(void *) space in ELF data section. */ -static bool get_map_field_int(const char *map_name, const struct btf *btf, - const struct btf_member *m, __u32 *res) +static struct btf_array *get_map_field_arr_info(const char *map_name, + const struct btf *btf, + const struct btf_member *m) { const struct btf_type *t = skip_mods_and_typedefs(btf, m->type, NULL); const char *name = btf__name_by_offset(btf, m->name_off); - const struct btf_array *arr_info; const struct btf_type *arr_t; if (!btf_is_ptr(t)) { pr_warn("map '%s': attr '%s': expected PTR, got %u.\n", map_name, name, btf_kind(t)); - return false; + return NULL; } arr_t = btf__type_by_id(btf, t->type); if (!arr_t) { pr_warn("map '%s': attr '%s': type [%u] not found.\n", map_name, name, t->type); - return false; + return NULL; } if (!btf_is_array(arr_t)) { pr_warn("map '%s': attr '%s': expected ARRAY, got %u.\n", map_name, name, btf_kind(arr_t)); - return false; + return NULL; } - arr_info = btf_array(arr_t); + return btf_array(arr_t); +} + +static bool get_map_field_int(const char *map_name, const struct btf *btf, + const struct btf_member *m, __u32 *res) +{ + const struct btf_array *arr_info; + + arr_info = get_map_field_arr_info(map_name, btf, m); + if (arr_info == NULL) + return false; *res = arr_info->nelems; return true; } +static void set_map_field_int(const char *map_name, const struct btf *btf, + const struct btf_member *m, __u32 val) +{ + struct btf_array *arr_info; + + arr_info = get_map_field_arr_info(map_name, btf, m); + arr_info->nelems = val; +} + static int build_map_pin_path(struct bpf_map *map, const char *path) { char buf[PATH_MAX]; @@ -1951,6 +1970,13 @@ static int parse_btf_map_def(struct bpf_object *obj, return -EINVAL; pr_debug("map '%s': found max_entries = %u.\n", map->name, map->def.max_entries); + if (map->def.max_entries == NUM_POSSIBLE_CPUS) { + map->def.max_entries = libbpf_num_possible_cpus(); + set_map_field_int(map->name, obj->btf, m, + map->def.max_entries); + pr_debug("map '%s': adjusting max_entries = %u.\n", + map->name, map->def.max_entries); + } } else if (strcmp(name, "map_flags") == 0) { if (!get_map_field_int(map->name, obj->btf, m, &map->def.map_flags)) diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 334437af3014..42cba5bb1b04 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -717,6 +717,10 @@ enum libbpf_tristate { TRI_MODULE = 2, }; +enum libbpf_max_entries { + NUM_POSSIBLE_CPUS = -1, +}; + #ifdef __cplusplus } /* extern "C" */ #endif