Commit 5a67da2a authored by John Fastabend's avatar John Fastabend Committed by David S. Miller

bpf: add support for sockmap detach programs

The bpf map sockmap supports adding programs via attach commands. This
patch adds the detach command to keep the API symmetric and allow
users to remove previously added programs. Otherwise the user would
have to delete the map and re-add it to get in this state.

This also adds a series of additional tests to capture detach operation
and also attaching/detaching invalid prog types.

API note: socks will run (or not run) programs depending on the state
of the map at the time the sock is added. We do not for example walk
the map and remove programs from previously attached socks.
Acked-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Signed-off-by: default avatarJohn Fastabend <john.fastabend@gmail.com>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bbbe211c
...@@ -385,16 +385,16 @@ static inline void __dev_map_flush(struct bpf_map *map) ...@@ -385,16 +385,16 @@ static inline void __dev_map_flush(struct bpf_map *map)
#if defined(CONFIG_STREAM_PARSER) && defined(CONFIG_BPF_SYSCALL) #if defined(CONFIG_STREAM_PARSER) && defined(CONFIG_BPF_SYSCALL)
struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key); struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key);
int sock_map_attach_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type); int sock_map_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type);
#else #else
static inline struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key) static inline struct sock *__sock_map_lookup_elem(struct bpf_map *map, u32 key)
{ {
return NULL; return NULL;
} }
static inline int sock_map_attach_prog(struct bpf_map *map, static inline int sock_map_prog(struct bpf_map *map,
struct bpf_prog *prog, struct bpf_prog *prog,
u32 type) u32 type)
{ {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
......
...@@ -792,7 +792,7 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops, ...@@ -792,7 +792,7 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
return err; return err;
} }
int sock_map_attach_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type) int sock_map_prog(struct bpf_map *map, struct bpf_prog *prog, u32 type)
{ {
struct bpf_stab *stab = container_of(map, struct bpf_stab, map); struct bpf_stab *stab = container_of(map, struct bpf_stab, map);
struct bpf_prog *orig; struct bpf_prog *orig;
......
...@@ -1096,10 +1096,10 @@ static int bpf_obj_get(const union bpf_attr *attr) ...@@ -1096,10 +1096,10 @@ static int bpf_obj_get(const union bpf_attr *attr)
#define BPF_PROG_ATTACH_LAST_FIELD attach_flags #define BPF_PROG_ATTACH_LAST_FIELD attach_flags
static int sockmap_get_from_fd(const union bpf_attr *attr) static int sockmap_get_from_fd(const union bpf_attr *attr, bool attach)
{ {
struct bpf_prog *prog = NULL;
int ufd = attr->target_fd; int ufd = attr->target_fd;
struct bpf_prog *prog;
struct bpf_map *map; struct bpf_map *map;
struct fd f; struct fd f;
int err; int err;
...@@ -1109,16 +1109,20 @@ static int sockmap_get_from_fd(const union bpf_attr *attr) ...@@ -1109,16 +1109,20 @@ static int sockmap_get_from_fd(const union bpf_attr *attr)
if (IS_ERR(map)) if (IS_ERR(map))
return PTR_ERR(map); return PTR_ERR(map);
prog = bpf_prog_get_type(attr->attach_bpf_fd, BPF_PROG_TYPE_SK_SKB); if (attach) {
if (IS_ERR(prog)) { prog = bpf_prog_get_type(attr->attach_bpf_fd,
fdput(f); BPF_PROG_TYPE_SK_SKB);
return PTR_ERR(prog); if (IS_ERR(prog)) {
fdput(f);
return PTR_ERR(prog);
}
} }
err = sock_map_attach_prog(map, prog, attr->attach_type); err = sock_map_prog(map, prog, attr->attach_type);
if (err) { if (err) {
fdput(f); fdput(f);
bpf_prog_put(prog); if (prog)
bpf_prog_put(prog);
return err; return err;
} }
...@@ -1155,7 +1159,7 @@ static int bpf_prog_attach(const union bpf_attr *attr) ...@@ -1155,7 +1159,7 @@ static int bpf_prog_attach(const union bpf_attr *attr)
break; break;
case BPF_SK_SKB_STREAM_PARSER: case BPF_SK_SKB_STREAM_PARSER:
case BPF_SK_SKB_STREAM_VERDICT: case BPF_SK_SKB_STREAM_VERDICT:
return sockmap_get_from_fd(attr); return sockmap_get_from_fd(attr, true);
default: default:
return -EINVAL; return -EINVAL;
} }
...@@ -1204,7 +1208,10 @@ static int bpf_prog_detach(const union bpf_attr *attr) ...@@ -1204,7 +1208,10 @@ static int bpf_prog_detach(const union bpf_attr *attr)
ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false); ret = cgroup_bpf_update(cgrp, NULL, attr->attach_type, false);
cgroup_put(cgrp); cgroup_put(cgrp);
break; break;
case BPF_SK_SKB_STREAM_PARSER:
case BPF_SK_SKB_STREAM_VERDICT:
ret = sockmap_get_from_fd(attr, false);
break;
default: default:
return -EINVAL; return -EINVAL;
} }
......
...@@ -558,7 +558,7 @@ static void test_sockmap(int tasks, void *data) ...@@ -558,7 +558,7 @@ static void test_sockmap(int tasks, void *data)
} }
} }
/* Test attaching bad fds */ /* Test attaching/detaching bad fds */
err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_PARSER, 0); err = bpf_prog_attach(-1, fd, BPF_SK_SKB_STREAM_PARSER, 0);
if (!err) { if (!err) {
printf("Failed invalid parser prog attach\n"); printf("Failed invalid parser prog attach\n");
...@@ -571,6 +571,30 @@ static void test_sockmap(int tasks, void *data) ...@@ -571,6 +571,30 @@ static void test_sockmap(int tasks, void *data)
goto out_sockmap; goto out_sockmap;
} }
err = bpf_prog_attach(-1, fd, __MAX_BPF_ATTACH_TYPE, 0);
if (!err) {
printf("Failed unknown prog attach\n");
goto out_sockmap;
}
err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_PARSER);
if (err) {
printf("Failed empty parser prog detach\n");
goto out_sockmap;
}
err = bpf_prog_detach(fd, BPF_SK_SKB_STREAM_VERDICT);
if (err) {
printf("Failed empty verdict prog detach\n");
goto out_sockmap;
}
err = bpf_prog_detach(fd, __MAX_BPF_ATTACH_TYPE);
if (!err) {
printf("Detach invalid prog successful\n");
goto out_sockmap;
}
/* Load SK_SKB program and Attach */ /* Load SK_SKB program and Attach */
err = bpf_prog_load(SOCKMAP_PARSE_PROG, err = bpf_prog_load(SOCKMAP_PARSE_PROG,
BPF_PROG_TYPE_SK_SKB, &obj, &parse_prog); BPF_PROG_TYPE_SK_SKB, &obj, &parse_prog);
...@@ -643,6 +667,13 @@ static void test_sockmap(int tasks, void *data) ...@@ -643,6 +667,13 @@ static void test_sockmap(int tasks, void *data)
goto out_sockmap; goto out_sockmap;
} }
err = bpf_prog_attach(verdict_prog, map_fd_rx,
__MAX_BPF_ATTACH_TYPE, 0);
if (!err) {
printf("Attached unknown bpf prog\n");
goto out_sockmap;
}
/* Test map update elem afterwards fd lives in fd and map_fd */ /* Test map update elem afterwards fd lives in fd and map_fd */
for (i = 0; i < 6; i++) { for (i = 0; i < 6; i++) {
err = bpf_map_update_elem(map_fd_rx, &i, &sfd[i], BPF_ANY); err = bpf_map_update_elem(map_fd_rx, &i, &sfd[i], BPF_ANY);
...@@ -809,6 +840,24 @@ static void test_sockmap(int tasks, void *data) ...@@ -809,6 +840,24 @@ static void test_sockmap(int tasks, void *data)
assert(status == 0); assert(status == 0);
} }
err = bpf_prog_detach(map_fd_rx, __MAX_BPF_ATTACH_TYPE);
if (!err) {
printf("Detached an invalid prog type.\n");
goto out_sockmap;
}
err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_PARSER);
if (err) {
printf("Failed parser prog detach\n");
goto out_sockmap;
}
err = bpf_prog_detach(map_fd_rx, BPF_SK_SKB_STREAM_VERDICT);
if (err) {
printf("Failed parser prog detach\n");
goto out_sockmap;
}
/* Test map close sockets */ /* Test map close sockets */
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
close(sfd[i]); close(sfd[i]);
......
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