@@ -66,6 +66,12 @@ enum mptcp_pm_type {
__MPTCP_PM_TYPE_MAX = __MPTCP_PM_TYPE_NR - 1,
};
+enum mptcp_pm_family {
+ IPV4 = 0,
+ IPV6,
+ IPV4MAPPED,
+};
+
static const unsigned int total_bytes = 10 * 1024 * 1024;
static int duration;
@@ -797,6 +803,242 @@ static void test_iters_address(void)
close(cgroup_fd);
}
+static int userspace_pm_add_addr(__u32 token, char *addr, __u8 id)
+{
+ return SYS_NOFAIL("ip netns exec %s %s ann %s id %u token %u",
+ NS_TEST, PM_CTL, addr, id, token);
+}
+
+static int userspace_pm_get_addr(__u32 token, __u8 id, char *output)
+{
+ char cmd[1024];
+ FILE *fp;
+
+ sprintf(cmd, "ip netns exec %s %s get %u token %u",
+ NS_TEST, PM_CTL, id, token);
+ fp = popen(cmd, "r");
+ if (!fp)
+ return -1;
+
+ bzero(output, BUFSIZ);
+ fread(output, 1, BUFSIZ, fp);
+ pclose(fp);
+
+ return 0;
+}
+
+static int userspace_pm_dump_addr(__u32 token, char *output)
+{
+ char cmd[1024];
+ FILE *fp;
+
+ sprintf(cmd, "ip netns exec %s %s dump token %u",
+ NS_TEST, PM_CTL, token);
+ fp = popen(cmd, "r");
+ if (!fp)
+ return -1;
+
+ bzero(output, BUFSIZ);
+ fread(output, 1, BUFSIZ, fp);
+ pclose(fp);
+
+ return 0;
+}
+
+static int userspace_pm_set_flags(__u32 token, char *addr, char *flags)
+{
+ bool ipv6 = strstr(addr, ":");
+ char line[1024], *str;
+ __u32 sport, dport;
+
+ if (userspace_pm_get_events_line("type:10", line))
+ return -1;
+
+ str = strstr(line, "sport");
+ if (!str || sscanf(str, "sport:%u,dport:%u,", &sport, &dport) != 2) {
+ log_err("set_flags error, str=%s\n", str);
+ return -1;
+ }
+
+ str = ipv6 ? (strstr(addr, ".") ? "::ffff:"ADDR_1 : ADDR6_1) : ADDR_1;
+ return SYS_NOFAIL("ip netns exec %s %s set %s port %u rip %s rport %u flags %s token %u",
+ NS_TEST, PM_CTL, addr, sport, str, dport, flags, token);
+}
+
+static int userspace_pm_rm_subflow(__u32 token, char *addr, __u8 id)
+{
+ bool ipv6 = strstr(addr, ":");
+ char line[1024], *str;
+ __u32 sport, dport;
+
+ if (userspace_pm_get_events_line("type:10", line))
+ return -1;
+
+ str = strstr(line, "sport");
+ if (!str || sscanf(str, "sport:%u,dport:%u,", &sport, &dport) != 2) {
+ log_err("rm_subflow error, str=%s\n", str);
+ return -1;
+ }
+
+ str = ipv6 ? (strstr(addr, ".") ? "::ffff:"ADDR_1 : ADDR6_1) : ADDR_1;
+ return SYS_NOFAIL("ip netns exec %s %s dsf lip %s lport %u rip %s rport %u token %u",
+ NS_TEST, PM_CTL, addr, sport, str, dport, token);
+}
+
+static int userspace_pm_rm_addr(__u32 token, __u8 id)
+{
+ return SYS_NOFAIL("ip netns exec %s %s rem id %u token %u",
+ NS_TEST, PM_CTL, id, token);
+}
+
+static void run_userspace_pm(enum mptcp_pm_family family)
+{
+ bool ipv6 = (family == IPV6 || family == IPV4MAPPED);
+ bool ipv4mapped = (family == IPV4MAPPED);
+ int server_fd, client_fd, accept_fd;
+ char output[BUFSIZ], expect[1024];
+ __u32 token;
+ char *addr;
+ int err;
+
+ addr = ipv6 ? (ipv4mapped ? "::ffff:"ADDR_1 : ADDR6_1) : ADDR_1;
+ server_fd = start_mptcp_server(ipv6 ? AF_INET6 : AF_INET, addr, PORT_1, 0);
+ if (!ASSERT_OK_FD(server_fd, "start_mptcp_server"))
+ return;
+
+ client_fd = connect_to_fd(server_fd, 0);
+ if (!ASSERT_OK_FD(client_fd, "connect_to_fd"))
+ goto close_server;
+
+ accept_fd = accept(server_fd, NULL, NULL);
+ if (!ASSERT_OK_FD(accept_fd, "accept"))
+ goto close_client;
+
+ token = userspace_pm_get_token(client_fd);
+ if (!token)
+ goto close_client;
+ recv_byte(accept_fd);
+ usleep(200000); /* 0.2s */
+
+ addr = ipv6 ? (ipv4mapped ? "::ffff:"ADDR_2 : ADDR6_2) : ADDR_2;
+ err = userspace_pm_add_subflow(token, addr, 100);
+ if (!ASSERT_OK(err, "userspace_pm_add_subflow 100"))
+ goto close_accept;
+
+ send_byte(accept_fd);
+ recv_byte(client_fd);
+
+ sprintf(expect, "id 100 flags subflow %s\n", addr);
+ err = userspace_pm_get_addr(token, 100, output);
+ if (!ASSERT_OK(err, "userspace_pm_get_addr 100") ||
+ !ASSERT_STRNEQ(output, expect, sizeof(expect), "get_addr"))
+ goto close_accept;
+
+ send_byte(client_fd);
+ recv_byte(accept_fd);
+
+ err = userspace_pm_set_flags(token, addr, "backup");
+ if (!ASSERT_OK(err, "userspace_pm_set_flags backup"))
+ goto close_accept;
+
+ send_byte(accept_fd);
+ recv_byte(client_fd);
+
+ sprintf(expect, "id 100 flags subflow,backup %s\n", addr);
+ err = userspace_pm_get_addr(token, 100, output);
+ if (!ASSERT_OK(err, "userspace_pm_get_addr 100") ||
+ !ASSERT_STRNEQ(output, expect, sizeof(expect), "get_addr"))
+ goto close_accept;
+
+ send_byte(client_fd);
+ recv_byte(accept_fd);
+
+ err = userspace_pm_set_flags(token, addr, "nobackup");
+ if (!ASSERT_OK(err, "userspace_pm_set_flags nobackup"))
+ goto close_accept;
+
+ send_byte(accept_fd);
+ recv_byte(client_fd);
+
+ sprintf(expect, "id 100 flags subflow %s\n", addr);
+ err = userspace_pm_get_addr(token, 100, output);
+ if (!ASSERT_OK(err, "userspace_pm_get_addr 100") ||
+ !ASSERT_STRNEQ(output, expect, sizeof(expect), "get_addr"))
+ goto close_accept;
+
+ send_byte(client_fd);
+ recv_byte(accept_fd);
+
+ err = userspace_pm_rm_subflow(token, addr, 100);
+ if (!ASSERT_OK(err, "userspace_pm_rm_subflow 100"))
+ goto close_accept;
+
+ send_byte(accept_fd);
+ recv_byte(client_fd);
+
+ err = userspace_pm_dump_addr(token, output);
+ if (!ASSERT_OK(err, "userspace_pm_dump_addr") ||
+ !ASSERT_STRNEQ(output, "", sizeof(output), "dump_addr"))
+ goto close_accept;
+
+ send_byte(client_fd);
+ recv_byte(accept_fd);
+
+ addr = ipv6 ? (ipv4mapped ? "::ffff:"ADDR_3 : ADDR6_3) : ADDR_3;
+ err = userspace_pm_add_addr(token, addr, 200);
+ if (!ASSERT_OK(err, "userspace_pm_add_addr 200"))
+ goto close_accept;
+
+ send_byte(accept_fd);
+ recv_byte(client_fd);
+
+ sprintf(expect, "id 200 flags signal %s\n", addr);
+ err = userspace_pm_dump_addr(token, output);
+ if (!ASSERT_OK(err, "userspace_pm_dump_addr") ||
+ !ASSERT_STRNEQ(output, expect, sizeof(expect), "dump_addr"))
+ goto close_accept;
+
+ send_byte(client_fd);
+ recv_byte(accept_fd);
+
+ err = userspace_pm_rm_addr(token, 200);
+ if (!ASSERT_OK(err, "userspace_pm_rm_addr 200"))
+ goto close_accept;
+
+ send_byte(accept_fd);
+ recv_byte(client_fd);
+
+ err = userspace_pm_rm_addr(token, 0);
+ ASSERT_OK(err, "userspace_pm_rm_addr 0");
+
+close_accept:
+ close(accept_fd);
+close_client:
+ close(client_fd);
+close_server:
+ close(server_fd);
+}
+
+static void test_userspace_pm(void)
+{
+ struct nstoken *nstoken;
+ int err;
+
+ nstoken = create_netns();
+ if (!ASSERT_OK_PTR(nstoken, "create_netns"))
+ return;
+
+ err = userspace_pm_init(MPTCP_PM_TYPE_USERSPACE);
+ if (!ASSERT_OK(err, "userspace_pm_init: userspace pm"))
+ goto fail;
+
+ run_userspace_pm(IPV4);
+
+ userspace_pm_cleanup();
+fail:
+ cleanup_netns(nstoken);
+}
+
static struct nstoken *sched_init(char *flags, char *sched)
{
struct nstoken *nstoken;
@@ -982,6 +1224,8 @@ void test_mptcp(void)
test_iters_subflow();
if (test__start_subtest("iters_address"))
test_iters_address();
+ if (test__start_subtest("userspace_pm"))
+ test_userspace_pm();
if (test__start_subtest("default"))
test_default();
if (test__start_subtest("first"))