From adf2da9becde422bdaf0d223c27cd50193aa7d23 Mon Sep 17 00:00:00 2001 From: Abhishek Vijeev Date: Fri, 24 Jul 2020 17:18:32 +0530 Subject: [PATCH] criu: parse information about BPF maps from procfs This commit enables CRIU to: (a) identify an anonymous inode as being a BPF map (b) parse information about BPF maps from procfs Source files modified: * files.c - Checks anonymous inodes to see whether they are BPF maps. If so, sets struct fdtype_ops *ops to a structure that knows how to dump BPF maps * proc_parse.c - Function parse_fdinfo_pid_s() now checks whether the current file being processed is a BPF map. If so, it calls a newly defined function parse_bpfmap() which knows how to parse information about BPF maps from procfs Signed-off-by: Abhishek Vijeev --- criu/files.c | 5 ++++ criu/proc_parse.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/criu/files.c b/criu/files.c index 2cfc9040e..45105f673 100644 --- a/criu/files.c +++ b/criu/files.c @@ -48,6 +48,7 @@ #include "string.h" #include "kerndat.h" #include "fdstore.h" +#include "bpfmap.h" #include "protobuf.h" #include "util.h" @@ -539,6 +540,10 @@ static int dump_one_file(struct pid *pid, int fd, int lfd, struct fd_opts *opts, ops = &signalfd_dump_ops; else if (is_timerfd_link(link)) ops = &timerfd_dump_ops; +#ifdef CONFIG_HAS_LIBBPF + else if (is_bpfmap_link(link)) + ops = &bpfmap_dump_ops; +#endif else return dump_unsupp_fd(&p, lfd, "anon", link, e); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 77f1b216c..7473bcf67 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1682,6 +1682,57 @@ nodata: goto parse_err; } +typedef struct bpfmap_fmt { + char *fmt; + void *value; +} bpfmap_fmt; + +static int parse_bpfmap(struct bfd *f, char *str, BpfmapFileEntry *bpf) +{ + /* + * Format is: + * + * uint32_t map_type + * uint32_t key_size + * uint32_t value_size + * uint32_t max_entries + * uint32_t map_flags + * uint64_t memlock + * uint32_t map_id + * boolean frozen + */ + + bpfmap_fmt map[] = { + {"map_type: %u", &bpf->map_type }, + {"key_size: %u", &bpf->key_size }, + {"value_size: %u", &bpf->value_size }, + {"max_entries: %u", &bpf->max_entries }, + {"map_flags: %"PRIx32"", &bpf->map_flags }, + {"memlock: %"PRIu64"", &bpf->memlock }, + {"map_id: %u", &bpf->map_id }, + {"frozen: %d", &bpf->frozen }, + }; + + size_t n = sizeof(map) / sizeof(bpfmap_fmt); + int i; + + for (i = 0; i < n; i++) { + if (sscanf(str, map[i].fmt, map[i].value) != 1) + return -1; + + if (i == n - 1) + break; + + str = breadline(f); + if (IS_ERR_OR_NULL(str)) { + pr_err("No data left in proc file while parsing bpfmap\n"); + return -1; + } + } + + return 0; +} + #define fdinfo_field(str, field) !strncmp(str, field":", sizeof(field)) static int parse_file_lock_buf(char *buf, struct file_lock *fl, @@ -2014,6 +2065,18 @@ static int parse_fdinfo_pid_s(int pid, int fd, int type, void *arg) entry_met = true; continue; } + if (fdinfo_field(str, "map_type")) { + BpfmapFileEntry *bpf = arg; + if (type != FD_TYPES__BPFMAP) + goto parse_err; + + ret = parse_bpfmap(&f, str, bpf); + if (ret) + goto parse_err; + + entry_met = true; + continue; + } } exit_code = 0;