mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-23 10:09:57 +00:00
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:
parent
62941bdff4
commit
c46225ea80
2 changed files with 105 additions and 1 deletions
103
criu/bpfmap.c
103
criu/bpfmap.c
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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__ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue