criu: dumping BPF map data

This commit enables CRIU to dump data(key-value) pairs stored in BPF
maps

Source files modified:

* bpfmap.c

    - Function dump_one_bpfmap_data() reads the map's keys and
    values into two buffers using bpf_map_lookup_batch() and then
    writes them out to a protobuf image along with the number of
    key-value pairs read

    - Function dump_one_bpfmap() now dumps the data as well before
    returning

* include/bpfmap.h - Includes headers and declares functions needed to
dump BPF map data

Signed-off-by: Abhishek Vijeev <abhishek.vijeev@gmail.com>
This commit is contained in:
Abhishek Vijeev 2020-07-24 21:51:13 +05:30 committed by Andrei Vagin
parent 62941bdff4
commit c46225ea80
2 changed files with 105 additions and 1 deletions

View file

@ -1,5 +1,6 @@
#include <stdio.h>
#include <linux/bpf.h>
#include <bpf/bpf.h>
#include "common/compiler.h"
#include "imgset.h"
@ -22,6 +23,103 @@ static void pr_info_bpfmap(char *action, BpfmapFileEntry *bpf)
action, bpf->id, bpf->map_id, bpf->map_type, bpf->map_flags);
}
int dump_one_bpfmap_data(BpfmapFileEntry *bpf, int lfd, const struct fd_parms *p)
{
/*
* Linux kernel patch notes for bpf_map_*_batch():
*
* in_batch/out_batch are opaque values use to communicate between
* user/kernel space, in_batch/out_batch must be of key_size length.
* To start iterating from the beginning in_batch must be null,
* count is the # of key/value elements to retrieve. Note that the 'keys'
* buffer must be a buffer of key_size * count size and the 'values' buffer
* must be value_size * count, where value_size must be aligned to 8 bytes
* by userspace if it's dealing with percpu maps. 'count' will contain the
* number of keys/values successfully retrieved. Note that 'count' is an
* input/output variable and it can contain a lower value after a call.
*
* If there's no more entries to retrieve, ENOENT will be returned. If error
* is ENOENT, count might be > 0 in case it copied some values but there were
* no more entries to retrieve.
*
* Note that if the return code is an error and not -EFAULT,
* count indicates the number of elements successfully processed.
*/
struct cr_img *img;
uint32_t key_size, value_size, max_entries, count;
void *keys = NULL, *values = NULL;
void *in_batch = NULL, *out_batch = NULL;
BpfmapDataEntry bde = BPFMAP_DATA_ENTRY__INIT;
DECLARE_LIBBPF_OPTS(bpf_map_batch_opts, opts,
.elem_flags = 0,
.flags = 0,
);
int ret;
key_size = bpf->key_size;
value_size = bpf->value_size;
max_entries = bpf->max_entries;
count = max_entries;
keys = mmap(NULL, key_size * max_entries, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, 0, 0);
if (keys == MAP_FAILED) {
pr_perror("Can't map memory for BPF map keys");
goto err;
}
values = mmap(NULL, value_size * max_entries, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, 0, 0);
if (values == MAP_FAILED) {
pr_perror("Can't map memory for BPF map values");
goto err;
}
out_batch = mmap(NULL, key_size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, 0, 0);
if (out_batch == MAP_FAILED) {
pr_perror("Can't map memory for BPF map out_batch");
goto err;
}
ret = bpf_map_lookup_batch(lfd, in_batch, out_batch, keys, values, &count, &opts);
if (ret && errno != ENOENT) {
pr_perror("Can't perform a batch lookup on BPF map");
goto err;
}
img = img_from_set(glob_imgset, CR_FD_BPFMAP_DATA);
bde.map_id = bpf->map_id;
bde.keys_bytes = (key_size * count);
bde.values_bytes = (value_size * count);
bde.count = count;
if (pb_write_one(img, &bde, PB_BPFMAP_DATA))
goto err;
if (write(img_raw_fd(img), keys, key_size * count) != (key_size * count)) {
pr_perror("Can't write BPF map's keys");
goto err;
}
if (write(img_raw_fd(img), values, value_size * count) != (value_size * count)) {
pr_perror("Can't write BPF map's values");
goto err;
}
munmap(keys, key_size * max_entries);
munmap(values, value_size * max_entries);
munmap(out_batch, key_size);
return 0;
err:
munmap(keys, key_size * max_entries);
munmap(values, value_size * max_entries);
munmap(out_batch, key_size);
return -1;
}
static int dump_one_bpfmap(int lfd, u32 id, const struct fd_parms *p)
{
BpfmapFileEntry bpf = BPFMAP_FILE_ENTRY__INIT;
@ -44,7 +142,10 @@ static int dump_one_bpfmap(int lfd, u32 id, const struct fd_parms *p)
fe.bpf = &bpf;
pr_info_bpfmap("Dumping ", &bpf);
ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE);
if (pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE))
return -1;
pr_info_bpfmap("Dumping data for ", &bpf);
ret = dump_one_bpfmap_data(&bpf, lfd, p);
break;
default:

View file

@ -3,8 +3,11 @@
#include "files.h"
#include "bpfmap-file.pb-c.h"
#include "bpfmap-data.pb-c.h"
extern int is_bpfmap_link(char *link);
extern int dump_one_bpfmap_data(BpfmapFileEntry *bpf, int lfd, const struct fd_parms *p);
extern const struct fdtype_ops bpfmap_dump_ops;
#endif /* __CR_BPFMAP_H__ */