Skip to content

Commit 74b247f

Browse files
committed
Merge branch 'bpf-btf-for-htab-lru'
Yonghong Song says: ==================== Commit a26ca7c ("bpf: btf: Add pretty print support to the basic arraymap") added pretty print support to array map. This patch adds pretty print for hash and lru_hash maps. The following example shows the pretty-print result of a pinned hashmap. Without this patch set, user will get an error instead. struct map_value { int count_a; int count_b; }; cat /sys/fs/bpf/pinned_hash_map: 87907: {87907,87908} 57354: {37354,57355} 76625: {76625,76626} ... Patch #1 fixed a bug in bpffs map_seq_next() function so that all elements in the hash table will be traversed. Patch #2 implemented map_seq_show_elem() and map_check_btf() callback functions for hash and lru hash maps. Patch #3 enhanced tools/testing/selftests/bpf/test_btf.c to test bpffs hash and lru hash map pretty print. ==================== Signed-off-by: Daniel Borkmann <[email protected]>
2 parents 60afdf0 + af2a81d commit 74b247f

File tree

3 files changed

+121
-18
lines changed

3 files changed

+121
-18
lines changed

kernel/bpf/hashtab.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
* General Public License for more details.
1212
*/
1313
#include <linux/bpf.h>
14+
#include <linux/btf.h>
1415
#include <linux/jhash.h>
1516
#include <linux/filter.h>
1617
#include <linux/rculist_nulls.h>
18+
#include <uapi/linux/btf.h>
1719
#include "percpu_freelist.h"
1820
#include "bpf_lru_list.h"
1921
#include "map_in_map.h"
@@ -1162,6 +1164,44 @@ static void htab_map_free(struct bpf_map *map)
11621164
kfree(htab);
11631165
}
11641166

