summaryrefslogtreecommitdiff
path: root/tools/testing/selftests/net/tcp_ao
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/net/tcp_ao')
-rw-r--r--tools/testing/selftests/net/tcp_ao/Makefile5
-rw-r--r--tools/testing/selftests/net/tcp_ao/bench-lookups.c2
-rw-r--r--tools/testing/selftests/net/tcp_ao/config1
-rw-r--r--tools/testing/selftests/net/tcp_ao/connect-deny.c83
-rw-r--r--tools/testing/selftests/net/tcp_ao/connect.c28
-rw-r--r--tools/testing/selftests/net/tcp_ao/icmps-discard.c19
-rw-r--r--tools/testing/selftests/net/tcp_ao/key-management.c94
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/aolib.h295
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/ftrace-tcp.c556
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/ftrace.c543
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/kconfig.c31
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/setup.c17
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/sock.c316
-rw-r--r--tools/testing/selftests/net/tcp_ao/lib/utils.c26
-rw-r--r--tools/testing/selftests/net/tcp_ao/restore.c101
-rw-r--r--tools/testing/selftests/net/tcp_ao/rst.c49
-rw-r--r--tools/testing/selftests/net/tcp_ao/self-connect.c58
-rw-r--r--tools/testing/selftests/net/tcp_ao/seq-ext.c60
-rw-r--r--tools/testing/selftests/net/tcp_ao/setsockopt-closed.c190
-rw-r--r--tools/testing/selftests/net/tcp_ao/unsigned-md5.c153
20 files changed, 2197 insertions, 430 deletions
diff --git a/tools/testing/selftests/net/tcp_ao/Makefile b/tools/testing/selftests/net/tcp_ao/Makefile
index 522d991e310e..5b0205c70c39 100644
--- a/tools/testing/selftests/net/tcp_ao/Makefile
+++ b/tools/testing/selftests/net/tcp_ao/Makefile
@@ -26,12 +26,13 @@ LIB := $(LIBDIR)/libaotst.a
LDLIBS += $(LIB) -pthread
LIBDEPS := lib/aolib.h Makefile
-CFLAGS := -Wall -O2 -g -D_GNU_SOURCE -fno-strict-aliasing
+CFLAGS += -Wall -O2 -g -fno-strict-aliasing
CFLAGS += $(KHDR_INCLUDES)
CFLAGS += -iquote ./lib/ -I ../../../../include/
# Library
-LIBSRC := kconfig.c netlink.c proc.c repair.c setup.c sock.c utils.c
+LIBSRC := ftrace.c ftrace-tcp.c kconfig.c netlink.c
+LIBSRC += proc.c repair.c setup.c sock.c utils.c
LIBOBJ := $(LIBSRC:%.c=$(LIBDIR)/%.o)
EXTRA_CLEAN += $(LIBOBJ) $(LIB)
diff --git a/tools/testing/selftests/net/tcp_ao/bench-lookups.c b/tools/testing/selftests/net/tcp_ao/bench-lookups.c
index a1e6e007c291..6736484996a3 100644
--- a/tools/testing/selftests/net/tcp_ao/bench-lookups.c
+++ b/tools/testing/selftests/net/tcp_ao/bench-lookups.c
@@ -355,6 +355,6 @@ static void *client_fn(void *arg)
int main(int argc, char *argv[])
{
- test_init(30, server_fn, client_fn);
+ test_init(31, server_fn, client_fn);
return 0;
}
diff --git a/tools/testing/selftests/net/tcp_ao/config b/tools/testing/selftests/net/tcp_ao/config
index d3277a9de987..3605e38711cb 100644
--- a/tools/testing/selftests/net/tcp_ao/config
+++ b/tools/testing/selftests/net/tcp_ao/config
@@ -7,4 +7,5 @@ CONFIG_NET_L3_MASTER_DEV=y
CONFIG_NET_VRF=y
CONFIG_TCP_AO=y
CONFIG_TCP_MD5SIG=y
+CONFIG_TRACEPOINTS=y
CONFIG_VETH=m
diff --git a/tools/testing/selftests/net/tcp_ao/connect-deny.c b/tools/testing/selftests/net/tcp_ao/connect-deny.c
index 185a2f6e5ff3..93b61e9a36f1 100644
--- a/tools/testing/selftests/net/tcp_ao/connect-deny.c
+++ b/tools/testing/selftests/net/tcp_ao/connect-deny.c
@@ -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) {
@@ -71,12 +75,14 @@ static void try_accept(const char *tst_name, unsigned int port, const char *pwd,
}
}
- if (pwd && test_get_tcp_ao_counters(lsk, &ao_cnt2))
- test_error("test_get_tcp_ao_counters()");
+ synchronize_threads(); /* before counter checks */
+ 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;
@@ -84,10 +90,10 @@ static void try_accept(const char *tst_name, unsigned int port, const char *pwd,
after_cnt = netstat_get_one(cnt_name, NULL);
if (after_cnt <= before_cnt) {
- test_fail("%s: %s counter did not increase: %zu <= %zu",
+ test_fail("%s: %s counter did not increase: %" PRIu64 " <= %" PRIu64,
tst_name, cnt_name, after_cnt, before_cnt);
} else {
- test_ok("%s: counter %s increased %zu => %zu",
+ test_ok("%s: counter %s increased %" PRIu64 " => %" PRIu64,
tst_name, cnt_name, before_cnt, after_cnt);
}
@@ -107,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,
@@ -133,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,
@@ -161,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);
@@ -172,15 +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)) {
@@ -199,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() */
@@ -212,30 +220,49 @@ out:
static void *client_fn(void *arg)
{
- union tcp_addr wrong_addr, network_addr;
+ union tcp_addr wrong_addr, network_addr, addr_any = {};
unsigned int port = test_server_port;
if (inet_pton(TEST_FAMILY, TEST_WRONG_IP, &wrong_addr) != 1)
test_error("Can't convert ip address %s", TEST_WRONG_IP);
+ trace_ao_event_expect(TCP_AO_KEY_NOT_FOUND, this_ip_addr, this_ip_dest,
+ -1, port, 0, 0, 1, 0, 0, 0, 100, 100, -1);
try_connect("Non-AO server + AO client", port++, DEFAULT_TEST_PASSWORD,
this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+ trace_hash_event_expect(TCP_HASH_AO_REQUIRED, this_ip_addr, this_ip_dest,
+ -1, port, 0, 0, 1, 0, 0, 0);
try_connect("AO server + Non-AO client", port++, NULL,
this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+ trace_ao_event_expect(TCP_AO_MISMATCH, this_ip_addr, this_ip_dest,
+ -1, port, 0, 0, 1, 0, 0, 0, 100, 100, -1);
try_connect("Wrong password", port++, DEFAULT_TEST_PASSWORD,
this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+ trace_ao_event_expect(TCP_AO_KEY_NOT_FOUND, this_ip_addr, this_ip_dest,
+ -1, port, 0, 0, 1, 0, 0, 0, 100, 100, -1);
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,
this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+ trace_ao_event_expect(TCP_AO_WRONG_MACLEN, this_ip_addr, this_ip_dest,
+ -1, port, 0, 0, 1, 0, 0, 0, 100, 100, -1);
try_connect("Different maclen", port++, DEFAULT_TEST_PASSWORD,
this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
+ trace_ao_event_expect(TCP_AO_KEY_NOT_FOUND, this_ip_addr, this_ip_dest,
+ -1, port, 0, 0, 1, 0, 0, 0, 100, 100, -1);
try_connect("Server: Wrong addr", port++, DEFAULT_TEST_PASSWORD,
this_ip_dest, -1, 100, 100, 0, FAULT_TIMEOUT);
@@ -259,6 +286,6 @@ static void *client_fn(void *arg)
int main(int argc, char *argv[])
{
- test_init(21, server_fn, client_fn);
+ test_init(22, server_fn, client_fn);
return 0;
}
diff --git a/tools/testing/selftests/net/tcp_ao/connect.c b/tools/testing/selftests/net/tcp_ao/connect.c
index 81653b47f303..340f00e979ea 100644
--- a/tools/testing/selftests/net/tcp_ao/connect.c
+++ b/tools/testing/selftests/net/tcp_ao/connect.c
@@ -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,41 +50,41 @@ 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);
if (nr_packets > (after_aogood - before_aogood)) {
- test_fail("TCPAOGood counter mismatch: %zu > (%zu - %zu)",
+ test_fail("TCPAOGood counter mismatch: %zu > (%" PRIu64 " - %" PRIu64 ")",
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 %" PRIu64,
- 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,
+ test_ok("connect TCPAOGood %" PRIu64 "/%" PRIu64 "/%" PRIu64 " => %" PRIu64 "/%" PRIu64 "/%" PRIu64 ", sent %zu",
+ 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;
}
int main(int argc, char *argv[])
{
- test_init(1, server_fn, client_fn);
+ test_init(2, server_fn, client_fn);
return 0;
}
diff --git a/tools/testing/selftests/net/tcp_ao/icmps-discard.c b/tools/testing/selftests/net/tcp_ao/icmps-discard.c
index d69bcba3c929..85c1a1e958c6 100644
--- a/tools/testing/selftests/net/tcp_ao/icmps-discard.c
+++ b/tools/testing/selftests/net/tcp_ao/icmps-discard.c
@@ -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;
}
@@ -444,6 +443,6 @@ static void *client_fn(void *arg)
int main(int argc, char *argv[])
{
- test_init(3, server_fn, client_fn);
+ test_init(4, server_fn, client_fn);
return 0;
}
diff --git a/tools/testing/selftests/net/tcp_ao/key-management.c b/tools/testing/selftests/net/tcp_ao/key-management.c
index 24e62120b792..69d9a7a05d5c 100644
--- a/tools/testing/selftests/net/tcp_ao/key-management.c
+++ b/tools/testing/selftests/net/tcp_ao/key-management.c
@@ -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 @@ out:
}
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);
@@ -965,7 +965,7 @@ static void end_client(const char *tst_name, int sk, unsigned int nr_keys,
synchronize_threads(); /* 5: counters */
}
-static void try_unmatched_keys(int sk, int *rnext_index)
+static void try_unmatched_keys(int sk, int *rnext_index, unsigned int port)
{
struct test_key *key;
unsigned int i = 0;
@@ -1013,7 +1013,10 @@ static void try_unmatched_keys(int sk, int *rnext_index)
test_error("all keys on server match the client");
if (test_set_key(sk, -1, key->server_keyid))
test_error("Can't change the current key");
- if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
+ 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_fail("verify failed");
*rnext_index = i;
}
@@ -1045,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,
@@ -1054,7 +1057,11 @@ static void check_current_back(const char *tst_name, unsigned int port,
return;
if (test_set_key(sk, collection.keys[rotate_to_index].client_keyid, -1))
test_error("Can't change the current key");
- if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
+ trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, this_ip_dest, this_ip_addr,
+ 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_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
@@ -1074,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;
@@ -1085,12 +1092,17 @@ static void roll_over_keys(const char *tst_name, unsigned int port,
for (i = rnext_index + 1; rotations > 0; i++, rotations--) {
if (i >= collection.nr_keys)
i = 0;
+ trace_ao_event_expect(TCP_AO_RNEXT_REQUEST,
+ this_ip_addr, this_ip_dest,
+ -1, port, 0, -1, -1, -1, -1, -1,
+ i == 0 ? -1 : collection.keys[i - 1].server_keyid,
+ 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,
@@ -1104,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,
@@ -1124,7 +1136,7 @@ static void try_client_match(const char *tst_name, unsigned int port,
rnext_index, msg_len, nr_packets);
if (sk < 0)
return;
- try_unmatched_keys(sk, &rnext_index);
+ try_unmatched_keys(sk, &rnext_index, port);
end_client(tst_name, sk, nr_keys, current_index, rnext_index, NULL);
}
@@ -1181,6 +1193,6 @@ static void *client_fn(void *arg)
int main(int argc, char *argv[])
{
- test_init(120, server_fn, client_fn);
+ test_init(121, server_fn, client_fn);
return 0;
}
diff --git a/tools/testing/selftests/net/tcp_ao/lib/aolib.h b/tools/testing/selftests/net/tcp_ao/lib/aolib.h
index fbc7f6111815..ebb2899c12fe 100644
--- a/tools/testing/selftests/net/tcp_ao/lib/aolib.h
+++ b/tools/testing/selftests/net/tcp_ao/lib/aolib.h
@@ -37,17 +37,59 @@ extern void __test_xfail(const char *buf);
extern void __test_error(const char *buf);
extern void __test_skip(const char *buf);
-__attribute__((__format__(__printf__, 2, 3)))
-static inline void __test_print(void (*fn)(const char *), const char *fmt, ...)
+static inline char *test_snprintf(const char *fmt, va_list vargs)
{
-#define TEST_MSG_BUFFER_SIZE 4096
- char buf[TEST_MSG_BUFFER_SIZE];
- va_list arg;
-
- va_start(arg, fmt);
- vsnprintf(buf, sizeof(buf), fmt, arg);
- va_end(arg);
- fn(buf);
+ char *ret = NULL;
+ size_t size = 0;
+ va_list tmp;
+ int n = 0;
+
+ va_copy(tmp, vargs);
+ n = vsnprintf(ret, size, fmt, tmp);
+ va_end(tmp);
+ if (n < 0)
+ return NULL;
+
+ size = n + 1;
+ ret = malloc(size);
+ if (!ret)
+ return NULL;
+
+ n = vsnprintf(ret, size, fmt, vargs);
+ if (n < 0 || n > size - 1) {
+ free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+static __printf(1, 2) inline char *test_sprintf(const char *fmt, ...)
+{
+ va_list vargs;
+ char *ret;
+
+ va_start(vargs, fmt);
+ ret = test_snprintf(fmt, vargs);
+ va_end(vargs);
+
+ return ret;
+}
+
+static __printf(2, 3) inline void __test_print(void (*fn)(const char *),
+ const char *fmt, ...)
+{
+ va_list vargs;
+ char *msg;
+
+ va_start(vargs, fmt);
+ msg = test_snprintf(fmt, vargs);
+ va_end(vargs);
+
+ if (!msg)
+ return;
+
+ fn(msg);
+ free(msg);
}
#define test_print(fmt, ...) \
@@ -103,6 +145,7 @@ enum test_needs_kconfig {
KCONFIG_TCP_AO, /* required */
KCONFIG_TCP_MD5, /* optional, for TCP-MD5 features */
KCONFIG_NET_VRF, /* optional, for L3/VRF testing */
+ KCONFIG_FTRACE, /* optional, for tracepoints checks */
__KCONFIG_LAST__
};
extern bool kernel_config_has(enum test_needs_kconfig k);
@@ -142,6 +185,8 @@ static inline void test_init2(unsigned int ntests,
__test_init(ntests, family, prefix, taddr1, taddr2, peer1, peer2);
}
extern void test_add_destructor(void (*d)(void));
+extern void test_init_ftrace(int nsfd1, int nsfd2);
+extern int test_setup_tracing(void);
/* To adjust optmem socket limit, approximately estimate a number,
* that is bigger than sizeof(struct tcp_ao_key).
@@ -216,12 +261,17 @@ static inline void test_init(unsigned int ntests,
}
extern void synchronize_threads(void);
extern void switch_ns(int fd);
+extern int switch_save_ns(int fd);
+extern void switch_close_ns(int fd);
extern __thread union tcp_addr this_ip_addr;
extern __thread union tcp_addr this_ip_dest;
extern int test_family;
extern void randomize_buffer(void *buf, size_t buflen);
+extern __printf(3, 4) int test_echo(const char *fname, bool append,
+ const char *fmt, ...);
+
extern int open_netns(void);
extern int unshare_open_netns(void);
extern const char veth_name[];
@@ -239,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,
@@ -281,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,
@@ -433,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;
@@ -462,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)
@@ -476,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 | \
@@ -489,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);
+
+/*
+ * 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_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_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;
}
@@ -602,4 +718,115 @@ static inline int test_add_repaired_key(int sk,
return test_verify_socket_key(sk, &tmp);
}
+#define DEFAULT_FTRACE_BUFFER_KB 10000
+#define DEFAULT_TRACER_LINES_ARR 200
+struct test_ftracer;
+extern uint64_t ns_cookie1, ns_cookie2;
+
+enum ftracer_op {
+ FTRACER_LINE_DISCARD = 0,
+ FTRACER_LINE_PRESERVE,
+ FTRACER_EXIT,
+};
+
+extern struct test_ftracer *create_ftracer(const char *name,
+ enum ftracer_op (*process_line)(const char *line),
+ void (*destructor)(struct test_ftracer *tracer),
+ bool (*expecting_more)(void),
+ size_t lines_buf_sz, size_t buffer_size_kb);
+extern int setup_trace_event(struct test_ftracer *tracer,
+ const char *event, const char *filter);
+extern void destroy_ftracer(struct test_ftracer *tracer);
+extern const size_t tracer_get_savedlines_nr(struct test_ftracer *tracer);
+extern const char **tracer_get_savedlines(struct test_ftracer *tracer);
+
+enum trace_events {
+ /* TCP_HASH_EVENT */
+ TCP_HASH_BAD_HEADER = 0,
+ TCP_HASH_MD5_REQUIRED,
+ TCP_HASH_MD5_UNEXPECTED,
+ TCP_HASH_MD5_MISMATCH,
+ TCP_HASH_AO_REQUIRED,
+ /* TCP_AO_EVENT */
+ TCP_AO_HANDSHAKE_FAILURE,
+ TCP_AO_WRONG_MACLEN,
+ TCP_AO_MISMATCH,
+ TCP_AO_KEY_NOT_FOUND,
+ TCP_AO_RNEXT_REQUEST,
+ /* TCP_AO_EVENT_SK */
+ TCP_AO_SYNACK_NO_KEY,
+ /* TCP_AO_EVENT_SNE */
+ TCP_AO_SND_SNE_UPDATE,
+ TCP_AO_RCV_SNE_UPDATE,
+ __MAX_TRACE_EVENTS
+};
+
+extern int __trace_event_expect(enum trace_events type, int family,
+ union tcp_addr src, union tcp_addr dst,
+ int src_port, int dst_port, int L3index,
+ int fin, int syn, int rst, int psh, int ack,
+ int keyid, int rnext, int maclen, int sne);
+
+static inline void trace_hash_event_expect(enum trace_events type,
+ union tcp_addr src, union tcp_addr dst,
+ int src_port, int dst_port, int L3index,
+ int fin, int syn, int rst, int psh, int ack)
+{
+ int err;
+
+ err = __trace_event_expect(type, TEST_FAMILY, src, dst,
+ src_port, dst_port, L3index,
+ fin, syn, rst, psh, ack,
+ -1, -1, -1, -1);
+ if (err)
+ test_error("Couldn't add a trace event: %d", err);
+}
+
+static inline void trace_ao_event_expect(enum trace_events type,
+ union tcp_addr src, union tcp_addr dst,
+ int src_port, int dst_port, int L3index,
+ int fin, int syn, int rst, int psh, int ack,
+ int keyid, int rnext, int maclen)
+{
+ int err;
+
+ err = __trace_event_expect(type, TEST_FAMILY, src, dst,
+ src_port, dst_port, L3index,
+ fin, syn, rst, psh, ack,
+ keyid, rnext, maclen, -1);
+ if (err)
+ test_error("Couldn't add a trace event: %d", err);
+}
+
+static inline void trace_ao_event_sk_expect(enum trace_events type,
+ union tcp_addr src, union tcp_addr dst,
+ int src_port, int dst_port,
+ int keyid, int rnext)
+{
+ int err;
+
+ err = __trace_event_expect(type, TEST_FAMILY, src, dst,
+ src_port, dst_port, -1,
+ -1, -1, -1, -1, -1,
+ keyid, rnext, -1, -1);
+ if (err)
+ test_error("Couldn't add a trace event: %d", err);
+}
+
+static inline void trace_ao_event_sne_expect(enum trace_events type,
+ union tcp_addr src, union tcp_addr dst,
+ int src_port, int dst_port, int sne)
+{
+ int err;
+
+ err = __trace_event_expect(type, TEST_FAMILY, src, dst,
+ src_port, dst_port, -1,
+ -1, -1, -1, -1, -1,
+ -1, -1, -1, sne);
+ if (err)
+ test_error("Couldn't add a trace event: %d", err);
+}
+
+extern int setup_aolib_ftracer(void);
+
#endif /* _AOLIB_H_ */
diff --git a/tools/testing/selftests/net/tcp_ao/lib/ftrace-tcp.c b/tools/testing/selftests/net/tcp_ao/lib/ftrace-tcp.c
new file mode 100644
index 000000000000..27403f875054
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/lib/ftrace-tcp.c
@@ -0,0 +1,556 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <inttypes.h>
+#include <pthread.h>
+#include "aolib.h"
+
+static const char *trace_event_names[__MAX_TRACE_EVENTS] = {
+ /* TCP_HASH_EVENT */
+ "tcp_hash_bad_header",
+ "tcp_hash_md5_required",
+ "tcp_hash_md5_unexpected",
+ "tcp_hash_md5_mismatch",
+ "tcp_hash_ao_required",
+ /* TCP_AO_EVENT */
+ "tcp_ao_handshake_failure",
+ "tcp_ao_wrong_maclen",
+ "tcp_ao_mismatch",
+ "tcp_ao_key_not_found",
+ "tcp_ao_rnext_request",
+ /* TCP_AO_EVENT_SK */
+ "tcp_ao_synack_no_key",
+ /* TCP_AO_EVENT_SNE */
+ "tcp_ao_snd_sne_update",
+ "tcp_ao_rcv_sne_update"
+};
+
+struct expected_trace_point {
+ /* required */
+ enum trace_events type;
+ int family;
+ union tcp_addr src;
+ union tcp_addr dst;
+
+ /* optional */
+ int src_port;
+ int dst_port;
+ int L3index;
+
+ int fin;
+ int syn;
+ int rst;
+ int psh;
+ int ack;
+
+ int keyid;
+ int rnext;
+ int maclen;
+ int sne;
+
+ size_t matched;
+};
+
+static struct expected_trace_point *exp_tps;
+static size_t exp_tps_nr;
+static size_t exp_tps_size;
+static pthread_mutex_t exp_tps_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+int __trace_event_expect(enum trace_events type, int family,
+ union tcp_addr src, union tcp_addr dst,
+ int src_port, int dst_port, int L3index,
+ int fin, int syn, int rst, int psh, int ack,
+ int keyid, int rnext, int maclen, int sne)
+{
+ struct expected_trace_point new_tp = {
+ .type = type,
+ .family = family,
+ .src = src,
+ .dst = dst,
+ .src_port = src_port,
+ .dst_port = dst_port,
+ .L3index = L3index,
+ .fin = fin,
+ .syn = syn,
+ .rst = rst,
+ .psh = psh,
+ .ack = ack,
+ .keyid = keyid,
+ .rnext = rnext,
+ .maclen = maclen,
+ .sne = sne,
+ .matched = 0,
+ };
+ int ret = 0;
+
+ if (!kernel_config_has(KCONFIG_FTRACE))
+ return 0;
+
+ pthread_mutex_lock(&exp_tps_mutex);
+ if (exp_tps_nr == exp_tps_size) {
+ struct expected_trace_point *tmp;
+
+ if (exp_tps_size == 0)
+ exp_tps_size = 10;
+ else
+ exp_tps_size = exp_tps_size * 1.6;
+
+ tmp = reallocarray(exp_tps, exp_tps_size, sizeof(exp_tps[0]));
+ if (!tmp) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ exp_tps = tmp;
+ }
+ exp_tps[exp_tps_nr] = new_tp;
+ exp_tps_nr++;
+out:
+ pthread_mutex_unlock(&exp_tps_mutex);
+ return ret;
+}
+
+static void free_expected_events(void)
+{
+ /* We're from the process destructor - not taking the mutex */
+ exp_tps_size = 0;
+ exp_tps = NULL;
+ free(exp_tps);
+}
+
+struct trace_point {
+ int family;
+ union tcp_addr src;
+ union tcp_addr dst;
+ unsigned int src_port;
+ unsigned int dst_port;
+ int L3index;
+ unsigned int fin:1,
+ syn:1,
+ rst:1,
+ psh:1,
+ ack:1;
+
+ unsigned int keyid;
+ unsigned int rnext;
+ unsigned int maclen;
+
+ unsigned int sne;
+};
+
+static bool lookup_expected_event(int event_type, struct trace_point *e)
+{
+ size_t i;
+
+ pthread_mutex_lock(&exp_tps_mutex);
+ for (i = 0; i < exp_tps_nr; i++) {
+ struct expected_trace_point *p = &exp_tps[i];
+ size_t sk_size;
+
+ if (p->type != event_type)
+ continue;
+ if (p->family != e->family)
+ continue;
+ if (p->family == AF_INET)
+ sk_size = sizeof(p->src.a4);
+ else
+ sk_size = sizeof(p->src.a6);
+ if (memcmp(&p->src, &e->src, sk_size))
+ continue;
+ if (memcmp(&p->dst, &e->dst, sk_size))
+ continue;
+ if (p->src_port >= 0 && p->src_port != e->src_port)
+ continue;
+ if (p->dst_port >= 0 && p->dst_port != e->dst_port)
+ continue;
+ if (p->L3index >= 0 && p->L3index != e->L3index)
+ continue;
+
+ if (p->fin >= 0 && p->fin != e->fin)
+ continue;
+ if (p->syn >= 0 && p->syn != e->syn)
+ continue;
+ if (p->rst >= 0 && p->rst != e->rst)
+ continue;
+ if (p->psh >= 0 && p->psh != e->psh)
+ continue;
+ if (p->ack >= 0 && p->ack != e->ack)
+ continue;
+
+ if (p->keyid >= 0 && p->keyid != e->keyid)
+ continue;
+ if (p->rnext >= 0 && p->rnext != e->rnext)
+ continue;
+ if (p->maclen >= 0 && p->maclen != e->maclen)
+ continue;
+ if (p->sne >= 0 && p->sne != e->sne)
+ continue;
+ p->matched++;
+ pthread_mutex_unlock(&exp_tps_mutex);
+ return true;
+ }
+ pthread_mutex_unlock(&exp_tps_mutex);
+ return false;
+}
+
+static int check_event_type(const char *line)
+{
+ size_t i;
+
+ /*
+ * This should have been a set or hashmap, but it's a selftest,
+ * so... KISS.
+ */
+ for (i = 0; i < __MAX_TRACE_EVENTS; i++) {
+ if (!strncmp(trace_event_names[i], line, strlen(trace_event_names[i])))
+ return i;
+ }
+ return -1;
+}
+
+static bool event_has_flags(enum trace_events event)
+{
+ switch (event) {
+ case TCP_HASH_BAD_HEADER:
+ case TCP_HASH_MD5_REQUIRED:
+ case TCP_HASH_MD5_UNEXPECTED:
+ case TCP_HASH_MD5_MISMATCH:
+ case TCP_HASH_AO_REQUIRED:
+ case TCP_AO_HANDSHAKE_FAILURE:
+ case TCP_AO_WRONG_MACLEN:
+ case TCP_AO_MISMATCH:
+ case TCP_AO_KEY_NOT_FOUND:
+ case TCP_AO_RNEXT_REQUEST:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int tracer_ip_split(int family, char *src, char **addr, char **port)
+{
+ char *p;
+
+ if (family == AF_INET) {
+ /* fomat is <addr>:port, i.e.: 10.0.254.1:7015 */
+ *addr = src;
+ p = strchr(src, ':');
+ if (!p) {
+ test_print("Couldn't parse trace event addr:port %s", src);
+ return -EINVAL;
+ }
+ *p++ = '\0';
+ *port = p;
+ return 0;
+ }
+ if (family != AF_INET6)
+ return -EAFNOSUPPORT;
+
+ /* format is [<addr>]:port, i.e.: [2001:db8:254::1]:7013 */
+ *addr = strchr(src, '[');
+ p = strchr(src, ']');
+
+ if (!p || !*addr) {
+ test_print("Couldn't parse trace event [addr]:port %s", src);
+ return -EINVAL;
+ }
+
+ *addr = *addr + 1; /* '[' */
+ *p++ = '\0'; /* ']' */
+ if (*p != ':') {
+ test_print("Couldn't parse trace event :port %s", p);
+ return -EINVAL;
+ }
+ *p++ = '\0'; /* ':' */
+ *port = p;
+ return 0;
+}
+
+static int tracer_scan_address(int family, char *src,
+ union tcp_addr *dst, unsigned int *port)
+{
+ char *addr, *port_str;
+ int ret;
+
+ ret = tracer_ip_split(family, src, &addr, &port_str);
+ if (ret)
+ return ret;
+
+ if (inet_pton(family, addr, dst) != 1) {
+ test_print("Couldn't parse trace event addr %s", addr);
+ return -EINVAL;
+ }
+ errno = 0;
+ *port = (unsigned int)strtoul(port_str, NULL, 10);
+ if (errno != 0) {
+ test_print("Couldn't parse trace event port %s", port_str);
+ return -errno;
+ }
+ return 0;
+}
+
+static int tracer_scan_event(const char *line, enum trace_events event,
+ struct trace_point *out)
+{
+ char *src = NULL, *dst = NULL, *family = NULL;
+ char fin, syn, rst, psh, ack;
+ int nr_matched, ret = 0;
+ uint64_t netns_cookie;
+
+ switch (event) {
+ case TCP_HASH_BAD_HEADER:
+ case TCP_HASH_MD5_REQUIRED:
+ case TCP_HASH_MD5_UNEXPECTED:
+ case TCP_HASH_MD5_MISMATCH:
+ case TCP_HASH_AO_REQUIRED: {
+ nr_matched = sscanf(line, "%*s net=%" PRIu64 " state%*s family=%ms src=%ms dest=%ms L3index=%d [%c%c%c%c%c]",
+ &netns_cookie, &family,
+ &src, &dst, &out->L3index,
+ &fin, &syn, &rst, &psh, &ack);
+ if (nr_matched != 10)
+ test_print("Couldn't parse trace event, matched = %d/10",
+ nr_matched);
+ break;
+ }
+ case TCP_AO_HANDSHAKE_FAILURE:
+ case TCP_AO_WRONG_MACLEN:
+ case TCP_AO_MISMATCH:
+ case TCP_AO_KEY_NOT_FOUND:
+ case TCP_AO_RNEXT_REQUEST: {
+ nr_matched = sscanf(line, "%*s net=%" PRIu64 " state%*s family=%ms src=%ms dest=%ms L3index=%d [%c%c%c%c%c] keyid=%u rnext=%u maclen=%u",
+ &netns_cookie, &family,
+ &src, &dst, &out->L3index,
+ &fin, &syn, &rst, &psh, &ack,
+ &out->keyid, &out->rnext, &out->maclen);
+ if (nr_matched != 13)
+ test_print("Couldn't parse trace event, matched = %d/13",
+ nr_matched);
+ break;
+ }
+ case TCP_AO_SYNACK_NO_KEY: {
+ nr_matched = sscanf(line, "%*s net=%" PRIu64 " state%*s family=%ms src=%ms dest=%ms keyid=%u rnext=%u",
+ &netns_cookie, &family,
+ &src, &dst, &out->keyid, &out->rnext);
+ if (nr_matched != 6)
+ test_print("Couldn't parse trace event, matched = %d/6",
+ nr_matched);
+ break;
+ }
+ case TCP_AO_SND_SNE_UPDATE:
+ case TCP_AO_RCV_SNE_UPDATE: {
+ nr_matched = sscanf(line, "%*s net=%" PRIu64 " state%*s family=%ms src=%ms dest=%ms sne=%u",
+ &netns_cookie, &family,
+ &src, &dst, &out->sne);
+ if (nr_matched != 5)
+ test_print("Couldn't parse trace event, matched = %d/5",
+ nr_matched);
+ break;
+ }
+ default:
+ return -1;
+ }
+
+ if (family) {
+ if (!strcmp(family, "AF_INET")) {
+ out->family = AF_INET;
+ } else if (!strcmp(family, "AF_INET6")) {
+ out->family = AF_INET6;
+ } else {
+ test_print("Couldn't parse trace event family %s", family);
+ ret = -EINVAL;
+ goto out_free;
+ }
+ }
+
+ if (event_has_flags(event)) {
+ out->fin = (fin == 'F');
+ out->syn = (syn == 'S');
+ out->rst = (rst == 'R');
+ out->psh = (psh == 'P');
+ out->ack = (ack == '.');
+
+ if ((fin != 'F' && fin != ' ') ||
+ (syn != 'S' && syn != ' ') ||
+ (rst != 'R' && rst != ' ') ||
+ (psh != 'P' && psh != ' ') ||
+ (ack != '.' && ack != ' ')) {
+ test_print("Couldn't parse trace event flags %c%c%c%c%c",
+ fin, syn, rst, psh, ack);
+ ret = -EINVAL;
+ goto out_free;
+ }
+ }
+
+ if (src && tracer_scan_address(out->family, src, &out->src, &out->src_port)) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ if (dst && tracer_scan_address(out->family, dst, &out->dst, &out->dst_port)) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ if (netns_cookie != ns_cookie1 && netns_cookie != ns_cookie2) {
+ test_print("Net namespace filter for trace event didn't work: %" PRIu64 " != %" PRIu64 " OR %" PRIu64,
+ netns_cookie, ns_cookie1, ns_cookie2);
+ ret = -EINVAL;
+ }
+
+out_free:
+ free(src);
+ free(dst);
+ free(family);
+ return ret;
+}
+
+static enum ftracer_op aolib_tracer_process_event(const char *line)
+{
+ int event_type = check_event_type(line);
+ struct trace_point tmp = {};
+
+ if (event_type < 0)
+ return FTRACER_LINE_PRESERVE;
+
+ if (tracer_scan_event(line, event_type, &tmp))
+ return FTRACER_LINE_PRESERVE;
+
+ return lookup_expected_event(event_type, &tmp) ?
+ FTRACER_LINE_DISCARD : FTRACER_LINE_PRESERVE;
+}
+
+static void dump_trace_event(struct expected_trace_point *e)
+{
+ char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
+
+ if (!inet_ntop(e->family, &e->src, src, INET6_ADDRSTRLEN))
+ test_error("inet_ntop()");
+ if (!inet_ntop(e->family, &e->dst, dst, INET6_ADDRSTRLEN))
+ test_error("inet_ntop()");
+ 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 ? "F" : "", e->syn ? "S" : "", e->rst ? "R" : "",
+ e->psh ? "P" : "", e->ack ? "." : "",
+ e->keyid, e->rnext, e->maclen, e->sne, e->matched);
+}
+
+static void print_match_stats(bool unexpected_events)
+{
+ size_t matches_per_type[__MAX_TRACE_EVENTS] = {};
+ bool expected_but_none = false;
+ size_t i, total_matched = 0;
+ char *stat_line = NULL;
+
+ for (i = 0; i < exp_tps_nr; i++) {
+ struct expected_trace_point *e = &exp_tps[i];
+
+ total_matched += e->matched;
+ matches_per_type[e->type] += e->matched;
+ if (!e->matched)
+ expected_but_none = true;
+ }
+ for (i = 0; i < __MAX_TRACE_EVENTS; i++) {
+ if (!matches_per_type[i])
+ continue;
+ stat_line = test_sprintf("%s%s[%zu] ", stat_line ?: "",
+ trace_event_names[i],
+ matches_per_type[i]);
+ if (!stat_line)
+ test_error("test_sprintf()");
+ }
+
+ if (unexpected_events || expected_but_none) {
+ for (i = 0; i < exp_tps_nr; i++)
+ dump_trace_event(&exp_tps[i]);
+ }
+
+ if (unexpected_events)
+ return;
+
+ if (expected_but_none)
+ test_fail("Some trace events were expected, but didn't occur");
+ else if (total_matched)
+ test_ok("Trace events matched expectations: %zu %s",
+ total_matched, stat_line);
+ else
+ test_ok("No unexpected trace events during the test run");
+}
+
+#define dump_events(fmt, ...) \
+ __test_print(__test_msg, fmt, ##__VA_ARGS__)
+static void check_free_events(struct test_ftracer *tracer)
+{
+ const char **lines;
+ size_t nr;
+
+ if (!kernel_config_has(KCONFIG_FTRACE)) {
+ test_skip("kernel config doesn't have ftrace - no checks");
+ return;
+ }
+
+ nr = tracer_get_savedlines_nr(tracer);
+ lines = tracer_get_savedlines(tracer);
+ print_match_stats(!!nr);
+ if (!nr)
+ return;
+
+ errno = 0;
+ test_xfail("Trace events [%zu] were not expected:", nr);
+ while (nr)
+ dump_events("\t%s", lines[--nr]);
+}
+
+static int setup_tcp_trace_events(struct test_ftracer *tracer)
+{
+ char *filter;
+ size_t i;
+ int ret;
+
+ filter = test_sprintf("net_cookie == %zu || net_cookie == %zu",
+ ns_cookie1, ns_cookie2);
+ if (!filter)
+ return -ENOMEM;
+
+ for (i = 0; i < __MAX_TRACE_EVENTS; i++) {
+ char *event_name = test_sprintf("tcp/%s", trace_event_names[i]);
+
+ if (!event_name) {
+ ret = -ENOMEM;
+ break;
+ }
+ ret = setup_trace_event(tracer, event_name, filter);
+ free(event_name);
+ if (ret)
+ break;
+ }
+
+ free(filter);
+ return ret;
+}
+
+static void aolib_tracer_destroy(struct test_ftracer *tracer)
+{
+ check_free_events(tracer);
+ free_expected_events();
+}
+
+static bool aolib_tracer_expecting_more(void)
+{
+ size_t i;
+
+ for (i = 0; i < exp_tps_nr; i++)
+ if (!exp_tps[i].matched)
+ return true;
+ return false;
+}
+
+int setup_aolib_ftracer(void)
+{
+ struct test_ftracer *f;
+
+ f = create_ftracer("aolib", aolib_tracer_process_event,
+ aolib_tracer_destroy, aolib_tracer_expecting_more,
+ DEFAULT_FTRACE_BUFFER_KB, DEFAULT_TRACER_LINES_ARR);
+ if (!f)
+ return -1;
+
+ return setup_tcp_trace_events(f);
+}
diff --git a/tools/testing/selftests/net/tcp_ao/lib/ftrace.c b/tools/testing/selftests/net/tcp_ao/lib/ftrace.c
new file mode 100644
index 000000000000..e4d0b173bc94
--- /dev/null
+++ b/tools/testing/selftests/net/tcp_ao/lib/ftrace.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <inttypes.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mount.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include "../../../../../include/linux/kernel.h"
+#include "aolib.h"
+
+static char ftrace_path[] = "ksft-ftrace-XXXXXX";
+static bool ftrace_mounted;
+uint64_t ns_cookie1, ns_cookie2;
+
+struct test_ftracer {
+ pthread_t tracer_thread;
+ int error;
+ char *instance_path;
+ FILE *trace_pipe;
+
+ enum ftracer_op (*process_line)(const char *line);
+ void (*destructor)(struct test_ftracer *tracer);
+ bool (*expecting_more)(void);
+
+ char **saved_lines;
+ size_t saved_lines_size;
+ size_t next_line_ind;
+
+ pthread_cond_t met_all_expected;
+ pthread_mutex_t met_all_expected_lock;
+
+ struct test_ftracer *next;
+};
+
+static struct test_ftracer *ftracers;
+static pthread_mutex_t ftracers_lock = PTHREAD_MUTEX_INITIALIZER;
+
+static int mount_ftrace(void)
+{
+ if (!mkdtemp(ftrace_path))
+ test_error("Can't create temp dir");
+
+ if (mount("tracefs", ftrace_path, "tracefs", 0, "rw"))
+ return -errno;
+
+ ftrace_mounted = true;
+
+ return 0;
+}
+
+static void unmount_ftrace(void)
+{
+ if (ftrace_mounted && umount(ftrace_path))
+ test_print("Failed on cleanup: can't unmount tracefs: %m");
+
+ if (rmdir(ftrace_path))
+ test_error("Failed on cleanup: can't remove ftrace dir %s",
+ ftrace_path);
+}
+
+struct opts_list_t {
+ char *opt_name;
+ struct opts_list_t *next;
+};
+
+static int disable_trace_options(const char *ftrace_path)
+{
+ struct opts_list_t *opts_list = NULL;
+ char *fopts, *line = NULL;
+ size_t buf_len = 0;
+ ssize_t line_len;
+ int ret = 0;
+ FILE *opts;
+
+ fopts = test_sprintf("%s/%s", ftrace_path, "trace_options");
+ if (!fopts)
+ return -ENOMEM;
+
+ opts = fopen(fopts, "r+");
+ if (!opts) {
+ ret = -errno;
+ goto out_free;
+ }
+
+ while ((line_len = getline(&line, &buf_len, opts)) != -1) {
+ struct opts_list_t *tmp;
+
+ if (!strncmp(line, "no", 2))
+ continue;
+
+ tmp = malloc(sizeof(*tmp));
+ if (!tmp) {
+ ret = -ENOMEM;
+ goto out_free_opts_list;
+ }
+ tmp->next = opts_list;
+ tmp->opt_name = test_sprintf("no%s", line);
+ if (!tmp->opt_name) {
+ ret = -ENOMEM;
+ free(tmp);
+ goto out_free_opts_list;
+ }
+ opts_list = tmp;
+ }
+
+ while (opts_list) {
+ struct opts_list_t *tmp = opts_list;
+
+ fseek(opts, 0, SEEK_SET);
+ fwrite(tmp->opt_name, 1, strlen(tmp->opt_name), opts);
+
+ opts_list = opts_list->next;
+ free(tmp->opt_name);
+ free(tmp);
+ }
+
+out_free_opts_list:
+ while (opts_list) {
+ struct opts_list_t *tmp = opts_list;
+
+ opts_list = opts_list->next;
+ free(tmp->opt_name);
+ free(tmp);
+ }
+ free(line);
+ fclose(opts);
+out_free:
+ free(fopts);
+ return ret;
+}
+
+static int setup_buffer_size(const char *ftrace_path, size_t sz)
+{
+ char *fbuf_size = test_sprintf("%s/buffer_size_kb", ftrace_path);
+ int ret;
+
+ if (!fbuf_size)
+ return -1;
+
+ ret = test_echo(fbuf_size, 0, "%zu", sz);
+ free(fbuf_size);
+ return ret;
+}
+
+static int setup_ftrace_instance(struct test_ftracer *tracer, const char *name)
+{
+ char *tmp;
+
+ tmp = test_sprintf("%s/instances/ksft-%s-XXXXXX", ftrace_path, name);
+ if (!tmp)
+ return -ENOMEM;
+
+ tracer->instance_path = mkdtemp(tmp);
+ if (!tracer->instance_path) {
+ free(tmp);
+ return -errno;
+ }
+
+ return 0;
+}
+
+static void remove_ftrace_instance(struct test_ftracer *tracer)
+{
+ if (rmdir(tracer->instance_path))
+ test_print("Failed on cleanup: can't remove ftrace instance %s",
+ tracer->instance_path);
+ free(tracer->instance_path);
+}
+
+static void tracer_cleanup(void *arg)
+{
+ struct test_ftracer *tracer = arg;
+
+ fclose(tracer->trace_pipe);
+}
+
+static void tracer_set_error(struct test_ftracer *tracer, int error)
+{
+ if (!tracer->error)
+ tracer->error = error;
+}
+
+const size_t tracer_get_savedlines_nr(struct test_ftracer *tracer)
+{
+ return tracer->next_line_ind;
+}
+
+const char **tracer_get_savedlines(struct test_ftracer *tracer)
+{
+ return (const char **)tracer->saved_lines;
+}
+
+static void *tracer_thread_func(void *arg)
+{
+ struct test_ftracer *tracer = arg;
+
+ pthread_cleanup_push(tracer_cleanup, arg);
+
+ while (tracer->next_line_ind < tracer->saved_lines_size) {
+ char **lp = &tracer->saved_lines[tracer->next_line_ind];
+ enum ftracer_op op;
+ size_t buf_len = 0;
+ ssize_t line_len;
+
+ line_len = getline(lp, &buf_len, tracer->trace_pipe);
+ if (line_len == -1)
+ break;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ op = tracer->process_line(*lp);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+
+ if (tracer->expecting_more) {
+ pthread_mutex_lock(&tracer->met_all_expected_lock);
+ if (!tracer->expecting_more())
+ pthread_cond_signal(&tracer->met_all_expected);
+ pthread_mutex_unlock(&tracer->met_all_expected_lock);
+ }
+
+ if (op == FTRACER_LINE_DISCARD)
+ continue;
+ if (op == FTRACER_EXIT)
+ break;
+ if (op != FTRACER_LINE_PRESERVE)
+ test_error("unexpected tracer command %d", op);
+
+ tracer->next_line_ind++;
+ buf_len = 0;
+ }
+ test_print("too many lines in ftracer buffer %zu, exiting tracer",
+ tracer->next_line_ind);
+
+ pthread_cleanup_pop(1);
+ return NULL;
+}
+
+static int setup_trace_thread(struct test_ftracer *tracer)
+{
+ int ret = 0;
+ char *path;
+
+ path = test_sprintf("%s/trace_pipe", tracer->instance_path);
+ if (!path)
+ return -ENOMEM;
+
+ tracer->trace_pipe = fopen(path, "r");
+ if (!tracer->trace_pipe) {
+ ret = -errno;
+ goto out_free;
+ }
+
+ if (pthread_create(&tracer->tracer_thread, NULL,
+ tracer_thread_func, (void *)tracer)) {
+ ret = -errno;
+ fclose(tracer->trace_pipe);
+ }
+
+out_free:
+ free(path);
+ return ret;
+}
+
+static void stop_trace_thread(struct test_ftracer *tracer)
+{
+ void *res;
+
+ if (pthread_cancel(tracer->tracer_thread)) {
+ test_print("Can't stop tracer pthread: %m");
+ tracer_set_error(tracer, -errno);
+ }
+ if (pthread_join(tracer->tracer_thread, &res)) {
+ test_print("Can't join tracer pthread: %m");
+ tracer_set_error(tracer, -errno);
+ }
+ if (res != PTHREAD_CANCELED) {
+ test_print("Tracer thread wasn't canceled");
+ tracer_set_error(tracer, -errno);
+ }
+ if (tracer->error)
+ test_fail("tracer errored by %s", strerror(tracer->error));
+}
+
+static void final_wait_for_events(struct test_ftracer *tracer,
+ unsigned timeout_sec)
+{
+ struct timespec timeout;
+ struct timeval now;
+ int ret = 0;
+
+ if (!tracer->expecting_more)
+ return;
+
+ pthread_mutex_lock(&tracer->met_all_expected_lock);
+ gettimeofday(&now, NULL);
+ timeout.tv_sec = now.tv_sec + timeout_sec;
+ timeout.tv_nsec = now.tv_usec * 1000;
+
+ while (tracer->expecting_more() && ret != ETIMEDOUT)
+ ret = pthread_cond_timedwait(&tracer->met_all_expected,
+ &tracer->met_all_expected_lock, &timeout);
+ pthread_mutex_unlock(&tracer->met_all_expected_lock);
+}
+
+int setup_trace_event(struct test_ftracer *tracer,
+ const char *event, const char *filter)
+{
+ char *enable_path, *filter_path, *instance = tracer->instance_path;
+ int ret;
+
+ enable_path = test_sprintf("%s/events/%s/enable", instance, event);
+ if (!enable_path)
+ return -ENOMEM;
+
+ filter_path = test_sprintf("%s/events/%s/filter", instance, event);
+ if (!filter_path) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ ret = test_echo(filter_path, 0, "%s", filter);
+ if (!ret)
+ ret = test_echo(enable_path, 0, "1");
+
+out_free:
+ free(filter_path);
+ free(enable_path);
+ return ret;
+}
+
+struct test_ftracer *create_ftracer(const char *name,
+ enum ftracer_op (*process_line)(const char *line),
+ void (*destructor)(struct test_ftracer *tracer),
+ bool (*expecting_more)(void),
+ size_t lines_buf_sz, size_t buffer_size_kb)
+{
+ struct test_ftracer *tracer;
+ int err;
+
+ /* XXX: separate __create_ftracer() helper and do here
+ * if (!kernel_config_has(KCONFIG_FTRACE))
+ * return NULL;
+ */
+
+ tracer = malloc(sizeof(*tracer));
+ if (!tracer) {
+ test_print("malloc()");
+ return NULL;
+ }
+
+ memset(tracer, 0, sizeof(*tracer));
+
+ err = setup_ftrace_instance(tracer, name);
+ if (err) {
+ test_print("setup_ftrace_instance(): %d", err);
+ goto err_free;
+ }
+
+ err = disable_trace_options(tracer->instance_path);
+ if (err) {
+ test_print("disable_trace_options(): %d", err);
+ goto err_remove;
+ }
+
+ err = setup_buffer_size(tracer->instance_path, buffer_size_kb);
+ if (err) {
+ test_print("disable_trace_options(): %d", err);
+ goto err_remove;
+ }
+
+ tracer->saved_lines = calloc(lines_buf_sz, sizeof(tracer->saved_lines[0]));
+ if (!tracer->saved_lines) {
+ test_print("calloc()");
+ goto err_remove;
+ }
+ tracer->saved_lines_size = lines_buf_sz;
+
+ tracer->process_line = process_line;
+ tracer->destructor = destructor;
+ tracer->expecting_more = expecting_more;
+
+ err = pthread_cond_init(&tracer->met_all_expected, NULL);
+ if (err) {
+ test_print("pthread_cond_init(): %d", err);
+ goto err_free_lines;
+ }
+
+ err = pthread_mutex_init(&tracer->met_all_expected_lock, NULL);
+ if (err) {
+ test_print("pthread_mutex_init(): %d", err);
+ goto err_cond_destroy;
+ }
+
+ err = setup_trace_thread(tracer);
+ if (err) {
+ test_print("setup_trace_thread(): %d", err);
+ goto err_mutex_destroy;
+ }
+
+ pthread_mutex_lock(&ftracers_lock);
+ tracer->next = ftracers;
+ ftracers = tracer;
+ pthread_mutex_unlock(&ftracers_lock);
+
+ return tracer;
+
+err_mutex_destroy:
+ pthread_mutex_destroy(&tracer->met_all_expected_lock);
+err_cond_destroy:
+ pthread_cond_destroy(&tracer->met_all_expected);
+err_free_lines:
+ free(tracer->saved_lines);
+err_remove:
+ remove_ftrace_instance(tracer);
+err_free:
+ free(tracer);
+ return NULL;
+}
+
+static void __destroy_ftracer(struct test_ftracer *tracer)
+{
+ size_t i;
+
+ final_wait_for_events(tracer, TEST_TIMEOUT_SEC);
+ stop_trace_thread(tracer);
+ remove_ftrace_instance(tracer);
+ if (tracer->destructor)
+ tracer->destructor(tracer);
+ for (i = 0; i < tracer->saved_lines_size; i++)
+ free(tracer->saved_lines[i]);
+ pthread_cond_destroy(&tracer->met_all_expected);
+ pthread_mutex_destroy(&tracer->met_all_expected_lock);
+ free(tracer);
+}
+
+void destroy_ftracer(struct test_ftracer *tracer)
+{
+ pthread_mutex_lock(&ftracers_lock);
+ if (tracer == ftracers) {
+ ftracers = tracer->next;
+ } else {
+ struct test_ftracer *f = ftracers;
+
+ while (f->next != tracer) {
+ if (!f->next)
+ test_error("tracers list corruption or double free %p", tracer);
+ f = f->next;
+ }
+ f->next = tracer->next;
+ }
+ tracer->next = NULL;
+ pthread_mutex_unlock(&ftracers_lock);
+ __destroy_ftracer(tracer);
+}
+
+static void destroy_all_ftracers(void)
+{
+ struct test_ftracer *f;
+
+ pthread_mutex_lock(&ftracers_lock);
+ f = ftracers;
+ ftracers = NULL;
+ pthread_mutex_unlock(&ftracers_lock);
+
+ while (f) {
+ struct test_ftracer *n = f->next;
+
+ f->next = NULL;
+ __destroy_ftracer(f);
+ f = n;
+ }
+}
+
+static void test_unset_tracing(void)
+{
+ destroy_all_ftracers();
+ unmount_ftrace();
+}
+
+int test_setup_tracing(void)
+{
+ /*
+ * Just a basic protection - this should be called only once from
+ * lib/kconfig. Not thread safe, which is fine as it's early, before
+ * threads are created.
+ */
+ static int already_set;
+ int err;
+
+ if (already_set)
+ return -1;
+
+ /* Needs net-namespace cookies for filters */
+ if (ns_cookie1 == ns_cookie2) {
+ test_print("net-namespace cookies: %" PRIu64 " == %" PRIu64 ", can't set up tracing",
+ ns_cookie1, ns_cookie2);
+ return -1;
+ }
+
+ already_set = 1;
+
+ test_add_destructor(test_unset_tracing);
+
+ err = mount_ftrace();
+ if (err) {
+ test_print("failed to mount_ftrace(): %d", err);
+ return err;
+ }
+
+ return setup_aolib_ftracer();
+}
+
+static int get_ns_cookie(int nsfd, uint64_t *out)
+{
+ int old_ns = switch_save_ns(nsfd);
+ socklen_t size = sizeof(*out);
+ int sk;
+
+ sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0) {
+ test_print("socket(): %m");
+ return -errno;
+ }
+
+ if (getsockopt(sk, SOL_SOCKET, SO_NETNS_COOKIE, out, &size)) {
+ test_print("getsockopt(SO_NETNS_COOKIE): %m");
+ close(sk);
+ return -errno;
+ }
+
+ close(sk);
+ switch_close_ns(old_ns);
+ return 0;
+}
+
+void test_init_ftrace(int nsfd1, int nsfd2)
+{
+ get_ns_cookie(nsfd1, &ns_cookie1);
+ get_ns_cookie(nsfd2, &ns_cookie2);
+ /* Populate kernel config state */
+ kernel_config_has(KCONFIG_FTRACE);
+}
diff --git a/tools/testing/selftests/net/tcp_ao/lib/kconfig.c b/tools/testing/selftests/net/tcp_ao/lib/kconfig.c
index f279ffc3843b..9f1c175846f8 100644
--- a/tools/testing/selftests/net/tcp_ao/lib/kconfig.c
+++ b/tools/testing/selftests/net/tcp_ao/lib/kconfig.c
@@ -6,7 +6,7 @@
#include "aolib.h"
struct kconfig_t {
- int _errno; /* the returned error if not supported */
+ int _error; /* negative errno if not supported */
int (*check_kconfig)(int *error);
};
@@ -62,7 +62,7 @@ static int has_tcp_ao(int *err)
memcpy(&tmp.addr, &addr, sizeof(addr));
*err = 0;
if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tmp, sizeof(tmp)) < 0) {
- *err = errno;
+ *err = -errno;
if (errno != ENOPROTOOPT)
ret = -errno;
}
@@ -87,7 +87,7 @@ static int has_tcp_md5(int *err)
*/
*err = 0;
if (test_set_md5(sk, addr_any, 0, -1, DEFAULT_TEST_PASSWORD)) {
- *err = errno;
+ *err = -errno;
if (errno != ENOPROTOOPT && errno == ENOMEM) {
test_print("setsockopt(TCP_MD5SIG_EXT): %m");
ret = -errno;
@@ -116,13 +116,21 @@ static int has_vrfs(int *err)
return ret;
}
+static int has_ftrace(int *err)
+{
+ *err = test_setup_tracing();
+ return 0;
+}
+
+#define KCONFIG_UNKNOWN 1
static pthread_mutex_t kconfig_lock = PTHREAD_MUTEX_INITIALIZER;
static struct kconfig_t kconfig[__KCONFIG_LAST__] = {
- { -1, has_net_ns },
- { -1, has_veth },
- { -1, has_tcp_ao },
- { -1, has_tcp_md5 },
- { -1, has_vrfs },
+ { KCONFIG_UNKNOWN, has_net_ns },
+ { KCONFIG_UNKNOWN, has_veth },
+ { KCONFIG_UNKNOWN, has_tcp_ao },
+ { KCONFIG_UNKNOWN, has_tcp_md5 },
+ { KCONFIG_UNKNOWN, has_vrfs },
+ { KCONFIG_UNKNOWN, has_ftrace },
};
const char *tests_skip_reason[__KCONFIG_LAST__] = {
@@ -131,6 +139,7 @@ const char *tests_skip_reason[__KCONFIG_LAST__] = {
"Tests require TCP-AO support (CONFIG_TCP_AO)",
"setsockopt(TCP_MD5SIG_EXT) is not supported (CONFIG_TCP_MD5)",
"VRFs are not supported (CONFIG_NET_VRF)",
+ "Ftrace points are not supported (CONFIG_TRACEPOINTS)",
};
bool kernel_config_has(enum test_needs_kconfig k)
@@ -138,11 +147,11 @@ bool kernel_config_has(enum test_needs_kconfig k)
bool ret;
pthread_mutex_lock(&kconfig_lock);
- if (kconfig[k]._errno == -1) {
- if (kconfig[k].check_kconfig(&kconfig[k]._errno))
+ if (kconfig[k]._error == KCONFIG_UNKNOWN) {
+ if (kconfig[k].check_kconfig(&kconfig[k]._error))
test_error("Failed to initialize kconfig %u", k);
}
- ret = kconfig[k]._errno == 0;
+ ret = kconfig[k]._error == 0;
pthread_mutex_unlock(&kconfig_lock);
return ret;
}
diff --git a/tools/testing/selftests/net/tcp_ao/lib/setup.c b/tools/testing/selftests/net/tcp_ao/lib/setup.c
index e408b9243b2c..a27cc03c9fbd 100644
--- a/tools/testing/selftests/net/tcp_ao/lib/setup.c
+++ b/tools/testing/selftests/net/tcp_ao/lib/setup.c
@@ -111,7 +111,7 @@ static void sig_int(int signo)
int open_netns(void)
{
- const char *netns_path = "/proc/self/ns/net";
+ const char *netns_path = "/proc/thread-self/ns/net";
int fd;
fd = open(netns_path, O_RDONLY);
@@ -142,6 +142,13 @@ int switch_save_ns(int new_ns)
return ret;
}
+void switch_close_ns(int fd)
+{
+ if (setns(fd, CLONE_NEWNET))
+ test_error("setns()");
+ close(fd);
+}
+
static int nsfd_outside = -1;
static int nsfd_parent = -1;
static int nsfd_child = -1;
@@ -243,9 +250,9 @@ void __test_init(unsigned int ntests, int family, unsigned int prefix,
test_print("rand seed %u", (unsigned int)seed);
srand(seed);
-
ksft_print_header();
init_namespaces();
+ test_init_ftrace(nsfd_parent, nsfd_child);
if (add_veth(veth_name, nsfd_parent, nsfd_child))
test_error("Failed to add veth");
@@ -296,7 +303,7 @@ static bool is_optmem_namespaced(void)
int old_ns = switch_save_ns(nsfd_child);
optmem_ns = !access(optmem_file, F_OK);
- switch_ns(old_ns);
+ switch_close_ns(old_ns);
}
return !!optmem_ns;
}
@@ -317,7 +324,7 @@ size_t test_get_optmem(void)
test_error("can't read from %s", optmem_file);
fclose(foptmem);
if (!is_optmem_namespaced())
- switch_ns(old_ns);
+ switch_close_ns(old_ns);
return ret;
}
@@ -339,7 +346,7 @@ static void __test_set_optmem(size_t new, size_t *old)
test_error("can't write %zu to %s", new, optmem_file);
fclose(foptmem);
if (!is_optmem_namespaced())
- switch_ns(old_ns);
+ switch_close_ns(old_ns);
}
static void test_revert_optmem(void)
diff --git a/tools/testing/selftests/net/tcp_ao/lib/sock.c b/tools/testing/selftests/net/tcp_ao/lib/sock.c
index 15aeb0963058..ef8e9031d47a 100644
--- a/tools/testing/selftests/net/tcp_ao/lib/sock.c
+++ b/tools/testing/selftests/net/tcp_ao/lib/sock.c
@@ -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 @@ out:
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,14 +448,13 @@ 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;
key_dump[0].nkeys = nr_keys;
key_dump[0].get_all = 1;
- key_dump[0].get_all = 1;
err = getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS,
key_dump, &key_dump_sz);
if (err) {
@@ -387,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", \
@@ -462,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",
@@ -486,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;
@@ -508,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;
@@ -519,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;
@@ -534,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)");
@@ -548,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;
@@ -562,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;
@@ -581,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;
diff --git a/tools/testing/selftests/net/tcp_ao/lib/utils.c b/tools/testing/selftests/net/tcp_ao/lib/utils.c
index 372daca525f5..bdf5522c9213 100644
--- a/tools/testing/selftests/net/tcp_ao/lib/utils.c
+++ b/tools/testing/selftests/net/tcp_ao/lib/utils.c
@@ -21,6 +21,32 @@ void randomize_buffer(void *buf, size_t buflen)
}
}
+__printf(3, 4) int test_echo(const char *fname, bool append,
+ const char *fmt, ...)
+{
+ size_t len, written;
+ va_list vargs;
+ char *msg;
+ FILE *f;
+
+ f = fopen(fname, append ? "a" : "w");
+ if (!f)
+ return -errno;
+
+ va_start(vargs, fmt);
+ msg = test_snprintf(fmt, vargs);
+ va_end(vargs);
+ if (!msg) {
+ fclose(f);
+ return -1;
+ }
+ len = strlen(msg);
+ written = fwrite(msg, 1, len, f);
+ fclose(f);
+ free(msg);
+ return written == len ? 0 : -1;
+}
+
const struct sockaddr_in6 addr_any6 = {
.sin6_family = AF_INET6,
};
diff --git a/tools/testing/selftests/net/tcp_ao/restore.c b/tools/testing/selftests/net/tcp_ao/restore.c
index 8fdc808df325..9a059b6c4523 100644
--- a/tools/testing/selftests/net/tcp_ao/restore.c
+++ b/tools/testing/selftests/net/tcp_ao/restore.c
@@ -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);
@@ -64,17 +63,18 @@ static void try_server_run(const char *tst_name, unsigned int port,
else
test_ok("%s: server alive", tst_name);
}
- if (test_get_tcp_ao_counters(sk, &ao2))
- test_error("test_get_tcp_ao_counters()");
+ synchronize_threads(); /* 3: counters checks */
+ 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: %zu <= %zu",
- 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 %zu => %zu",
+ test_ok("%s(server): counter %s increased %" PRIu64 " => %" PRIu64,
tst_name, cnt_name, before_cnt, after_cnt);
}
@@ -82,7 +82,7 @@ static void try_server_run(const char *tst_name, unsigned int port,
* 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 */
+ synchronize_threads(); /* 4: verified => closed */
out:
close(sk);
}
@@ -91,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;
@@ -124,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);
@@ -138,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";
@@ -158,38 +158,39 @@ 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);
}
- if (test_get_tcp_ao_counters(sk, &ao2))
- test_error("test_get_tcp_ao_counters()");
+
+ synchronize_threads(); /* 3: counters checks */
+ 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: %zu <= %zu",
+ test_fail("%s: %s counter did not increase: %" PRIu64 " <= %" PRIu64,
tst_name, cnt_name, after_cnt, before_cnt);
} else {
- test_ok("%s: counter %s increased %zu => %zu",
+ test_ok("%s: counter %s increased %" PRIu64 " => %" PRIu64,
tst_name, cnt_name, before_cnt, after_cnt);
}
- synchronize_threads(); /* 3: verified => closed */
+ synchronize_threads(); /* 4: verified => closed */
close(sk);
}
@@ -201,29 +202,43 @@ 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);
ao_img.snt_isn += 1;
- test_sk_restore("TCP-AO with wrong send ISN", port++,
+ trace_ao_event_expect(TCP_AO_MISMATCH, this_ip_addr, this_ip_dest,
+ -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 (client)", 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++,
+ trace_ao_event_expect(TCP_AO_MISMATCH, this_ip_addr, this_ip_dest,
+ -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 (client)", 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,
+ 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 (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);
ao_img.rcv_sne += 1;
- test_sk_restore("TCP-AO with wrong receive SEQ ext number", port++,
- &saddr, &tcp_img, &ao_img, FAULT_TIMEOUT,
+ /* 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 (client)",
+ port++, &saddr, &tcp_img, &ao_img, FAULT_TIMEOUT,
TEST_CNT_NS_GOOD | TEST_CNT_BAD);
return NULL;
@@ -231,6 +246,6 @@ static void *client_fn(void *arg)
int main(int argc, char *argv[])
{
- test_init(20, server_fn, client_fn);
+ test_init(21, server_fn, client_fn);
return 0;
}
diff --git a/tools/testing/selftests/net/tcp_ao/rst.c b/tools/testing/selftests/net/tcp_ao/rst.c
index a2fe88d35ac0..883cddf377cf 100644
--- a/tools/testing/selftests/net/tcp_ao/rst.c
+++ b/tools/testing/selftests/net/tcp_ao/rst.c
@@ -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)
@@ -455,6 +454,6 @@ static void *client_fn(void *arg)
int main(int argc, char *argv[])
{
- test_init(14, server_fn, client_fn);
+ test_init(15, server_fn, client_fn);
return 0;
}
diff --git a/tools/testing/selftests/net/tcp_ao/self-connect.c b/tools/testing/selftests/net/tcp_ao/self-connect.c
index e154d9e198a9..2c73bea698a6 100644
--- a/tools/testing/selftests/net/tcp_ao/self-connect.c
+++ b/tools/testing/selftests/net/tcp_ao/self-connect.c
@@ -16,6 +16,9 @@ static void __setup_lo_intf(const char *lo_intf,
if (link_set_up(lo_intf))
test_error("Failed to bring %s up", lo_intf);
+
+ if (ip_route_add(lo_intf, TEST_FAMILY, local_addr, local_addr))
+ test_error("Failed to add a local route %s", lo_intf);
}
static void setup_lo_intf(const char *lo_intf)
@@ -30,9 +33,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)
{
- uint64_t before_challenge_ack, after_challenge_ack;
- uint64_t before_syn_challenge, after_syn_challenge;
- 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;
@@ -62,19 +63,17 @@ static void tcp_self_connect(const char *tst, unsigned int port,
ns_before = netstat_read();
before_aogood = netstat_get(ns_before, "TCPAOGood", NULL);
- before_challenge_ack = netstat_get(ns_before, "TCPChallengeACK", NULL);
- before_syn_challenge = netstat_get(ns_before, "TCPSYNChallenge", 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;
@@ -82,10 +81,8 @@ static void tcp_self_connect(const char *tst, unsigned int port,
ns_after = netstat_read();
after_aogood = netstat_get(ns_after, "TCPAOGood", NULL);
- after_challenge_ack = netstat_get(ns_after, "TCPChallengeACK", NULL);
- after_syn_challenge = netstat_get(ns_after, "TCPSYNChallenge", 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,25 +90,13 @@ static void tcp_self_connect(const char *tst, unsigned int port,
netstat_free(ns_after);
if (after_aogood <= before_aogood) {
- test_fail("%s: TCPAOGood counter mismatch: %zu <= %zu",
+ test_fail("%s: TCPAOGood counter mismatch: %" PRIu64 " <= %" PRIu64,
tst, after_aogood, before_aogood);
close(sk);
return;
}
- if (after_challenge_ack <= before_challenge_ack ||
- after_syn_challenge <= before_syn_challenge) {
- /*
- * It's also meant to test simultaneous open, so check
- * these counters as well.
- */
- test_fail("%s: Didn't challenge SYN or ACK: %zu <= %zu OR %zu <= %zu",
- tst, after_challenge_ack, before_challenge_ack,
- after_syn_challenge, before_syn_challenge);
- close(sk);
- 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;
}
@@ -154,7 +139,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;
@@ -166,7 +151,7 @@ static void tcp_self_connect(const char *tst, unsigned int port,
netstat_free(ns_after);
close(sk);
if (after_aogood <= before_aogood) {
- test_fail("%s: TCPAOGood counter mismatch: %zu <= %zu",
+ test_fail("%s: TCPAOGood counter mismatch: %" PRIu64 " <= %" PRIu64,
tst, after_aogood, before_aogood);
return;
}
@@ -181,17 +166,26 @@ static void *client_fn(void *arg)
setup_lo_intf("lo");
tcp_self_connect("self-connect(same keyids)", port++, false, false);
+
+ /* expecting rnext to change based on the first segment RNext != Current */
+ trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, local_addr, local_addr,
+ port, port, 0, -1, -1, -1, -1, -1, 7, 5, -1);
tcp_self_connect("self-connect(different keyids)", port++, true, false);
tcp_self_connect("self-connect(restore)", port, false, true);
- port += 2;
+ port += 2; /* restore test restores over different port */
+ trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, local_addr, local_addr,
+ port, port, 0, -1, -1, -1, -1, -1, 7, 5, -1);
+ /* intentionally on restore they are added to the socket in different order */
+ trace_ao_event_expect(TCP_AO_RNEXT_REQUEST, local_addr, local_addr,
+ port + 1, port + 1, 0, -1, -1, -1, -1, -1, 5, 7, -1);
tcp_self_connect("self-connect(restore, different keyids)", port, true, true);
- port += 2;
+ port += 2; /* restore test restores over different port */
return NULL;
}
int main(int argc, char *argv[])
{
- test_init(4, client_fn, NULL);
+ test_init(5, client_fn, NULL);
return 0;
}
diff --git a/tools/testing/selftests/net/tcp_ao/seq-ext.c b/tools/testing/selftests/net/tcp_ao/seq-ext.c
index ad4e77d6823e..f00245263b20 100644
--- a/tools/testing/selftests/net/tcp_ao/seq-ext.c
+++ b/tools/testing/selftests/net/tcp_ao/seq-ext.c
@@ -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,9 +114,17 @@ 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);
-
- synchronize_threads(); /* 5: verify counters during SEQ-number rollover */
+ 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);
+ trace_ao_event_sne_expect(TCP_AO_SND_SNE_UPDATE, this_ip_dest,
+ this_ip_addr, client_new_port, test_server_port + 1, 1);
+ trace_ao_event_sne_expect(TCP_AO_RCV_SNE_UPDATE, this_ip_addr,
+ this_ip_dest, test_server_port + 1, client_new_port, 1);
+ trace_ao_event_sne_expect(TCP_AO_RCV_SNE_UPDATE, this_ip_dest,
+ this_ip_addr, client_new_port, test_server_port + 1, 1);
+ synchronize_threads(); /* 5: verify the connection during SEQ-number rollover */
bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
if (bytes != quota) {
if (bytes > 0)
@@ -127,22 +135,23 @@ static void *server_fn(void *arg)
test_ok("server alive");
}
- if (test_get_tcp_ao_counters(sk, &ao2))
- test_error("test_get_tcp_ao_counters()");
+ synchronize_threads(); /* 6: verify counters after SEQ-number rollover */
+ 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: %zu <= %zu",
+ test_fail("TCPAOGood counter did not increase: %" PRIu64 " <= %" PRIu64,
after_good, before_good);
} else {
- test_ok("TCPAOGood counter increased %zu => %zu",
+ test_ok("TCPAOGood counter increased %" PRIu64 " => %" PRIu64,
before_good, after_good);
}
after_bad = netstat_get_one("TCPAOBad", NULL);
if (after_bad)
- test_fail("TCPAOBad counter is non-zero: %zu", after_bad);
+ test_fail("TCPAOBad counter is non-zero: %" PRIu64, after_bad);
else
test_ok("TCPAOBad counter didn't increase");
test_enable_repair(sk);
@@ -164,7 +173,7 @@ out:
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;
@@ -182,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;
}
@@ -204,30 +213,31 @@ 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 counters during SEQ-number rollover */
- if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
+ synchronize_threads(); /* 5: verify the connection during SEQ-number rollover */
+ if (test_client_verify(sk, msg_len, nr_packets))
test_fail("post-migrate verify failed");
else
test_ok("post-migrate connection alive");
- if (test_get_tcp_ao_counters(sk, &ao2))
- test_error("test_get_tcp_ao_counters()");
+ synchronize_threads(); /* 5: verify counters after SEQ-number rollover */
+ 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: %zu <= %zu",
+ test_fail("TCPAOGood counter did not increase: %" PRIu64 " <= %" PRIu64,
after_good, before_good);
} else {
- test_ok("TCPAOGood counter increased %zu => %zu",
+ test_ok("TCPAOGood counter increased %" PRIu64 " => %" PRIu64,
before_good, after_good);
}
after_bad = netstat_get_one("TCPAOBad", NULL);
if (after_bad)
- test_fail("TCPAOBad counter is non-zero: %zu", after_bad);
+ test_fail("TCPAOBad counter is non-zero: %" PRIu64, after_bad);
else
test_ok("TCPAOBad counter didn't increase");
@@ -240,6 +250,6 @@ static void *client_fn(void *arg)
int main(int argc, char *argv[])
{
- test_init(7, server_fn, client_fn);
+ test_init(8, server_fn, client_fn);
return 0;
}
diff --git a/tools/testing/selftests/net/tcp_ao/setsockopt-closed.c b/tools/testing/selftests/net/tcp_ao/setsockopt-closed.c
index 517930f9721b..0abb9807d742 100644
--- a/tools/testing/selftests/net/tcp_ao/setsockopt-closed.c
+++ b/tools/testing/selftests/net/tcp_ao/setsockopt-closed.c
@@ -6,6 +6,8 @@
static union tcp_addr tcp_md5_client;
+#define FILTER_TEST_NKEYS 16
+
static int test_port = 7788;
static void make_listen(int sk)
{
@@ -30,8 +32,8 @@ static void test_vefify_ao_info(int sk, struct tcp_ao_info_opt *info,
#define __cmp_ao(member) \
do { \
if (info->member != tmp.member) { \
- test_fail("%s: getsockopt(): " __stringify(member) " %zu != %zu", \
- tst, (size_t)info->member, (size_t)tmp.member); \
+ test_fail("%s: getsockopt(): " __stringify(member) " %" PRIu64 " != %" PRIu64, \
+ tst, (uint64_t)info->member, (uint64_t)tmp.member); \
return; \
} \
} while(0)
@@ -813,23 +815,197 @@ static void duplicate_tests(void)
setsockopt_checked(sk, TCP_AO_ADD_KEY, &ao, EEXIST, "duplicate: SendID differs");
}
+static void fetch_all_keys(int sk, struct tcp_ao_getsockopt *keys)
+{
+ socklen_t optlen = sizeof(struct tcp_ao_getsockopt);
+
+ memset(keys, 0, sizeof(struct tcp_ao_getsockopt) * FILTER_TEST_NKEYS);
+ keys[0].get_all = 1;
+ keys[0].nkeys = FILTER_TEST_NKEYS;
+ if (getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, &keys[0], &optlen))
+ test_error("getsockopt");
+}
+
+static int prepare_test_keys(struct tcp_ao_getsockopt *keys)
+{
+ const char *test_password = "Test password number ";
+ struct tcp_ao_add test_ao[FILTER_TEST_NKEYS];
+ char test_password_scratch[64] = {};
+ u8 rcvid = 100, sndid = 100;
+ int sk;
+
+ sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
+ if (sk < 0)
+ test_error("socket()");
+
+ for (int i = 0; i < FILTER_TEST_NKEYS; i++) {
+ snprintf(test_password_scratch, 64, "%s %d", test_password, i);
+ test_prepare_key(&test_ao[i], DEFAULT_TEST_ALGO, this_ip_dest,
+ false, false, DEFAULT_TEST_PREFIX, 0, sndid++,
+ rcvid++, 0, 0, strlen(test_password_scratch),
+ test_password_scratch);
+ }
+ test_ao[0].set_current = 1;
+ test_ao[1].set_rnext = 1;
+ /* One key with a different addr and overlapping sndid, rcvid */
+ tcp_addr_to_sockaddr_in(&test_ao[2].addr, &this_ip_addr, 0);
+ test_ao[2].sndid = 100;
+ test_ao[2].rcvid = 100;
+
+ /* Add keys in a random order */
+ for (int i = 0; i < FILTER_TEST_NKEYS; i++) {
+ int randidx = rand() % (FILTER_TEST_NKEYS - i);
+
+ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY,
+ &test_ao[randidx], sizeof(struct tcp_ao_add)))
+ test_error("setsockopt()");
+ memcpy(&test_ao[randidx], &test_ao[FILTER_TEST_NKEYS - 1 - i],
+ sizeof(struct tcp_ao_add));
+ }
+
+ fetch_all_keys(sk, keys);
+
+ return sk;
+}
+
+/* Assumes passwords are unique */
+static int compare_mkts(struct tcp_ao_getsockopt *expected, int nexpected,
+ struct tcp_ao_getsockopt *actual, int nactual)
+{
+ int matches = 0;
+
+ for (int i = 0; i < nexpected; i++) {
+ for (int j = 0; j < nactual; j++) {
+ if (memcmp(expected[i].key, actual[j].key,
+ TCP_AO_MAXKEYLEN) == 0)
+ matches++;
+ }
+ }
+ return nexpected - matches;
+}
+
+static void filter_keys_checked(int sk, struct tcp_ao_getsockopt *filter,
+ struct tcp_ao_getsockopt *expected,
+ unsigned int nexpected, const char *tst)
+{
+ struct tcp_ao_getsockopt filtered_keys[FILTER_TEST_NKEYS] = {};
+ struct tcp_ao_getsockopt all_keys[FILTER_TEST_NKEYS] = {};
+ socklen_t len = sizeof(struct tcp_ao_getsockopt);
+
+ fetch_all_keys(sk, all_keys);
+ memcpy(&filtered_keys[0], filter, sizeof(struct tcp_ao_getsockopt));
+ filtered_keys[0].nkeys = FILTER_TEST_NKEYS;
+ if (getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, filtered_keys, &len))
+ test_error("getsockopt");
+ if (filtered_keys[0].nkeys != nexpected) {
+ test_fail("wrong nr of keys, expected %u got %u", nexpected,
+ filtered_keys[0].nkeys);
+ goto out_close;
+ }
+ if (compare_mkts(expected, nexpected, filtered_keys,
+ filtered_keys[0].nkeys)) {
+ test_fail("got wrong keys back");
+ goto out_close;
+ }
+ test_ok("filter keys: %s", tst);
+
+out_close:
+ close(sk);
+ memset(filter, 0, sizeof(struct tcp_ao_getsockopt));
+}
+
+static void filter_tests(void)
+{
+ struct tcp_ao_getsockopt original_keys[FILTER_TEST_NKEYS];
+ struct tcp_ao_getsockopt expected_keys[FILTER_TEST_NKEYS];
+ struct tcp_ao_getsockopt filter = {};
+ int sk, f, nmatches;
+ socklen_t len;
+
+ f = 2;
+ sk = prepare_test_keys(original_keys);
+ filter.rcvid = original_keys[f].rcvid;
+ filter.sndid = original_keys[f].sndid;
+ memcpy(&filter.addr, &original_keys[f].addr,
+ sizeof(original_keys[f].addr));
+ filter.prefix = original_keys[f].prefix;
+ filter_keys_checked(sk, &filter, &original_keys[f], 1,
+ "by sndid, rcvid, address");
+
+ f = -1;
+ sk = prepare_test_keys(original_keys);
+ for (int i = 0; i < original_keys[0].nkeys; i++) {
+ if (original_keys[i].is_current) {
+ f = i;
+ break;
+ }
+ }
+ if (f < 0)
+ test_error("No current key after adding one");
+ filter.is_current = 1;
+ filter_keys_checked(sk, &filter, &original_keys[f], 1, "by is_current");
+
+ f = -1;
+ sk = prepare_test_keys(original_keys);
+ for (int i = 0; i < original_keys[0].nkeys; i++) {
+ if (original_keys[i].is_rnext) {
+ f = i;
+ break;
+ }
+ }
+ if (f < 0)
+ test_error("No rnext key after adding one");
+ filter.is_rnext = 1;
+ filter_keys_checked(sk, &filter, &original_keys[f], 1, "by is_rnext");
+
+ f = -1;
+ nmatches = 0;
+ sk = prepare_test_keys(original_keys);
+ for (int i = 0; i < original_keys[0].nkeys; i++) {
+ if (original_keys[i].sndid == 100) {
+ f = i;
+ memcpy(&expected_keys[nmatches], &original_keys[i],
+ sizeof(struct tcp_ao_getsockopt));
+ nmatches++;
+ }
+ }
+ if (f < 0)
+ test_error("No key for sndid 100");
+ if (nmatches != 2)
+ test_error("Should have 2 keys with sndid 100");
+ filter.rcvid = original_keys[f].rcvid;
+ filter.sndid = original_keys[f].sndid;
+ filter.addr.ss_family = test_family;
+ filter_keys_checked(sk, &filter, expected_keys, nmatches,
+ "by sndid, rcvid");
+
+ sk = prepare_test_keys(original_keys);
+ filter.get_all = 1;
+ filter.nkeys = FILTER_TEST_NKEYS / 2;
+ len = sizeof(struct tcp_ao_getsockopt);
+ if (getsockopt(sk, IPPROTO_TCP, TCP_AO_GET_KEYS, &filter, &len))
+ test_error("getsockopt");
+ if (filter.nkeys == FILTER_TEST_NKEYS)
+ test_ok("filter keys: correct nkeys when in.nkeys < matches");
+ else
+ test_fail("filter keys: wrong nkeys, expected %u got %u",
+ FILTER_TEST_NKEYS, filter.nkeys);
+}
+
static void *client_fn(void *arg)
{
if (inet_pton(TEST_FAMILY, __TEST_CLIENT_IP(2), &tcp_md5_client) != 1)
test_error("Can't convert ip address");
extend_tests();
einval_tests();
+ filter_tests();
duplicate_tests();
- /*
- * TODO: check getsockopt(TCP_AO_GET_KEYS) with different filters
- * returning proper nr & keys;
- */
return NULL;
}
int main(int argc, char *argv[])
{
- test_init(120, client_fn, NULL);
+ test_init(126, client_fn, NULL);
return 0;
}
diff --git a/tools/testing/selftests/net/tcp_ao/unsigned-md5.c b/tools/testing/selftests/net/tcp_ao/unsigned-md5.c
index 6b59a652159f..a1467b64390a 100644
--- a/tools/testing/selftests/net/tcp_ao/unsigned-md5.c
+++ b/tools/testing/selftests/net/tcp_ao/unsigned-md5.c
@@ -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,21 +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) {
@@ -88,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) {
@@ -100,18 +105,18 @@ static void try_accept(const char *tst_name, unsigned int port,
after_cnt = netstat_get_one(cnt_name, NULL);
if (after_cnt <= before_cnt) {
- test_fail("%s: %s counter did not increase: %zu <= %zu",
+ test_fail("%s: %s counter did not increase: %" PRIu64 " <= %" PRIu64,
tst_name, cnt_name, after_cnt, before_cnt);
} else {
- test_ok("%s: counter %s increased %zu => %zu",
+ test_ok("%s: counter %s increased %" PRIu64 " => %" PRIu64,
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);
}
@@ -152,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);
@@ -258,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))
@@ -280,10 +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))
@@ -303,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);
}
@@ -435,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))
@@ -448,10 +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);
- if (ret <= 0) {
+ synchronize_threads(); /* connect()/accept() timeouts */
+ if (ret < 0) {
test_error("%s: connect() returned %d", tst_name, ret);
goto out;
}
@@ -487,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);
}
@@ -671,24 +676,38 @@ static void *client_fn(void *arg)
try_connect("AO server (INADDR_ANY): AO client", port++, NULL, 0,
&addr_any, 0, 100, 100, 0, 0, 0, &this_ip_addr);
+ trace_hash_event_expect(TCP_HASH_MD5_UNEXPECTED, this_ip_addr,
+ this_ip_dest, -1, port, 0, 0, 1, 0, 0, 0);
try_connect("AO server (INADDR_ANY): MD5 client", port++, &addr_any, 0,
NULL, 0, 100, 100, 0, FAULT_TIMEOUT, 1, &this_ip_addr);
+ trace_hash_event_expect(TCP_HASH_AO_REQUIRED, this_ip_addr,
+ this_ip_dest, -1, port, 0, 0, 1, 0, 0, 0);
try_connect("AO server (INADDR_ANY): unsigned client", port++, NULL, 0,
NULL, 0, 100, 100, 0, FAULT_TIMEOUT, 0, &this_ip_addr);
try_connect("AO server (AO_REQUIRED): AO client", port++, NULL, 0,
&addr_any, 0, 100, 100, 0, 0, 0, &this_ip_addr);
+ trace_hash_event_expect(TCP_HASH_AO_REQUIRED, client2,
+ this_ip_dest, -1, port, 0, 0, 1, 0, 0, 0);
try_connect("AO server (AO_REQUIRED): unsigned client", port++, NULL, 0,
NULL, 0, 100, 100, 0, FAULT_TIMEOUT, 0, &client2);
+ trace_ao_event_expect(TCP_AO_KEY_NOT_FOUND, this_ip_addr, this_ip_dest,
+ -1, port, 0, 0, 1, 0, 0, 0, 100, 100, -1);
try_connect("MD5 server (INADDR_ANY): AO client", port++, NULL, 0,
&addr_any, 0, 100, 100, 0, FAULT_TIMEOUT, 1, &this_ip_addr);
try_connect("MD5 server (INADDR_ANY): MD5 client", port++, &addr_any, 0,
NULL, 0, 100, 100, 0, 0, 1, &this_ip_addr);
+ trace_hash_event_expect(TCP_HASH_MD5_REQUIRED, this_ip_addr,
+ this_ip_dest, -1, port, 0, 0, 1, 0, 0, 0);
try_connect("MD5 server (INADDR_ANY): no sign client", port++, NULL, 0,
NULL, 0, 100, 100, 0, FAULT_TIMEOUT, 1, &this_ip_addr);
+ trace_ao_event_expect(TCP_AO_KEY_NOT_FOUND, this_ip_addr, this_ip_dest,
+ -1, port, 0, 0, 1, 0, 0, 0, 100, 100, -1);
try_connect("no sign server: AO client", port++, NULL, 0,
&addr_any, 0, 100, 100, 0, FAULT_TIMEOUT, 0, &this_ip_addr);
+ trace_hash_event_expect(TCP_HASH_MD5_UNEXPECTED, this_ip_addr,
+ this_ip_dest, -1, port, 0, 0, 1, 0, 0, 0);
try_connect("no sign server: MD5 client", port++, &addr_any, 0,
NULL, 0, 100, 100, 0, FAULT_TIMEOUT, 1, &this_ip_addr);
try_connect("no sign server: no sign client", port++, NULL, 0,
@@ -696,25 +715,37 @@ static void *client_fn(void *arg)
try_connect("AO+MD5 server: AO client (matching)", port++, NULL, 0,
&addr_any, 0, 100, 100, 0, 0, 1, &client2);
+ trace_ao_event_expect(TCP_AO_KEY_NOT_FOUND, this_ip_addr, this_ip_dest,
+ -1, port, 0, 0, 1, 0, 0, 0, 100, 100, -1);
try_connect("AO+MD5 server: AO client (misconfig, matching MD5)",
port++, NULL, 0, &addr_any, 0, 100, 100, 0,
FAULT_TIMEOUT, 1, &this_ip_addr);
+ trace_ao_event_expect(TCP_AO_KEY_NOT_FOUND, client3, this_ip_dest,
+ -1, port, 0, 0, 1, 0, 0, 0, 100, 100, -1);
try_connect("AO+MD5 server: AO client (misconfig, non-matching)",
port++, NULL, 0, &addr_any, 0, 100, 100, 0,
FAULT_TIMEOUT, 1, &client3);
try_connect("AO+MD5 server: MD5 client (matching)", port++, &addr_any, 0,
NULL, 0, 100, 100, 0, 0, 1, &this_ip_addr);
+ trace_hash_event_expect(TCP_HASH_MD5_UNEXPECTED, client2,
+ this_ip_dest, -1, port, 0, 0, 1, 0, 0, 0);
try_connect("AO+MD5 server: MD5 client (misconfig, matching AO)",
port++, &addr_any, 0, NULL, 0, 100, 100, 0, FAULT_TIMEOUT,
1, &client2);
+ trace_hash_event_expect(TCP_HASH_MD5_UNEXPECTED, client3,
+ this_ip_dest, -1, port, 0, 0, 1, 0, 0, 0);
try_connect("AO+MD5 server: MD5 client (misconfig, non-matching)",
port++, &addr_any, 0, NULL, 0, 100, 100, 0, FAULT_TIMEOUT,
1, &client3);
try_connect("AO+MD5 server: no sign client (unmatched)",
port++, NULL, 0, NULL, 0, 100, 100, 0, 0, 1, &client3);
+ trace_hash_event_expect(TCP_HASH_AO_REQUIRED, client2,
+ this_ip_dest, -1, port, 0, 0, 1, 0, 0, 0);
try_connect("AO+MD5 server: no sign client (misconfig, matching AO)",
port++, NULL, 0, NULL, 0, 100, 100, 0, FAULT_TIMEOUT,
1, &client2);
+ trace_hash_event_expect(TCP_HASH_MD5_REQUIRED, this_ip_addr,
+ this_ip_dest, -1, port, 0, 0, 1, 0, 0, 0);
try_connect("AO+MD5 server: no sign client (misconfig, matching MD5)",
port++, NULL, 0, NULL, 0, 100, 100, 0, FAULT_TIMEOUT,
1, &this_ip_addr);
@@ -736,6 +767,6 @@ static void *client_fn(void *arg)
int main(int argc, char *argv[])
{
- test_init(72, server_fn, client_fn);
+ test_init(73, server_fn, client_fn);
return 0;
}