Merge branch 'bpftool_sockmap'
John Fastabend says: ==================== The first patch adds support for attaching programs to maps. This is needed to support sock{map|hash} use from bpftool. Currently, I carry around custom code to do this so doing it using standard bpftool will be great. The second patch adds a compat mode to ignore non-zero entries in the map def. This allows using bpftool with maps that have a extra fields that the user knows can be ignored. This is needed to work correctly with maps being loaded by other tools or directly via syscalls. v3: add bash completion and doc updates for --mapcompat ==================== Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
commit
2f1d774f7d
|
@ -25,6 +25,8 @@ MAP COMMANDS
|
|||
| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}]
|
||||
| **bpftool** **prog pin** *PROG* *FILE*
|
||||
| **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
|
||||
| **bpftool** **prog attach** *PROG* *ATTACH_TYPE* *MAP*
|
||||
| **bpftool** **prog detach** *PROG* *ATTACH_TYPE* *MAP*
|
||||
| **bpftool** **prog help**
|
||||
|
|
||||
| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
|
||||
|
@ -37,6 +39,7 @@ MAP COMMANDS
|
|||
| **cgroup/bind4** | **cgroup/bind6** | **cgroup/post_bind4** | **cgroup/post_bind6** |
|
||||
| **cgroup/connect4** | **cgroup/connect6** | **cgroup/sendmsg4** | **cgroup/sendmsg6**
|
||||
| }
|
||||
| *ATTACH_TYPE* := { **msg_verdict** | **skb_verdict** | **skb_parse** }
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
|
@ -90,6 +93,14 @@ DESCRIPTION
|
|||
|
||||
Note: *FILE* must be located in *bpffs* mount.
|
||||
|
||||
**bpftool prog attach** *PROG* *ATTACH_TYPE* *MAP*
|
||||
Attach bpf program *PROG* (with type specified by *ATTACH_TYPE*)
|
||||
to the map *MAP*.
|
||||
|
||||
**bpftool prog detach** *PROG* *ATTACH_TYPE* *MAP*
|
||||
Detach bpf program *PROG* (with type specified by *ATTACH_TYPE*)
|
||||
from the map *MAP*.
|
||||
|
||||
**bpftool prog help**
|
||||
Print short help message.
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ SYNOPSIS
|
|||
| **pin** | **event_pipe** | **help** }
|
||||
|
||||
*PROG-COMMANDS* := { **show** | **list** | **dump jited** | **dump xlated** | **pin**
|
||||
| **load** | **help** }
|
||||
| **load** | **attach** | **detach** | **help** }
|
||||
|
||||
*CGROUP-COMMANDS* := { **show** | **list** | **attach** | **detach** | **help** }
|
||||
|
||||
|
@ -57,6 +57,10 @@ OPTIONS
|
|||
-p, --pretty
|
||||
Generate human-readable JSON output. Implies **-j**.
|
||||
|
||||
-m, --mapcompat
|
||||
Allow loading maps with unknown map definitions.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
========
|
||||
**bpftool-map**\ (8), **bpftool-prog**\ (8), **bpftool-cgroup**\ (8)
|
||||
|
|
|
@ -184,7 +184,7 @@ _bpftool()
|
|||
|
||||
# Deal with options
|
||||
if [[ ${words[cword]} == -* ]]; then
|
||||
local c='--version --json --pretty --bpffs'
|
||||
local c='--version --json --pretty --bpffs --mapcompat'
|
||||
COMPREPLY=( $( compgen -W "$c" -- "$cur" ) )
|
||||
return 0
|
||||
fi
|
||||
|
@ -292,6 +292,23 @@ _bpftool()
|
|||
fi
|
||||
return 0
|
||||
;;
|
||||
attach|detach)
|
||||
if [[ ${#words[@]} == 7 ]]; then
|
||||
COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) )
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ ${#words[@]} == 6 ]]; then
|
||||
COMPREPLY=( $( compgen -W "msg_verdict skb_verdict skb_parse" -- "$cur" ) )
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ $prev == "$command" ]]; then
|
||||
COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) )
|
||||
return 0
|
||||
fi
|
||||
return 0
|
||||
;;
|
||||
load)
|
||||
local obj
|
||||
|
||||
|
@ -347,7 +364,7 @@ _bpftool()
|
|||
;;
|
||||
*)
|
||||
[[ $prev == $object ]] && \
|
||||
COMPREPLY=( $( compgen -W 'dump help pin load \
|
||||
COMPREPLY=( $( compgen -W 'dump help pin attach detach load \
|
||||
show list' -- "$cur" ) )
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -55,6 +55,7 @@ json_writer_t *json_wtr;
|
|||
bool pretty_output;
|
||||
bool json_output;
|
||||
bool show_pinned;
|
||||
int bpf_flags;
|
||||
struct pinned_obj_table prog_table;
|
||||
struct pinned_obj_table map_table;
|
||||
|
||||
|
@ -341,6 +342,7 @@ int main(int argc, char **argv)
|
|||
{ "pretty", no_argument, NULL, 'p' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ "bpffs", no_argument, NULL, 'f' },
|
||||
{ "mapcompat", no_argument, NULL, 'm' },
|
||||
{ 0 }
|
||||
};
|
||||
int opt, ret;
|
||||
|
@ -355,7 +357,7 @@ int main(int argc, char **argv)
|
|||
hash_init(map_table.table);
|
||||
|
||||
opterr = 0;
|
||||
while ((opt = getopt_long(argc, argv, "Vhpjf",
|
||||
while ((opt = getopt_long(argc, argv, "Vhpjfm",
|
||||
options, NULL)) >= 0) {
|
||||
switch (opt) {
|
||||
case 'V':
|
||||
|
@ -379,6 +381,9 @@ int main(int argc, char **argv)
|
|||
case 'f':
|
||||
show_pinned = true;
|
||||
break;
|
||||
case 'm':
|
||||
bpf_flags = MAPS_RELAX_COMPAT;
|
||||
break;
|
||||
default:
|
||||
p_err("unrecognized option '%s'", argv[optind - 1]);
|
||||
if (json_output)
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
#define HELP_SPEC_PROGRAM \
|
||||
"PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }"
|
||||
#define HELP_SPEC_OPTIONS \
|
||||
"OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }"
|
||||
"OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} | {-m|--mapcompat}"
|
||||
#define HELP_SPEC_MAP \
|
||||
"MAP := { id MAP_ID | pinned FILE }"
|
||||
|
||||
|
@ -89,6 +89,7 @@ extern const char *bin_name;
|
|||
extern json_writer_t *json_wtr;
|
||||
extern bool json_output;
|
||||
extern bool show_pinned;
|
||||
extern int bpf_flags;
|
||||
extern struct pinned_obj_table prog_table;
|
||||
extern struct pinned_obj_table map_table;
|
||||
|
||||
|
|
|
@ -77,6 +77,26 @@ static const char * const prog_type_name[] = {
|
|||
[BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector",
|
||||
};
|
||||
|
||||
static const char * const attach_type_strings[] = {
|
||||
[BPF_SK_SKB_STREAM_PARSER] = "stream_parser",
|
||||
[BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict",
|
||||
[BPF_SK_MSG_VERDICT] = "msg_verdict",
|
||||
[__MAX_BPF_ATTACH_TYPE] = NULL,
|
||||
};
|
||||
|
||||
enum bpf_attach_type parse_attach_type(const char *str)
|
||||
{
|
||||
enum bpf_attach_type type;
|
||||
|
||||
for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
|
||||
if (attach_type_strings[type] &&
|
||||
is_prefix(str, attach_type_strings[type]))
|
||||
return type;
|
||||
}
|
||||
|
||||
return __MAX_BPF_ATTACH_TYPE;
|
||||
}
|
||||
|
||||
static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
|
||||
{
|
||||
struct timespec real_time_ts, boot_time_ts;
|
||||
|
@ -697,6 +717,77 @@ int map_replace_compar(const void *p1, const void *p2)
|
|||
return a->idx - b->idx;
|
||||
}
|
||||
|
||||
static int do_attach(int argc, char **argv)
|
||||
{
|
||||
enum bpf_attach_type attach_type;
|
||||
int err, mapfd, progfd;
|
||||
|
||||
if (!REQ_ARGS(5)) {
|
||||
p_err("too few parameters for map attach");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
progfd = prog_parse_fd(&argc, &argv);
|
||||
if (progfd < 0)
|
||||
return progfd;
|
||||
|
||||
attach_type = parse_attach_type(*argv);
|
||||
if (attach_type == __MAX_BPF_ATTACH_TYPE) {
|
||||
p_err("invalid attach type");
|
||||
return -EINVAL;
|
||||
}
|
||||
NEXT_ARG();
|
||||
|
||||
mapfd = map_parse_fd(&argc, &argv);
|
||||
if (mapfd < 0)
|
||||
return mapfd;
|
||||
|
||||
err = bpf_prog_attach(progfd, mapfd, attach_type, 0);
|
||||
if (err) {
|
||||
p_err("failed prog attach to map");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (json_output)
|
||||
jsonw_null(json_wtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_detach(int argc, char **argv)
|
||||
{
|
||||
enum bpf_attach_type attach_type;
|
||||
int err, mapfd, progfd;
|
||||
|
||||
if (!REQ_ARGS(5)) {
|
||||
p_err("too few parameters for map detach");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
progfd = prog_parse_fd(&argc, &argv);
|
||||
if (progfd < 0)
|
||||
return progfd;
|
||||
|
||||
attach_type = parse_attach_type(*argv);
|
||||
if (attach_type == __MAX_BPF_ATTACH_TYPE) {
|
||||
p_err("invalid attach type");
|
||||
return -EINVAL;
|
||||
}
|
||||
NEXT_ARG();
|
||||
|
||||
mapfd = map_parse_fd(&argc, &argv);
|
||||
if (mapfd < 0)
|
||||
return mapfd;
|
||||
|
||||
err = bpf_prog_detach2(progfd, mapfd, attach_type);
|
||||
if (err) {
|
||||
p_err("failed prog detach from map");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (json_output)
|
||||
jsonw_null(json_wtr);
|
||||
return 0;
|
||||
}
|
||||
static int do_load(int argc, char **argv)
|
||||
{
|
||||
enum bpf_attach_type expected_attach_type;
|
||||
|
@ -817,7 +908,7 @@ static int do_load(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
obj = bpf_object__open_xattr(&attr);
|
||||
obj = __bpf_object__open_xattr(&attr, bpf_flags);
|
||||
if (IS_ERR_OR_NULL(obj)) {
|
||||
p_err("failed to open object file");
|
||||
goto err_free_reuse_maps;
|
||||
|
@ -942,6 +1033,8 @@ static int do_help(int argc, char **argv)
|
|||
" %s %s pin PROG FILE\n"
|
||||
" %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n"
|
||||
" [map { idx IDX | name NAME } MAP]\n"
|
||||
" %s %s attach PROG ATTACH_TYPE MAP\n"
|
||||
" %s %s detach PROG ATTACH_TYPE MAP\n"
|
||||
" %s %s help\n"
|
||||
"\n"
|
||||
" " HELP_SPEC_MAP "\n"
|
||||
|
@ -953,10 +1046,12 @@ static int do_help(int argc, char **argv)
|
|||
" cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n"
|
||||
" cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n"
|
||||
" cgroup/sendmsg4 | cgroup/sendmsg6 }\n"
|
||||
" ATTACH_TYPE := { msg_verdict | skb_verdict | skb_parse }\n"
|
||||
" " HELP_SPEC_OPTIONS "\n"
|
||||
"",
|
||||
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
|
||||
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2]);
|
||||
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
|
||||
bin_name, argv[-2], bin_name, argv[-2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -968,6 +1063,8 @@ static const struct cmd cmds[] = {
|
|||
{ "dump", do_dump },
|
||||
{ "pin", do_pin },
|
||||
{ "load", do_load },
|
||||
{ "attach", do_attach },
|
||||
{ "detach", do_detach },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
|
|
@ -69,6 +69,9 @@ struct bpf_load_program_attr {
|
|||
__u32 prog_ifindex;
|
||||
};
|
||||
|
||||
/* Flags to direct loading requirements */
|
||||
#define MAPS_RELAX_COMPAT 0x01
|
||||
|
||||
/* Recommend log buffer size */
|
||||
#define BPF_LOG_BUF_SIZE (256 * 1024)
|
||||
int bpf_load_program_xattr(const struct bpf_load_program_attr *load_attr,
|
||||
|
|
|
@ -562,8 +562,9 @@ static int compare_bpf_map(const void *_a, const void *_b)
|
|||
}
|
||||
|
||||
static int
|
||||
bpf_object__init_maps(struct bpf_object *obj)
|
||||
bpf_object__init_maps(struct bpf_object *obj, int flags)
|
||||
{
|
||||
bool strict = !(flags & MAPS_RELAX_COMPAT);
|
||||
int i, map_idx, map_def_sz, nr_maps = 0;
|
||||
Elf_Scn *scn;
|
||||
Elf_Data *data;
|
||||
|
@ -685,7 +686,8 @@ bpf_object__init_maps(struct bpf_object *obj)
|
|||
"has unrecognized, non-zero "
|
||||
"options\n",
|
||||
obj->path, map_name);
|
||||
return -EINVAL;
|
||||
if (strict)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
memcpy(&obj->maps[map_idx].def, def,
|
||||
|
@ -716,7 +718,7 @@ static bool section_have_execinstr(struct bpf_object *obj, int idx)
|
|||
return false;
|
||||
}
|
||||
|
||||
static int bpf_object__elf_collect(struct bpf_object *obj)
|
||||
static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
|
||||
{
|
||||
Elf *elf = obj->efile.elf;
|
||||
GElf_Ehdr *ep = &obj->efile.ehdr;
|
||||
|
@ -843,7 +845,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
|
|||
return LIBBPF_ERRNO__FORMAT;
|
||||
}
|
||||
if (obj->efile.maps_shndx >= 0) {
|
||||
err = bpf_object__init_maps(obj);
|
||||
err = bpf_object__init_maps(obj, flags);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
@ -1515,7 +1517,7 @@ static int bpf_object__validate(struct bpf_object *obj, bool needs_kver)
|
|||
|
||||
static struct bpf_object *
|
||||
__bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz,
|
||||
bool needs_kver)
|
||||
bool needs_kver, int flags)
|
||||
{
|
||||
struct bpf_object *obj;
|
||||
int err;
|
||||
|
@ -1531,7 +1533,7 @@ __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz,
|
|||
|
||||
CHECK_ERR(bpf_object__elf_init(obj), err, out);
|
||||
CHECK_ERR(bpf_object__check_endianness(obj), err, out);
|
||||
CHECK_ERR(bpf_object__elf_collect(obj), err, out);
|
||||
CHECK_ERR(bpf_object__elf_collect(obj, flags), err, out);
|
||||
CHECK_ERR(bpf_object__collect_reloc(obj), err, out);
|
||||
CHECK_ERR(bpf_object__validate(obj, needs_kver), err, out);
|
||||
|
||||
|
@ -1542,7 +1544,8 @@ out:
|
|||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr)
|
||||
struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr,
|
||||
int flags)
|
||||
{
|
||||
/* param validation */
|
||||
if (!attr->file)
|
||||
|
@ -1551,7 +1554,13 @@ struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr)
|
|||
pr_debug("loading %s\n", attr->file);
|
||||
|
||||
return __bpf_object__open(attr->file, NULL, 0,
|
||||
bpf_prog_type__needs_kver(attr->prog_type));
|
||||
bpf_prog_type__needs_kver(attr->prog_type),
|
||||
flags);
|
||||
}
|
||||
|
||||
struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr)
|
||||
{
|
||||
return __bpf_object__open_xattr(attr, 0);
|
||||
}
|
||||
|
||||
struct bpf_object *bpf_object__open(const char *path)
|
||||
|
@ -1584,7 +1593,7 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf,
|
|||
pr_debug("loading object '%s' from buffer\n",
|
||||
name);
|
||||
|
||||
return __bpf_object__open(name, obj_buf, obj_buf_sz, true);
|
||||
return __bpf_object__open(name, obj_buf, obj_buf_sz, true, true);
|
||||
}
|
||||
|
||||
int bpf_object__unload(struct bpf_object *obj)
|
||||
|
|
|
@ -61,6 +61,8 @@ struct bpf_object_open_attr {
|
|||
|
||||
struct bpf_object *bpf_object__open(const char *path);
|
||||
struct bpf_object *bpf_object__open_xattr(struct bpf_object_open_attr *attr);
|
||||
struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr,
|
||||
int flags);
|
||||
struct bpf_object *bpf_object__open_buffer(void *obj_buf,
|
||||
size_t obj_buf_sz,
|
||||
const char *name);
|
||||
|
|
Loading…
Reference in New Issue