diff mbox series

[08/12] selftests/net: Add TCP_REPAIR TCP-AO tests

Message ID 20231215-tcp-ao-selftests-v1-8-f6c08180b985@arista.com (mailing list archive)
State Accepted
Commit 3715d32dc97698e6d2f59b1579577178a1361686
Headers show
Series [01/12] selftests/net: Add TCP-AO library | expand

Commit Message

Dmitry Safonov Dec. 15, 2023, 2:36 a.m. UTC
The test plan is:
1. check that TCP-AO connection may be restored on another socket
2. check restore with wrong send/recv ISN (checking that they are
   part of MAC generation)
3. check restore with wrong SEQ number extension (checking that
   high bytes of it taken into MAC generation)

Sample output expected:
> # ./restore_ipv4
> 1..20
> # 1412[lib/setup.c:254] rand seed 1686610825
> TAP version 13
> ok 1 TCP-AO migrate to another socket: server alive
> ok 2 TCP-AO migrate to another socket: post-migrate connection is alive
> ok 3 TCP-AO migrate to another socket: counter TCPAOGood increased 23 => 44
> ok 4 TCP-AO migrate to another socket: counter TCPAOGood increased 22 => 42
> ok 5 TCP-AO with wrong send ISN: server couldn't serve
> ok 6 TCP-AO with wrong send ISN: post-migrate connection is broken
> ok 7 TCP-AO with wrong send ISN: counter TCPAOBad increased 0 => 4
> ok 8 TCP-AO with wrong send ISN: counter TCPAOBad increased 0 => 3
> ok 9 TCP-AO with wrong receive ISN: server couldn't serve
> ok 10 TCP-AO with wrong receive ISN: post-migrate connection is broken
> ok 11 TCP-AO with wrong receive ISN: counter TCPAOBad increased 4 => 8
> ok 12 TCP-AO with wrong receive ISN: counter TCPAOBad increased 5 => 10
> ok 13 TCP-AO with wrong send SEQ ext number: server couldn't serve
> ok 14 TCP-AO with wrong send SEQ ext number: post-migrate connection is broken
> ok 15 TCP-AO with wrong send SEQ ext number: counter TCPAOBad increased 9 => 10
> ok 16 TCP-AO with wrong send SEQ ext number: counter TCPAOBad increased 11 => 19
> ok 17 TCP-AO with wrong receive SEQ ext number: post-migrate connection is broken
> ok 18 TCP-AO with wrong receive SEQ ext number: server couldn't serve
> ok 19 TCP-AO with wrong receive SEQ ext number: counter TCPAOBad increased 10 => 18
> ok 20 TCP-AO with wrong receive SEQ ext number: counter TCPAOBad increased 20 => 23
> # Totals: pass:20 fail:0 xfail:0 xpass:0 skip:0 error:0

Signed-off-by: Dmitry Safonov <dima@arista.com>
---
 tools/testing/selftests/net/tcp_ao/Makefile  |   1 +
 tools/testing/selftests/net/tcp_ao/restore.c | 236 +++++++++++++++++++++++++++
 2 files changed, 237 insertions(+)

Comments

