lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <7adf11a446e02080d84eb4c7152078d1912a5454.1576673843.git.paul.chaignon@orange.com>
Date:   Wed, 18 Dec 2019 15:23:47 +0100
From:   Paul Chaignon <paul.chaignon@...nge.com>
To:     bpf@...r.kernel.org
Cc:     paul.chaignon@...il.com, netdev@...r.kernel.org,
        Alexei Starovoitov <ast@...nel.org>,
        Daniel Borkmann <daniel@...earbox.net>,
        Martin KaFai Lau <kafai@...com>,
        Song Liu <songliubraving@...com>, Yonghong Song <yhs@...com>,
        Andrii Nakryiko <andriin@...com>
Subject: [PATCH bpf-next 3/3] bpftool: Support single-cpu updates for per-cpu
 maps

This patch adds support for the new BPF_CPU flag in bpftool, to enable
single-cpu updates of per-cpu maps.  It can be combined with existing
flags; for example, to update the value for key 0 on CPU 9 only if it
doesn't already exist:

  bpftool map update key 0 0 0 0 value 1 0 0 0 noexist cpu 9

Signed-off-by: Paul Chaignon <paul.chaignon@...nge.com>
---
 .../bpf/bpftool/Documentation/bpftool-map.rst | 13 ++--
 tools/bpf/bpftool/bash-completion/bpftool     |  2 +-
 tools/bpf/bpftool/map.c                       | 70 ++++++++++++++-----
 3 files changed, 61 insertions(+), 24 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst
index cdeae8ae90ba..72aa9b72f08f 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-map.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst
@@ -25,7 +25,7 @@ MAP COMMANDS
 |	**bpftool** **map create**     *FILE* **type** *TYPE* **key** *KEY_SIZE* **value** *VALUE_SIZE* \
 |		**entries** *MAX_ENTRIES* **name** *NAME* [**flags** *FLAGS*] [**dev** *NAME*]
 |	**bpftool** **map dump**       *MAP*
-|	**bpftool** **map update**     *MAP* [**key** *DATA*] [**value** *VALUE*] [*UPDATE_FLAGS*]
+|	**bpftool** **map update**     *MAP* [**key** *DATA*] [**value** *VALUE*] [*UPDATE_FLAGS*]...
 |	**bpftool** **map lookup**     *MAP* [**key** *DATA*]
 |	**bpftool** **map getnext**    *MAP* [**key** *DATA*]
 |	**bpftool** **map delete**     *MAP*  **key** *DATA*
@@ -43,7 +43,7 @@ MAP COMMANDS
 |	*DATA* := { [**hex**] *BYTES* }
 |	*PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* | **name** *PROG_NAME* }
 |	*VALUE* := { *DATA* | *MAP* | *PROG* }
