Merge branch 'selftests-net-mixed-select-polling-mode-for-tcp-ao-tests'

Dmitry Safonov via says:

====================
selftests/net: Mixed select()+polling mode for TCP-AO tests

Should fix flaky tcp-ao/connect-deny-ipv6 test.

v1: https://lore.kernel.org/20250312-tcp-ao-selftests-polling-v1-0-72a642b855d5@gmail.com
====================

Link: https://patch.msgid.link/20250319-tcp-ao-selftests-polling-v2-0-da48040153d1@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2025-03-25 06:10:32 -07:00
12 changed files with 552 additions and 345 deletions

View File

@@ -4,6 +4,7 @@
#include "aolib.h"
#define fault(type) (inj == FAULT_ ## type)
static volatile int sk_pair;
static inline int test_add_key_maclen(int sk, const char *key, uint8_t maclen,
union tcp_addr in_addr, uint8_t prefix,
@@ -34,10 +35,10 @@ 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 */
test_cnt poll_cnt = (cnt_expected == TEST_CNT_GOOD) ? 0 : cnt_expected;
int lsk, err, sk = 0;
time_t timeout;
lsk = test_listen_socket(this_ip_addr, port, 1);
@@ -46,21 +47,24 @@ 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 */
timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
err = test_wait_fd(lsk, timeout, 0);
err = test_skpair_wait_poll(lsk, 0, poll_cnt, &sk_pair);
if (err == -ETIMEDOUT) {
sk_pair = err;
if (!fault(TIMEOUT))
test_fail("timed out for accept()");
test_fail("%s: timed out for accept()", tst_name);
} else if (err == -EKEYREJECTED) {
if (!fault(KEYREJECT))
test_fail("%s: key was rejected", tst_name);
} else if (err < 0) {
test_error("test_wait_fd()");
test_error("test_skpair_wait_poll()");
} else {
if (fault(TIMEOUT))
test_fail("ready to accept");
test_fail("%s: ready to accept", tst_name);
sk = accept(lsk, NULL, NULL);
if (sk < 0) {
@@ -72,13 +76,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_tcp_ao_counters_cmp(tst_name, &ao_cnt1, &ao_cnt2, cnt_expected);
test_assert_counters(tst_name, &cnt1, &cnt2, cnt_expected);
if (!cnt_name)
goto out;
@@ -109,7 +113,7 @@ static void *server_fn(void *arg)
try_accept("Non-AO server + AO client", port++, NULL,
this_ip_dest, -1, 100, 100, 0,
"TCPAOKeyNotFound", 0, FAULT_TIMEOUT);
"TCPAOKeyNotFound", TEST_CNT_NS_KEY_NOT_FOUND, FAULT_TIMEOUT);
try_accept("AO server + Non-AO client", port++, DEFAULT_TEST_PASSWORD,
this_ip_dest, -1, 100, 100, 0,
@@ -135,8 +139,9 @@ static void *server_fn(void *arg)
wrong_addr, -1, 100, 100, 0,
"TCPAOKeyNotFound", TEST_CNT_AO_KEY_NOT_FOUND, FAULT_TIMEOUT);
/* Key rejected by the other side, failing short through skpair */
try_accept("Client: Wrong addr", port++, NULL,
this_ip_dest, -1, 100, 100, 0, NULL, 0, FAULT_TIMEOUT);
this_ip_dest, -1, 100, 100, 0, NULL, 0, FAULT_KEYREJECT);
try_accept("rcv id != snd id", port++, DEFAULT_TEST_PASSWORD,
this_ip_dest, -1, 200, 100, 0,
@@ -163,8 +168,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;
time_t timeout;
struct tcp_counters cnt1, cnt2;
int sk, ret;
sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
@@ -174,16 +178,15 @@ 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 */
timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
ret = _test_connect_socket(sk, this_ip_dest, port, timeout);
ret = test_skpair_connect_poll(sk, this_ip_dest, port, cnt_expected, &sk_pair);
synchronize_threads(); /* before counter checks */
if (ret < 0) {
sk_pair = ret;
if (fault(KEYREJECT) && ret == -EKEYREJECTED) {
test_ok("%s: connect() was prevented", tst_name);
} else if (ret == -ETIMEDOUT && fault(TIMEOUT)) {
@@ -202,9 +205,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_tcp_ao_counters_cmp(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() */
@@ -241,6 +246,11 @@ static void *client_fn(void *arg)
try_connect("Wrong rcv id", port++, DEFAULT_TEST_PASSWORD,
this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
/*
* XXX: The test doesn't increase any counters, see tcp_make_synack().
* Potentially, it can be speed up by setting sk_pair = -ETIMEDOUT
* but the price would be increased complexity of the tracer thread.
*/
trace_ao_event_sk_expect(TCP_AO_SYNACK_NO_KEY, this_ip_dest, addr_any,
port, 0, 100, 100);
try_connect("Wrong snd id", port++, DEFAULT_TEST_PASSWORD,

View File

@@ -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,18 +50,18 @@ 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)) {
if (test_client_verify(sk, 100, nr_packets)) {
test_fail("verify failed");
return NULL;
}
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);
@@ -71,14 +71,14 @@ static void *client_fn(void *arg)
nr_packets, after_aogood, before_aogood);
return NULL;
}
if (test_tcp_ao_counters_cmp("connect", &ao1, &ao2, TEST_CNT_GOOD))
if (test_assert_counters("connect", &ao1, &ao2, TEST_CNT_GOOD))
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;
}

View File

@@ -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_tcp_ao_counters_cmp(NULL, &ao_cnt1, &ao_cnt2, TEST_CNT_GOOD);
test_assert_counters(NULL, &cnt1, &cnt2, TEST_CNT_GOOD);
#else
test_tcp_ao_counters_cmp(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,
@@ -395,7 +395,6 @@ static void icmp_interfere(const size_t nr, uint32_t rcv_nxt, void *src, void *d
static void send_interfered(int sk)
{
const unsigned int timeout = TEST_TIMEOUT_SEC;
struct sockaddr_in6 src, dst;
socklen_t addr_sz;
@@ -409,7 +408,7 @@ static void send_interfered(int sk)
while (1) {
uint32_t rcv_nxt;
if (test_client_verify(sk, packet_size, packets_nr, timeout)) {
if (test_client_verify(sk, packet_size, packets_nr)) {
test_fail("client: connection is broken");
return;
}

View File

@@ -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_tcp_ao_counters_cmp(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_tcp_ao_key_counters_cmp(tst_name, a, b,
rx_cnt_expected ? TEST_CNT_KEY_GOOD : 0,
sndid, rcvid);
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)
@@ -918,11 +918,11 @@ static int run_client(const char *tst_name, unsigned int port,
collection.keys[rnext_index].used_on_server_tx = 1;
synchronize_threads(); /* 3: accepted => send data */
if (test_client_verify(sk, msg_sz, msg_nr, TEST_TIMEOUT_SEC)) {
if (test_client_verify(sk, msg_sz, msg_nr)) {
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);
@@ -1016,7 +1016,7 @@ static void try_unmatched_keys(int sk, int *rnext_index, unsigned int port)
trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, this_ip_addr, this_ip_dest,
-1, port, 0, -1, -1, -1, -1, -1,
-1, key->server_keyid, -1);
if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
if (test_client_verify(sk, msg_len, nr_packets))
test_fail("verify failed");
*rnext_index = i;
}
@@ -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,
@@ -1061,7 +1061,7 @@ static void check_current_back(const char *tst_name, unsigned int port,
port, -1, 0, -1, -1, -1, -1, -1,
collection.keys[rotate_to_index].client_keyid,
collection.keys[current_index].client_keyid, -1);
if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
if (test_client_verify(sk, msg_len, nr_packets))
test_fail("verify failed");
/* There is a race here: between setting the current_key with
* setsockopt(TCP_AO_INFO) and starting to send some data - there
@@ -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;
@@ -1099,10 +1099,10 @@ static void roll_over_keys(const char *tst_name, unsigned int port,
collection.keys[i].server_keyid, -1);
if (test_set_key(sk, -1, collection.keys[i].server_keyid))
test_error("Can't change the Rnext key");
if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC)) {
if (test_client_verify(sk, msg_len, nr_packets)) {
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,

View File

@@ -289,7 +289,7 @@ extern int link_set_up(const char *intf);
extern const unsigned int test_server_port;
extern int test_wait_fd(int sk, time_t sec, bool write);
extern int __test_connect_socket(int sk, const char *device,
void *addr, size_t addr_sz, time_t timeout);
void *addr, size_t addr_sz, bool async);
extern int __test_listen_socket(int backlog, void *addr, size_t addr_sz);
static inline int test_listen_socket(const union tcp_addr taddr,
@@ -331,25 +331,26 @@ static inline int test_listen_socket(const union tcp_addr taddr,
* If set to 0 - kernel will try to retransmit SYN number of times, set in
* /proc/sys/net/ipv4/tcp_syn_retries
* By default set to 1 to make tests pass faster on non-busy machine.
* [in process of removal, don't use in new tests]
*/
#ifndef TEST_RETRANSMIT_SEC
#define TEST_RETRANSMIT_SEC 1
#endif
static inline int _test_connect_socket(int sk, const union tcp_addr taddr,
unsigned int port, time_t timeout)
unsigned int port, bool async)
{
sockaddr_af addr;
tcp_addr_to_sockaddr_in(&addr, &taddr, htons(port));
return __test_connect_socket(sk, veth_name,
(void *)&addr, sizeof(addr), timeout);
(void *)&addr, sizeof(addr), async);
}
static inline int test_connect_socket(int sk, const union tcp_addr taddr,
unsigned int port)
{
return _test_connect_socket(sk, taddr, port, TEST_TIMEOUT_SEC);
return _test_connect_socket(sk, taddr, port, false);
}
extern int __test_set_md5(int sk, void *addr, size_t addr_sz,
@@ -483,10 +484,7 @@ static inline int test_set_ao_flags(int sk, bool ao_required, bool accept_icmps)
}
extern ssize_t test_server_run(int sk, ssize_t quota, time_t timeout_sec);
extern ssize_t test_client_loop(int sk, char *buf, size_t buf_sz,
const size_t msg_len, time_t timeout_sec);
extern int test_client_verify(int sk, const size_t msg_len, const size_t nr,
time_t timeout_sec);
extern int test_client_verify(int sk, const size_t msg_len, const size_t nr);
struct tcp_ao_key_counters {
uint8_t sndid;
@@ -512,7 +510,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,8 +532,31 @@ 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(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.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)
#define TEST_CNT_AO_BAD (TEST_CNT_SOCK_BAD | TEST_CNT_NS_BAD)
#define TEST_CNT_AO_KEY_NOT_FOUND (TEST_CNT_SOCK_KEY_NOT_FOUND | \
@@ -539,34 +568,71 @@ typedef uint16_t test_cnt;
#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_tcp_ao_counters_cmp(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_tcp_ao_key_counters_cmp(const char *tst_name,
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().
* Polling for netns and socket counters during select()/connect() and also
* client/server messaging. Instead of constant timeout on underlying select(),
* check the counters and return early. This allows to pass the tests where
* timeout is expected without waiting for that fixing timeout (tests speed-up).
* Previously shorter timeouts were used for tests expecting to time out,
* but that leaded to sporadic false positives on counter checks failures,
* as one second timeouts aren't enough for TCP retransmit.
*
* Two sides of the socketpair (client/server) should synchronize failures
* using a shared variable *err, so that they can detect the other side's
* failure.
*/
extern int test_skpair_wait_poll(int sk, bool write, test_cnt cond,
volatile int *err);
extern int _test_skpair_connect_poll(int sk, const char *device,
void *addr, size_t addr_sz,
test_cnt cond, volatile int *err);
static inline int test_skpair_connect_poll(int sk, const union tcp_addr taddr,
unsigned int port,
test_cnt cond, volatile int *err)
{
sockaddr_af addr;
tcp_addr_to_sockaddr_in(&addr, &taddr, htons(port));
return _test_skpair_connect_poll(sk, veth_name,
(void *)&addr, sizeof(addr), cond, err);
}
extern int test_skpair_client(int sk, const size_t msg_len, const size_t nr,
test_cnt cond, volatile int *err);
extern int test_skpair_server(int sk, ssize_t quota,
test_cnt cond, volatile int *err);
/*
* 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_tcp_ao_counters_cmp(const char *tst_name,
struct tcp_ao_counters *before,
struct tcp_ao_counters *after,
test_cnt expected)
static inline int test_assert_counters(const char *tst_name,
struct tcp_counters *before,
struct tcp_counters *after,
test_cnt expected)
{
int ret;
ret = __test_tcp_ao_counters_cmp(tst_name, before, after, expected);
ret = test_assert_counters_sk(tst_name, before, after, expected);
if (ret)
goto out;
ret = test_tcp_ao_key_counters_cmp(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;
}

View File

@@ -427,11 +427,8 @@ static void dump_trace_event(struct expected_trace_point *e)
test_print("trace event filter %s [%s:%d => %s:%d, L3index %d, flags: %s%s%s%s%s, keyid: %d, rnext: %d, maclen: %d, sne: %d] = %zu",
trace_event_names[e->type],
src, e->src_port, dst, e->dst_port, e->L3index,
(e->fin > 0) ? "F" : (e->fin == 0) ? "!F" : "",
(e->syn > 0) ? "S" : (e->syn == 0) ? "!S" : "",
(e->rst > 0) ? "R" : (e->rst == 0) ? "!R" : "",
(e->psh > 0) ? "P" : (e->psh == 0) ? "!P" : "",
(e->ack > 0) ? "." : (e->ack == 0) ? "!." : "",
e->fin ? "F" : "", e->syn ? "S" : "", e->rst ? "R" : "",
e->psh ? "P" : "", e->ack ? "." : "",
e->keyid, e->rnext, e->maclen, e->sne, e->matched);
}

View File

@@ -34,10 +34,8 @@ int __test_listen_socket(int backlog, void *addr, size_t addr_sz)
return sk;
}
int test_wait_fd(int sk, time_t sec, bool write)
static int __test_wait_fd(int sk, struct timeval *tv, bool write)
{
struct timeval tv = { .tv_sec = sec };
struct timeval *ptv = NULL;
fd_set fds, efds;
int ret;
socklen_t slen = sizeof(ret);
@@ -47,14 +45,11 @@ int test_wait_fd(int sk, time_t sec, bool write)
FD_ZERO(&efds);
FD_SET(sk, &efds);
if (sec)
ptv = &tv;
errno = 0;
if (write)
ret = select(sk + 1, NULL, &fds, &efds, ptv);
ret = select(sk + 1, NULL, &fds, &efds, tv);
else
ret = select(sk + 1, &fds, NULL, &efds, ptv);
ret = select(sk + 1, &fds, NULL, &efds, tv);
if (ret < 0)
return -errno;
if (ret == 0) {
@@ -69,8 +64,54 @@ int test_wait_fd(int sk, time_t sec, bool write)
return 0;
}
int test_wait_fd(int sk, time_t sec, bool write)
{
struct timeval tv = { .tv_sec = sec, };
return __test_wait_fd(sk, sec ? &tv : NULL, write);
}
static bool __skpair_poll_should_stop(int sk, struct tcp_counters *c,
test_cnt condition)
{
struct tcp_counters c2;
test_cnt diff;
if (test_get_tcp_counters(sk, &c2))
test_error("test_get_tcp_counters()");
diff = test_cmp_counters(c, &c2);
test_tcp_counters_free(&c2);
return (diff & condition) == condition;
}
/* How often wake up and check netns counters & paired (*err) */
#define POLL_USEC 150
static int __test_skpair_poll(int sk, bool write, uint64_t timeout,
struct tcp_counters *c, test_cnt cond,
volatile int *err)
{
uint64_t t;
for (t = 0; t <= timeout * 1000000; t += POLL_USEC) {
struct timeval tv = { .tv_usec = POLL_USEC, };
int ret;
ret = __test_wait_fd(sk, &tv, write);
if (ret != -ETIMEDOUT)
return ret;
if (c && cond && __skpair_poll_should_stop(sk, c, cond))
break;
if (err && *err)
return *err;
}
if (err)
*err = -ETIMEDOUT;
return -ETIMEDOUT;
}
int __test_connect_socket(int sk, const char *device,
void *addr, size_t addr_sz, time_t timeout)
void *addr, size_t addr_sz, bool async)
{
long flags;
int err;
@@ -82,15 +123,6 @@ int __test_connect_socket(int sk, const char *device,
test_error("setsockopt(SO_BINDTODEVICE, %s)", device);
}
if (!timeout) {
err = connect(sk, addr, addr_sz);
if (err) {
err = -errno;
goto out;
}
return 0;
}
flags = fcntl(sk, F_GETFL);
if ((flags < 0) || (fcntl(sk, F_SETFL, flags | O_NONBLOCK) < 0))
test_error("fcntl()");
@@ -100,9 +132,9 @@ int __test_connect_socket(int sk, const char *device,
err = -errno;
goto out;
}
if (timeout < 0)
if (async)
return sk;
err = test_wait_fd(sk, timeout, 1);
err = test_wait_fd(sk, TEST_TIMEOUT_SEC, 1);
if (err)
goto out;
}
@@ -113,6 +145,45 @@ int __test_connect_socket(int sk, const char *device,
return err;
}
int test_skpair_wait_poll(int sk, bool write,
test_cnt cond, volatile int *err)
{
struct tcp_counters c;
int ret;
*err = 0;
if (test_get_tcp_counters(sk, &c))
test_error("test_get_tcp_counters()");
synchronize_threads(); /* 1: init skpair & read nscounters */
ret = __test_skpair_poll(sk, write, TEST_TIMEOUT_SEC, &c, cond, err);
test_tcp_counters_free(&c);
return ret;
}
int _test_skpair_connect_poll(int sk, const char *device,
void *addr, size_t addr_sz,
test_cnt condition, volatile int *err)
{
struct tcp_counters c;
int ret;
*err = 0;
if (test_get_tcp_counters(sk, &c))
test_error("test_get_tcp_counters()");
synchronize_threads(); /* 1: init skpair & read nscounters */
ret = __test_connect_socket(sk, device, addr, addr_sz, true);
if (ret < 0) {
test_tcp_counters_free(&c);
return (*err = ret);
}
ret = __test_skpair_poll(sk, 1, TEST_TIMEOUT_SEC, &c, condition, err);
if (ret < 0)
close(sk);
test_tcp_counters_free(&c);
return ret;
}
int __test_set_md5(int sk, void *addr, size_t addr_sz, uint8_t prefix,
int vrf, const char *password)
{
@@ -333,12 +404,12 @@ do { \
return 0;
}
int test_get_tcp_ao_counters(int sk, struct tcp_ao_counters *out)
int test_get_tcp_counters(int sk, struct tcp_counters *out)
{
struct tcp_ao_getsockopt *key_dump;
socklen_t key_dump_sz = sizeof(*key_dump);
struct tcp_ao_info_opt info = {};
bool c1, c2, c3, c4, c5;
bool c1, c2, c3, c4, c5, c6, c7, c8;
struct netstat *ns;
int err, nr_keys;
@@ -346,25 +417,30 @@ int test_get_tcp_ao_counters(int sk, struct tcp_ao_counters *out)
/* per-netns */
ns = netstat_read();
out->netns_ao_good = netstat_get(ns, "TCPAOGood", &c1);
out->netns_ao_bad = netstat_get(ns, "TCPAOBad", &c2);
out->netns_ao_key_not_found = netstat_get(ns, "TCPAOKeyNotFound", &c3);
out->netns_ao_required = netstat_get(ns, "TCPAORequired", &c4);
out->netns_ao_dropped_icmp = netstat_get(ns, "TCPAODroppedIcmps", &c5);
out->ao.netns_ao_good = netstat_get(ns, "TCPAOGood", &c1);
out->ao.netns_ao_bad = netstat_get(ns, "TCPAOBad", &c2);
out->ao.netns_ao_key_not_found = netstat_get(ns, "TCPAOKeyNotFound", &c3);
out->ao.netns_ao_required = netstat_get(ns, "TCPAORequired", &c4);
out->ao.netns_ao_dropped_icmp = netstat_get(ns, "TCPAODroppedIcmps", &c5);
out->netns_md5_notfound = netstat_get(ns, "TCPMD5NotFound", &c6);
out->netns_md5_unexpected = netstat_get(ns, "TCPMD5Unexpected", &c7);
out->netns_md5_failure = netstat_get(ns, "TCPMD5Failure", &c8);
netstat_free(ns);
if (c1 || c2 || c3 || c4 || c5)
if (c1 || c2 || c3 || c4 || c5 || c6 || c7 || c8)
return -EOPNOTSUPP;
err = test_get_ao_info(sk, &info);
if (err == -ENOENT)
return 0;
if (err)
return err;
/* per-socket */
out->ao_info_pkt_good = info.pkt_good;
out->ao_info_pkt_bad = info.pkt_bad;
out->ao_info_pkt_key_not_found = info.pkt_key_not_found;
out->ao_info_pkt_ao_required = info.pkt_ao_required;
out->ao_info_pkt_dropped_icmp = info.pkt_dropped_icmp;
out->ao.ao_info_pkt_good = info.pkt_good;
out->ao.ao_info_pkt_bad = info.pkt_bad;
out->ao.ao_info_pkt_key_not_found = info.pkt_key_not_found;
out->ao.ao_info_pkt_ao_required = info.pkt_ao_required;
out->ao.ao_info_pkt_dropped_icmp = info.pkt_dropped_icmp;
/* per-key */
nr_keys = test_get_ao_keys_nr(sk);
@@ -372,7 +448,7 @@ int test_get_tcp_ao_counters(int sk, struct tcp_ao_counters *out)
return nr_keys;
if (nr_keys == 0)
test_error("test_get_ao_keys_nr() == 0");
out->nr_keys = (size_t)nr_keys;
out->ao.nr_keys = (size_t)nr_keys;
key_dump = calloc(nr_keys, key_dump_sz);
if (!key_dump)
return -errno;
@@ -386,72 +462,84 @@ int test_get_tcp_ao_counters(int sk, struct tcp_ao_counters *out)
return -errno;
}
out->key_cnts = calloc(nr_keys, sizeof(out->key_cnts[0]));
if (!out->key_cnts) {
out->ao.key_cnts = calloc(nr_keys, sizeof(out->ao.key_cnts[0]));
if (!out->ao.key_cnts) {
free(key_dump);
return -errno;
}
while (nr_keys--) {
out->key_cnts[nr_keys].sndid = key_dump[nr_keys].sndid;
out->key_cnts[nr_keys].rcvid = key_dump[nr_keys].rcvid;
out->key_cnts[nr_keys].pkt_good = key_dump[nr_keys].pkt_good;
out->key_cnts[nr_keys].pkt_bad = key_dump[nr_keys].pkt_bad;
out->ao.key_cnts[nr_keys].sndid = key_dump[nr_keys].sndid;
out->ao.key_cnts[nr_keys].rcvid = key_dump[nr_keys].rcvid;
out->ao.key_cnts[nr_keys].pkt_good = key_dump[nr_keys].pkt_good;
out->ao.key_cnts[nr_keys].pkt_bad = key_dump[nr_keys].pkt_bad;
}
free(key_dump);
return 0;
}
int __test_tcp_ao_counters_cmp(const char *tst_name,
struct tcp_ao_counters *before,
struct tcp_ao_counters *after,
test_cnt expected)
test_cnt test_cmp_counters(struct tcp_counters *before,
struct tcp_counters *after)
{
#define __cmp_ao(cnt, expecting_inc) \
#define __cmp(cnt, e_cnt) \
do { \
if (before->cnt > after->cnt) \
test_error("counter " __stringify(cnt) " decreased"); \
if (before->cnt != after->cnt) \
ret |= e_cnt; \
} while (0)
test_cnt ret = 0;
size_t i;
if (before->ao.nr_keys != after->ao.nr_keys)
test_error("the number of keys has changed");
_for_each_counter(__cmp);
i = before->ao.nr_keys;
while (i--) {
__cmp(ao.key_cnts[i].pkt_good, TEST_CNT_KEY_GOOD);
__cmp(ao.key_cnts[i].pkt_bad, TEST_CNT_KEY_BAD);
}
#undef __cmp
return ret;
}
int test_assert_counters_sk(const char *tst_name,
struct tcp_counters *before,
struct tcp_counters *after,
test_cnt expected)
{
#define __cmp_ao(cnt, e_cnt) \
do { \
if (before->cnt > after->cnt) { \
test_fail("%s: Decreased counter " __stringify(cnt) " %" PRIu64 " > %" PRIu64, \
tst_name ?: "", before->cnt, after->cnt); \
tst_name ?: "", before->cnt, after->cnt); \
return -1; \
} \
if ((before->cnt != after->cnt) != (expecting_inc)) { \
if ((before->cnt != after->cnt) != !!(expected & e_cnt)) { \
test_fail("%s: Counter " __stringify(cnt) " was %sexpected to increase %" PRIu64 " => %" PRIu64, \
tst_name ?: "", (expecting_inc) ? "" : "not ", \
tst_name ?: "", (expected & e_cnt) ? "" : "not ", \
before->cnt, after->cnt); \
return -1; \
} \
} while(0)
} while (0)
errno = 0;
/* per-netns */
__cmp_ao(netns_ao_good, !!(expected & TEST_CNT_NS_GOOD));
__cmp_ao(netns_ao_bad, !!(expected & TEST_CNT_NS_BAD));
__cmp_ao(netns_ao_key_not_found,
!!(expected & TEST_CNT_NS_KEY_NOT_FOUND));
__cmp_ao(netns_ao_required, !!(expected & TEST_CNT_NS_AO_REQUIRED));
__cmp_ao(netns_ao_dropped_icmp,
!!(expected & TEST_CNT_NS_DROPPED_ICMP));
/* per-socket */
__cmp_ao(ao_info_pkt_good, !!(expected & TEST_CNT_SOCK_GOOD));
__cmp_ao(ao_info_pkt_bad, !!(expected & TEST_CNT_SOCK_BAD));
__cmp_ao(ao_info_pkt_key_not_found,
!!(expected & TEST_CNT_SOCK_KEY_NOT_FOUND));
__cmp_ao(ao_info_pkt_ao_required, !!(expected & TEST_CNT_SOCK_AO_REQUIRED));
__cmp_ao(ao_info_pkt_dropped_icmp,
!!(expected & TEST_CNT_SOCK_DROPPED_ICMP));
_for_each_counter(__cmp_ao);
return 0;
#undef __cmp_ao
}
int test_tcp_ao_key_counters_cmp(const char *tst_name,
struct tcp_ao_counters *before,
struct tcp_ao_counters *after,
test_cnt expected,
int sndid, int rcvid)
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)
{
size_t i;
#define __cmp_ao(i, cnt, expecting_inc) \
#define __cmp_ao(i, cnt, e_cnt) \
do { \
if (before->key_cnts[i].cnt > after->key_cnts[i].cnt) { \
test_fail("%s: Decreased counter " __stringify(cnt) " %" PRIu64 " > %" PRIu64 " for key %u:%u", \
@@ -461,16 +549,16 @@ do { \
before->key_cnts[i].rcvid); \
return -1; \
} \
if ((before->key_cnts[i].cnt != after->key_cnts[i].cnt) != (expecting_inc)) { \
if ((before->key_cnts[i].cnt != after->key_cnts[i].cnt) != !!(expected & e_cnt)) { \
test_fail("%s: Counter " __stringify(cnt) " was %sexpected to increase %" PRIu64 " => %" PRIu64 " for key %u:%u", \
tst_name ?: "", (expecting_inc) ? "" : "not ",\
tst_name ?: "", (expected & e_cnt) ? "" : "not ",\
before->key_cnts[i].cnt, \
after->key_cnts[i].cnt, \
before->key_cnts[i].sndid, \
before->key_cnts[i].rcvid); \
return -1; \
} \
} while(0)
} while (0)
if (before->nr_keys != after->nr_keys) {
test_fail("%s: Keys changed on the socket %zu != %zu",
@@ -485,20 +573,22 @@ do { \
continue;
if (rcvid >= 0 && before->key_cnts[i].rcvid != rcvid)
continue;
__cmp_ao(i, pkt_good, !!(expected & TEST_CNT_KEY_GOOD));
__cmp_ao(i, pkt_bad, !!(expected & TEST_CNT_KEY_BAD));
__cmp_ao(i, pkt_good, TEST_CNT_KEY_GOOD);
__cmp_ao(i, pkt_bad, TEST_CNT_KEY_BAD);
}
return 0;
#undef __cmp_ao
}
void test_tcp_ao_counters_free(struct tcp_ao_counters *cnts)
void test_tcp_counters_free(struct tcp_counters *cnts)
{
free(cnts->key_cnts);
free(cnts->ao.key_cnts);
}
#define TEST_BUF_SIZE 4096
ssize_t test_server_run(int sk, ssize_t quota, time_t timeout_sec)
static ssize_t _test_server_run(int sk, ssize_t quota, struct tcp_counters *c,
test_cnt cond, volatile int *err,
time_t timeout_sec)
{
ssize_t total = 0;
@@ -507,7 +597,7 @@ ssize_t test_server_run(int sk, ssize_t quota, time_t timeout_sec)
ssize_t bytes, sent;
int ret;
ret = test_wait_fd(sk, timeout_sec, 0);
ret = __test_skpair_poll(sk, 0, timeout_sec, c, cond, err);
if (ret)
return ret;
@@ -518,7 +608,7 @@ ssize_t test_server_run(int sk, ssize_t quota, time_t timeout_sec)
if (bytes == 0)
break;
ret = test_wait_fd(sk, timeout_sec, 1);
ret = __test_skpair_poll(sk, 1, timeout_sec, c, cond, err);
if (ret)
return ret;
@@ -533,13 +623,41 @@ ssize_t test_server_run(int sk, ssize_t quota, time_t timeout_sec)
return total;
}
ssize_t test_client_loop(int sk, char *buf, size_t buf_sz,
const size_t msg_len, time_t timeout_sec)
ssize_t test_server_run(int sk, ssize_t quota, time_t timeout_sec)
{
return _test_server_run(sk, quota, NULL, 0, NULL,
timeout_sec ?: TEST_TIMEOUT_SEC);
}
int test_skpair_server(int sk, ssize_t quota, test_cnt cond, volatile int *err)
{
struct tcp_counters c;
ssize_t ret;
*err = 0;
if (test_get_tcp_counters(sk, &c))
test_error("test_get_tcp_counters()");
synchronize_threads(); /* 1: init skpair & read nscounters */
ret = _test_server_run(sk, quota, &c, cond, err, TEST_TIMEOUT_SEC);
test_tcp_counters_free(&c);
return ret;
}
static ssize_t test_client_loop(int sk, size_t buf_sz, const size_t msg_len,
struct tcp_counters *c, test_cnt cond,
volatile int *err)
{
char msg[msg_len];
int nodelay = 1;
char *buf;
size_t i;
buf = alloca(buf_sz);
if (!buf)
return -ENOMEM;
randomize_buffer(buf, buf_sz);
if (setsockopt(sk, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)))
test_error("setsockopt(TCP_NODELAY)");
@@ -547,7 +665,7 @@ ssize_t test_client_loop(int sk, char *buf, size_t buf_sz,
size_t sent, bytes = min(msg_len, buf_sz - i);
int ret;
ret = test_wait_fd(sk, timeout_sec, 1);
ret = __test_skpair_poll(sk, 1, TEST_TIMEOUT_SEC, c, cond, err);
if (ret)
return ret;
@@ -561,7 +679,8 @@ ssize_t test_client_loop(int sk, char *buf, size_t buf_sz,
do {
ssize_t got;
ret = test_wait_fd(sk, timeout_sec, 0);
ret = __test_skpair_poll(sk, 0, TEST_TIMEOUT_SEC,
c, cond, err);
if (ret)
return ret;
@@ -580,15 +699,31 @@ ssize_t test_client_loop(int sk, char *buf, size_t buf_sz,
return i;
}
int test_client_verify(int sk, const size_t msg_len, const size_t nr,
time_t timeout_sec)
int test_client_verify(int sk, const size_t msg_len, const size_t nr)
{
size_t buf_sz = msg_len * nr;
char *buf = alloca(buf_sz);
ssize_t ret;
randomize_buffer(buf, buf_sz);
ret = test_client_loop(sk, buf, buf_sz, msg_len, timeout_sec);
ret = test_client_loop(sk, buf_sz, msg_len, NULL, 0, NULL);
if (ret < 0)
return (int)ret;
return ret != buf_sz ? -1 : 0;
}
int test_skpair_client(int sk, const size_t msg_len, const size_t nr,
test_cnt cond, volatile int *err)
{
struct tcp_counters c;
size_t buf_sz = msg_len * nr;
ssize_t ret;
*err = 0;
if (test_get_tcp_counters(sk, &c))
test_error("test_get_tcp_counters()");
synchronize_threads(); /* 1: init skpair & read nscounters */
ret = test_client_loop(sk, buf_sz, msg_len, &c, cond, err);
test_tcp_counters_free(&c);
if (ret < 0)
return (int)ret;
return ret != buf_sz ? -1 : 0;

View File

@@ -16,11 +16,11 @@ const size_t quota = nr_packets * msg_len;
static void try_server_run(const char *tst_name, unsigned int port,
fault_t inj, test_cnt cnt_expected)
{
test_cnt poll_cnt = (cnt_expected == TEST_CNT_GOOD) ? 0 : cnt_expected;
const char *cnt_name = "TCPAOGood";
struct tcp_ao_counters ao1, ao2;
struct tcp_counters cnt1, cnt2;
uint64_t before_cnt, after_cnt;
int sk, lsk;
time_t timeout;
int sk, lsk, dummy;
ssize_t bytes;
if (fault(TIMEOUT))
@@ -48,11 +48,10 @@ static void try_server_run(const char *tst_name, unsigned int port,
}
before_cnt = netstat_get_one(cnt_name, NULL);
if (test_get_tcp_ao_counters(sk, &ao1))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(sk, &cnt1))
test_error("test_get_tcp_counters()");
timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
bytes = test_server_run(sk, quota, timeout);
bytes = test_skpair_server(sk, quota, poll_cnt, &dummy);
if (fault(TIMEOUT)) {
if (bytes > 0)
test_fail("%s: server served: %zd", tst_name, bytes);
@@ -65,17 +64,17 @@ static void try_server_run(const char *tst_name, unsigned int port,
test_ok("%s: server alive", tst_name);
}
synchronize_threads(); /* 3: counters checks */
if (test_get_tcp_ao_counters(sk, &ao2))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(sk, &cnt2))
test_error("test_get_tcp_counters()");
after_cnt = netstat_get_one(cnt_name, NULL);
test_tcp_ao_counters_cmp(tst_name, &ao1, &ao2, cnt_expected);
test_assert_counters(tst_name, &cnt1, &cnt2, cnt_expected);
if (after_cnt <= before_cnt) {
test_fail("%s: %s counter did not increase: %" PRIu64 " <= %" PRIu64,
tst_name, cnt_name, after_cnt, before_cnt);
test_fail("%s(server): %s counter did not increase: %" PRIu64 " <= %" PRIu64,
tst_name, cnt_name, after_cnt, before_cnt);
} else {
test_ok("%s: counter %s increased %" PRIu64 " => %" PRIu64,
test_ok("%s(server): counter %s increased %" PRIu64 " => %" PRIu64,
tst_name, cnt_name, before_cnt, after_cnt);
}
@@ -92,16 +91,16 @@ static void *server_fn(void *arg)
{
unsigned int port = test_server_port;
try_server_run("TCP-AO migrate to another socket", port++,
try_server_run("TCP-AO migrate to another socket (server)", port++,
0, TEST_CNT_GOOD);
try_server_run("TCP-AO with wrong send ISN", port++,
try_server_run("TCP-AO with wrong send ISN (server)", port++,
FAULT_TIMEOUT, TEST_CNT_BAD);
try_server_run("TCP-AO with wrong receive ISN", port++,
try_server_run("TCP-AO with wrong receive ISN (server)", port++,
FAULT_TIMEOUT, TEST_CNT_BAD);
try_server_run("TCP-AO with wrong send SEQ ext number", port++,
try_server_run("TCP-AO with wrong send SEQ ext number (server)", 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);
try_server_run("TCP-AO with wrong receive SEQ ext number (server)",
port++, FAULT_TIMEOUT, TEST_CNT_NS_BAD | TEST_CNT_GOOD);
synchronize_threads(); /* don't race to exit: client exits */
return NULL;
@@ -125,7 +124,7 @@ static void test_get_sk_checkpoint(unsigned int server_port, sockaddr_af *saddr,
test_error("failed to connect()");
synchronize_threads(); /* 2: accepted => send data */
if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
if (test_client_verify(sk, msg_len, nr_packets))
test_fail("pre-migrate verify failed");
test_enable_repair(sk);
@@ -139,11 +138,11 @@ static void test_sk_restore(const char *tst_name, unsigned int server_port,
struct tcp_ao_repair *ao_img,
fault_t inj, test_cnt cnt_expected)
{
test_cnt poll_cnt = (cnt_expected == TEST_CNT_GOOD) ? 0 : cnt_expected;
const char *cnt_name = "TCPAOGood";
struct tcp_ao_counters ao1, ao2;
struct tcp_counters cnt1, cnt2;
uint64_t before_cnt, after_cnt;
time_t timeout;
int sk;
int sk, dummy;
if (fault(TIMEOUT))
cnt_name = "TCPAOBad";
@@ -159,30 +158,30 @@ static void test_sk_restore(const char *tst_name, unsigned int server_port,
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()");
if (test_get_tcp_counters(sk, &cnt1))
test_error("test_get_tcp_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 (test_skpair_client(sk, msg_len, nr_packets, poll_cnt, &dummy)) {
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);
test_fail("%s: post-migrate connection is working", tst_name);
else
test_ok("%s: post-migrate connection is alive", tst_name);
}
synchronize_threads(); /* 3: counters checks */
if (test_get_tcp_ao_counters(sk, &ao2))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(sk, &cnt2))
test_error("test_get_tcp_counters()");
after_cnt = netstat_get_one(cnt_name, NULL);
test_tcp_ao_counters_cmp(tst_name, &ao1, &ao2, cnt_expected);
test_assert_counters(tst_name, &cnt1, &cnt2, cnt_expected);
if (after_cnt <= before_cnt) {
test_fail("%s: %s counter did not increase: %" PRIu64 " <= %" PRIu64,
@@ -203,7 +202,7 @@ static void *client_fn(void *arg)
sockaddr_af saddr;
test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
test_sk_restore("TCP-AO migrate to another socket", port++,
test_sk_restore("TCP-AO migrate to another socket (client)", port++,
&saddr, &tcp_img, &ao_img, 0, TEST_CNT_GOOD);
test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
@@ -212,7 +211,7 @@ static void *client_fn(void *arg)
-1, port, 0, -1, -1, -1, -1, -1, 100, 100, -1);
trace_ao_event_expect(TCP_AO_MISMATCH, this_ip_dest, this_ip_addr,
port, -1, 0, -1, -1, -1, -1, -1, 100, 100, -1);
test_sk_restore("TCP-AO with wrong send ISN", port++,
test_sk_restore("TCP-AO with wrong send ISN (client)", port++,
&saddr, &tcp_img, &ao_img, FAULT_TIMEOUT, TEST_CNT_BAD);
test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
@@ -221,7 +220,7 @@ static void *client_fn(void *arg)
-1, port, 0, -1, -1, -1, -1, -1, 100, 100, -1);
trace_ao_event_expect(TCP_AO_MISMATCH, this_ip_dest, this_ip_addr,
port, -1, 0, -1, -1, -1, -1, -1, 100, 100, -1);
test_sk_restore("TCP-AO with wrong receive ISN", port++,
test_sk_restore("TCP-AO with wrong receive ISN (client)", port++,
&saddr, &tcp_img, &ao_img, FAULT_TIMEOUT, TEST_CNT_BAD);
test_get_sk_checkpoint(port, &saddr, &tcp_img, &ao_img);
@@ -229,8 +228,8 @@ static void *client_fn(void *arg)
trace_ao_event_expect(TCP_AO_MISMATCH, this_ip_addr, this_ip_dest,
-1, port, 0, -1, -1, -1, -1, -1, 100, 100, -1);
/* not expecting server => client mismatches as only snd sne is broken */
test_sk_restore("TCP-AO with wrong send SEQ ext number", port++,
&saddr, &tcp_img, &ao_img, FAULT_TIMEOUT,
test_sk_restore("TCP-AO with wrong send SEQ ext number (client)",
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);
@@ -238,8 +237,8 @@ static void *client_fn(void *arg)
/* not expecting client => server mismatches as only rcv sne is broken */
trace_ao_event_expect(TCP_AO_MISMATCH, this_ip_dest, this_ip_addr,
port, -1, 0, -1, -1, -1, -1, -1, 100, 100, -1);
test_sk_restore("TCP-AO with wrong receive SEQ ext number", port++,
&saddr, &tcp_img, &ao_img, FAULT_TIMEOUT,
test_sk_restore("TCP-AO with wrong receive SEQ ext number (client)",
port++, &saddr, &tcp_img, &ao_img, FAULT_TIMEOUT,
TEST_CNT_NS_GOOD | TEST_CNT_BAD);
return NULL;

View File

@@ -84,15 +84,15 @@ static void close_forced(int sk)
static void test_server_active_rst(unsigned int port)
{
struct tcp_ao_counters cnt1, cnt2;
struct tcp_counters cnt1, cnt2;
ssize_t bytes;
int sk, lsk;
lsk = test_listen_socket(this_ip_addr, port, backlog);
if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
test_error("setsockopt(TCP_AO_ADD_KEY)");
if (test_get_tcp_ao_counters(lsk, &cnt1))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(lsk, &cnt1))
test_error("test_get_tcp_counters()");
synchronize_threads(); /* 1: MKT added */
if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
@@ -103,8 +103,8 @@ static void test_server_active_rst(unsigned int port)
test_error("accept()");
synchronize_threads(); /* 2: connection accept()ed, another queued */
if (test_get_tcp_ao_counters(lsk, &cnt2))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(lsk, &cnt2))
test_error("test_get_tcp_counters()");
synchronize_threads(); /* 3: close listen socket */
close(lsk);
@@ -120,7 +120,7 @@ static void test_server_active_rst(unsigned int port)
synchronize_threads(); /* 5: closed active sk */
synchronize_threads(); /* 6: counters checks */
if (test_tcp_ao_counters_cmp("active RST server", &cnt1, &cnt2, TEST_CNT_GOOD))
if (test_assert_counters("active RST server", &cnt1, &cnt2, TEST_CNT_GOOD))
test_fail("MKT counters (server) have not only good packets");
else
test_ok("MKT counters are good on server");
@@ -128,7 +128,7 @@ static void test_server_active_rst(unsigned int port)
static void test_server_passive_rst(unsigned int port)
{
struct tcp_ao_counters ao1, ao2;
struct tcp_counters cnt1, cnt2;
int sk, lsk;
ssize_t bytes;
@@ -147,8 +147,8 @@ static void test_server_passive_rst(unsigned int port)
synchronize_threads(); /* 2: accepted => send data */
close(lsk);
if (test_get_tcp_ao_counters(sk, &ao1))
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, quota, TEST_TIMEOUT_SEC);
if (bytes != quota) {
@@ -160,12 +160,12 @@ static void test_server_passive_rst(unsigned int port)
synchronize_threads(); /* 3: checkpoint the client */
synchronize_threads(); /* 4: close the server, creating twsk */
if (test_get_tcp_ao_counters(sk, &ao2))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(sk, &cnt2))
test_error("test_get_tcp_counters()");
close(sk);
synchronize_threads(); /* 5: restore the socket, send more data */
test_tcp_ao_counters_cmp("passive RST server", &ao1, &ao2, TEST_CNT_GOOD);
test_assert_counters("passive RST server", &cnt1, &cnt2, TEST_CNT_GOOD);
synchronize_threads(); /* 6: server exits */
}
@@ -271,8 +271,7 @@ static void test_client_active_rst(unsigned int port)
synchronize_threads(); /* 1: MKT added */
for (i = 0; i < last; i++) {
err = _test_connect_socket(sk[i], this_ip_dest, port,
(i == 0) ? TEST_TIMEOUT_SEC : -1);
err = _test_connect_socket(sk[i], this_ip_dest, port, i != 0);
if (err < 0)
test_error("failed to connect()");
}
@@ -283,12 +282,12 @@ static void test_client_active_rst(unsigned int port)
test_error("test_wait_fds(): %d", err);
/* async connect() with third sk to get into request_sock_queue */
err = _test_connect_socket(sk[last], this_ip_dest, port, -1);
err = _test_connect_socket(sk[last], this_ip_dest, port, 1);
if (err < 0)
test_error("failed to connect()");
synchronize_threads(); /* 3: close listen socket */
if (test_client_verify(sk[0], packet_sz, quota / packet_sz, TEST_TIMEOUT_SEC))
if (test_client_verify(sk[0], packet_sz, quota / packet_sz))
test_fail("Failed to send data on connected socket");
else
test_ok("Verified established tcp connection");
@@ -323,7 +322,7 @@ static void test_client_active_rst(unsigned int port)
static void test_client_passive_rst(unsigned int port)
{
struct tcp_ao_counters ao1, ao2;
struct tcp_counters cnt1, cnt2;
struct tcp_ao_repair ao_img;
struct tcp_sock_state img;
sockaddr_af saddr;
@@ -341,7 +340,7 @@ static void test_client_passive_rst(unsigned int port)
test_error("failed to connect()");
synchronize_threads(); /* 2: accepted => send data */
if (test_client_verify(sk, packet_sz, quota / packet_sz, TEST_TIMEOUT_SEC))
if (test_client_verify(sk, packet_sz, quota / packet_sz))
test_fail("Failed to send data on connected socket");
else
test_ok("Verified established tcp connection");
@@ -397,8 +396,8 @@ static void test_client_passive_rst(unsigned int port)
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()");
if (test_get_tcp_counters(sk, &cnt1))
test_error("test_get_tcp_counters()");
test_disable_repair(sk);
test_sock_state_free(&img);
@@ -417,7 +416,7 @@ static void test_client_passive_rst(unsigned int port)
* IP 10.0.254.1.7011 > 10.0.1.1.59772: Flags [R], seq 3215596252, win 0,
* options [tcp-ao keyid 100 rnextkeyid 100 mac 0x0bcfbbf497bce844312304b2], length 0
*/
err = test_client_verify(sk, packet_sz, quota / packet_sz, 2 * TEST_TIMEOUT_SEC);
err = test_client_verify(sk, packet_sz, quota / packet_sz);
/* Make sure that the connection was reset, not timeouted */
if (err && err == -ECONNRESET)
test_ok("client sock was passively reset post-seq-adjust");
@@ -426,12 +425,12 @@ static void test_client_passive_rst(unsigned int port)
else
test_fail("client sock is yet connected post-seq-adjust");
if (test_get_tcp_ao_counters(sk, &ao2))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(sk, &cnt2))
test_error("test_get_tcp_counters()");
synchronize_threads(); /* 6: server exits */
close(sk);
test_tcp_ao_counters_cmp("client passive RST", &ao1, &ao2, TEST_CNT_GOOD);
test_assert_counters("client passive RST", &cnt1, &cnt2, TEST_CNT_GOOD);
}
static void *client_fn(void *arg)

View File

@@ -30,7 +30,7 @@ static void setup_lo_intf(const char *lo_intf)
static void tcp_self_connect(const char *tst, unsigned int port,
bool different_keyids, bool check_restore)
{
struct tcp_ao_counters before_ao, after_ao;
struct tcp_counters before, after;
uint64_t before_aogood, after_aogood;
struct netstat *ns_before, *ns_after;
const size_t nr_packets = 20;
@@ -60,17 +60,17 @@ static void tcp_self_connect(const char *tst, unsigned int port,
ns_before = netstat_read();
before_aogood = netstat_get(ns_before, "TCPAOGood", NULL);
if (test_get_tcp_ao_counters(sk, &before_ao))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(sk, &before))
test_error("test_get_tcp_counters()");
if (__test_connect_socket(sk, "lo", (struct sockaddr *)&addr,
sizeof(addr), TEST_TIMEOUT_SEC) < 0) {
sizeof(addr), 0) < 0) {
ns_after = netstat_read();
netstat_print_diff(ns_before, ns_after);
test_error("failed to connect()");
}
if (test_client_verify(sk, 100, nr_packets, TEST_TIMEOUT_SEC)) {
if (test_client_verify(sk, 100, nr_packets)) {
test_fail("%s: tcp connection verify failed", tst);
close(sk);
return;
@@ -78,8 +78,8 @@ static void tcp_self_connect(const char *tst, unsigned int port,
ns_after = netstat_read();
after_aogood = netstat_get(ns_after, "TCPAOGood", NULL);
if (test_get_tcp_ao_counters(sk, &after_ao))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(sk, &after))
test_error("test_get_tcp_counters()");
if (!check_restore) {
/* to debug: netstat_print_diff(ns_before, ns_after); */
netstat_free(ns_before);
@@ -93,7 +93,7 @@ static void tcp_self_connect(const char *tst, unsigned int port,
return;
}
if (test_tcp_ao_counters_cmp(tst, &before_ao, &after_ao, TEST_CNT_GOOD)) {
if (test_assert_counters(tst, &before, &after, TEST_CNT_GOOD)) {
close(sk);
return;
}
@@ -136,7 +136,7 @@ static void tcp_self_connect(const char *tst, unsigned int port,
test_ao_restore(sk, &ao_img);
test_disable_repair(sk);
test_sock_state_free(&img);
if (test_client_verify(sk, 100, nr_packets, TEST_TIMEOUT_SEC)) {
if (test_client_verify(sk, 100, nr_packets)) {
test_fail("%s: tcp connection verify failed", tst);
close(sk);
return;

View File

@@ -40,7 +40,7 @@ static void test_adjust_seqs(struct tcp_sock_state *img,
static int test_sk_restore(struct tcp_sock_state *img,
struct tcp_ao_repair *ao_img, sockaddr_af *saddr,
const union tcp_addr daddr, unsigned int dport,
struct tcp_ao_counters *cnt)
struct tcp_counters *cnt)
{
int sk;
@@ -54,8 +54,8 @@ static int test_sk_restore(struct tcp_sock_state *img,
test_error("setsockopt(TCP_AO_ADD_KEY)");
test_ao_restore(sk, ao_img);
if (test_get_tcp_ao_counters(sk, cnt))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(sk, cnt))
test_error("test_get_tcp_counters()");
test_disable_repair(sk);
test_sock_state_free(img);
@@ -65,7 +65,7 @@ static int test_sk_restore(struct tcp_sock_state *img,
static void *server_fn(void *arg)
{
uint64_t before_good, after_good, after_bad;
struct tcp_ao_counters ao1, ao2;
struct tcp_counters cnt1, cnt2;
struct tcp_sock_state img;
struct tcp_ao_repair ao_img;
sockaddr_af saddr;
@@ -114,7 +114,7 @@ static void *server_fn(void *arg)
test_adjust_seqs(&img, &ao_img, true);
synchronize_threads(); /* 4: dump finished */
sk = test_sk_restore(&img, &ao_img, &saddr, this_ip_dest,
client_new_port, &ao1);
client_new_port, &cnt1);
trace_ao_event_sne_expect(TCP_AO_SND_SNE_UPDATE, this_ip_addr,
this_ip_dest, test_server_port + 1, client_new_port, 1);
@@ -136,11 +136,11 @@ static void *server_fn(void *arg)
}
synchronize_threads(); /* 6: verify counters after SEQ-number rollover */
if (test_get_tcp_ao_counters(sk, &ao2))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(sk, &cnt2))
test_error("test_get_tcp_counters()");
after_good = netstat_get_one("TCPAOGood", NULL);
test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD);
test_assert_counters(NULL, &cnt1, &cnt2, TEST_CNT_GOOD);
if (after_good <= before_good) {
test_fail("TCPAOGood counter did not increase: %" PRIu64 " <= %" PRIu64,
@@ -173,7 +173,7 @@ static void *server_fn(void *arg)
static void *client_fn(void *arg)
{
uint64_t before_good, after_good, after_bad;
struct tcp_ao_counters ao1, ao2;
struct tcp_counters cnt1, cnt2;
struct tcp_sock_state img;
struct tcp_ao_repair ao_img;
sockaddr_af saddr;
@@ -191,7 +191,7 @@ static void *client_fn(void *arg)
test_error("failed to connect()");
synchronize_threads(); /* 2: accepted => send data */
if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC)) {
if (test_client_verify(sk, msg_len, nr_packets)) {
test_fail("pre-migrate verify failed");
return NULL;
}
@@ -213,20 +213,20 @@ static void *client_fn(void *arg)
test_adjust_seqs(&img, &ao_img, false);
synchronize_threads(); /* 4: dump finished */
sk = test_sk_restore(&img, &ao_img, &saddr, this_ip_dest,
test_server_port + 1, &ao1);
test_server_port + 1, &cnt1);
synchronize_threads(); /* 5: verify the connection during SEQ-number rollover */
if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
if (test_client_verify(sk, msg_len, nr_packets))
test_fail("post-migrate verify failed");
else
test_ok("post-migrate connection alive");
synchronize_threads(); /* 5: verify counters after SEQ-number rollover */
if (test_get_tcp_ao_counters(sk, &ao2))
test_error("test_get_tcp_ao_counters()");
if (test_get_tcp_counters(sk, &cnt2))
test_error("test_get_tcp_counters()");
after_good = netstat_get_one("TCPAOGood", NULL);
test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD);
test_assert_counters(NULL, &cnt1, &cnt2, TEST_CNT_GOOD);
if (after_good <= before_good) {
test_fail("TCPAOGood counter did not increase: %" PRIu64 " <= %" PRIu64,

View File

@@ -6,6 +6,7 @@
#define fault(type) (inj == FAULT_ ## type)
static const char *md5_password = "Some evil genius, enemy to mankind, must have been the first contriver.";
static const char *ao_password = DEFAULT_TEST_PASSWORD;
static volatile int sk_pair;
static union tcp_addr client2;
static union tcp_addr client3;
@@ -41,10 +42,10 @@ static void try_accept(const char *tst_name, unsigned int port,
const char *cnt_name, test_cnt cnt_expected,
int needs_tcp_md5, 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;
test_cnt poll_cnt = (cnt_expected == TEST_CNT_GOOD) ? 0 : cnt_expected;
int lsk, err, sk = -1;
if (needs_tcp_md5 && should_skip_test(tst_name, KCONFIG_TCP_MD5))
return;
@@ -63,22 +64,25 @@ static void try_accept(const char *tst_name, unsigned int port,
if (cnt_name)
before_cnt = netstat_get_one(cnt_name, NULL);
if (ao_addr && test_get_tcp_ao_counters(lsk, &ao_cnt1))
test_error("test_get_tcp_ao_counters()");
if (ao_addr && test_get_tcp_counters(lsk, &cnt1))
test_error("test_get_tcp_counters()");
synchronize_threads(); /* preparations done */
timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
err = test_wait_fd(lsk, timeout, 0);
err = test_skpair_wait_poll(lsk, 0, poll_cnt, &sk_pair);
synchronize_threads(); /* connect()/accept() timeouts */
if (err == -ETIMEDOUT) {
sk_pair = err;
if (!fault(TIMEOUT))
test_fail("timed out for accept()");
test_fail("%s: timed out for accept()", tst_name);
} else if (err == -EKEYREJECTED) {
if (!fault(KEYREJECT))
test_fail("%s: key was rejected", tst_name);
} else if (err < 0) {
test_error("test_wait_fd()");
test_error("test_skpair_wait_poll()");
} else {
if (fault(TIMEOUT))
test_fail("ready to accept");
test_fail("%s: ready to accept", tst_name);
sk = accept(lsk, NULL, NULL);
if (sk < 0) {
@@ -89,8 +93,8 @@ static void try_accept(const char *tst_name, unsigned int port,
}
}
if (ao_addr && test_get_tcp_ao_counters(lsk, &ao_cnt2))
test_error("test_get_tcp_ao_counters()");
if (ao_addr && test_get_tcp_counters(lsk, &cnt2))
test_error("test_get_tcp_counters()");
close(lsk);
if (!cnt_name) {
@@ -108,11 +112,11 @@ static void try_accept(const char *tst_name, unsigned int port,
tst_name, cnt_name, before_cnt, after_cnt);
}
if (ao_addr)
test_tcp_ao_counters_cmp(tst_name, &ao_cnt1, &ao_cnt2, cnt_expected);
test_assert_counters(tst_name, &cnt1, &cnt2, cnt_expected);
out:
synchronize_threads(); /* test_kill_sk() */
if (sk > 0)
if (sk >= 0)
test_kill_sk(sk);
}
@@ -153,78 +157,82 @@ static void *server_fn(void *arg)
server_add_routes();
try_accept("AO server (INADDR_ANY): AO client", port++, NULL, 0,
try_accept("[server] AO server (INADDR_ANY): AO client", port++, NULL, 0,
&addr_any, 0, 0, 100, 100, 0, "TCPAOGood",
TEST_CNT_GOOD, 0, 0);
try_accept("AO server (INADDR_ANY): MD5 client", port++, NULL, 0,
try_accept("[server] AO server (INADDR_ANY): MD5 client", port++, NULL, 0,
&addr_any, 0, 0, 100, 100, 0, "TCPMD5Unexpected",
0, 1, FAULT_TIMEOUT);
try_accept("AO server (INADDR_ANY): no sign client", port++, NULL, 0,
TEST_CNT_NS_MD5_UNEXPECTED, 1, FAULT_TIMEOUT);
try_accept("[server] AO server (INADDR_ANY): no sign client", port++, NULL, 0,
&addr_any, 0, 0, 100, 100, 0, "TCPAORequired",
TEST_CNT_AO_REQUIRED, 0, FAULT_TIMEOUT);
try_accept("AO server (AO_REQUIRED): AO client", port++, NULL, 0,
try_accept("[server] AO server (AO_REQUIRED): AO client", port++, NULL, 0,
&this_ip_dest, TEST_PREFIX, true,
100, 100, 0, "TCPAOGood", TEST_CNT_GOOD, 0, 0);
try_accept("AO server (AO_REQUIRED): unsigned client", port++, NULL, 0,
try_accept("[server] AO server (AO_REQUIRED): unsigned client", port++, NULL, 0,
&this_ip_dest, TEST_PREFIX, true,
100, 100, 0, "TCPAORequired",
TEST_CNT_AO_REQUIRED, 0, FAULT_TIMEOUT);
try_accept("MD5 server (INADDR_ANY): AO client", port++, &addr_any, 0,
try_accept("[server] MD5 server (INADDR_ANY): AO client", port++, &addr_any, 0,
NULL, 0, 0, 0, 0, 0, "TCPAOKeyNotFound",
0, 1, FAULT_TIMEOUT);
try_accept("MD5 server (INADDR_ANY): MD5 client", port++, &addr_any, 0,
TEST_CNT_NS_KEY_NOT_FOUND, 1, FAULT_TIMEOUT);
try_accept("[server] MD5 server (INADDR_ANY): MD5 client", port++, &addr_any, 0,
NULL, 0, 0, 0, 0, 0, NULL, 0, 1, 0);
try_accept("MD5 server (INADDR_ANY): no sign client", port++, &addr_any,
try_accept("[server] MD5 server (INADDR_ANY): no sign client", port++, &addr_any,
0, NULL, 0, 0, 0, 0, 0, "TCPMD5NotFound",
0, 1, FAULT_TIMEOUT);
TEST_CNT_NS_MD5_NOT_FOUND, 1, FAULT_TIMEOUT);
try_accept("no sign server: AO client", port++, NULL, 0,
try_accept("[server] no sign server: AO client", port++, NULL, 0,
NULL, 0, 0, 0, 0, 0, "TCPAOKeyNotFound",
TEST_CNT_AO_KEY_NOT_FOUND, 0, FAULT_TIMEOUT);
try_accept("no sign server: MD5 client", port++, NULL, 0,
TEST_CNT_NS_KEY_NOT_FOUND, 0, FAULT_TIMEOUT);
try_accept("[server] no sign server: MD5 client", port++, NULL, 0,
NULL, 0, 0, 0, 0, 0, "TCPMD5Unexpected",
0, 1, FAULT_TIMEOUT);
try_accept("no sign server: no sign client", port++, NULL, 0,
TEST_CNT_NS_MD5_UNEXPECTED, 1, FAULT_TIMEOUT);
try_accept("[server] no sign server: no sign client", port++, NULL, 0,
NULL, 0, 0, 0, 0, 0, "CurrEstab", 0, 0, 0);
try_accept("AO+MD5 server: AO client (matching)", port++,
try_accept("[server] AO+MD5 server: AO client (matching)", port++,
&this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
100, 100, 0, "TCPAOGood", TEST_CNT_GOOD, 1, 0);
try_accept("AO+MD5 server: AO client (misconfig, matching MD5)", port++,
try_accept("[server] AO+MD5 server: AO client (misconfig, matching MD5)", port++,
&this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
100, 100, 0, "TCPAOKeyNotFound", TEST_CNT_AO_KEY_NOT_FOUND,
1, FAULT_TIMEOUT);
try_accept("AO+MD5 server: AO client (misconfig, non-matching)", port++,
try_accept("[server] AO+MD5 server: AO client (misconfig, non-matching)", port++,
&this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
100, 100, 0, "TCPAOKeyNotFound", TEST_CNT_AO_KEY_NOT_FOUND,
1, FAULT_TIMEOUT);
try_accept("AO+MD5 server: MD5 client (matching)", port++,
try_accept("[server] AO+MD5 server: MD5 client (matching)", port++,
&this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
100, 100, 0, NULL, 0, 1, 0);
try_accept("AO+MD5 server: MD5 client (misconfig, matching AO)", port++,
try_accept("[server] AO+MD5 server: MD5 client (misconfig, matching AO)", port++,
&this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
100, 100, 0, "TCPMD5Unexpected", 0, 1, FAULT_TIMEOUT);
try_accept("AO+MD5 server: MD5 client (misconfig, non-matching)", port++,
100, 100, 0, "TCPMD5Unexpected",
TEST_CNT_NS_MD5_UNEXPECTED, 1, FAULT_TIMEOUT);
try_accept("[server] AO+MD5 server: MD5 client (misconfig, non-matching)", port++,
&this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
100, 100, 0, "TCPMD5Unexpected", 0, 1, FAULT_TIMEOUT);
try_accept("AO+MD5 server: no sign client (unmatched)", port++,
100, 100, 0, "TCPMD5Unexpected",
TEST_CNT_NS_MD5_UNEXPECTED, 1, FAULT_TIMEOUT);
try_accept("[server] AO+MD5 server: no sign client (unmatched)", port++,
&this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
100, 100, 0, "CurrEstab", 0, 1, 0);
try_accept("AO+MD5 server: no sign client (misconfig, matching AO)",
try_accept("[server] AO+MD5 server: no sign client (misconfig, matching AO)",
port++, &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
100, 100, 0, "TCPAORequired",
TEST_CNT_AO_REQUIRED, 1, FAULT_TIMEOUT);
try_accept("AO+MD5 server: no sign client (misconfig, matching MD5)",
try_accept("[server] AO+MD5 server: no sign client (misconfig, matching MD5)",
port++, &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
100, 100, 0, "TCPMD5NotFound", 0, 1, FAULT_TIMEOUT);
100, 100, 0, "TCPMD5NotFound",
TEST_CNT_NS_MD5_NOT_FOUND, 1, FAULT_TIMEOUT);
try_accept("AO+MD5 server: client with both [TCP-MD5] and TCP-AO keys",
/* Key rejected by the other side, failing short through skpair */
try_accept("[server] AO+MD5 server: client with both [TCP-MD5] and TCP-AO keys",
port++, &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
100, 100, 0, NULL, 0, 1, FAULT_TIMEOUT);
try_accept("AO+MD5 server: client with both TCP-MD5 and [TCP-AO] keys",
100, 100, 0, NULL, 0, 1, FAULT_KEYREJECT);
try_accept("[server] AO+MD5 server: client with both TCP-MD5 and [TCP-AO] keys",
port++, &this_ip_dest, TEST_PREFIX, &client2, TEST_PREFIX, 0,
100, 100, 0, NULL, 0, 1, FAULT_TIMEOUT);
100, 100, 0, NULL, 0, 1, FAULT_KEYREJECT);
server_add_fail_tests(&port);
@@ -259,7 +267,6 @@ static void try_connect(const char *tst_name, unsigned int port,
uint8_t sndid, uint8_t rcvid, uint8_t vrf,
fault_t inj, int needs_tcp_md5, union tcp_addr *bind_addr)
{
time_t timeout;
int sk, ret;
if (needs_tcp_md5 && should_skip_test(tst_name, KCONFIG_TCP_MD5))
@@ -281,11 +288,10 @@ static void try_connect(const char *tst_name, unsigned int port,
synchronize_threads(); /* preparations done */
timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
ret = _test_connect_socket(sk, this_ip_dest, port, timeout);
ret = test_skpair_connect_poll(sk, this_ip_dest, port, 0, &sk_pair);
synchronize_threads(); /* connect()/accept() timeouts */
if (ret < 0) {
sk_pair = ret;
if (fault(KEYREJECT) && ret == -EKEYREJECTED)
test_ok("%s: connect() was prevented", tst_name);
else if (ret == -ETIMEDOUT && fault(TIMEOUT))
@@ -305,8 +311,7 @@ static void try_connect(const char *tst_name, unsigned int port,
out:
synchronize_threads(); /* test_kill_sk() */
/* _test_connect_socket() cleans up on failure */
if (ret > 0)
if (ret > 0) /* test_skpair_connect_poll() cleans up on failure */
test_kill_sk(sk);
}
@@ -437,7 +442,6 @@ static void try_to_add(const char *tst_name, unsigned int port,
int ao_vrf, uint8_t sndid, uint8_t rcvid,
int needs_tcp_md5, fault_t inj)
{
time_t timeout;
int sk, ret;
if (needs_tcp_md5 && should_skip_test(tst_name, KCONFIG_TCP_MD5))
@@ -450,11 +454,10 @@ static void try_to_add(const char *tst_name, unsigned int port,
synchronize_threads(); /* preparations done */
timeout = fault(TIMEOUT) ? TEST_RETRANSMIT_SEC : TEST_TIMEOUT_SEC;
ret = _test_connect_socket(sk, this_ip_dest, port, timeout);
ret = test_skpair_connect_poll(sk, this_ip_dest, port, 0, &sk_pair);
synchronize_threads(); /* connect()/accept() timeouts */
if (ret <= 0) {
if (ret < 0) {
test_error("%s: connect() returned %d", tst_name, ret);
goto out;
}
@@ -490,8 +493,7 @@ static void try_to_add(const char *tst_name, unsigned int port,
out:
synchronize_threads(); /* test_kill_sk() */
/* _test_connect_socket() cleans up on failure */
if (ret > 0)
if (ret > 0) /* test_skpair_connect_poll() cleans up on failure */
test_kill_sk(sk);
}