/* Ensure map_info_alloc() has at least what the bpftool needs */
map_info_alloc_len = map_info_type->size; if (map_info_alloc_len < sizeof(struct bpf_map_info))
map_info_alloc_len = sizeof(struct bpf_map_info);
return map_info_type_id;
}
/* If the subcmd needs to print out the bpf_map_info, * it should always call map_info_alloc to allocate * a bpf_map_info object instead of allocating it * on the stack. * * map_info_alloc() will take the running kernel's btf * into account. i.e. it will consider the * sizeof(struct bpf_map_info) of the running kernel. * * It will enable the "struct_ops" cmd to print the latest * "struct bpf_map_info". * * [ Recall that "struct_ops" requires the kernel's btf to * be available ]
*/ staticstruct bpf_map_info *map_info_alloc(__u32 *alloc_len)
{ struct bpf_map_info *info;
if (get_map_info_type_id() < 0) return NULL;
info = calloc(1, map_info_alloc_len); if (!info)
p_err("mem alloc failed"); else
*alloc_len = map_info_alloc_len;
return info;
}
/* It iterates all struct_ops maps of the system. * It returns the fd in "*res_fd" and map_info in "*info". * In the very first iteration, info->id should be 0. * An optional map "*name" filter can be specified. * The filter can be made more flexible in the future. * e.g. filter by kernel-struct-ops-name, regex-name, glob-name, ...etc. * * Return value: * 1: A struct_ops map found. It is returned in "*res_fd" and "*info". * The caller can continue to call get_next in the future. * 0: No struct_ops map is returned. * All struct_ops map has been found. * -1: Error and the caller should abort the iteration.
*/ staticint get_next_struct_ops_map(constchar *name, int *res_fd, struct bpf_map_info *info, __u32 info_len)
{
__u32 id = info->id; int err, fd;
while (true) {
err = bpf_map_get_next_id(id, &id); if (err) { if (errno == ENOENT) return 0;
p_err("can't get next map: %s", strerror(errno)); return -1;
}
fd = bpf_map_get_fd_by_id(id); if (fd < 0) { if (errno == ENOENT) continue;
p_err("can't get map by id (%u): %s",
id, strerror(errno)); return -1;
}
err = bpf_map_get_info_by_fd(fd, info, &info_len); if (err) {
p_err("can't get map info: %s", strerror(errno));
close(fd); return -1;
}
staticint cmd_retval(conststruct res *res, bool must_have_one_map)
{ if (res->nr_errs || (!res->nr_maps && must_have_one_map)) return -1;
return 0;
}
/* "data" is the work_func private storage */ typedefint (*work_func)(int fd, conststruct bpf_map_info *info, void *data, struct json_writer *wtr);
/* Find all struct_ops map in the system. * Filter out by "name" (if specified). * Then call "func(fd, info, data, wtr)" on each struct_ops map found.
*/ staticstruct res do_search(constchar *name, work_func func, void *data, struct json_writer *wtr)
{ struct bpf_map_info *info; struct res res = {};
__u32 info_len; int fd, err;
info = map_info_alloc(&info_len); if (!info) {
res.nr_errs++; return res;
}
if (wtr)
jsonw_start_array(wtr); while ((err = get_next_struct_ops_map(name, &fd, info, info_len)) == 1) {
res.nr_maps++;
err = func(fd, info, data, wtr); if (err)
res.nr_errs++;
close(fd);
} if (wtr)
jsonw_end_array(wtr);
if (err)
res.nr_errs++;
if (!wtr && name && !res.nr_errs && !res.nr_maps) /* It is not printing empty []. * Thus, needs to specifically say nothing found * for "name" here.
*/
p_err("no struct_ops found for %s", name); elseif (!wtr && json_output && !res.nr_errs) /* The "func()" above is not writing any json (i.e. !wtr * test here). * * However, "-j" is enabled and there is no errs here, * so call json_null() as the current convention of * other cmds.
*/
jsonw_null(json_wtr);
free(info); return res;
}
staticstruct res do_one_id(constchar *id_str, work_func func, void *data, struct json_writer *wtr)
{ struct bpf_map_info *info; struct res res = {}; unsignedlong id;
__u32 info_len; char *endptr; int fd;
id = strtoul(id_str, &endptr, 0); if (*endptr || !id || id > UINT32_MAX) {
p_err("invalid id %s", id_str);
res.nr_errs++; return res;
}
fd = bpf_map_get_fd_by_id(id); if (fd < 0) {
p_err("can't get map by id (%lu): %s", id, strerror(errno));
res.nr_errs++; return res;
}
info = map_info_alloc(&info_len); if (!info) {
res.nr_errs++; goto done;
}
if (bpf_map_get_info_by_fd(fd, info, &info_len)) {
p_err("can't get map info: %s", strerror(errno));
res.nr_errs++; goto done;
}
if (info->type != BPF_MAP_TYPE_STRUCT_OPS) {
p_err("%s id %u is not a struct_ops map", info->name, info->id);
res.nr_errs++; goto done;
}
res.nr_maps++;
if (wtr)
jsonw_start_array(wtr);
if (func(fd, info, data, wtr))
res.nr_errs++; elseif (!wtr && json_output) /* The "func()" above is not writing any json (i.e. !wtr * test here). * * However, "-j" is enabled and there is no errs here, * so call json_null() as the current convention of * other cmds.
*/
jsonw_null(json_wtr);
if (wtr)
jsonw_end_array(wtr);
done:
free(info);
close(fd);
return res;
}
staticstruct res do_work_on_struct_ops(constchar *search_type, constchar *search_term,
work_func func, void *data, struct json_writer *wtr)
{ if (search_type) { if (is_prefix(search_type, "id")) return do_one_id(search_term, func, data, wtr); elseif (!is_prefix(search_type, "name"))
usage();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.