mirror of
https://github.com/torvalds/linux.git
synced 2024-12-21 02:21:36 +00:00
selftests/net: Add SEQ number extension test
Check that on SEQ number wraparound there is no disruption or TCPAOBad segments produced. Sample of expected output: > # ./seq-ext_ipv4 > 1..7 > # 1436[lib/setup.c:254] rand seed 1686611079 > TAP version 13 > ok 1 server alive > ok 2 post-migrate connection alive > ok 3 TCPAOGood counter increased 1002 => 3002 > ok 4 TCPAOGood counter increased 1003 => 3003 > ok 5 TCPAOBad counter didn't increase > ok 6 TCPAOBad counter didn't increase > ok 7 SEQ extension incremented: 1/1999, 1/998999 > # Totals: pass:7 fail:0 xfail:0 xpass:0 skip:0 error:0 Signed-off-by: Dmitry Safonov <dima@arista.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3715d32dc9
commit
0d16eae574
@ -4,6 +4,7 @@ TEST_BOTH_AF += connect
|
||||
TEST_BOTH_AF += connect-deny
|
||||
TEST_BOTH_AF += icmps-accept icmps-discard
|
||||
TEST_BOTH_AF += restore
|
||||
TEST_BOTH_AF += seq-ext
|
||||
TEST_BOTH_AF += setsockopt-closed
|
||||
TEST_BOTH_AF += unsigned-md5
|
||||
|
||||
|
245
tools/testing/selftests/net/tcp_ao/seq-ext.c
Normal file
245
tools/testing/selftests/net/tcp_ao/seq-ext.c
Normal file
@ -0,0 +1,245 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Check that after SEQ number wrap-around:
|
||||
* 1. SEQ-extension has upper bytes set
|
||||
* 2. TCP conneciton is alive and no TCPAOBad segments
|
||||
* In order to test (2), the test doesn't just adjust seq number for a queue
|
||||
* on a connected socket, but migrates it to another sk+port number, so
|
||||
* that there won't be any delayed packets that will fail to verify
|
||||
* with the new SEQ numbers.
|
||||
*/
|
||||
#include <inttypes.h>
|
||||
#include "aolib.h"
|
||||
|
||||
const unsigned int nr_packets = 1000;
|
||||
const unsigned int msg_len = 1000;
|
||||
const unsigned int quota = nr_packets * msg_len;
|
||||
unsigned int client_new_port;
|
||||
|
||||
/* Move them closer to roll-over */
|
||||
static void test_adjust_seqs(struct tcp_sock_state *img,
|
||||
struct tcp_ao_repair *ao_img,
|
||||
bool server)
|
||||
{
|
||||
uint32_t new_seq1, new_seq2;
|
||||
|
||||
/* make them roll-over during quota, but on different segments */
|
||||
if (server) {
|
||||
new_seq1 = ((uint32_t)-1) - msg_len;
|
||||
new_seq2 = ((uint32_t)-1) - (quota - 2 * msg_len);
|
||||
} else {
|
||||
new_seq1 = ((uint32_t)-1) - (quota - 2 * msg_len);
|
||||
new_seq2 = ((uint32_t)-1) - msg_len;
|
||||
}
|
||||
|
||||
img->in.seq = new_seq1;
|
||||
img->trw.snd_wl1 = img->in.seq - msg_len;
|
||||
img->out.seq = new_seq2;
|
||||
img->trw.rcv_wup = img->in.seq;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int sk;
|
||||
|
||||
sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sk < 0)
|
||||
test_error("socket()");
|
||||
|
||||
test_enable_repair(sk);
|
||||
test_sock_restore(sk, img, saddr, daddr, dport);
|
||||
if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0, daddr, -1, 100, 100))
|
||||
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()");
|
||||
|
||||
test_disable_repair(sk);
|
||||
test_sock_state_free(img);
|
||||
return sk;
|
||||
}
|
||||
|
||||
static void *server_fn(void *arg)
|
||||
{
|
||||
uint64_t before_good, after_good, after_bad;
|
||||
struct tcp_ao_counters ao1, ao2;
|
||||
struct tcp_sock_state img;
|
||||
struct tcp_ao_repair ao_img;
|
||||
sockaddr_af saddr;
|
||||
ssize_t bytes;
|
||||
int sk, lsk;
|
||||
|
||||
lsk = test_listen_socket(this_ip_addr, test_server_port, 1);
|
||||
|
||||
if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
|
||||
test_error("setsockopt(TCP_AO_ADD_KEY)");
|
||||
|
||||
synchronize_threads(); /* 1: MKT added => connect() */
|
||||
|
||||
if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
|
||||
test_error("test_wait_fd()");
|
||||
|
||||
sk = accept(lsk, NULL, NULL);
|
||||
if (sk < 0)
|
||||
test_error("accept()");
|
||||
|
||||
synchronize_threads(); /* 2: accepted => send data */
|
||||
close(lsk);
|
||||
|
||||
bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
|
||||
if (bytes != quota) {
|
||||
if (bytes > 0)
|
||||
test_fail("server served: %zd", bytes);
|
||||
else
|
||||
test_fail("server returned: %zd", bytes);
|
||||
goto out;
|
||||
}
|
||||
|
||||
before_good = netstat_get_one("TCPAOGood", NULL);
|
||||
|
||||
synchronize_threads(); /* 3: restore the connection on another port */
|
||||
|
||||
test_enable_repair(sk);
|
||||
test_sock_checkpoint(sk, &img, &saddr);
|
||||
test_ao_checkpoint(sk, &ao_img);
|
||||
test_kill_sk(sk);
|
||||
#ifdef IPV6_TEST
|
||||
saddr.sin6_port = htons(ntohs(saddr.sin6_port) + 1);
|
||||
#else
|
||||
saddr.sin_port = htons(ntohs(saddr.sin_port) + 1);
|
||||
#endif
|
||||
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 */
|
||||
bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
|
||||
if (bytes != quota) {
|
||||
if (bytes > 0)
|
||||
test_fail("server served: %zd", bytes);
|
||||
else
|
||||
test_fail("server returned: %zd", bytes);
|
||||
} else {
|
||||
test_ok("server alive");
|
||||
}
|
||||
|
||||
if (test_get_tcp_ao_counters(sk, &ao2))
|
||||
test_error("test_get_tcp_ao_counters()");
|
||||
after_good = netstat_get_one("TCPAOGood", NULL);
|
||||
|
||||
test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD);
|
||||
|
||||
if (after_good <= before_good) {
|
||||
test_fail("TCPAOGood counter did not increase: %zu <= %zu",
|
||||
after_good, before_good);
|
||||
} else {
|
||||
test_ok("TCPAOGood counter increased %zu => %zu",
|
||||
before_good, after_good);
|
||||
}
|
||||
after_bad = netstat_get_one("TCPAOBad", NULL);
|
||||
if (after_bad)
|
||||
test_fail("TCPAOBad counter is non-zero: %zu", after_bad);
|
||||
else
|
||||
test_ok("TCPAOBad counter didn't increase");
|
||||
test_enable_repair(sk);
|
||||
test_ao_checkpoint(sk, &ao_img);
|
||||
if (ao_img.snd_sne && ao_img.rcv_sne) {
|
||||
test_ok("SEQ extension incremented: %u/%u",
|
||||
ao_img.snd_sne, ao_img.rcv_sne);
|
||||
} else {
|
||||
test_fail("SEQ extension was not incremented: %u/%u",
|
||||
ao_img.snd_sne, ao_img.rcv_sne);
|
||||
}
|
||||
|
||||
synchronize_threads(); /* 6: verified => closed */
|
||||
out:
|
||||
close(sk);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *client_fn(void *arg)
|
||||
{
|
||||
uint64_t before_good, after_good, after_bad;
|
||||
struct tcp_ao_counters ao1, ao2;
|
||||
struct tcp_sock_state img;
|
||||
struct tcp_ao_repair ao_img;
|
||||
sockaddr_af saddr;
|
||||
int sk;
|
||||
|
||||
sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (sk < 0)
|
||||
test_error("socket()");
|
||||
|
||||
if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
|
||||
test_error("setsockopt(TCP_AO_ADD_KEY)");
|
||||
|
||||
synchronize_threads(); /* 1: MKT added => connect() */
|
||||
if (test_connect_socket(sk, this_ip_dest, test_server_port) <= 0)
|
||||
test_error("failed to connect()");
|
||||
|
||||
synchronize_threads(); /* 2: accepted => send data */
|
||||
if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC)) {
|
||||
test_fail("pre-migrate verify failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
before_good = netstat_get_one("TCPAOGood", NULL);
|
||||
|
||||
synchronize_threads(); /* 3: restore the connection on another port */
|
||||
test_enable_repair(sk);
|
||||
test_sock_checkpoint(sk, &img, &saddr);
|
||||
test_ao_checkpoint(sk, &ao_img);
|
||||
test_kill_sk(sk);
|
||||
#ifdef IPV6_TEST
|
||||
client_new_port = ntohs(saddr.sin6_port) + 1;
|
||||
saddr.sin6_port = htons(ntohs(saddr.sin6_port) + 1);
|
||||
#else
|
||||
client_new_port = ntohs(saddr.sin_port) + 1;
|
||||
saddr.sin_port = htons(ntohs(saddr.sin_port) + 1);
|
||||
#endif
|
||||
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);
|
||||
|
||||
synchronize_threads(); /* 5: verify counters during SEQ-number rollover */
|
||||
if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
|
||||
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()");
|
||||
after_good = netstat_get_one("TCPAOGood", NULL);
|
||||
|
||||
test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD);
|
||||
|
||||
if (after_good <= before_good) {
|
||||
test_fail("TCPAOGood counter did not increase: %zu <= %zu",
|
||||
after_good, before_good);
|
||||
} else {
|
||||
test_ok("TCPAOGood counter increased %zu => %zu",
|
||||
before_good, after_good);
|
||||
}
|
||||
after_bad = netstat_get_one("TCPAOBad", NULL);
|
||||
if (after_bad)
|
||||
test_fail("TCPAOBad counter is non-zero: %zu", after_bad);
|
||||
else
|
||||
test_ok("TCPAOBad counter didn't increase");
|
||||
|
||||
synchronize_threads(); /* 6: verified => closed */
|
||||
close(sk);
|
||||
|
||||
synchronize_threads(); /* don't race to exit: let server exit() */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
test_init(7, server_fn, client_fn);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user