Skip to content

Commit

Permalink
bpf, sockmap: Build helper to create connected socket pair
Browse files Browse the repository at this point in the history
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
  • Loading branch information
John Fastabend authored and Daniel Borkmann committed May 23, 2023
1 parent 4e02588 commit 298970c
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 102 deletions.
118 changes: 118 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/sockmap_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
107 changes: 5 additions & 102 deletions tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -758,49 +687,26 @@ 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)
FAIL_ERRNO("%s: write", log_prefix);
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);
Expand All @@ -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);
Expand Down

0 comments on commit 298970c

Please sign in to comment.