-|	*UPDATE_FLAGS* := { **any** | **exist** | **noexist** }
+|	*UPDATE_FLAGS* := { **any** | **exist** | **noexist** | **cpu** *CPU_ID* }
 |	*TYPE* := { **hash** | **array** | **prog_array** | **perf_event_array** | **percpu_hash**
 |		| **percpu_array** | **stack_trace** | **cgroup_array** | **lru_hash**
 |		| **lru_percpu_hash** | **lpm_trie** | **array_of_maps** | **hash_of_maps**
@@ -73,9 +73,12 @@ DESCRIPTION
 	**bpftool map update**  *MAP* [**key** *DATA*] [**value** *VALUE*] [*UPDATE_FLAGS*]
 		  Update map entry for a given *KEY*.
 
-		  *UPDATE_FLAGS* can be one of: **any** update existing entry
-		  or add if doesn't exit; **exist** update only if entry already
-		  exists; **noexist** update only if entry doesn't exist.
+		  *UPDATE_FLAGS* can be: **any** update existing entry or add
+		  if doesn't exit; **exist** update only if entry already
+		  exists; **noexist** update only if entry doesn't exist;
+		  **cpu** update only value for given *CPU_ID* in per-CPU map.
+		  Only one of **any**, **exist**, and **noexist** can be
+		  specified.
 
 		  If the **hex** keyword is provided in front of the bytes
 		  sequence, the bytes are parsed as hexadeximal values, even if
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 754d8395e451..116bf3dffb47 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -689,7 +689,7 @@ _bpftool()
                             esac
 
                             _bpftool_once_attr 'key'
-                            local UPDATE_FLAGS='any exist noexist'
+                            local UPDATE_FLAGS='any exist noexist cpu'
                             for (( idx=3; idx < ${#words[@]}-1; idx++ )); do
                                 if [[ ${words[idx]} == 'value' ]]; then
                                     # 'value' is present, but is not the last
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index c01f76fa6876..da1455f460b1 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -470,9 +470,10 @@ static void fill_per_cpu_value(struct bpf_map_info *info, void *value)
 		memcpy(value + i * step, value, info->value_size);
 }
 
-static int parse_elem(char **argv, struct bpf_map_info *info,
-		      void *key, void *value, __u32 key_size, __u32 value_size,
-		      __u32 *flags, __u32 **value_fd)
+static int
+__parse_elem(char **argv, struct bpf_map_info *info, void *key, void *value,
+	     __u32 key_size, __u32 value_size, __u64 *flags, __u32 **value_fd,
+	     bool any_flag)
 {
 	if (!*argv) {
 		if (!key && !value)
@@ -494,8 +495,8 @@ static int parse_elem(char **argv, struct bpf_map_info *info,
 		if (!argv)
 			return -1;
 
-		return parse_elem(argv, info, NULL, value, key_size, value_size,
-				  flags, value_fd);
+		return __parse_elem(argv, info, NULL, value, key_size,
+				    value_size, flags, value_fd, any_flag);
 	} else if (is_prefix(*argv, "value")) {
 		int fd;
 
@@ -556,30 +557,63 @@ static int parse_elem(char **argv, struct bpf_map_info *info,
 			fill_per_cpu_value(info, value);
 		}
 
-		return parse_elem(argv, info, key, NULL, key_size, value_size,
-				  flags, NULL);
+		return __parse_elem(argv, info, key, NULL, key_size,
+				    value_size, flags, NULL, any_flag);
 	} else if (is_prefix(*argv, "any") || is_prefix(*argv, "noexist") ||
 		   is_prefix(*argv, "exist")) {
-		if (!flags) {
+		if (any_flag || *flags & (BPF_NOEXIST | BPF_EXIST)) {
 			p_err("flags specified multiple times: %s", *argv);
 			return -1;
 		}
 
-		if (is_prefix(*argv, "any"))
-			*flags = BPF_ANY;
-		else if (is_prefix(*argv, "noexist"))
-			*flags = BPF_NOEXIST;
-		else if (is_prefix(*argv, "exist"))
-			*flags = BPF_EXIST;
+		if (is_prefix(*argv, "any")) {
+			*flags |= BPF_ANY;
+			any_flag = true;
+		} else if (is_prefix(*argv, "noexist")) {
+			*flags |= BPF_NOEXIST;
+		} else if (is_prefix(*argv, "exist")) {
+			*flags |= BPF_EXIST;
+		}
+
+		return __parse_elem(argv + 1, info, key, value, key_size,
+				    value_size, flags, value_fd, any_flag);
+	} else if (is_prefix(*argv, "cpu")) {
+		unsigned long long cpuid;
+		char *endptr;
+
+		if (*flags & BPF_CPU) {
+			p_err("flags specified multiple times: %s", *argv);
+			return -1;
+		}
 
-		return parse_elem(argv + 1, info, key, value, key_size,
-				  value_size, NULL, value_fd);
+		cpuid = strtoull(*(argv + 1), &endptr, 0);
+		if (*endptr) {
+			p_err("can't parse CPU id %s", *(argv + 1));
+			return -1;
+		}
+		if (cpuid >= get_possible_cpus()) {
+			p_err("incorrect value for CPU id");
+			return -1;
+		}
+
+		*flags |= (cpuid << 32) | BPF_CPU;
+
+		return __parse_elem(argv + 2, info, key, value, key_size,
+				    value_size, flags, value_fd, any_flag);
 	}
 
 	p_err("expected key or value, got: %s", *argv);
 	return -1;
 }
 
+static int
+parse_elem(char **argv, struct bpf_map_info *info, void *key, void *value,
+	   __u32 key_size, __u32 value_size, __u64 *flags, __u32 **value_fd)
+{
+	return __parse_elem(argv, info, key, value, key_size, value_size,
+			    flags, value_fd, false);
+}
+
 static void show_map_header_json(struct bpf_map_info *info, json_writer_t *wtr)
 {
 	jsonw_uint_field(wtr, "id", info->id);
@@ -1114,7 +1148,7 @@ static int do_update(int argc, char **argv)
 	struct bpf_map_info info = {};
 	__u32 len = sizeof(info);
 	__u32 *value_fd = NULL;
-	__u32 flags = BPF_ANY;
+	__u64 flags = BPF_ANY;
 	void *key, *value;
 	int fd, err;
 
@@ -1558,7 +1592,7 @@ static int do_help(int argc, char **argv)
 		"       DATA := { [hex] BYTES }\n"
 		"       " HELP_SPEC_PROGRAM "\n"
 		"       VALUE := { DATA | MAP | PROG }\n"
-		"       UPDATE_FLAGS := { any | exist | noexist }\n"
+		"       UPDATE_FLAGS := { any | exist | noexist | cpu CPU_ID }\n"
 		"       TYPE := { hash | array | prog_array | perf_event_array | percpu_hash |\n"
 		"                 percpu_array | stack_trace | cgroup_array | lru_hash |\n"
 		"                 lru_percpu_hash | lpm_trie | array_of_maps | hash_of_maps |\n"
-- 
2.24.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