Hangbin Liu Dec. 18, 2023, 9:10 a.m. UTC | #1
On Fri, Dec 15, 2023 at 02:36:22AM +0000, Dmitry Safonov wrote:
> The test plan is:
> 1. check that TCP-AO connection may be restored on another socket
> 2. check restore with wrong send/recv ISN (checking that they are
>    part of MAC generation)
> 3. check restore with wrong SEQ number extension (checking that
>    high bytes of it taken into MAC generation)
> 
> Sample output expected:
> > # ./restore_ipv4
> > 1..20
> > # 1412[lib/setup.c:254] rand seed 1686610825
> > TAP version 13
> > ok 1 TCP-AO migrate to another socket: server alive
> > ok 2 TCP-AO migrate to another socket: post-migrate connection is alive
> > ok 3 TCP-AO migrate to another socket: counter TCPAOGood increased 23 => 44
> > ok 4 TCP-AO migrate to another socket: counter TCPAOGood increased 22 => 42
> > ok 5 TCP-AO with wrong send ISN: server couldn't serve
> > ok 6 TCP-AO with wrong send ISN: post-migrate connection is broken
> > ok 7 TCP-AO with wrong send ISN: counter TCPAOBad increased 0 => 4
> > ok 8 TCP-AO with wrong send ISN: counter TCPAOBad increased 0 => 3
> > ok 9 TCP-AO with wrong receive ISN: server couldn't serve
> > ok 10 TCP-AO with wrong receive ISN: post-migrate connection is broken
> > ok 11 TCP-AO with wrong receive ISN: counter TCPAOBad increased 4 => 8
> > ok 12 TCP-AO with wrong receive ISN: counter TCPAOBad increased 5 => 10
> > ok 13 TCP-AO with wrong send SEQ ext number: server couldn't serve
> > ok 14 TCP-AO with wrong send SEQ ext number: post-migrate connection is broken
> > ok 15 TCP-AO with wrong send SEQ ext number: counter TCPAOBad increased 9 => 10
> > ok 16 TCP-AO with wrong send SEQ ext number: counter TCPAOBad increased 11 => 19
> > ok 17 TCP-AO with wrong receive SEQ ext number: post-migrate connection is broken
> > ok 18 TCP-AO with wrong receive SEQ ext number: server couldn't serve
> > ok 19 TCP-AO with wrong receive SEQ ext number: counter TCPAOBad increased 10 => 18
> > ok 20 TCP-AO with wrong receive SEQ ext number: counter TCPAOBad increased 20 => 23
> > # Totals: pass:20 fail:0 xfail:0 xpass:0 skip:0 error:0
> 
> Signed-off-by: Dmitry Safonov <dima@arista.com>

Tested-by: Hangbin Liu <liuhangbin@gmail.com>
diff mbox series

Patch

diff --git a/tools/testing/selftests/net/tcp_ao/Makefile b/tools/testing/selftests/net/tcp_ao/Makefile
index f0b218b99506..aa11a855c3e0 100644
--- a/tools/testing/selftests/net/tcp_ao/Makefile
+++ b/tools/testing/selftests/net/tcp_ao/Makefile
@@ -3,6 +3,7 @@  TEST_BOTH_AF := bench-lookups
 TEST_BOTH_AF += connect
 TEST_BOTH_AF += connect-deny
 TEST_BOTH_AF += icmps-accept icmps-discard
+TEST_BOTH_AF += restore
 TEST_BOTH_AF += setsockopt-closed
 TEST_BOTH_AF += unsigned-md5
 
