forked from Minki/linux
tools/bpf: add bpffs percpu map pretty print tests in test_btf
The bpf selftest test_btf is extended to test bpffs percpu map pretty print for percpu array, percpu hash and percpu lru hash. Signed-off-by: Yonghong Song <yhs@fb.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
parent
c7b27c37af
commit
6493ebf724
@ -4,6 +4,7 @@
|
|||||||
#include <linux/bpf.h>
|
#include <linux/bpf.h>
|
||||||
#include <linux/btf.h>
|
#include <linux/btf.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <bpf/bpf.h>
|
#include <bpf/bpf.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <libelf.h>
|
#include <libelf.h>
|
||||||
@ -45,7 +46,6 @@ static int count_result(int err)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
|
||||||
#define __printf(a, b) __attribute__((format(printf, a, b)))
|
#define __printf(a, b) __attribute__((format(printf, a, b)))
|
||||||
|
|
||||||
__printf(1, 2)
|
__printf(1, 2)
|
||||||
@ -130,6 +130,7 @@ struct btf_raw_test {
|
|||||||
bool map_create_err;
|
bool map_create_err;
|
||||||
bool ordered_map;
|
bool ordered_map;
|
||||||
bool lossless_map;
|
bool lossless_map;
|
||||||
|
bool percpu_map;
|
||||||
int hdr_len_delta;
|
int hdr_len_delta;
|
||||||
int type_off_delta;
|
int type_off_delta;
|
||||||
int str_off_delta;
|
int str_off_delta;
|
||||||
@ -2157,6 +2158,7 @@ static struct btf_pprint_test_meta {
|
|||||||
const char *map_name;
|
const char *map_name;
|
||||||
bool ordered_map;
|
bool ordered_map;
|
||||||
bool lossless_map;
|
bool lossless_map;
|
||||||
|
bool percpu_map;
|
||||||
} pprint_tests_meta[] = {
|
} pprint_tests_meta[] = {
|
||||||
{
|
{
|
||||||
.descr = "BTF pretty print array",
|
.descr = "BTF pretty print array",
|
||||||
@ -2164,6 +2166,7 @@ static struct btf_pprint_test_meta {
|
|||||||
.map_name = "pprint_test_array",
|
.map_name = "pprint_test_array",
|
||||||
.ordered_map = true,
|
.ordered_map = true,
|
||||||
.lossless_map = true,
|
.lossless_map = true,
|
||||||
|
.percpu_map = false,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -2172,6 +2175,7 @@ static struct btf_pprint_test_meta {
|
|||||||
.map_name = "pprint_test_hash",
|
.map_name = "pprint_test_hash",
|
||||||
.ordered_map = false,
|
.ordered_map = false,
|
||||||
.lossless_map = true,
|
.lossless_map = true,
|
||||||
|
.percpu_map = false,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -2180,30 +2184,83 @@ static struct btf_pprint_test_meta {
|
|||||||
.map_name = "pprint_test_lru_hash",
|
.map_name = "pprint_test_lru_hash",
|
||||||
.ordered_map = false,
|
.ordered_map = false,
|
||||||
.lossless_map = false,
|
.lossless_map = false,
|
||||||
|
.percpu_map = false,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.descr = "BTF pretty print percpu array",
|
||||||
|
.map_type = BPF_MAP_TYPE_PERCPU_ARRAY,
|
||||||
|
.map_name = "pprint_test_percpu_array",
|
||||||
|
.ordered_map = true,
|
||||||
|
.lossless_map = true,
|
||||||
|
.percpu_map = true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.descr = "BTF pretty print percpu hash",
|
||||||
|
.map_type = BPF_MAP_TYPE_PERCPU_HASH,
|
||||||
|
.map_name = "pprint_test_percpu_hash",
|
||||||
|
.ordered_map = false,
|
||||||
|
.lossless_map = true,
|
||||||
|
.percpu_map = true,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
.descr = "BTF pretty print lru percpu hash",
|
||||||
|
.map_type = BPF_MAP_TYPE_LRU_PERCPU_HASH,
|
||||||
|
.map_name = "pprint_test_lru_percpu_hash",
|
||||||
|
.ordered_map = false,
|
||||||
|
.lossless_map = false,
|
||||||
|
.percpu_map = true,
|
||||||
},
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i)
|
static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i,
|
||||||
|
int num_cpus, int rounded_value_size)
|
||||||
{
|
{
|
||||||
v->ui32 = i;
|
int cpu;
|
||||||
v->si32 = -i;
|
|
||||||
v->unused_bits2a = 3;
|
for (cpu = 0; cpu < num_cpus; cpu++) {
|
||||||
v->bits28 = i;
|
v->ui32 = i + cpu;
|
||||||
v->unused_bits2b = 3;
|
v->si32 = -i;
|
||||||
v->ui64 = i;
|
v->unused_bits2a = 3;
|
||||||
v->aenum = i & 0x03;
|
v->bits28 = i;
|
||||||
|
v->unused_bits2b = 3;
|
||||||
|
v->ui64 = i;
|
||||||
|
v->aenum = i & 0x03;
|
||||||
|
v = (void *)v + rounded_value_size;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_line(const char *expected_line, int nexpected_line,
|
||||||
|
int expected_line_len, const char *line)
|
||||||
|
{
|
||||||
|
if (CHECK(nexpected_line == expected_line_len,
|
||||||
|
"expected_line is too long"))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (strcmp(expected_line, line)) {
|
||||||
|
fprintf(stderr, "unexpected pprint output\n");
|
||||||
|
fprintf(stderr, "expected: %s", expected_line);
|
||||||
|
fprintf(stderr, " read: %s", line);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_test_pprint(void)
|
static int do_test_pprint(void)
|
||||||
{
|
{
|
||||||
const struct btf_raw_test *test = &pprint_test_template;
|
const struct btf_raw_test *test = &pprint_test_template;
|
||||||
struct bpf_create_map_attr create_attr = {};
|
struct bpf_create_map_attr create_attr = {};
|
||||||
|
bool ordered_map, lossless_map, percpu_map;
|
||||||
|
int err, ret, num_cpus, rounded_value_size;
|
||||||
|
struct pprint_mapv *mapv = NULL;
|
||||||
unsigned int key, nr_read_elems;
|
unsigned int key, nr_read_elems;
|
||||||
bool ordered_map, lossless_map;
|
|
||||||
int map_fd = -1, btf_fd = -1;
|
int map_fd = -1, btf_fd = -1;
|
||||||
struct pprint_mapv mapv = {};
|
|
||||||
unsigned int raw_btf_size;
|
unsigned int raw_btf_size;
|
||||||
char expected_line[255];
|
char expected_line[255];
|
||||||
FILE *pin_file = NULL;
|
FILE *pin_file = NULL;
|
||||||
@ -2212,7 +2269,6 @@ static int do_test_pprint(void)
|
|||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
uint8_t *raw_btf;
|
uint8_t *raw_btf;
|
||||||
ssize_t nread;
|
ssize_t nread;
|
||||||
int err, ret;
|
|
||||||
|
|
||||||
fprintf(stderr, "%s......", test->descr);
|
fprintf(stderr, "%s......", test->descr);
|
||||||
raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types,
|
raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types,
|
||||||
@ -2261,9 +2317,18 @@ static int do_test_pprint(void)
|
|||||||
if (CHECK(err, "bpf_obj_pin(%s): errno:%d.", pin_path, errno))
|
if (CHECK(err, "bpf_obj_pin(%s): errno:%d.", pin_path, errno))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
percpu_map = test->percpu_map;
|
||||||
|
num_cpus = percpu_map ? bpf_num_possible_cpus() : 1;
|
||||||
|
rounded_value_size = round_up(sizeof(struct pprint_mapv), 8);
|
||||||
|
mapv = calloc(num_cpus, rounded_value_size);
|
||||||
|
if (CHECK(!mapv, "mapv allocation failure")) {
|
||||||
|
err = -1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
for (key = 0; key < test->max_entries; key++) {
|
for (key = 0; key < test->max_entries; key++) {
|
||||||
set_pprint_mapv(&mapv, key);
|
set_pprint_mapv(mapv, key, num_cpus, rounded_value_size);
|
||||||
bpf_map_update_elem(map_fd, &key, &mapv, 0);
|
bpf_map_update_elem(map_fd, &key, mapv, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pin_file = fopen(pin_path, "r");
|
pin_file = fopen(pin_path, "r");
|
||||||
@ -2286,33 +2351,74 @@ static int do_test_pprint(void)
|
|||||||
ordered_map = test->ordered_map;
|
ordered_map = test->ordered_map;
|
||||||
lossless_map = test->lossless_map;
|
lossless_map = test->lossless_map;
|
||||||
do {
|
do {
|
||||||
|
struct pprint_mapv *cmapv;
|
||||||
ssize_t nexpected_line;
|
ssize_t nexpected_line;
|
||||||
unsigned int next_key;
|
unsigned int next_key;
|
||||||
|
int cpu;
|
||||||
|
|
||||||
next_key = ordered_map ? nr_read_elems : atoi(line);
|
next_key = ordered_map ? nr_read_elems : atoi(line);
|
||||||
set_pprint_mapv(&mapv, next_key);
|
set_pprint_mapv(mapv, next_key, num_cpus, rounded_value_size);
|
||||||
nexpected_line = snprintf(expected_line, sizeof(expected_line),
|
cmapv = mapv;
|
||||||
"%u: {%u,0,%d,0x%x,0x%x,0x%x,{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n",
|
|
||||||
next_key,
|
|
||||||
mapv.ui32, mapv.si32,
|
|
||||||
mapv.unused_bits2a, mapv.bits28, mapv.unused_bits2b,
|
|
||||||
mapv.ui64,
|
|
||||||
mapv.ui8a[0], mapv.ui8a[1], mapv.ui8a[2], mapv.ui8a[3],
|
|
||||||
mapv.ui8a[4], mapv.ui8a[5], mapv.ui8a[6], mapv.ui8a[7],
|
|
||||||
pprint_enum_str[mapv.aenum]);
|
|
||||||
|
|
||||||
if (CHECK(nexpected_line == sizeof(expected_line),
|
for (cpu = 0; cpu < num_cpus; cpu++) {
|
||||||
"expected_line is too long")) {
|
if (percpu_map) {
|
||||||
err = -1;
|
/* for percpu map, the format looks like:
|
||||||
goto done;
|
* <key>: {
|
||||||
|
* cpu0: <value_on_cpu0>
|
||||||
|
* cpu1: <value_on_cpu1>
|
||||||
|
* ...
|
||||||
|
* cpun: <value_on_cpun>
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* let us verify the line containing the key here.
|
||||||
|
*/
|
||||||
|
if (cpu == 0) {
|
||||||
|
nexpected_line = snprintf(expected_line,
|
||||||
|
sizeof(expected_line),
|
||||||
|
"%u: {\n",
|
||||||
|
next_key);
|
||||||
|
|
||||||
|
err = check_line(expected_line, nexpected_line,
|
||||||
|
sizeof(expected_line), line);
|
||||||
|
if (err == -1)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read value@cpu */
|
||||||
|
nread = getline(&line, &line_len, pin_file);
|
||||||
|
if (nread < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
nexpected_line = snprintf(expected_line, sizeof(expected_line),
|
||||||
|
"%s%u: {%u,0,%d,0x%x,0x%x,0x%x,"
|
||||||
|
"{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n",
|
||||||
|
percpu_map ? "\tcpu" : "",
|
||||||
|
percpu_map ? cpu : next_key,
|
||||||
|
cmapv->ui32, cmapv->si32,
|
||||||
|
cmapv->unused_bits2a,
|
||||||
|
cmapv->bits28,
|
||||||
|
cmapv->unused_bits2b,
|
||||||
|
cmapv->ui64,
|
||||||
|
cmapv->ui8a[0], cmapv->ui8a[1],
|
||||||
|
cmapv->ui8a[2], cmapv->ui8a[3],
|
||||||
|
cmapv->ui8a[4], cmapv->ui8a[5],
|
||||||
|
cmapv->ui8a[6], cmapv->ui8a[7],
|
||||||
|
pprint_enum_str[cmapv->aenum]);
|
||||||
|
|
||||||
|
err = check_line(expected_line, nexpected_line,
|
||||||
|
sizeof(expected_line), line);
|
||||||
|
if (err == -1)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
cmapv = (void *)cmapv + rounded_value_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(expected_line, line)) {
|
if (percpu_map) {
|
||||||
err = -1;
|
/* skip the last bracket for the percpu map */
|
||||||
fprintf(stderr, "unexpected pprint output\n");
|
nread = getline(&line, &line_len, pin_file);
|
||||||
fprintf(stderr, "expected: %s", expected_line);
|
if (nread < 0)
|
||||||
fprintf(stderr, " read: %s", line);
|
break;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nread = getline(&line, &line_len, pin_file);
|
nread = getline(&line, &line_len, pin_file);
|
||||||
@ -2334,6 +2440,8 @@ static int do_test_pprint(void)
|
|||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
if (mapv)
|
||||||
|
free(mapv);
|
||||||
if (!err)
|
if (!err)
|
||||||
fprintf(stderr, "OK");
|
fprintf(stderr, "OK");
|
||||||
if (*btf_log_buf && (err || args.always_log))
|
if (*btf_log_buf && (err || args.always_log))
|
||||||
@ -2361,6 +2469,7 @@ static int test_pprint(void)
|
|||||||
pprint_test_template.map_name = pprint_tests_meta[i].map_name;
|
pprint_test_template.map_name = pprint_tests_meta[i].map_name;
|
||||||
pprint_test_template.ordered_map = pprint_tests_meta[i].ordered_map;
|
pprint_test_template.ordered_map = pprint_tests_meta[i].ordered_map;
|
||||||
pprint_test_template.lossless_map = pprint_tests_meta[i].lossless_map;
|
pprint_test_template.lossless_map = pprint_tests_meta[i].lossless_map;
|
||||||
|
pprint_test_template.percpu_map = pprint_tests_meta[i].percpu_map;
|
||||||
|
|
||||||
err |= count_result(do_test_pprint());
|
err |= count_result(do_test_pprint());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user