Commit 5a0a3193 authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Jakub Kicinski
Browse files

selftests/net: Fetch and check TCP-MD5 counters



There are related TCP-MD5 <=> TCP and TCP-MD5 <=> TCP-AO tests
that can benefit from checking the related counters, not only from
validating operations timeouts.

It also prepares the code for introduction of mixed select()+poll mode,
see the follow-up patches.

Signed-off-by: default avatarDmitry Safonov <0x7f454c46@gmail.com>
Link: https://patch.msgid.link/20250319-tcp-ao-selftests-polling-v2-3-da48040153d1@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 1fe42210
Loading
Loading
Loading
Loading
+14 −12
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ static void try_accept(const char *tst_name, unsigned int port, const char *pwd,
		       const char *cnt_name, test_cnt cnt_expected,
		       fault_t inj)
{
	struct tcp_ao_counters ao_cnt1, ao_cnt2;
	struct tcp_counters cnt1, cnt2;
	uint64_t before_cnt = 0, after_cnt = 0; /* silence GCC */
	int lsk, err, sk = 0;
	time_t timeout;
@@ -46,8 +46,8 @@ static void try_accept(const char *tst_name, unsigned int port, const char *pwd,

	if (cnt_name)
		before_cnt = netstat_get_one(cnt_name, NULL);
	if (pwd && test_get_tcp_ao_counters(lsk, &ao_cnt1))
		test_error("test_get_tcp_ao_counters()");
	if (pwd && test_get_tcp_counters(lsk, &cnt1))
		test_error("test_get_tcp_counters()");

	synchronize_threads(); /* preparations done */

@@ -72,13 +72,13 @@ static void try_accept(const char *tst_name, unsigned int port, const char *pwd,
	}

	synchronize_threads(); /* before counter checks */
	if (pwd && test_get_tcp_ao_counters(lsk, &ao_cnt2))
		test_error("test_get_tcp_ao_counters()");
	if (pwd && test_get_tcp_counters(lsk, &cnt2))
		test_error("test_get_tcp_counters()");

	close(lsk);

	if (pwd)
		test_assert_counters(tst_name, &ao_cnt1, &ao_cnt2, cnt_expected);
		test_assert_counters(tst_name, &cnt1, &cnt2, cnt_expected);

	if (!cnt_name)
		goto out;
@@ -163,7 +163,7 @@ static void try_connect(const char *tst_name, unsigned int port,
			uint8_t sndid, uint8_t rcvid,
			test_cnt cnt_expected, fault_t inj)
{
	struct tcp_ao_counters ao_cnt1, ao_cnt2;
	struct tcp_counters cnt1, cnt2;
	time_t timeout;
	int sk, ret;

@@ -174,8 +174,8 @@ static void try_connect(const char *tst_name, unsigned int port,
	if (pwd && test_add_key(sk, pwd, addr, prefix, sndid, rcvid))
		test_error("setsockopt(TCP_AO_ADD_KEY)");

	if (pwd && test_get_tcp_ao_counters(sk, &ao_cnt1))
		test_error("test_get_tcp_ao_counters()");
	if (pwd && test_get_tcp_counters(sk, &cnt1))
		test_error("test_get_tcp_counters()");

	synchronize_threads(); /* preparations done */

@@ -202,9 +202,11 @@ static void try_connect(const char *tst_name, unsigned int port,
	else
		test_ok("%s: connected", tst_name);
	if (pwd && ret > 0) {
		if (test_get_tcp_ao_counters(sk, &ao_cnt2))
			test_error("test_get_tcp_ao_counters()");
		test_assert_counters(tst_name, &ao_cnt1, &ao_cnt2, cnt_expected);
		if (test_get_tcp_counters(sk, &cnt2))
			test_error("test_get_tcp_counters()");
		test_assert_counters(tst_name, &cnt1, &cnt2, cnt_expected);
	} else if (pwd) {
		test_tcp_counters_free(&cnt1);
	}
out:
	synchronize_threads(); /* close() */
+9 −9
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ static void *client_fn(void *arg)
	uint64_t before_aogood, after_aogood;
	const size_t nr_packets = 20;
	struct netstat *ns_before, *ns_after;
	struct tcp_ao_counters ao1, ao2;
	struct tcp_counters ao1, ao2;

	if (sk < 0)
		test_error("socket()");
@@ -50,8 +50,8 @@ static void *client_fn(void *arg)

	ns_before = netstat_read();
	before_aogood = netstat_get(ns_before, "TCPAOGood", NULL);
	if (test_get_tcp_ao_counters(sk, &ao1))
		test_error("test_get_tcp_ao_counters()");
	if (test_get_tcp_counters(sk, &ao1))
		test_error("test_get_tcp_counters()");

	if (test_client_verify(sk, 100, nr_packets, TEST_TIMEOUT_SEC)) {
		test_fail("verify failed");
@@ -60,8 +60,8 @@ static void *client_fn(void *arg)

	ns_after = netstat_read();
	after_aogood = netstat_get(ns_after, "TCPAOGood", NULL);
	if (test_get_tcp_ao_counters(sk, &ao2))
		test_error("test_get_tcp_ao_counters()");
	if (test_get_tcp_counters(sk, &ao2))
		test_error("test_get_tcp_counters()");
	netstat_print_diff(ns_before, ns_after);
	netstat_free(ns_before);
	netstat_free(ns_after);
@@ -75,10 +75,10 @@ static void *client_fn(void *arg)
		return NULL;

	test_ok("connect TCPAOGood %" PRIu64 "/%" PRIu64 "/%" PRIu64 " => %" PRIu64 "/%" PRIu64 "/%" PRIu64 ", sent %zu",
			before_aogood, ao1.ao_info_pkt_good,
			ao1.key_cnts[0].pkt_good,
			after_aogood, ao2.ao_info_pkt_good,
			ao2.key_cnts[0].pkt_good,
			before_aogood, ao1.ao.ao_info_pkt_good,
			ao1.ao.key_cnts[0].pkt_good,
			after_aogood, ao2.ao.ao_info_pkt_good,
			ao2.ao.key_cnts[0].pkt_good,
			nr_packets);
	return NULL;
}
+7 −7
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ static void serve_interfered(int sk)
	ssize_t test_quota = packet_size * packets_nr * 10;
	uint64_t dest_unreach_a, dest_unreach_b;
	uint64_t icmp_ignored_a, icmp_ignored_b;
	struct tcp_ao_counters ao_cnt1, ao_cnt2;
	struct tcp_counters cnt1, cnt2;
	bool counter_not_found;
	struct netstat *ns_after, *ns_before;
	ssize_t bytes;
@@ -61,16 +61,16 @@ static void serve_interfered(int sk)
	ns_before = netstat_read();
	dest_unreach_a = netstat_get(ns_before, dst_unreach, NULL);
	icmp_ignored_a = netstat_get(ns_before, tcpao_icmps, NULL);
	if (test_get_tcp_ao_counters(sk, &ao_cnt1))
		test_error("test_get_tcp_ao_counters()");
	if (test_get_tcp_counters(sk, &cnt1))
		test_error("test_get_tcp_counters()");
	bytes = test_server_run(sk, test_quota, 0);
	ns_after = netstat_read();
	netstat_print_diff(ns_before, ns_after);
	dest_unreach_b = netstat_get(ns_after, dst_unreach, NULL);
	icmp_ignored_b = netstat_get(ns_after, tcpao_icmps,
					&counter_not_found);
	if (test_get_tcp_ao_counters(sk, &ao_cnt2))
		test_error("test_get_tcp_ao_counters()");
	if (test_get_tcp_counters(sk, &cnt2))
		test_error("test_get_tcp_counters()");

	netstat_free(ns_before);
	netstat_free(ns_after);
@@ -91,9 +91,9 @@ static void serve_interfered(int sk)
		return;
	}
#ifdef TEST_ICMPS_ACCEPT
	test_assert_counters(NULL, &ao_cnt1, &ao_cnt2, TEST_CNT_GOOD);
	test_assert_counters(NULL, &cnt1, &cnt2, TEST_CNT_GOOD);
#else
	test_assert_counters(NULL, &ao_cnt1, &ao_cnt2, TEST_CNT_GOOD | TEST_CNT_AO_DROPPED_ICMP);
	test_assert_counters(NULL, &cnt1, &cnt2, TEST_CNT_GOOD | TEST_CNT_AO_DROPPED_ICMP);
#endif
	if (icmp_ignored_a >= icmp_ignored_b) {
		test_icmps_fail("%s counter didn't change: %" PRIu64 " >= %" PRIu64,
+32 −32
Original line number Diff line number Diff line
@@ -629,11 +629,11 @@ static int key_collection_socket(bool server, unsigned int port)
}

static void verify_counters(const char *tst_name, bool is_listen_sk, bool server,
			    struct tcp_ao_counters *a, struct tcp_ao_counters *b)
			    struct tcp_counters *a, struct tcp_counters *b)
{
	unsigned int i;

	test_assert_counters_ao(tst_name, a, b, TEST_CNT_GOOD);
	test_assert_counters_sk(tst_name, a, b, TEST_CNT_GOOD);

	for (i = 0; i < collection.nr_keys; i++) {
		struct test_key *key = &collection.keys[i];
@@ -652,12 +652,12 @@ static void verify_counters(const char *tst_name, bool is_listen_sk, bool server
			rx_cnt_expected = key->used_on_server_tx;
		}

		test_assert_counters_key(tst_name, a, b,
		test_assert_counters_key(tst_name, &a->ao, &b->ao,
					 rx_cnt_expected ? TEST_CNT_KEY_GOOD : 0,
					 sndid, rcvid);
	}
	test_tcp_ao_counters_free(a);
	test_tcp_ao_counters_free(b);
	test_tcp_counters_free(a);
	test_tcp_counters_free(b);
	test_ok("%s: passed counters checks", tst_name);
}

@@ -791,17 +791,17 @@ static void verify_keys(const char *tst_name, int sk,
}

static int start_server(const char *tst_name, unsigned int port, size_t quota,
			struct tcp_ao_counters *begin,
			struct tcp_counters *begin,
			unsigned int current_index, unsigned int rnext_index)
{
	struct tcp_ao_counters lsk_c1, lsk_c2;
	struct tcp_counters lsk_c1, lsk_c2;
	ssize_t bytes;
	int sk, lsk;

	synchronize_threads(); /* 1: key collection initialized */
	lsk = key_collection_socket(true, port);
	if (test_get_tcp_ao_counters(lsk, &lsk_c1))
		test_error("test_get_tcp_ao_counters()");
	if (test_get_tcp_counters(lsk, &lsk_c1))
		test_error("test_get_tcp_counters()");
	synchronize_threads(); /* 2: MKTs added => connect() */
	if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
		test_error("test_wait_fd()");
@@ -809,12 +809,12 @@ static int start_server(const char *tst_name, unsigned int port, size_t quota,
	sk = accept(lsk, NULL, NULL);
	if (sk < 0)
		test_error("accept()");
	if (test_get_tcp_ao_counters(sk, begin))
		test_error("test_get_tcp_ao_counters()");
	if (test_get_tcp_counters(sk, begin))
		test_error("test_get_tcp_counters()");

	synchronize_threads(); /* 3: accepted => send data */
	if (test_get_tcp_ao_counters(lsk, &lsk_c2))
		test_error("test_get_tcp_ao_counters()");
	if (test_get_tcp_counters(lsk, &lsk_c2))
		test_error("test_get_tcp_counters()");
	verify_keys(tst_name, lsk, true, true);
	close(lsk);

@@ -830,12 +830,12 @@ static int start_server(const char *tst_name, unsigned int port, size_t quota,
}

static void end_server(const char *tst_name, int sk,
		       struct tcp_ao_counters *begin)
		       struct tcp_counters *begin)
{
	struct tcp_ao_counters end;
	struct tcp_counters end;

	if (test_get_tcp_ao_counters(sk, &end))
		test_error("test_get_tcp_ao_counters()");
	if (test_get_tcp_counters(sk, &end))
		test_error("test_get_tcp_counters()");
	verify_keys(tst_name, sk, false, true);

	synchronize_threads(); /* 4: verified => closed */
@@ -848,7 +848,7 @@ static void end_server(const char *tst_name, int sk,
static void try_server_run(const char *tst_name, unsigned int port, size_t quota,
			   unsigned int current_index, unsigned int rnext_index)
{
	struct tcp_ao_counters tmp;
	struct tcp_counters tmp;
	int sk;

	sk = start_server(tst_name, port, quota, &tmp,
@@ -860,7 +860,7 @@ static void server_rotations(const char *tst_name, unsigned int port,
			     size_t quota, unsigned int rotations,
			     unsigned int current_index, unsigned int rnext_index)
{
	struct tcp_ao_counters tmp;
	struct tcp_counters tmp;
	unsigned int i;
	int sk;

@@ -886,7 +886,7 @@ static void server_rotations(const char *tst_name, unsigned int port,

static int run_client(const char *tst_name, unsigned int port,
		      unsigned int nr_keys, int current_index, int rnext_index,
		      struct tcp_ao_counters *before,
		      struct tcp_counters *before,
		      const size_t msg_sz, const size_t msg_nr)
{
	int sk;
@@ -904,8 +904,8 @@ static int run_client(const char *tst_name, unsigned int port,
		if (test_set_key(sk, sndid, rcvid))
			test_error("failed to set current/rnext keys");
	}
	if (before && test_get_tcp_ao_counters(sk, before))
		test_error("test_get_tcp_ao_counters()");
	if (before && test_get_tcp_counters(sk, before))
		test_error("test_get_tcp_counters()");

	synchronize_threads(); /* 2: MKTs added => connect() */
	if (test_connect_socket(sk, this_ip_dest, port++) <= 0)
@@ -922,7 +922,7 @@ static int run_client(const char *tst_name, unsigned int port,
		test_fail("verify failed");
		close(sk);
		if (before)
			test_tcp_ao_counters_free(before);
			test_tcp_counters_free(before);
		return -1;
	}

@@ -931,7 +931,7 @@ static int run_client(const char *tst_name, unsigned int port,

static int start_client(const char *tst_name, unsigned int port,
			unsigned int nr_keys, int current_index, int rnext_index,
			struct tcp_ao_counters *before,
			struct tcp_counters *before,
			const size_t msg_sz, const size_t msg_nr)
{
	if (init_default_key_collection(nr_keys, true))
@@ -943,9 +943,9 @@ static int start_client(const char *tst_name, unsigned int port,

static void end_client(const char *tst_name, int sk, unsigned int nr_keys,
		       int current_index, int rnext_index,
		       struct tcp_ao_counters *start)
		       struct tcp_counters *start)
{
	struct tcp_ao_counters end;
	struct tcp_counters end;

	/* Some application may become dependent on this kernel choice */
	if (current_index < 0)
@@ -955,8 +955,8 @@ static void end_client(const char *tst_name, int sk, unsigned int nr_keys,
	verify_current_rnext(tst_name, sk,
			     collection.keys[current_index].client_keyid,
			     collection.keys[rnext_index].server_keyid);
	if (start && test_get_tcp_ao_counters(sk, &end))
		test_error("test_get_tcp_ao_counters()");
	if (start && test_get_tcp_counters(sk, &end))
		test_error("test_get_tcp_counters()");
	verify_keys(tst_name, sk, false, false);
	synchronize_threads(); /* 4: verify => closed */
	close(sk);
@@ -1048,7 +1048,7 @@ static void check_current_back(const char *tst_name, unsigned int port,
			       unsigned int current_index, unsigned int rnext_index,
			       unsigned int rotate_to_index)
{
	struct tcp_ao_counters tmp;
	struct tcp_counters tmp;
	int sk;

	sk = start_client(tst_name, port, nr_keys, current_index, rnext_index,
@@ -1081,7 +1081,7 @@ static void roll_over_keys(const char *tst_name, unsigned int port,
			   unsigned int nr_keys, unsigned int rotations,
			   unsigned int current_index, unsigned int rnext_index)
{
	struct tcp_ao_counters tmp;
	struct tcp_counters tmp;
	unsigned int i;
	int sk;

@@ -1102,7 +1102,7 @@ static void roll_over_keys(const char *tst_name, unsigned int port,
		if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC)) {
			test_fail("verify failed");
			close(sk);
			test_tcp_ao_counters_free(&tmp);
			test_tcp_counters_free(&tmp);
			return;
		}
		verify_current_rnext(tst_name, sk, -1,
@@ -1116,7 +1116,7 @@ static void roll_over_keys(const char *tst_name, unsigned int port,
static void try_client_run(const char *tst_name, unsigned int port,
			   unsigned int nr_keys, int current_index, int rnext_index)
{
	struct tcp_ao_counters tmp;
	struct tcp_counters tmp;
	int sk;

	sk = start_client(tst_name, port, nr_keys, current_index, rnext_index,
+41 −22
Original line number Diff line number Diff line
@@ -512,7 +512,15 @@ struct tcp_ao_counters {
	size_t nr_keys;
	struct tcp_ao_key_counters *key_cnts;
};
extern int test_get_tcp_ao_counters(int sk, struct tcp_ao_counters *out);

struct tcp_counters {
	struct tcp_ao_counters ao;
	uint64_t netns_md5_notfound;
	uint64_t netns_md5_unexpected;
	uint64_t netns_md5_failure;
};

extern int test_get_tcp_counters(int sk, struct tcp_counters *out);

#define TEST_CNT_KEY_GOOD		BIT(0)
#define TEST_CNT_KEY_BAD		BIT(1)
@@ -526,22 +534,29 @@ extern int test_get_tcp_ao_counters(int sk, struct tcp_ao_counters *out);
#define TEST_CNT_NS_KEY_NOT_FOUND	BIT(9)
#define TEST_CNT_NS_AO_REQUIRED		BIT(10)
#define TEST_CNT_NS_DROPPED_ICMP	BIT(11)
#define TEST_CNT_NS_MD5_NOT_FOUND	BIT(12)
#define TEST_CNT_NS_MD5_UNEXPECTED	BIT(13)
#define TEST_CNT_NS_MD5_FAILURE		BIT(14)
typedef uint16_t test_cnt;

#define _for_each_counter(f)						\
do {									\
	/* per-netns */							\
	f(netns_ao_good,		TEST_CNT_NS_GOOD);		\
	f(netns_ao_bad,			TEST_CNT_NS_BAD);		\
	f(netns_ao_key_not_found,	TEST_CNT_NS_KEY_NOT_FOUND);	\
	f(netns_ao_required,		TEST_CNT_NS_AO_REQUIRED);	\
	f(netns_ao_dropped_icmp,	TEST_CNT_NS_DROPPED_ICMP);	\
	f(ao.netns_ao_good,		TEST_CNT_NS_GOOD);		\
	f(ao.netns_ao_bad,		TEST_CNT_NS_BAD);		\
	f(ao.netns_ao_key_not_found,	TEST_CNT_NS_KEY_NOT_FOUND);	\
	f(ao.netns_ao_required,		TEST_CNT_NS_AO_REQUIRED);	\
	f(ao.netns_ao_dropped_icmp,	TEST_CNT_NS_DROPPED_ICMP);	\
	/* per-socket */						\
	f(ao_info_pkt_good,		TEST_CNT_SOCK_GOOD);		\
	f(ao_info_pkt_bad,		TEST_CNT_SOCK_BAD);		\
	f(ao_info_pkt_key_not_found,	TEST_CNT_SOCK_KEY_NOT_FOUND);	\
	f(ao_info_pkt_ao_required,	TEST_CNT_SOCK_AO_REQUIRED);	\
	f(ao_info_pkt_dropped_icmp,	TEST_CNT_SOCK_DROPPED_ICMP);	\
	f(ao.ao_info_pkt_good,		TEST_CNT_SOCK_GOOD);		\
	f(ao.ao_info_pkt_bad,		TEST_CNT_SOCK_BAD);		\
	f(ao.ao_info_pkt_key_not_found,	TEST_CNT_SOCK_KEY_NOT_FOUND);	\
	f(ao.ao_info_pkt_ao_required,	TEST_CNT_SOCK_AO_REQUIRED);	\
	f(ao.ao_info_pkt_dropped_icmp,	TEST_CNT_SOCK_DROPPED_ICMP);	\
	/* non-AO */							\
	f(netns_md5_notfound,		TEST_CNT_NS_MD5_NOT_FOUND);	\
	f(netns_md5_unexpected,		TEST_CNT_NS_MD5_UNEXPECTED);	\
	f(netns_md5_failure,		TEST_CNT_NS_MD5_FAILURE);	\
} while (0)

#define TEST_CNT_AO_GOOD		(TEST_CNT_SOCK_GOOD | TEST_CNT_NS_GOOD)
@@ -555,33 +570,37 @@ do { \
#define TEST_CNT_GOOD			(TEST_CNT_KEY_GOOD | TEST_CNT_AO_GOOD)
#define TEST_CNT_BAD			(TEST_CNT_KEY_BAD | TEST_CNT_AO_BAD)

extern int test_assert_counters_ao(const char *tst_name,
		struct tcp_ao_counters *before, struct tcp_ao_counters *after,
extern test_cnt test_cmp_counters(struct tcp_counters *before,
				  struct tcp_counters *after);
extern int test_assert_counters_sk(const char *tst_name,
		struct tcp_counters *before, struct tcp_counters *after,
		test_cnt expected);
extern int test_assert_counters_key(const char *tst_name,
		struct tcp_ao_counters *before, struct tcp_ao_counters *after,
		test_cnt expected, int sndid, int rcvid);
extern void test_tcp_ao_counters_free(struct tcp_ao_counters *cnts);
extern void test_tcp_counters_free(struct tcp_counters *cnts);

/*
 * Frees buffers allocated in test_get_tcp_ao_counters().
 * Frees buffers allocated in test_get_tcp_counters().
 * The function doesn't expect new keys or keys removed between calls
 * to test_get_tcp_ao_counters(). Check key counters manually if they
 * to test_get_tcp_counters(). Check key counters manually if they
 * may change.
 */
static inline int test_assert_counters(const char *tst_name,
				       struct tcp_ao_counters *before,
				       struct tcp_ao_counters *after,
				       struct tcp_counters *before,
				       struct tcp_counters *after,
				       test_cnt expected)
{
	int ret;

	ret = test_assert_counters_ao(tst_name, before, after, expected);
	ret = test_assert_counters_sk(tst_name, before, after, expected);
	if (ret)
		goto out;
	ret = test_assert_counters_key(tst_name, before, after, expected, -1, -1);
	ret = test_assert_counters_key(tst_name, &before->ao, &after->ao,
				       expected, -1, -1);
out:
	test_tcp_ao_counters_free(before);
	test_tcp_ao_counters_free(after);
	test_tcp_counters_free(before);
	test_tcp_counters_free(after);
	return ret;
}

Loading