bpf, sockmap: Build helper to create connected socket pair
A common operation for testing is to spin up a pair of sockets that are connected. Then we can use these to run specific tests that need to send data, check BPF programs and so on. The sockmap_listen programs already have this logic lets move it into the new sockmap_helpers header file for general use. Signed-off-by: John Fastabend <john.fastabend@gmail.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Reviewed-by: Jakub Sitnicki <jakub@cloudflare.com> Link: https://lore.kernel.org/bpf/20230523025618.113937-11-john.fastabend@gmail.com
This commit is contained in:
parent
4e02588d9a
commit
298970c8af
|
@ -269,4 +269,122 @@ static inline struct sockaddr *sockaddr(struct sockaddr_storage *ss)
|
|||
return (struct sockaddr *)ss;
|
||||
}
|
||||
|
||||
static inline int add_to_sockmap(int sock_mapfd, int fd1, int fd2)
|
||||
{
|
||||
u64 value;
|
||||
u32 key;
|
||||
int err;
|
||||
|
||||
key = 0;
|
||||
value = fd1;
|
||||
err = xbpf_map_update_elem(sock_mapfd, &key, &value, BPF_NOEXIST);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
key = 1;
|
||||
value = fd2;
|
||||
return xbpf_map_update_elem(sock_mapfd, &key, &value, BPF_NOEXIST);
|
||||
}
|
||||
|
||||
static inline int create_pair(int s, int family, int sotype, int *c, int *p)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len;
|
||||
int err = 0;
|
||||
|
||||
len = sizeof(addr);
|
||||
err = xgetsockname(s, sockaddr(&addr), &len);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*c = xsocket(family, sotype, 0);
|
||||
if (*c < 0)
|
||||
return errno;
|
||||
err = xconnect(*c, sockaddr(&addr), len);
|
||||
if (err) {
|
||||
err = errno;
|
||||
goto close_cli0;
|
||||
}
|
||||
|
||||
*p = xaccept_nonblock(s, NULL, NULL);
|
||||
if (*p < 0) {
|
||||
err = errno;
|
||||
goto close_cli0;
|
||||
}
|
||||
return err;
|
||||
close_cli0:
|
||||
close(*c);
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int create_socket_pairs(int s, int family, int sotype,
|
||||
int *c0, int *c1, int *p0, int *p1)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = create_pair(s, family, sotype, c0, p0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = create_pair(s, family, sotype, c1, p1);
|
||||
if (err) {
|
||||
close(*c0);
|
||||
close(*p0);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int enable_reuseport(int s, int progfd)
|
||||
{
|
||||
int err, one = 1;
|
||||
|
||||
err = xsetsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
|
||||
if (err)
|
||||
return -1;
|
||||
err = xsetsockopt(s, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &progfd,
|
||||
sizeof(progfd));
|
||||
if (err)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int socket_loopback_reuseport(int family, int sotype, int progfd)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len;
|
||||
int err, s;
|
||||
|
||||
init_addr_loopback(family, &addr, &len);
|
||||
|
||||
s = xsocket(family, sotype, 0);
|
||||
if (s == -1)
|
||||
return -1;
|
||||
|
||||
if (progfd >= 0)
|
||||
enable_reuseport(s, progfd);
|
||||
|
||||
err = xbind(s, sockaddr(&addr), len);
|
||||
if (err)
|
||||
goto close;
|
||||
|
||||
if (sotype & SOCK_DGRAM)
|
||||
return s;
|
||||
|
||||
err = xlisten(s, SOMAXCONN);
|
||||
if (err)
|
||||
goto close;
|
||||
|
||||
return s;
|
||||
close:
|
||||
xclose(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int socket_loopback(int family, int sotype)
|
||||
{
|
||||
return socket_loopback_reuseport(family, sotype, -1);
|
||||
}
|
||||
|
||||
|
||||
#endif // __SOCKMAP_HELPERS__
|
||||
|
|
|
@ -29,58 +29,6 @@
|
|||
|
||||
#include "sockmap_helpers.h"
|
||||
|
||||
static int enable_reuseport(int s, int progfd)
|
||||
{
|
||||
int err, one = 1;
|
||||
|
||||
err = xsetsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
|
||||
if (err)
|
||||
return -1;
|
||||
err = xsetsockopt(s, SOL_SOCKET, SO_ATTACH_REUSEPORT_EBPF, &progfd,
|
||||
sizeof(progfd));
|
||||
if (err)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int socket_loopback_reuseport(int family, int sotype, int progfd)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t len;
|
||||
int err, s;
|
||||
|
||||
init_addr_loopback(family, &addr, &len);
|
||||
|
||||
s = xsocket(family, sotype, 0);
|
||||
if (s == -1)
|
||||
return -1;
|
||||
|
||||
if (progfd >= 0)
|
||||
enable_reuseport(s, progfd);
|
||||
|
||||
err = xbind(s, sockaddr(&addr), len);
|
||||
if (err)
|
||||
goto close;
|
||||
|
||||
if (sotype & SOCK_DGRAM)
|
||||
return s;
|
||||
|
||||
err = xlisten(s, SOMAXCONN);
|
||||
if (err)
|
||||
goto close;
|
||||
|
||||
return s;
|
||||
close:
|
||||
xclose(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int socket_loopback(int family, int sotype)
|
||||
{
|
||||
return socket_loopback_reuseport(family, sotype, -1);
|
||||
}
|
||||
|
||||
static void test_insert_invalid(struct test_sockmap_listen *skel __always_unused,
|
||||
int family, int sotype, int mapfd)
|
||||
{
|
||||
|
@ -723,31 +671,12 @@ static const char *redir_mode_str(enum redir_mode mode)
|
|||
}
|
||||
}
|
||||
|
||||
static int add_to_sockmap(int sock_mapfd, int fd1, int fd2)
|
||||
{
|
||||
u64 value;
|
||||
u32 key;
|
||||
int err;
|
||||
|
||||
key = 0;
|
||||
value = fd1;
|
||||
err = xbpf_map_update_elem(sock_mapfd, &key, &value, BPF_NOEXIST);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
key = 1;
|
||||
value = fd2;
|
||||
return xbpf_map_update_elem(sock_mapfd, &key, &value, BPF_NOEXIST);
|
||||
}
|
||||
|
||||
static void redir_to_connected(int family, int sotype, int sock_mapfd,
|
||||
int verd_mapfd, enum redir_mode mode)
|
||||
{
|
||||
const char *log_prefix = redir_mode_str(mode);
|
||||
struct sockaddr_storage addr;
|
||||
int s, c0, c1, p0, p1;
|
||||
unsigned int pass;
|
||||
socklen_t len;
|
||||
int err, n;
|
||||
u32 key;
|
||||
char b;
|
||||
|
@ -758,36 +687,13 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd,
|
|||
if (s < 0)
|
||||
return;
|
||||
|
||||
len = sizeof(addr);
|
||||
err = xgetsockname(s, sockaddr(&addr), &len);
|
||||
err = create_socket_pairs(s, family, sotype, &c0, &c1, &p0, &p1);
|
||||
if (err)
|
||||
goto close_srv;
|
||||
|
||||
c0 = xsocket(family, sotype, 0);
|
||||
if (c0 < 0)
|
||||
goto close_srv;
|
||||
err = xconnect(c0, sockaddr(&addr), len);
|
||||
if (err)
|
||||
goto close_cli0;
|
||||
|
||||
p0 = xaccept_nonblock(s, NULL, NULL);
|
||||
if (p0 < 0)
|
||||
goto close_cli0;
|
||||
|
||||
c1 = xsocket(family, sotype, 0);
|
||||
if (c1 < 0)
|
||||
goto close_peer0;
|
||||
err = xconnect(c1, sockaddr(&addr), len);
|
||||
if (err)
|
||||
goto close_cli1;
|
||||
|
||||
p1 = xaccept_nonblock(s, NULL, NULL);
|
||||
if (p1 < 0)
|
||||
goto close_cli1;
|
||||
|
||||
err = add_to_sockmap(sock_mapfd, p0, p1);
|
||||
if (err)
|
||||
goto close_peer1;
|
||||
goto close;
|
||||
|
||||
n = write(mode == REDIR_INGRESS ? c1 : p1, "a", 1);
|
||||
if (n < 0)
|
||||
|
@ -795,12 +701,12 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd,
|
|||
if (n == 0)
|
||||
FAIL("%s: incomplete write", log_prefix);
|
||||
if (n < 1)
|
||||
goto close_peer1;
|
||||
goto close;
|
||||
|
||||
key = SK_PASS;
|
||||
err = xbpf_map_lookup_elem(verd_mapfd, &key, &pass);
|
||||
if (err)
|
||||
goto close_peer1;
|
||||
goto close;
|
||||
if (pass != 1)
|
||||
FAIL("%s: want pass count 1, have %d", log_prefix, pass);
|
||||
n = recv_timeout(c0, &b, 1, 0, IO_TIMEOUT_SEC);
|
||||
|
@ -809,13 +715,10 @@ static void redir_to_connected(int family, int sotype, int sock_mapfd,
|
|||
if (n == 0)
|
||||
FAIL("%s: incomplete recv", log_prefix);
|
||||
|
||||
close_peer1:
|
||||
close:
|
||||
xclose(p1);
|
||||
close_cli1:
|
||||
xclose(c1);
|
||||
close_peer0:
|
||||
xclose(p0);
|
||||
close_cli0:
|
||||
xclose(c0);
|
||||
close_srv:
|
||||
xclose(s);
|
||||
|
|
Loading…
Reference in New Issue