summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuentin Monnet <quentin.monnet@netronome.com>2019-01-17 10:27:54 -0500
committerAlexei Starovoitov <ast@kernel.org>2019-01-23 01:15:40 -0500
commitf99e166397f0298fe78bce24c55c6d074f9bf196 (patch)
treee9f31b1ccd938793704a80cce059d7fd25541842
parent1bf4b05810fe38c5f09973295e8d4234a4fd5d87 (diff)
tools: bpftool: add probes for eBPF map types
Add new probes for eBPF map types, to detect what are the ones available on the system. Try creating one map of each type, and see if the kernel complains. Sample output: # bpftool feature probe kernel ... Scanning eBPF map types... eBPF map_type hash is available eBPF map_type array is available eBPF map_type prog_array is available ... # bpftool --json --pretty feature probe kernel { ... "map_types": { "have_hash_map_type": true, "have_array_map_type": true, "have_prog_array_map_type": true, ... } } v5: - In libbpf.map, move global symbol to the new LIBBPF_0.0.2 section. v3: - Use a switch with all enum values for setting specific map parameters, so that gcc complains at compile time (-Wswitch-enum) if new map types were added to the kernel but libbpf was not updated. v2: - Move probes from bpftool to libbpf. - Remove C-style macros output from this patch. Signed-off-by: Quentin Monnet <quentin.monnet@netronome.com> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Stanislav Fomichev <sdf@google.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
-rw-r--r--tools/bpf/bpftool/feature.c26
-rw-r--r--tools/bpf/bpftool/main.h3
-rw-r--r--tools/bpf/bpftool/map.c4
-rw-r--r--tools/lib/bpf/libbpf.h1
-rw-r--r--tools/lib/bpf/libbpf.map1
-rw-r--r--tools/lib/bpf/libbpf_probes.c84
6 files changed, 118 insertions, 1 deletions
diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index d6508dde4808..cc731475c74b 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -438,6 +438,26 @@ static void probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types)
438 print_bool_feature(feat_name, plain_desc, res); 438 print_bool_feature(feat_name, plain_desc, res);
439} 439}
440 440
441static void probe_map_type(enum bpf_map_type map_type)
442{
443 const char *plain_comment = "eBPF map_type ";
444 char feat_name[128], plain_desc[128];
445 size_t maxlen;
446 bool res;
447
448 res = bpf_probe_map_type(map_type, 0);
449
450 maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
451 if (strlen(map_type_name[map_type]) > maxlen) {
452 p_info("map type name too long");
453 return;
454 }
455
456 sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]);
457 sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]);
458 print_bool_feature(feat_name, plain_desc, res);
459}
460
441static int do_probe(int argc, char **argv) 461static int do_probe(int argc, char **argv)
442{ 462{
443 enum probe_component target = COMPONENT_UNSPEC; 463 enum probe_component target = COMPONENT_UNSPEC;
@@ -507,6 +527,12 @@ static int do_probe(int argc, char **argv)
507 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) 527 for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
508 probe_prog_type(i, supported_types); 528 probe_prog_type(i, supported_types);
509 529
530 print_end_then_start_section("map_types",
531 "Scanning eBPF map types...");
532
533 for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
534 probe_map_type(i);
535
510exit_close_json: 536exit_close_json:
511 if (json_output) { 537 if (json_output) {
512 /* End current "section" of probes */ 538 /* End current "section" of probes */
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 5cfc6601de9b..d7dd84d3c660 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -75,6 +75,9 @@ static const char * const prog_type_name[] = {
75 [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector", 75 [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector",
76}; 76};
77 77
78extern const char * const map_type_name[];
79extern const size_t map_type_name_size;
80
78enum bpf_obj_type { 81enum bpf_obj_type {
79 BPF_OBJ_UNKNOWN, 82 BPF_OBJ_UNKNOWN,
80 BPF_OBJ_PROG, 83 BPF_OBJ_PROG,
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index 850c99ac980f..f15c520195b7 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -21,7 +21,7 @@
21#include "json_writer.h" 21#include "json_writer.h"
22#include "main.h" 22#include "main.h"
23 23
24static const char * const map_type_name[] = { 24const char * const map_type_name[] = {
25 [BPF_MAP_TYPE_UNSPEC] = "unspec", 25 [BPF_MAP_TYPE_UNSPEC] = "unspec",
26 [BPF_MAP_TYPE_HASH] = "hash", 26 [BPF_MAP_TYPE_HASH] = "hash",
27 [BPF_MAP_TYPE_ARRAY] = "array", 27 [BPF_MAP_TYPE_ARRAY] = "array",
@@ -48,6 +48,8 @@ static const char * const map_type_name[] = {
48 [BPF_MAP_TYPE_STACK] = "stack", 48 [BPF_MAP_TYPE_STACK] = "stack",
49}; 49};
50 50
51const size_t map_type_name_size = ARRAY_SIZE(map_type_name);
52
51static bool map_is_per_cpu(__u32 type) 53static bool map_is_per_cpu(__u32 type)
52{ 54{
53 return type == BPF_MAP_TYPE_PERCPU_HASH || 55 return type == BPF_MAP_TYPE_PERCPU_HASH ||
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 8e63821109ab..72385f6f9415 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -365,6 +365,7 @@ bpf_prog_linfo__lfind(const struct bpf_prog_linfo *prog_linfo,
365 */ 365 */
366LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type, 366LIBBPF_API bool bpf_probe_prog_type(enum bpf_prog_type prog_type,
367 __u32 ifindex); 367 __u32 ifindex);
368LIBBPF_API bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex);
368 369
369#ifdef __cplusplus 370#ifdef __cplusplus
370} /* extern "C" */ 371} /* extern "C" */
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index c7ec3ffa24e9..bb2dfc3b2d7b 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -127,5 +127,6 @@ LIBBPF_0.0.1 {
127 127
128LIBBPF_0.0.2 { 128LIBBPF_0.0.2 {
129 global: 129 global:
130 bpf_probe_map_type;
130 bpf_probe_prog_type; 131 bpf_probe_prog_type;
131} LIBBPF_0.0.1; 132} LIBBPF_0.0.1;
diff --git a/tools/lib/bpf/libbpf_probes.c b/tools/lib/bpf/libbpf_probes.c
index 056c0c186f2a..f511bd317b87 100644
--- a/tools/lib/bpf/libbpf_probes.c
+++ b/tools/lib/bpf/libbpf_probes.c
@@ -93,3 +93,87 @@ bool bpf_probe_prog_type(enum bpf_prog_type prog_type, __u32 ifindex)
93 93
94 return errno != EINVAL && errno != EOPNOTSUPP; 94 return errno != EINVAL && errno != EOPNOTSUPP;
95} 95}
96
97bool bpf_probe_map_type(enum bpf_map_type map_type, __u32 ifindex)
98{
99 int key_size, value_size, max_entries, map_flags;
100 struct bpf_create_map_attr attr = {};
101 int fd = -1, fd_inner;
102
103 key_size = sizeof(__u32);
104 value_size = sizeof(__u32);
105 max_entries = 1;
106 map_flags = 0;
107
108 switch (map_type) {
109 case BPF_MAP_TYPE_STACK_TRACE:
110 value_size = sizeof(__u64);
111 break;
112 case BPF_MAP_TYPE_LPM_TRIE:
113 key_size = sizeof(__u64);
114 value_size = sizeof(__u64);
115 map_flags = BPF_F_NO_PREALLOC;
116 break;
117 case BPF_MAP_TYPE_CGROUP_STORAGE:
118 case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE:
119 key_size = sizeof(struct bpf_cgroup_storage_key);
120 value_size = sizeof(__u64);
121 max_entries = 0;
122 break;
123 case BPF_MAP_TYPE_QUEUE:
124 case BPF_MAP_TYPE_STACK:
125 key_size = 0;
126 break;
127 case BPF_MAP_TYPE_UNSPEC:
128 case BPF_MAP_TYPE_HASH:
129 case BPF_MAP_TYPE_ARRAY:
130 case BPF_MAP_TYPE_PROG_ARRAY:
131 case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
132 case BPF_MAP_TYPE_PERCPU_HASH:
133 case BPF_MAP_TYPE_PERCPU_ARRAY:
134 case BPF_MAP_TYPE_CGROUP_ARRAY:
135 case BPF_MAP_TYPE_LRU_HASH:
136 case BPF_MAP_TYPE_LRU_PERCPU_HASH:
137 case BPF_MAP_TYPE_ARRAY_OF_MAPS:
138 case BPF_MAP_TYPE_HASH_OF_MAPS:
139 case BPF_MAP_TYPE_DEVMAP:
140 case BPF_MAP_TYPE_SOCKMAP:
141 case BPF_MAP_TYPE_CPUMAP:
142 case BPF_MAP_TYPE_XSKMAP:
143 case BPF_MAP_TYPE_SOCKHASH:
144 case BPF_MAP_TYPE_REUSEPORT_SOCKARRAY:
145 default:
146 break;
147 }
148
149 if (map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS ||
150 map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
151 /* TODO: probe for device, once libbpf has a function to create
152 * map-in-map for offload
153 */
154 if (ifindex)
155 return false;
156
157 fd_inner = bpf_create_map(BPF_MAP_TYPE_HASH,
158 sizeof(__u32), sizeof(__u32), 1, 0);
159 if (fd_inner < 0)
160 return false;
161 fd = bpf_create_map_in_map(map_type, NULL, sizeof(__u32),
162 fd_inner, 1, 0);
163 close(fd_inner);
164 } else {
165 /* Note: No other restriction on map type probes for offload */
166 attr.map_type = map_type;
167 attr.key_size = key_size;
168 attr.value_size = value_size;
169 attr.max_entries = max_entries;
170 attr.map_flags = map_flags;
171 attr.map_ifindex = ifindex;
172
173 fd = bpf_create_map_xattr(&attr);
174 }
175 if (fd >= 0)
176 close(fd);
177
178 return fd >= 0;
179}