bpf pull-request 2023-08-09
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQRdM/uy1Ege0+EN1fNar9k/UBDW4wUCZNRuIQAKCRBar9k/UBDW 4++9AP9ymOcPOKTKdQwZ6cnq3vkmvN37H6teufTyM8vsCha9NAD+OQE+vg1304RM aETtG6d5Nb+byIHZGJrdUyT7g9jRzgw= =qr/C -----END PGP SIGNATURE----- Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf Martin KaFai Lau says: ==================== pull-request: bpf 2023-08-09 We've added 5 non-merge commits during the last 7 day(s) which contain a total of 6 files changed, 102 insertions(+), 8 deletions(-). The main changes are: 1) A bpf sockmap memleak fix and a fix in accessing the programs of a sockmap under the incorrect map type from Xu Kuohai. 2) A refcount underflow fix in xsk from Magnus Karlsson. * tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: selftests/bpf: Add sockmap test for redirecting partial skb data selftests/bpf: fix a CI failure caused by vsock sockmap test bpf, sockmap: Fix bug that strp_done cannot be called bpf, sockmap: Fix map type error in sock_map_del_link xsk: fix refcount underflow in error path ==================== Link: https://lore.kernel.org/r/20230810055303.120917-1-martin.lau@linux.dev Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
62d02fca8b
@ -62,6 +62,7 @@ struct sk_psock_progs {
|
|||||||
|
|
||||||
enum sk_psock_state_bits {
|
enum sk_psock_state_bits {
|
||||||
SK_PSOCK_TX_ENABLED,
|
SK_PSOCK_TX_ENABLED,
|
||||||
|
SK_PSOCK_RX_STRP_ENABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sk_psock_link {
|
struct sk_psock_link {
|
||||||
|
@ -1120,13 +1120,19 @@ static void sk_psock_strp_data_ready(struct sock *sk)
|
|||||||
|
|
||||||
int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock)
|
int sk_psock_init_strp(struct sock *sk, struct sk_psock *psock)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
static const struct strp_callbacks cb = {
|
static const struct strp_callbacks cb = {
|
||||||
.rcv_msg = sk_psock_strp_read,
|
.rcv_msg = sk_psock_strp_read,
|
||||||
.read_sock_done = sk_psock_strp_read_done,
|
.read_sock_done = sk_psock_strp_read_done,
|
||||||
.parse_msg = sk_psock_strp_parse,
|
.parse_msg = sk_psock_strp_parse,
|
||||||
};
|
};
|
||||||
|
|
||||||
return strp_init(&psock->strp, sk, &cb);
|
ret = strp_init(&psock->strp, sk, &cb);
|
||||||
|
if (!ret)
|
||||||
|
sk_psock_set_state(psock, SK_PSOCK_RX_STRP_ENABLED);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock)
|
void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock)
|
||||||
@ -1154,7 +1160,7 @@ void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock)
|
|||||||
static void sk_psock_done_strp(struct sk_psock *psock)
|
static void sk_psock_done_strp(struct sk_psock *psock)
|
||||||
{
|
{
|
||||||
/* Parser has been stopped */
|
/* Parser has been stopped */
|
||||||
if (psock->progs.stream_parser)
|
if (sk_psock_test_state(psock, SK_PSOCK_RX_STRP_ENABLED))
|
||||||
strp_done(&psock->strp);
|
strp_done(&psock->strp);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -146,13 +146,13 @@ static void sock_map_del_link(struct sock *sk,
|
|||||||
list_for_each_entry_safe(link, tmp, &psock->link, list) {
|
list_for_each_entry_safe(link, tmp, &psock->link, list) {
|
||||||
if (link->link_raw == link_raw) {
|
if (link->link_raw == link_raw) {
|
||||||
struct bpf_map *map = link->map;
|
struct bpf_map *map = link->map;
|
||||||
struct bpf_stab *stab = container_of(map, struct bpf_stab,
|
struct sk_psock_progs *progs = sock_map_progs(map);
|
||||||
map);
|
|
||||||
if (psock->saved_data_ready && stab->progs.stream_parser)
|
if (psock->saved_data_ready && progs->stream_parser)
|
||||||
strp_stop = true;
|
strp_stop = true;
|
||||||
if (psock->saved_data_ready && stab->progs.stream_verdict)
|
if (psock->saved_data_ready && progs->stream_verdict)
|
||||||
verdict_stop = true;
|
verdict_stop = true;
|
||||||
if (psock->saved_data_ready && stab->progs.skb_verdict)
|
if (psock->saved_data_ready && progs->skb_verdict)
|
||||||
verdict_stop = true;
|
verdict_stop = true;
|
||||||
list_del(&link->list);
|
list_del(&link->list);
|
||||||
sk_psock_free_link(link);
|
sk_psock_free_link(link);
|
||||||
|
@ -994,6 +994,7 @@ static int xsk_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
|
|||||||
err = xp_alloc_tx_descs(xs->pool, xs);
|
err = xp_alloc_tx_descs(xs->pool, xs);
|
||||||
if (err) {
|
if (err) {
|
||||||
xp_put_pool(xs->pool);
|
xp_put_pool(xs->pool);
|
||||||
|
xs->pool = NULL;
|
||||||
sockfd_put(sock);
|
sockfd_put(sock);
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
@ -869,6 +869,77 @@ static void test_msg_redir_to_listening(struct test_sockmap_listen *skel,
|
|||||||
xbpf_prog_detach2(verdict, sock_map, BPF_SK_MSG_VERDICT);
|
xbpf_prog_detach2(verdict, sock_map, BPF_SK_MSG_VERDICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void redir_partial(int family, int sotype, int sock_map, int parser_map)
|
||||||
|
{
|
||||||
|
int s, c0, c1, p0, p1;
|
||||||
|
int err, n, key, value;
|
||||||
|
char buf[] = "abc";
|
||||||
|
|
||||||
|
key = 0;
|
||||||
|
value = sizeof(buf) - 1;
|
||||||
|
err = xbpf_map_update_elem(parser_map, &key, &value, 0);
|
||||||
|
if (err)
|
||||||
|
return;
|
||||||
|
|
||||||
|
s = socket_loopback(family, sotype | SOCK_NONBLOCK);
|
||||||
|
if (s < 0)
|
||||||
|
goto clean_parser_map;
|
||||||
|
|
||||||
|
err = create_socket_pairs(s, family, sotype, &c0, &c1, &p0, &p1);
|
||||||
|
if (err)
|
||||||
|
goto close_srv;
|
||||||
|
|
||||||
|
err = add_to_sockmap(sock_map, p0, p1);
|
||||||
|
if (err)
|
||||||
|
goto close;
|
||||||
|
|
||||||
|
n = xsend(c1, buf, sizeof(buf), 0);
|
||||||
|
if (n < sizeof(buf))
|
||||||
|
FAIL("incomplete write");
|
||||||
|
|
||||||
|
n = xrecv_nonblock(c0, buf, sizeof(buf), 0);
|
||||||
|
if (n != sizeof(buf) - 1)
|
||||||
|
FAIL("expect %zu, received %d", sizeof(buf) - 1, n);
|
||||||
|
|
||||||
|
close:
|
||||||
|
xclose(c0);
|
||||||
|
xclose(p0);
|
||||||
|
xclose(c1);
|
||||||
|
xclose(p1);
|
||||||
|
close_srv:
|
||||||
|
xclose(s);
|
||||||
|
|
||||||
|
clean_parser_map:
|
||||||
|
key = 0;
|
||||||
|
value = 0;
|
||||||
|
xbpf_map_update_elem(parser_map, &key, &value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_skb_redir_partial(struct test_sockmap_listen *skel,
|
||||||
|
struct bpf_map *inner_map, int family,
|
||||||
|
int sotype)
|
||||||
|
{
|
||||||
|
int verdict = bpf_program__fd(skel->progs.prog_stream_verdict);
|
||||||
|
int parser = bpf_program__fd(skel->progs.prog_stream_parser);
|
||||||
|
int parser_map = bpf_map__fd(skel->maps.parser_map);
|
||||||
|
int sock_map = bpf_map__fd(inner_map);
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = xbpf_prog_attach(parser, sock_map, BPF_SK_SKB_STREAM_PARSER, 0);
|
||||||
|
if (err)
|
||||||
|
return;
|
||||||
|
|
||||||
|
err = xbpf_prog_attach(verdict, sock_map, BPF_SK_SKB_STREAM_VERDICT, 0);
|
||||||
|
if (err)
|
||||||
|
goto detach;
|
||||||
|
|
||||||
|
redir_partial(family, sotype, sock_map, parser_map);
|
||||||
|
|
||||||
|
xbpf_prog_detach2(verdict, sock_map, BPF_SK_SKB_STREAM_VERDICT);
|
||||||
|
detach:
|
||||||
|
xbpf_prog_detach2(parser, sock_map, BPF_SK_SKB_STREAM_PARSER);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_reuseport_select_listening(int family, int sotype,
|
static void test_reuseport_select_listening(int family, int sotype,
|
||||||
int sock_map, int verd_map,
|
int sock_map, int verd_map,
|
||||||
int reuseport_prog)
|
int reuseport_prog)
|
||||||
@ -1243,6 +1314,7 @@ static void test_redir(struct test_sockmap_listen *skel, struct bpf_map *map,
|
|||||||
} tests[] = {
|
} tests[] = {
|
||||||
TEST(test_skb_redir_to_connected),
|
TEST(test_skb_redir_to_connected),
|
||||||
TEST(test_skb_redir_to_listening),
|
TEST(test_skb_redir_to_listening),
|
||||||
|
TEST(test_skb_redir_partial),
|
||||||
TEST(test_msg_redir_to_connected),
|
TEST(test_msg_redir_to_connected),
|
||||||
TEST(test_msg_redir_to_listening),
|
TEST(test_msg_redir_to_listening),
|
||||||
};
|
};
|
||||||
@ -1432,7 +1504,7 @@ static void vsock_unix_redir_connectible(int sock_mapfd, int verd_mapfd,
|
|||||||
if (n < 1)
|
if (n < 1)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
n = recv(mode == REDIR_INGRESS ? u0 : u1, &b, sizeof(b), MSG_DONTWAIT);
|
n = xrecv_nonblock(mode == REDIR_INGRESS ? u0 : u1, &b, sizeof(b), 0);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
FAIL("%s: recv() err, errno=%d", log_prefix, errno);
|
FAIL("%s: recv() err, errno=%d", log_prefix, errno);
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
|
@ -28,12 +28,26 @@ struct {
|
|||||||
__type(value, unsigned int);
|
__type(value, unsigned int);
|
||||||
} verdict_map SEC(".maps");
|
} verdict_map SEC(".maps");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||||
|
__uint(max_entries, 1);
|
||||||
|
__type(key, int);
|
||||||
|
__type(value, int);
|
||||||
|
} parser_map SEC(".maps");
|
||||||
|
|
||||||
bool test_sockmap = false; /* toggled by user-space */
|
bool test_sockmap = false; /* toggled by user-space */
|
||||||
bool test_ingress = false; /* toggled by user-space */
|
bool test_ingress = false; /* toggled by user-space */
|
||||||
|
|
||||||
SEC("sk_skb/stream_parser")
|
SEC("sk_skb/stream_parser")
|
||||||
int prog_stream_parser(struct __sk_buff *skb)
|
int prog_stream_parser(struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
int *value;
|
||||||
|
__u32 key = 0;
|
||||||
|
|
||||||
|
value = bpf_map_lookup_elem(&parser_map, &key);
|
||||||
|
if (value && *value)
|
||||||
|
return *value;
|
||||||
|
|
||||||
return skb->len;
|
return skb->len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user