diff --git a/tools/testing/selftests/net/tcp_ao/restore.c b/tools/testing/selftests/net/tcp_ao/restore.c
new file mode 100644
index 000000000000..8fdc808df325
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/restore.c
@@ -0,0 +1,236 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Dmitry Safonov <dima@arista.com> */
+/* This is over-simplified TCP_REPAIR for TCP_ESTABLISHED sockets
+ * It tests that TCP-AO enabled connection can be restored.
+ * For the proper socket repair see:
+ * https://github.com/checkpoint-restore/criu/blob/criu-dev/soccr/soccr.h
+ */
+#include <inttypes.h>
+#include "aolib.h"
+
+const size_t nr_packets = 20;
+const size_t msg_len = 100;
+const size_t quota = nr_packets * msg_len;
+#define fault(type)	(inj == FAULT_ ## type)
+
+static void try_server_run(const char *tst_name, unsigned int port,
+			   fault_t inj, test_cnt cnt_expected)
+{
+	const char *cnt_name = "TCPAOGood";
+	struct tcp_ao_counters ao1, ao2;
+	uint64_t before_cnt, after_cnt;
+	int sk, lsk;
+	time_t timeout;
+	ssize_t bytes;
+
+	if (fault(TIMEOUT))
+		cnt_name = "TCPAOBad";
+	lsk = test_listen_socket(this_ip_addr, port, 1);
+
+	if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+		test_error("setsockopt(TCP_AO_ADD_KEY)");
+	synchronize_threads(); /* 1: MKT added => connect() */
+
+	if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
+		test_error("test_wait_fd()");
+
+	sk = accept(lsk, NULL, NULL);
+	if (sk < 0)
+		test_error("accept()");
+
+	synchronize_threads(); /* 2: accepted => send data */
+	close(lsk);
+
+	bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
+	if (bytes != quota) {
+		test_fail("%s: server served: %zd", tst_name, bytes);
+		goto out;
+	}
+
+	before_cnt = netstat_get_one(cnt_name, NULL);
+	if (test_get_tcp_ao_counters(sk, &ao1))
+		test_error("test_get_tcp_ao_counters()");
+
+	timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
+	bytes = test_server_run(sk, quota, timeout);
+	if (fault(TIMEOUT)) {
+		if (bytes > 0)
+			test_fail("%s: server served: %zd", tst_name, bytes);
+		else
+			test_ok("%s: server couldn't serve", tst_name);
+	} else {
+		if (bytes != quota)
+			test_fail("%s: server served: %zd", tst_name, bytes);
+		else
+			test_ok("%s: server alive", tst_name);
+	}
+	if (test_get_tcp_ao_counters(sk, &ao2))
+		test_error("test_get_tcp_ao_counters()");
+	after_cnt = netstat_get_one(cnt_name, NULL);
+
+	test_tcp_ao_counters_cmp(tst_name, &ao1, &ao2, cnt_expected);
+
+	if (after_cnt <= before_cnt) {
+		test_fail("%s: %s counter did not increase: %zu <= %zu",
+				tst_name, cnt_name, after_cnt, before_cnt);
+	} else {
+		test_ok("%s: counter %s increased %zu => %zu",
+			tst_name, cnt_name, before_cnt, after_cnt);
+	}
+
+	/*
+	 * Before close() as that will send FIN and move the peer in TCP_CLOSE
+	 * and that will prevent reading AO counters from the peer's socket.
+	 */
+	synchronize_threads(); /* 3: verified => closed */
+out:
+	close(sk);
+}
+
+static void *server_fn(void *arg)
+{
+	unsigned int port = test_server_port;
+
+	try_server_run("TCP-AO migrate to another socket", port++,
+		       0, TEST_CNT_GOOD);
+	try_server_run("TCP-AO with wrong send ISN", port++,
+		       FAULT_TIMEOUT, TEST_CNT_BAD);
+	try_server_run("TCP-AO with wrong receive ISN", port++,
+		       FAULT_TIMEOUT, TEST_CNT_BAD);
+	try_server_run("TCP-AO with wrong send SEQ ext number", port++,
+		       FAULT_TIMEOUT, TEST_CNT_BAD);
+	try_server_run("TCP-AO with wrong receive SEQ ext number", port++,
+		       FAULT_TIMEOUT, TEST_CNT_NS_BAD | TEST_CNT_GOOD);
+
+	synchronize_threads(); /* don't race to exit: client exits */
+	return NULL;
+}
+
+static void test_get_sk_checkpoint(unsigned int server_port, sockaddr_af *saddr,
+				   struct tcp_sock_state *img,
+				   struct tcp_ao_repair *ao_img)
+{
+	int sk;
+
+	sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+	if (sk < 0)
+		test_error("socket()");
+
+	if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
+		test_error("setsockopt(TCP_AO_ADD_KEY)");
+
+	synchronize_threads(); /* 1: MKT added => connect() */
+	if (test_connect_socket(sk, this_ip_dest, server_port) <= 0)
+		test_error("failed to connect()");
+
+	synchronize_threads(); /* 2: accepted => send data */
+	if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
+		test_fail("pre-migrate verify failed");
+
+	test_enable_repair(sk);
+	test_sock_checkpoint(sk, img, saddr);
+	test_ao_checkpoint(sk, ao_img);
+	test_kill_sk(sk);
+}
+
+static void test_sk_restore(const char *tst_name, unsigned int server_port,
+			    sockaddr_af *saddr, struct tcp_sock_state *img,
+			    struct tcp_ao_repair *ao_img,
+			    fault_t inj, test_cnt cnt_expected)
+{
+	const char *cnt_name = "TCPAOGood";
+	struct tcp_ao_counters ao1, ao2;
+	uint64_t before_cnt, after_cnt;
+	time_t timeout;
+	int sk;
+
+	if (fault(TIMEOUT))
+		cnt_name = "TCPAOBad";
+
+	before_cnt = netstat_get_one(cnt_name, NULL);
+	sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+	if (sk < 0)
+		test_error("socket()");
+
+	test_enable_repair(sk);
+	test_sock_restore(sk, img, saddr, this_ip_dest, server_port);
+	if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0, this_ip_dest, -1, 100, 100))
+		test_error("setsockopt(TCP_AO_ADD_KEY)");
+	test_ao_restore(sk, ao_img);
+
+	if (test_get_tcp_ao_counters(sk, &ao1))
+		test_error("test_get_tcp_ao_counters()");
+
+	test_disable_repair(sk);
+	test_sock_state_free(img);
+
+	timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
+	if (test_client_verify(sk, msg_len, nr_packets, timeout)) {
+		if (fault(TIMEOUT))
+			test_ok("%s: post-migrate connection is broken", tst_name);
+		else
+			test_fail("%s: post-migrate connection is working", tst_name);
+	} else {
+		if (fault(TIMEOUT))
+			test_fail("%s: post-migrate connection still working", tst_name);
+		else
+			test_ok("%s: post-migrate connection is alive", tst_name);
+	}
+	if (test_get_tcp_ao_counters(sk, &ao2))
+		test_error("test_get_tcp_ao_counters()");
+	after_cnt = netstat_get_one(cnt_name, NULL);
+
+	test_tcp_ao_counters_cmp(tst_name, &ao1, &ao2, cnt_expected);
+
+	if (after_cnt <= before_cnt) {
+		test_fail("%s: %s counter did not increase: %zu <= %zu",
+				tst_name, cnt_name, after_cnt, before_cnt);
+	} else {
+		test_ok("%s: counter %s increased %zu => %zu",
+			tst_name, cnt_name, before_cnt, after_cnt);
+	}
+	synchronize_threads(); /* 3: verified => closed */
+	close(sk);
+}
+
+static void *client_fn(void *arg)
+{
+	unsigned int port = test_server_port;
+	struct tcp_sock_state tcp_img;
+	struct tcp_ao_repair ao_img;
+	sockaddr_af saddr;
+
+	test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
+	test_sk_restore("TCP-AO migrate to another socket", port++,
+			&saddr, &tcp_img, &ao_img, 0, TEST_CNT_GOOD);
+
+	test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
+	ao_img.snt_isn += 1;
+	test_sk_restore("TCP-AO with wrong send ISN", port++,
+			&saddr, &tcp_img, &ao_img, FAULT_TIMEOUT, TEST_CNT_BAD);
+
+	test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
+	ao_img.rcv_isn += 1;
+	test_sk_restore("TCP-AO with wrong receive ISN", port++,
+			&saddr, &tcp_img, &ao_img, FAULT_TIMEOUT, TEST_CNT_BAD);
+
+	test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
+	ao_img.snd_sne += 1;
+	test_sk_restore("TCP-AO with wrong send SEQ ext number", port++,
+			&saddr, &tcp_img, &ao_img, FAULT_TIMEOUT,
+			TEST_CNT_NS_BAD | TEST_CNT_GOOD);
+
+	test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
+	ao_img.rcv_sne += 1;
+	test_sk_restore("TCP-AO with wrong receive SEQ ext number", port++,
+			&saddr, &tcp_img, &ao_img, FAULT_TIMEOUT,
+			TEST_CNT_NS_GOOD | TEST_CNT_BAD);
+
+	return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+	test_init(20, server_fn, client_fn);
+	return 0;
+}