Skip to content

Commit

Permalink
bpf: Add mptcp [gs]etsockopt per subflow
Browse files Browse the repository at this point in the history
Closes: multipath-tcp#76
Signed-off-by: Geliang Tang <[email protected]>
  • Loading branch information
Geliang Tang committed Mar 20, 2024
1 parent 187e13c commit ac2f154
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 0 deletions.
70 changes: 70 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/mptcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "network_helpers.h"
#include "mptcp_sock.skel.h"
#include "mptcpify.skel.h"
#include "mptcp_set_sf_sockopt_kern.skel.h"
#include "mptcp_bpf_first.skel.h"
#include "mptcp_bpf_bkup.skel.h"
#include "mptcp_bpf_rr.skel.h"
Expand Down Expand Up @@ -329,6 +330,73 @@ static void test_mptcpify(void)
close(cgroup_fd);
}

static int getsetsockopt(int map_fd)
{
int server_fd, client_fd, err = 0;

server_fd = start_mptcp_server(AF_INET, NULL, 0, 0);
if (!ASSERT_GE(server_fd, 0, "start_mptcp_server")) {
err = -EIO;
goto out;
}

client_fd = connect_to_fd(server_fd, 0);
if (!ASSERT_GE(client_fd, 0, "connect to fd")) {
err = -EIO;
goto close_server;
}

send_byte(client_fd);
SYS(out, "ip netns exec %s ss -Menita", NS_TEST);

close(client_fd);
close_server:
close(server_fd);
out:
return err;
}

static void run_test_sockopt(int cgroup_fd)
{
int prog_fd, map_fd, err;
struct mptcp_set_sf_sockopt_kern *skel;

skel = mptcp_set_sf_sockopt_kern__open_and_load();
if (!ASSERT_OK_PTR(skel, "skel_load"))
goto cleanup;

prog_fd = bpf_program__fd(skel->progs.mark_mptcp_sf);
map_fd = bpf_map__fd(skel->maps.mptcp_sf);
err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0);
if (!ASSERT_OK(err, "bpf_prog_attach"))
goto cleanup;

ASSERT_OK(getsetsockopt(map_fd), "getsetsockopt");

cleanup:
mptcp_set_sf_sockopt_kern__destroy(skel);
}

void test_sockopt_mptcp(void)
{
struct nstoken *nstoken = NULL;
int cgroup_fd;

cgroup_fd = test__join_cgroup("/sockopt_mptcp");
if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /sockopt_mptcp"))
return;

nstoken = create_netns();
if (!ASSERT_OK_PTR(nstoken, "create_netns"))
goto fail;

run_test_sockopt(cgroup_fd);

fail:
cleanup_netns(nstoken);
close(cgroup_fd);
}

static const unsigned int total_bytes = 10 * 1024 * 1024;
static int stop, duration;

Expand Down Expand Up @@ -693,6 +761,8 @@ void test_mptcp(void)
test_base();
if (test__start_subtest("mptcpify"))
test_mptcpify();
if (test__start_subtest("sockopt"))
test_sockopt_mptcp();
if (test__start_subtest("default"))
test_default();
if (test__start_subtest("first"))
Expand Down
96 changes: 96 additions & 0 deletions tools/testing/selftests/bpf/progs/mptcp_set_sf_sockopt_kern.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include <asm/socket.h> // SOL_SOCKET, SO_MARK, ...
#include <linux/tcp.h> // TCP_CONGESTION
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include "bpf_tcp_helpers.h"

char _license[] SEC("license") = "GPL";

#ifndef SOL_TCP
#define SOL_TCP 6
#endif

#ifndef TCP_CA_NAME_MAX
#define TCP_CA_NAME_MAX 16
#endif

char cc[TCP_CA_NAME_MAX] = "reno";

/* Associate a subflow counter to each token */
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(key_size, sizeof(__u32));
__uint(value_size, sizeof(__u32));
__uint(max_entries, 100);
} mptcp_sf SEC(".maps");

#define DEBUG 1

#ifdef DEBUG
char fmt1[] = "Mark <%u> : return code <%i>\n";
char fmt2[] = "Failed to get bpf_sock\n";
char fmt3[] = "Failed to get bpf_mptcp_sock\n";
char fmt4[] = "Failed to update sockopt cc err=%d\n";
char fmt5[] = "Failed to update sockopt mark\n";

#define pr_debug(msg, ...) bpf_trace_printk(msg, sizeof(msg), ##__VA_ARGS__);

#else

#define pr_debug(msg, ...)

#endif

SEC("sockops")
int mark_mptcp_sf(struct bpf_sock_ops *skops)
{
__u32 init = 1, key, mark, *cnt;
int err;

if (skops->op != BPF_SOCK_OPS_TCP_CONNECT_CB)
goto out;

struct bpf_sock *sk = skops->sk;
if (!sk) {
pr_debug(fmt2);
goto out;
}

struct mptcp_sock *msk = bpf_skc_to_mptcp_sock(sk);
if (!msk) {
pr_debug(fmt3);
goto out;
}

key = msk->token;
cnt = bpf_map_lookup_elem(&mptcp_sf, &key);

if (cnt) {
/* A new subflow is added to an existing MPTCP connection */
__sync_fetch_and_add(cnt, 1);
mark = *cnt;
} else {
/* A new MPTCP connection is just initiated and this is its primary
* subflow
*/
bpf_map_update_elem(&mptcp_sf, &key, &init, BPF_ANY);
mark = init;
}

/* Set the mark of the subflow's socket to its apparition order */
err = bpf_setsockopt(skops, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
pr_debug(fmt1, mark, err);

if (err < 0)
pr_debug(fmt5);

if (mark == 1)
err = err ?: bpf_setsockopt(skops, SOL_TCP, TCP_CONGESTION, cc,
TCP_CA_NAME_MAX);

if (err < 0)
pr_debug(fmt4, err);

out:
return 0;
}
14 changes: 14 additions & 0 deletions tools/testing/selftests/bpf/progs/mptcp_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
char _license[] SEC("license") = "GPL";
__u32 token = 0;

int page_size = 0; /* userspace should set it */

struct mptcp_storage {
__u32 invoked;
__u32 is_mptcp;
Expand Down Expand Up @@ -86,3 +88,15 @@ int BPF_PROG(trace_mptcp_pm_new_connection, struct mptcp_sock *msk,

return 0;
}

SEC("cgroup/getsockopt")
int _getsockopt(struct bpf_sockopt *ctx)
{
return 1;
}

SEC("cgroup/setsockopt")
int _setsockopt(struct bpf_sockopt *ctx)
{
return 1;
}

0 comments on commit ac2f154

Please sign in to comment.