1167+
static void htab_map_seq_show_elem(struct bpf_map *map, void *key,
1168+
struct seq_file *m)
1169+
{
1170+
void *value;
1171+
1172+
rcu_read_lock();
1173+
1174+
value = htab_map_lookup_elem(map, key);
1175+
if (!value) {
1176+
rcu_read_unlock();
1177+
return;
1178+
}
1179+
1180+
btf_type_seq_show(map->btf, map->btf_key_type_id, key, m);
1181+
seq_puts(m, ": ");
1182+
btf_type_seq_show(map->btf, map->btf_value_type_id, value, m);
1183+
seq_puts(m, "\n");
1184+
1185+
rcu_read_unlock();
1186+
}
1187+
1188+
static int htab_map_check_btf(const struct bpf_map *map, const struct btf *btf,
1189+
u32 btf_key_id, u32 btf_value_id)
1190+
{
1191+
const struct btf_type *key_type, *value_type;
1192+
u32 key_size, value_size;
1193+
1194+
key_type = btf_type_id_size(btf, &btf_key_id, &key_size);
1195+
if (!key_type || key_size != map->key_size)
1196+
return -EINVAL;
1197+
1198+
value_type = btf_type_id_size(btf, &btf_value_id, &value_size);
1199+
if (!value_type || value_size != map->value_size)
1200+
return -EINVAL;
1201+
1202+
return 0;
1203+
}
1204+
11651205
const struct bpf_map_ops htab_map_ops = {
11661206
.map_alloc_check = htab_map_alloc_check,
11671207
.map_alloc = htab_map_alloc,
@@ -1171,6 +1211,8 @@ const struct bpf_map_ops htab_map_ops = {
11711211
.map_update_elem = htab_map_update_elem,
11721212
.map_delete_elem = htab_map_delete_elem,
11731213
.map_gen_lookup = htab_map_gen_lookup,
1214+
.map_seq_show_elem = htab_map_seq_show_elem,
1215+
.map_check_btf = htab_map_check_btf,
11741216
};
11751217

11761218
const struct bpf_map_ops htab_lru_map_ops = {
@@ -1182,6 +1224,8 @@ const struct bpf_map_ops htab_lru_map_ops = {
11821224
.map_update_elem = htab_lru_map_update_elem,
11831225
.map_delete_elem = htab_lru_map_delete_elem,
11841226
.map_gen_lookup = htab_lru_map_gen_lookup,
1227+
.map_seq_show_elem = htab_map_seq_show_elem,
1228+
.map_check_btf = htab_map_check_btf,
11851229
};
11861230

11871231
/* Called from eBPF program */

kernel/bpf/inode.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,19 +196,21 @@ static void *map_seq_next(struct seq_file *m, void *v, loff_t *pos)
196196
{
197197
struct bpf_map *map = seq_file_to_map(m);
198198
void *key = map_iter(m)->key;
199+
void *prev_key;
199200

200201
if (map_iter(m)->done)
201202
return NULL;
202203

203204
if (unlikely(v == SEQ_START_TOKEN))
204-
goto done;
205+
prev_key = NULL;
206+
else
207+
prev_key = key;
205208

206-
if (map->ops->map_get_next_key(map, key, key)) {
209+
if (map->ops->map_get_next_key(map, prev_key, key)) {
207210
map_iter(m)->done = true;
208211
return NULL;
209212
}
210213

211-
done:
212214
++(*pos);
213215
return key;
214216
}

tools/testing/selftests/bpf/test_btf.c

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ struct btf_raw_test {
131131
__u32 max_entries;
132132
bool btf_load_err;
133133
bool map_create_err;
134+
bool ordered_map;
135+
bool lossless_map;
134136
int hdr_len_delta;
135137
int type_off_delta;
136138
int str_off_delta;
@@ -2093,8 +2095,7 @@ struct pprint_mapv {
20932095
} aenum;
20942096
};
20952097

2096-
static struct btf_raw_test pprint_test = {
2097-
.descr = "BTF pretty print test #1",
2098+
static struct btf_raw_test pprint_test_template = {
20982099
.raw_types = {
20992100
/* unsighed char */ /* [1] */
21002101
BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
@@ -2146,15 +2147,47 @@ static struct btf_raw_test pprint_test = {
21462147
},
21472148
.str_sec = "\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum",
21482149
.str_sec_size = sizeof("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"),
2149-
.map_type = BPF_MAP_TYPE_ARRAY,
2150-
.map_name = "pprint_test",
21512150
.key_size = sizeof(unsigned int),
21522151
.value_size = sizeof(struct pprint_mapv),
21532152
.key_type_id = 3, /* unsigned int */
21542153
.value_type_id = 16, /* struct pprint_mapv */
21552154
.max_entries = 128 * 1024,
21562155
};
21572156

2157+
static struct btf_pprint_test_meta {
2158+
const char *descr;
2159+
enum bpf_map_type map_type;
2160+
const char *map_name;
2161+
bool ordered_map;
2162+
bool lossless_map;
2163+
} pprint_tests_meta[] = {
2164+
{
2165+
.descr = "BTF pretty print array",
2166+
.map_type = BPF_MAP_TYPE_ARRAY,
2167+
.map_name = "pprint_test_array",
2168+
.ordered_map = true,
2169+
.lossless_map = true,
2170+
},
2171+
2172+
{
2173+
.descr = "BTF pretty print hash",
2174+
.map_type = BPF_MAP_TYPE_HASH,
2175+
.map_name = "pprint_test_hash",
2176+
.ordered_map = false,
2177+
.lossless_map = true,
2178+
},
2179+
2180+
{
2181+
.descr = "BTF pretty print lru hash",
2182+
.map_type = BPF_MAP_TYPE_LRU_HASH,
2183+
.map_name = "pprint_test_lru_hash",
2184+
.ordered_map = false,
2185+
.lossless_map = false,
2186+
},
2187+
2188+
};
2189+
2190+
21582191
static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i)
21592192
{
21602193
v->ui32 = i;
@@ -2166,10 +2199,12 @@ static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i)
21662199
v->aenum = i & 0x03;
21672200
}
21682201

2169-
static int test_pprint(void)
2202+
static int do_test_pprint(void)
21702203
{
2171-
const struct btf_raw_test *test = &pprint_test;
2204+
const struct btf_raw_test *test = &pprint_test_template;
21722205
struct bpf_create_map_attr create_attr = {};
2206+
unsigned int key, nr_read_elems;
2207+
bool ordered_map, lossless_map;
21732208
int map_fd = -1, btf_fd = -1;
21742209
struct pprint_mapv mapv = {};
21752210
unsigned int raw_btf_size;
@@ -2178,7 +2213,6 @@ static int test_pprint(void)
21782213
char pin_path[255];
21792214
size_t line_len = 0;
21802215
char *line = NULL;
2181-
unsigned int key;
21822216
uint8_t *raw_btf;
21832217
ssize_t nread;
21842218
int err, ret;
@@ -2251,14 +2285,18 @@ static int test_pprint(void)
22512285
goto done;
22522286
}
22532287

2254-
key = 0;
2288+
nr_read_elems = 0;
2289+
ordered_map = test->ordered_map;
2290+
lossless_map = test->lossless_map;
22552291
do {
22562292
ssize_t nexpected_line;
2293+
unsigned int next_key;
22572294

2258-
set_pprint_mapv(&mapv, key);
2295+
next_key = ordered_map ? nr_read_elems : atoi(line);
2296+
set_pprint_mapv(&mapv, next_key);
22592297
nexpected_line = snprintf(expected_line, sizeof(expected_line),
22602298
"%u: {%u,0,%d,0x%x,0x%x,0x%x,{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n",
2261-
key,
2299+
next_key,
22622300
mapv.ui32, mapv.si32,
22632301
mapv.unused_bits2a, mapv.bits28, mapv.unused_bits2b,
22642302
mapv.ui64,
@@ -2281,11 +2319,12 @@ static int test_pprint(void)
22812319
}
22822320

22832321
nread = getline(&line, &line_len, pin_file);
2284-
} while (++key < test->max_entries && nread > 0);
2322+
} while (++nr_read_elems < test->max_entries && nread > 0);
22852323

2286-
if (CHECK(key < test->max_entries,
2287-
"Unexpected EOF. key:%u test->max_entries:%u",
2288-
key, test->max_entries)) {
2324+
if (lossless_map &&
2325+
CHECK(nr_read_elems < test->max_entries,
2326+
"Unexpected EOF. nr_read_elems:%u test->max_entries:%u",
2327+
nr_read_elems, test->max_entries)) {
22892328
err = -1;
22902329
goto done;
22912330
}
@@ -2314,6 +2353,24 @@ static int test_pprint(void)
23142353
return err;
23152354
}
23162355

2356+
static int test_pprint(void)
2357+
{
2358+
unsigned int i;
2359+
int err = 0;
2360+
2361+
for (i = 0; i < ARRAY_SIZE(pprint_tests_meta); i++) {
2362+
pprint_test_template.descr = pprint_tests_meta[i].descr;
2363+
pprint_test_template.map_type = pprint_tests_meta[i].map_type;
2364+
pprint_test_template.map_name = pprint_tests_meta[i].map_name;
2365+
pprint_test_template.ordered_map = pprint_tests_meta[i].ordered_map;
2366+
pprint_test_template.lossless_map = pprint_tests_meta[i].lossless_map;
2367+
2368+
err |= count_result(do_test_pprint());
2369+
}
2370+
2371+
return err;
2372+
}
2373+
23172374
static void usage(const char *cmd)
23182375
{
23192376
fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] | [-g test_num (1 - %zu)] | [-f test_num (1 - %zu)] | [-p]]\n",
@@ -2409,7 +2466,7 @@ int main(int argc, char **argv)
24092466
err |= test_file();
24102467

24112468
if (args.pprint_test)
2412-
err |= count_result(test_pprint());
2469+
err |= test_pprint();
24132470

24142471
if (args.raw_test || args.get_info_test || args.file_test ||
24152472
args.pprint_test)

0 commit comments

Comments
 (0)