forked from Minki/linux
Merge branch 'bpf-bpftool-cgroup-ops'
Roman Gushchin says: ==================== This patchset adds basic cgroup bpf operations to bpftool. Right now there is no convenient way to perform these operations. The /samples/bpf/load_sock_ops.c implements attach/detacg operations, but only for BPF_CGROUP_SOCK_OPS programs. Bps (part of bcc) implements bpf introspection, but lacks any cgroup-related specific. I find having a tool to perform these basic operations in the kernel tree very useful, as it can be used in the corresponding bpf documentation without creating additional dependencies. And bpftool seems to be a right tool to extend with such functionality. v4: - ATTACH_FLAGS and ATTACH_TYPE are listed and described in docs and usage - ATTACH_FLAG names converted to "multi" and "override" - do_attach() recognizes ATTACH_FLAG abbreviations, e.g "mul" - Local variables sorted ("reverse Christmas tree") - unknown attach flags value will be never truncated v3: - SRC replaced with OBJ in prog load docs - Output unknown attach type in hex - License header in SPDX format - Minor style fixes (e.g. variable reordering) v2: - Added prog load operations - All cgroup operations are looking like bpftool cgroup <command> - All cgroup-related stuff is moved to a separate file - Added support for attach flags - Added support for attaching/detaching programs by id, pinned name, etc - Changed cgroup detach arguments order - Added empty json output for succesful programs - Style fixed: includes order, strncmp and macroses, error handling - Added man pages v1: https://lwn.net/Articles/740366/ ==================== Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
This commit is contained in:
commit
7310c23328
118
tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
Normal file
118
tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
Normal file
@ -0,0 +1,118 @@
|
||||
================
|
||||
bpftool-cgroup
|
||||
================
|
||||
-------------------------------------------------------------------------------
|
||||
tool for inspection and simple manipulation of eBPF progs
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
:Manual section: 8
|
||||
|
||||
SYNOPSIS
|
||||
========
|
||||
|
||||
**bpftool** [*OPTIONS*] **cgroup** *COMMAND*
|
||||
|
||||
*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } }
|
||||
|
||||
*COMMANDS* :=
|
||||
{ **list** | **attach** | **detach** | **help** }
|
||||
|
||||
MAP COMMANDS
|
||||
=============
|
||||
|
||||
| **bpftool** **cgroup list** *CGROUP*
|
||||
| **bpftool** **cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*]
|
||||
| **bpftool** **cgroup detach** *CGROUP* *ATTACH_TYPE* *PROG*
|
||||
| **bpftool** **cgroup help**
|
||||
|
|
||||
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
|
||||
| *ATTACH_TYPE* := { *ingress* | *egress* | *sock_create* | *sock_ops* | *device* }
|
||||
| *ATTACH_FLAGS* := { *multi* | *override* }
|
||||
|
||||
DESCRIPTION
|
||||
===========
|
||||
**bpftool cgroup list** *CGROUP*
|
||||
List all programs attached to the cgroup *CGROUP*.
|
||||
|
||||
Output will start with program ID followed by attach type,
|
||||
attach flags and program name.
|
||||
|
||||
**bpftool cgroup attach** *CGROUP* *ATTACH_TYPE* *PROG* [*ATTACH_FLAGS*]
|
||||
Attach program *PROG* to the cgroup *CGROUP* with attach type
|
||||
*ATTACH_TYPE* and optional *ATTACH_FLAGS*.
|
||||
|
||||
*ATTACH_FLAGS* can be one of: **override** if a sub-cgroup installs
|
||||
some bpf program, the program in this cgroup yields to sub-cgroup
|
||||
program; **multi** if a sub-cgroup installs some bpf program,
|
||||
that cgroup program gets run in addition to the program in this
|
||||
cgroup.
|
||||
|
||||
Only one program is allowed to be attached to a cgroup with
|
||||
no attach flags or the **override** flag. Attaching another
|
||||
program will release old program and attach the new one.
|
||||
|
||||
Multiple programs are allowed to be attached to a cgroup with
|
||||
**multi**. They are executed in FIFO order (those that were
|
||||
attached first, run first).
|
||||
|
||||
Non-default *ATTACH_FLAGS* are supported by kernel version 4.14
|
||||
and later.
|
||||
|
||||
*ATTACH_TYPE* can be on of:
|
||||
**ingress** ingress path of the inet socket (since 4.10);
|
||||
**egress** egress path of the inet socket (since 4.10);
|
||||
**sock_create** opening of an inet socket (since 4.10);
|
||||
**sock_ops** various socket operations (since 4.12);
|
||||
**device** device access (since 4.15).
|
||||
|
||||
**bpftool cgroup detach** *CGROUP* *ATTACH_TYPE* *PROG*
|
||||
Detach *PROG* from the cgroup *CGROUP* and attach type
|
||||
*ATTACH_TYPE*.
|
||||
|
||||
**bpftool prog help**
|
||||
Print short help message.
|
||||
|
||||
OPTIONS
|
||||
=======
|
||||
-h, --help
|
||||
Print short generic help message (similar to **bpftool help**).
|
||||
|
||||
-v, --version
|
||||
Print version number (similar to **bpftool version**).
|
||||
|
||||
-j, --json
|
||||
Generate JSON output. For commands that cannot produce JSON, this
|
||||
option has no effect.
|
||||
|
||||
-p, --pretty
|
||||
Generate human-readable JSON output. Implies **-j**.
|
||||
|
||||
-f, --bpffs
|
||||
Show file names of pinned programs.
|
||||
|
||||
EXAMPLES
|
||||
========
|
||||
|
|
||||
| **# mount -t bpf none /sys/fs/bpf/**
|
||||
| **# mkdir /sys/fs/cgroup/test.slice**
|
||||
| **# bpftool prog load ./device_cgroup.o /sys/fs/bpf/prog**
|
||||
| **# bpftool cgroup attach /sys/fs/cgroup/test.slice/ device id 1 allow_multi**
|
||||
|
||||
**# bpftool cgroup list /sys/fs/cgroup/test.slice/**
|
||||
|
||||
::
|
||||
|
||||
ID AttachType AttachFlags Name
|
||||
1 device allow_multi bpf_prog1
|
||||
|
||||
|
|
||||
| **# bpftool cgroup detach /sys/fs/cgroup/test.slice/ device id 1**
|
||||
| **# bpftool cgroup list /sys/fs/cgroup/test.slice/**
|
||||
|
||||
::
|
||||
|
||||
ID AttachType AttachFlags Name
|
||||
|
||||
SEE ALSO
|
||||
========
|
||||
**bpftool**\ (8), **bpftool-prog**\ (8), **bpftool-map**\ (8)
|
@ -128,4 +128,4 @@ EXAMPLES
|
||||
|
||||
SEE ALSO
|
||||
========
|
||||
**bpftool**\ (8), **bpftool-prog**\ (8)
|
||||
**bpftool**\ (8), **bpftool-prog**\ (8), **bpftool-cgroup**\ (8)
|
||||
|
@ -15,7 +15,7 @@ SYNOPSIS
|
||||
*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] | { **-f** | **--bpffs** } }
|
||||
|
||||
*COMMANDS* :=
|
||||
{ **show** | **dump xlated** | **dump jited** | **pin** | **help** }
|
||||
{ **show** | **dump xlated** | **dump jited** | **pin** | **load** | **help** }
|
||||
|
||||
MAP COMMANDS
|
||||
=============
|
||||
@ -24,6 +24,7 @@ MAP COMMANDS
|
||||
| **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes**}]
|
||||
| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}]
|
||||
| **bpftool** **prog pin** *PROG* *FILE*
|
||||
| **bpftool** **prog load** *OBJ* *FILE*
|
||||
| **bpftool** **prog help**
|
||||
|
|
||||
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
|
||||
@ -57,6 +58,11 @@ DESCRIPTION
|
||||
|
||||
Note: *FILE* must be located in *bpffs* mount.
|
||||
|
||||
**bpftool prog load** *OBJ* *FILE*
|
||||
Load bpf program from binary *OBJ* and pin as *FILE*.
|
||||
|
||||
Note: *FILE* must be located in *bpffs* mount.
|
||||
|
||||
**bpftool prog help**
|
||||
Print short help message.
|
||||
|
||||
@ -126,8 +132,10 @@ EXAMPLES
|
||||
|
|
||||
| **# mount -t bpf none /sys/fs/bpf/**
|
||||
| **# bpftool prog pin id 10 /sys/fs/bpf/prog**
|
||||
| **# bpftool prog load ./my_prog.o /sys/fs/bpf/prog2**
|
||||
| **# ls -l /sys/fs/bpf/**
|
||||
| -rw------- 1 root root 0 Jul 22 01:43 prog
|
||||
| -rw------- 1 root root 0 Jul 22 01:44 prog2
|
||||
|
||||
**# bpftool prog dum jited pinned /sys/fs/bpf/prog opcodes**
|
||||
|
||||
@ -147,4 +155,4 @@ EXAMPLES
|
||||
|
||||
SEE ALSO
|
||||
========
|
||||
**bpftool**\ (8), **bpftool-map**\ (8)
|
||||
**bpftool**\ (8), **bpftool-map**\ (8), **bpftool-cgroup**\ (8)
|
||||
|
@ -16,7 +16,7 @@ SYNOPSIS
|
||||
|
||||
**bpftool** **version**
|
||||
|
||||
*OBJECT* := { **map** | **program** }
|
||||
*OBJECT* := { **map** | **program** | **cgroup** }
|
||||
|
||||
*OPTIONS* := { { **-V** | **--version** } | { **-h** | **--help** }
|
||||
| { **-j** | **--json** } [{ **-p** | **--pretty** }] }
|
||||
@ -26,7 +26,9 @@ SYNOPSIS
|
||||
| **pin** | **help** }
|
||||
|
||||
*PROG-COMMANDS* := { **show** | **dump jited** | **dump xlated** | **pin**
|
||||
| **help** }
|
||||
| **load** | **help** }
|
||||
|
||||
*CGROUP-COMMANDS* := { **list** | **attach** | **detach** | **help** }
|
||||
|
||||
DESCRIPTION
|
||||
===========
|
||||
@ -53,4 +55,4 @@ OPTIONS
|
||||
|
||||
SEE ALSO
|
||||
========
|
||||
**bpftool-map**\ (8), **bpftool-prog**\ (8)
|
||||
**bpftool-map**\ (8), **bpftool-prog**\ (8), **bpftool-cgroup**\ (8)
|
||||
|
307
tools/bpf/bpftool/cgroup.c
Normal file
307
tools/bpf/bpftool/cgroup.c
Normal file
@ -0,0 +1,307 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Copyright (C) 2017 Facebook
|
||||
// Author: Roman Gushchin <guro@fb.com>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <bpf.h>
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#define HELP_SPEC_ATTACH_FLAGS \
|
||||
"ATTACH_FLAGS := { multi | override }"
|
||||
|
||||
#define HELP_SPEC_ATTACH_TYPES \
|
||||
"ATTACH_TYPE := { ingress | egress | sock_create | sock_ops | device }"
|
||||
|
||||
static const char * const attach_type_strings[] = {
|
||||
[BPF_CGROUP_INET_INGRESS] = "ingress",
|
||||
[BPF_CGROUP_INET_EGRESS] = "egress",
|
||||
[BPF_CGROUP_INET_SOCK_CREATE] = "sock_create",
|
||||
[BPF_CGROUP_SOCK_OPS] = "sock_ops",
|
||||
[BPF_CGROUP_DEVICE] = "device",
|
||||
[__MAX_BPF_ATTACH_TYPE] = NULL,
|
||||
};
|
||||
|
||||
static 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 int list_bpf_prog(int id, const char *attach_type_str,
|
||||
const char *attach_flags_str)
|
||||
{
|
||||
struct bpf_prog_info info = {};
|
||||
__u32 info_len = sizeof(info);
|
||||
int prog_fd;
|
||||
|
||||
prog_fd = bpf_prog_get_fd_by_id(id);
|
||||
if (prog_fd < 0)
|
||||
return -1;
|
||||
|
||||
if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len)) {
|
||||
close(prog_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (json_output) {
|
||||
jsonw_start_object(json_wtr);
|
||||
jsonw_uint_field(json_wtr, "id", info.id);
|
||||
jsonw_string_field(json_wtr, "attach_type",
|
||||
attach_type_str);
|
||||
jsonw_string_field(json_wtr, "attach_flags",
|
||||
attach_flags_str);
|
||||
jsonw_string_field(json_wtr, "name", info.name);
|
||||
jsonw_end_object(json_wtr);
|
||||
} else {
|
||||
printf("%-8u %-15s %-15s %-15s\n", info.id,
|
||||
attach_type_str,
|
||||
attach_flags_str,
|
||||
info.name);
|
||||
}
|
||||
|
||||
close(prog_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int list_attached_bpf_progs(int cgroup_fd, enum bpf_attach_type type)
|
||||
{
|
||||
__u32 prog_ids[1024] = {0};
|
||||
char *attach_flags_str;
|
||||
__u32 prog_cnt, iter;
|
||||
__u32 attach_flags;
|
||||
char buf[32];
|
||||
int ret;
|
||||
|
||||
prog_cnt = ARRAY_SIZE(prog_ids);
|
||||
ret = bpf_prog_query(cgroup_fd, type, 0, &attach_flags, prog_ids,
|
||||
&prog_cnt);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (prog_cnt == 0)
|
||||
return 0;
|
||||
|
||||
switch (attach_flags) {
|
||||
case BPF_F_ALLOW_MULTI:
|
||||
attach_flags_str = "multi";
|
||||
break;
|
||||
case BPF_F_ALLOW_OVERRIDE:
|
||||
attach_flags_str = "override";
|
||||
break;
|
||||
case 0:
|
||||
attach_flags_str = "";
|
||||
break;
|
||||
default:
|
||||
snprintf(buf, sizeof(buf), "unknown(%x)", attach_flags);
|
||||
attach_flags_str = buf;
|
||||
}
|
||||
|
||||
for (iter = 0; iter < prog_cnt; iter++)
|
||||
list_bpf_prog(prog_ids[iter], attach_type_strings[type],
|
||||
attach_flags_str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_list(int argc, char **argv)
|
||||
{
|
||||
enum bpf_attach_type type;
|
||||
int cgroup_fd;
|
||||
int ret = -1;
|
||||
|
||||
if (argc < 1) {
|
||||
p_err("too few parameters for cgroup list\n");
|
||||
goto exit;
|
||||
} else if (argc > 1) {
|
||||
p_err("too many parameters for cgroup list\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cgroup_fd = open(argv[0], O_RDONLY);
|
||||
if (cgroup_fd < 0) {
|
||||
p_err("can't open cgroup %s\n", argv[1]);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (json_output)
|
||||
jsonw_start_array(json_wtr);
|
||||
else
|
||||
printf("%-8s %-15s %-15s %-15s\n", "ID", "AttachType",
|
||||
"AttachFlags", "Name");
|
||||
|
||||
for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) {
|
||||
/*
|
||||
* Not all attach types may be supported, so it's expected,
|
||||
* that some requests will fail.
|
||||
* If we were able to get the list for at least one
|
||||
* attach type, let's return 0.
|
||||
*/
|
||||
if (list_attached_bpf_progs(cgroup_fd, type) == 0)
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (json_output)
|
||||
jsonw_end_array(json_wtr);
|
||||
|
||||
close(cgroup_fd);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_attach(int argc, char **argv)
|
||||
{
|
||||
enum bpf_attach_type attach_type;
|
||||
int cgroup_fd, prog_fd;
|
||||
int attach_flags = 0;
|
||||
int ret = -1;
|
||||
int i;
|
||||
|
||||
if (argc < 4) {
|
||||
p_err("too few parameters for cgroup attach\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cgroup_fd = open(argv[0], O_RDONLY);
|
||||
if (cgroup_fd < 0) {
|
||||
p_err("can't open cgroup %s\n", argv[1]);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
attach_type = parse_attach_type(argv[1]);
|
||||
if (attach_type == __MAX_BPF_ATTACH_TYPE) {
|
||||
p_err("invalid attach type\n");
|
||||
goto exit_cgroup;
|
||||
}
|
||||
|
||||
argc -= 2;
|
||||
argv = &argv[2];
|
||||
prog_fd = prog_parse_fd(&argc, &argv);
|
||||
if (prog_fd < 0)
|
||||
goto exit_cgroup;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (is_prefix(argv[i], "multi")) {
|
||||
attach_flags |= BPF_F_ALLOW_MULTI;
|
||||
} else if (is_prefix(argv[i], "override")) {
|
||||
attach_flags |= BPF_F_ALLOW_OVERRIDE;
|
||||
} else {
|
||||
p_err("unknown option: %s\n", argv[i]);
|
||||
goto exit_cgroup;
|
||||
}
|
||||
}
|
||||
|
||||
if (bpf_prog_attach(prog_fd, cgroup_fd, attach_type, attach_flags)) {
|
||||
p_err("failed to attach program");
|
||||
goto exit_prog;
|
||||
}
|
||||
|
||||
if (json_output)
|
||||
jsonw_null(json_wtr);
|
||||
|
||||
ret = 0;
|
||||
|
||||
exit_prog:
|
||||
close(prog_fd);
|
||||
exit_cgroup:
|
||||
close(cgroup_fd);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_detach(int argc, char **argv)
|
||||
{
|
||||
enum bpf_attach_type attach_type;
|
||||
int prog_fd, cgroup_fd;
|
||||
int ret = -1;
|
||||
|
||||
if (argc < 4) {
|
||||
p_err("too few parameters for cgroup detach\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
cgroup_fd = open(argv[0], O_RDONLY);
|
||||
if (cgroup_fd < 0) {
|
||||
p_err("can't open cgroup %s\n", argv[1]);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
attach_type = parse_attach_type(argv[1]);
|
||||
if (attach_type == __MAX_BPF_ATTACH_TYPE) {
|
||||
p_err("invalid attach type");
|
||||
goto exit_cgroup;
|
||||
}
|
||||
|
||||
argc -= 2;
|
||||
argv = &argv[2];
|
||||
prog_fd = prog_parse_fd(&argc, &argv);
|
||||
if (prog_fd < 0)
|
||||
goto exit_cgroup;
|
||||
|
||||
if (bpf_prog_detach2(prog_fd, cgroup_fd, attach_type)) {
|
||||
p_err("failed to detach program");
|
||||
goto exit_prog;
|
||||
}
|
||||
|
||||
if (json_output)
|
||||
jsonw_null(json_wtr);
|
||||
|
||||
ret = 0;
|
||||
|
||||
exit_prog:
|
||||
close(prog_fd);
|
||||
exit_cgroup:
|
||||
close(cgroup_fd);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_help(int argc, char **argv)
|
||||
{
|
||||
if (json_output) {
|
||||
jsonw_null(json_wtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"Usage: %s %s list CGROUP\n"
|
||||
" %s %s attach CGROUP ATTACH_TYPE PROG [ATTACH_FLAGS]\n"
|
||||
" %s %s detach CGROUP ATTACH_TYPE PROG\n"
|
||||
" %s %s help\n"
|
||||
"\n"
|
||||
" " HELP_SPEC_ATTACH_TYPES "\n"
|
||||
" " HELP_SPEC_ATTACH_FLAGS "\n"
|
||||
" " HELP_SPEC_PROGRAM "\n"
|
||||
" " HELP_SPEC_OPTIONS "\n"
|
||||
"",
|
||||
bin_name, argv[-2], bin_name, argv[-2],
|
||||
bin_name, argv[-2], bin_name, argv[-2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct cmd cmds[] = {
|
||||
{ "list", do_list },
|
||||
{ "attach", do_attach },
|
||||
{ "detach", do_detach },
|
||||
{ "help", do_help },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
int do_cgroup(int argc, char **argv)
|
||||
{
|
||||
return cmd_select(cmds, argc, argv, do_help);
|
||||
}
|
@ -163,13 +163,49 @@ int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type)
|
||||
return fd;
|
||||
}
|
||||
|
||||
int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
|
||||
int do_pin_fd(int fd, const char *name)
|
||||
{
|
||||
char err_str[ERR_MAX_LEN];
|
||||
unsigned int id;
|
||||
char *endptr;
|
||||
char *file;
|
||||
char *dir;
|
||||
int err = 0;
|
||||
|
||||
err = bpf_obj_pin(fd, name);
|
||||
if (!err)
|
||||
goto out;
|
||||
|
||||
file = malloc(strlen(name) + 1);
|
||||
strcpy(file, name);
|
||||
dir = dirname(file);
|
||||
|
||||
if (errno != EPERM || is_bpffs(dir)) {
|
||||
p_err("can't pin the object (%s): %s", name, strerror(errno));
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Attempt to mount bpffs, then retry pinning. */
|
||||
err = mnt_bpffs(dir, err_str, ERR_MAX_LEN);
|
||||
if (!err) {
|
||||
err = bpf_obj_pin(fd, name);
|
||||
if (err)
|
||||
p_err("can't pin the object (%s): %s", name,
|
||||
strerror(errno));
|
||||
} else {
|
||||
err_str[ERR_MAX_LEN - 1] = '\0';
|
||||
p_err("can't mount BPF file system to pin the object (%s): %s",
|
||||
name, err_str);
|
||||
}
|
||||
|
||||
out_free:
|
||||
free(file);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
|
||||
{
|
||||
unsigned int id;
|
||||
char *endptr;
|
||||
int err;
|
||||
int fd;
|
||||
|
||||
@ -195,35 +231,8 @@ int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32))
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = bpf_obj_pin(fd, *argv);
|
||||
if (!err)
|
||||
goto out_close;
|
||||
err = do_pin_fd(fd, *argv);
|
||||
|
||||
file = malloc(strlen(*argv) + 1);
|
||||
strcpy(file, *argv);
|
||||
dir = dirname(file);
|
||||
|
||||
if (errno != EPERM || is_bpffs(dir)) {
|
||||
p_err("can't pin the object (%s): %s", *argv, strerror(errno));
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* Attempt to mount bpffs, then retry pinning. */
|
||||
err = mnt_bpffs(dir, err_str, ERR_MAX_LEN);
|
||||
if (!err) {
|
||||
err = bpf_obj_pin(fd, *argv);
|
||||
if (err)
|
||||
p_err("can't pin the object (%s): %s", *argv,
|
||||
strerror(errno));
|
||||
} else {
|
||||
err_str[ERR_MAX_LEN - 1] = '\0';
|
||||
p_err("can't mount BPF file system to pin the object (%s): %s",
|
||||
*argv, err_str);
|
||||
}
|
||||
|
||||
out_free:
|
||||
free(file);
|
||||
out_close:
|
||||
close(fd);
|
||||
return err;
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ static int do_help(int argc, char **argv)
|
||||
" %s batch file FILE\n"
|
||||
" %s version\n"
|
||||
"\n"
|
||||
" OBJECT := { prog | map }\n"
|
||||
" OBJECT := { prog | map | cgroup }\n"
|
||||
" " HELP_SPEC_OPTIONS "\n"
|
||||
"",
|
||||
bin_name, bin_name, bin_name);
|
||||
@ -173,6 +173,7 @@ static const struct cmd cmds[] = {
|
||||
{ "batch", do_batch },
|
||||
{ "prog", do_prog },
|
||||
{ "map", do_map },
|
||||
{ "cgroup", do_cgroup },
|
||||
{ "version", do_version },
|
||||
{ 0 }
|
||||
};
|
||||
|
@ -111,9 +111,11 @@ char *get_fdinfo(int fd, const char *key);
|
||||
int open_obj_pinned(char *path);
|
||||
int open_obj_pinned_any(char *path, enum bpf_obj_type exp_type);
|
||||
int do_pin_any(int argc, char **argv, int (*get_fd_by_id)(__u32));
|
||||
int do_pin_fd(int fd, const char *name);
|
||||
|
||||
int do_prog(int argc, char **arg);
|
||||
int do_map(int argc, char **arg);
|
||||
int do_cgroup(int argc, char **arg);
|
||||
|
||||
int prog_parse_fd(int *argc, char ***argv);
|
||||
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <bpf.h>
|
||||
#include <libbpf.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "disasm.h"
|
||||
@ -635,6 +636,30 @@ static int do_pin(int argc, char **argv)
|
||||
return err;
|
||||
}
|
||||
|
||||
static int do_load(int argc, char **argv)
|
||||
{
|
||||
struct bpf_object *obj;
|
||||
int prog_fd;
|
||||
|
||||
if (argc != 2)
|
||||
usage();
|
||||
|
||||
if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) {
|
||||
p_err("failed to load program\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (do_pin_fd(prog_fd, argv[1])) {
|
||||
p_err("failed to pin program\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (json_output)
|
||||
jsonw_null(json_wtr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_help(int argc, char **argv)
|
||||
{
|
||||
if (json_output) {
|
||||
@ -647,13 +672,14 @@ static int do_help(int argc, char **argv)
|
||||
" %s %s dump xlated PROG [{ file FILE | opcodes }]\n"
|
||||
" %s %s dump jited PROG [{ file FILE | opcodes }]\n"
|
||||
" %s %s pin PROG FILE\n"
|
||||
" %s %s load OBJ FILE\n"
|
||||
" %s %s help\n"
|
||||
"\n"
|
||||
" " HELP_SPEC_PROGRAM "\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]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -663,6 +689,7 @@ static const struct cmd cmds[] = {
|
||||
{ "help", do_help },
|
||||
{ "dump", do_dump },
|
||||
{ "pin", do_pin },
|
||||
{ "load", do_load },
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
|
@ -387,6 +387,8 @@ bpf_object__init_prog_names(struct bpf_object *obj)
|
||||
continue;
|
||||
if (sym.st_shndx != prog->idx)
|
||||
continue;
|
||||
if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL)
|
||||
continue;
|
||||
|
||||
name = elf_strptr(obj->efile.elf,
|
||||
obj->efile.strtabidx,
|
||||
@ -1721,6 +1723,45 @@ BPF_PROG_TYPE_FNS(tracepoint, BPF_PROG_TYPE_TRACEPOINT);
|
||||
BPF_PROG_TYPE_FNS(xdp, BPF_PROG_TYPE_XDP);
|
||||
BPF_PROG_TYPE_FNS(perf_event, BPF_PROG_TYPE_PERF_EVENT);
|
||||
|
||||
#define BPF_PROG_SEC(string, type) { string, sizeof(string), type }
|
||||
static const struct {
|
||||
const char *sec;
|
||||
size_t len;
|
||||
enum bpf_prog_type prog_type;
|
||||
} section_names[] = {
|
||||
BPF_PROG_SEC("socket", BPF_PROG_TYPE_SOCKET_FILTER),
|
||||
BPF_PROG_SEC("kprobe/", BPF_PROG_TYPE_KPROBE),
|
||||
BPF_PROG_SEC("kretprobe/", BPF_PROG_TYPE_KPROBE),
|
||||
BPF_PROG_SEC("tracepoint/", BPF_PROG_TYPE_TRACEPOINT),
|
||||
BPF_PROG_SEC("xdp", BPF_PROG_TYPE_XDP),
|
||||
BPF_PROG_SEC("perf_event", BPF_PROG_TYPE_PERF_EVENT),
|
||||
BPF_PROG_SEC("cgroup/skb", BPF_PROG_TYPE_CGROUP_SKB),
|
||||
BPF_PROG_SEC("cgroup/sock", BPF_PROG_TYPE_CGROUP_SOCK),
|
||||
BPF_PROG_SEC("cgroup/dev", BPF_PROG_TYPE_CGROUP_DEVICE),
|
||||
BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS),
|
||||
BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB),
|
||||
};
|
||||
#undef BPF_PROG_SEC
|
||||
|
||||
static enum bpf_prog_type bpf_program__guess_type(struct bpf_program *prog)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!prog->section_name)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(section_names); i++)
|
||||
if (strncmp(prog->section_name, section_names[i].sec,
|
||||
section_names[i].len) == 0)
|
||||
return section_names[i].prog_type;
|
||||
|
||||
err:
|
||||
pr_warning("failed to guess program type based on section name %s\n",
|
||||
prog->section_name);
|
||||
|
||||
return BPF_PROG_TYPE_UNSPEC;
|
||||
}
|
||||
|
||||
int bpf_map__fd(struct bpf_map *map)
|
||||
{
|
||||
return map ? map->fd : -EINVAL;
|
||||
@ -1832,6 +1873,18 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* If type is not specified, try to guess it based on
|
||||
* section name.
|
||||
*/
|
||||
if (type == BPF_PROG_TYPE_UNSPEC) {
|
||||
type = bpf_program__guess_type(prog);
|
||||
if (type == BPF_PROG_TYPE_UNSPEC) {
|
||||
bpf_object__close(obj);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
bpf_program__set_type(prog, type);
|
||||
err = bpf_object__load(obj);
|
||||
if (err) {
|
||||
|
Loading…
Reference in New Issue
Block a user