Commit 91d88eeb authored by Daniel Borkmann's avatar Daniel Borkmann Committed by Stephen Hemminger

{f,m}_bpf: allow updates on program arrays

Since we have all infrastructure in place now, allow atomic live updates
on program arrays. This can be very useful e.g. in case programs that are
being tail-called need to be replaced, f.e. when classifier functionality
needs to be changed, new protocols added/removed during runtime, etc.

Thus, provide a way for in-place code updates, minimal example: Given is
an object file cls.o that contains the entry point in section 'classifier',
has a globally pinned program array 'jmp' with 2 slots and id of 0, and
two tail called programs under section '0/0' (prog array key 0) and '0/1'
(prog array key 1), the section encoding for the loader is <id/key>.
Adding the filter loads everything into cls_bpf:

  tc filter add dev foo parent ffff: bpf da obj cls.o

Now, the program under section '0/1' needs to be replaced with an updated
version that resides in the same section (also full path to tc's subfolder
of the mount point can be passed, e.g. /sys/fs/bpf/tc/globals/jmp):

  tc exec bpf graft m:globals/jmp obj cls.o sec 0/1

In case the program resides under a different section 'foo', it can also
be injected into the program array like:

  tc exec bpf graft m:globals/jmp key 1 obj cls.o sec foo

If the new tail called classifier program is already available as a pinned
object somewhere (here: /sys/fs/bpf/tc/progs/parser), it can be injected
into the prog array like:

  tc exec bpf graft m:globals/jmp key 1 fd m:progs/parser

In the kernel, the program on key 1 is being atomically replaced and the
old one's refcount dropped.
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent f6793eec
......@@ -26,10 +26,19 @@ static char *argv_default[] = { BPF_DEFAULT_CMD, NULL };
static void explain(void)
{
fprintf(stderr, "Usage: ... bpf [ import UDS_FILE ] [ run CMD ] [ debug ]\n\n");
fprintf(stderr, "Usage: ... bpf [ import UDS_FILE ] [ run CMD ]\n");
fprintf(stderr, " ... bpf [ debug ]\n");
fprintf(stderr, " ... bpf [ graft MAP_FILE ] [ key KEY ]\n");
fprintf(stderr, " `... [ object-file OBJ_FILE ] [ type TYPE ] [ section NAME ] [ verbose ]\n");
fprintf(stderr, " `... [ object-pinned PROG_FILE ]\n");
fprintf(stderr, "\n");
fprintf(stderr, "Where UDS_FILE provides the name of a unix domain socket file\n");
fprintf(stderr, "to import eBPF maps and the optional CMD denotes the command\n");
fprintf(stderr, "to be executed (default: \'%s\').\n", BPF_DEFAULT_CMD);
fprintf(stderr, "Where MAP_FILE points to a pinned map, OBJ_FILE to an object file\n");
fprintf(stderr, "and PROG_FILE to a pinned program. TYPE can be {cls, act}, where\n");
fprintf(stderr, "\'cls\' is default. KEY is optional and can be inferred from the\n");
fprintf(stderr, "section name, otherwise it needs to be provided.\n");
}
static int bpf_num_env_entries(void)
......@@ -67,6 +76,25 @@ static int parse_bpf(struct exec_util *eu, int argc, char **argv)
fprintf(stderr,
"No trace pipe, tracefs not mounted?\n");
return -1;
} else if (matches(*argv, "graft") == 0) {
const char *bpf_map_path;
bool has_key = false;
uint32_t key;
NEXT_ARG();
bpf_map_path = *argv;
NEXT_ARG();
if (matches(*argv, "key") == 0) {
NEXT_ARG();
if (get_unsigned(&key, *argv, 0)) {
fprintf(stderr, "Illegal \"key\"\n");
return -1;
}
has_key = true;
NEXT_ARG();
}
return bpf_graft_map(bpf_map_path, has_key ?
&key : NULL, argc, argv);
} else {
explain();
return -1;
......
This diff is collapsed.
......@@ -55,6 +55,7 @@ const char *bpf_default_section(const enum bpf_prog_type type);
int bpf_parse_common(int *ptr_argc, char ***ptr_argv, const int *nla_tbl,
enum bpf_prog_type type, const char **ptr_object,
const char **ptr_uds_name, struct nlmsghdr *n);
int bpf_graft_map(const char *map_path, uint32_t *key, int argc, char **argv);
void bpf_print_ops(FILE *f, struct rtattr *bpf_ops, __u16 len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment