Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / tools / testing / selftests / net / tcp_ao / seq-ext.c
blob8901a6785dc8158227414cf90b461c5d2fe39689
1 // SPDX-License-Identifier: GPL-2.0
2 /* Check that after SEQ number wrap-around:
3 * 1. SEQ-extension has upper bytes set
4 * 2. TCP conneciton is alive and no TCPAOBad segments
5 * In order to test (2), the test doesn't just adjust seq number for a queue
6 * on a connected socket, but migrates it to another sk+port number, so
7 * that there won't be any delayed packets that will fail to verify
8 * with the new SEQ numbers.
9 */
10 #include <inttypes.h>
11 #include "aolib.h"
13 const unsigned int nr_packets = 1000;
14 const unsigned int msg_len = 1000;
15 const unsigned int quota = nr_packets * msg_len;
16 unsigned int client_new_port;
18 /* Move them closer to roll-over */
19 static void test_adjust_seqs(struct tcp_sock_state *img,
20 struct tcp_ao_repair *ao_img,
21 bool server)
23 uint32_t new_seq1, new_seq2;
25 /* make them roll-over during quota, but on different segments */
26 if (server) {
27 new_seq1 = ((uint32_t)-1) - msg_len;
28 new_seq2 = ((uint32_t)-1) - (quota - 2 * msg_len);
29 } else {
30 new_seq1 = ((uint32_t)-1) - (quota - 2 * msg_len);
31 new_seq2 = ((uint32_t)-1) - msg_len;
34 img->in.seq = new_seq1;
35 img->trw.snd_wl1 = img->in.seq - msg_len;
36 img->out.seq = new_seq2;
37 img->trw.rcv_wup = img->in.seq;
40 static int test_sk_restore(struct tcp_sock_state *img,
41 struct tcp_ao_repair *ao_img, sockaddr_af *saddr,
42 const union tcp_addr daddr, unsigned int dport,
43 struct tcp_ao_counters *cnt)
45 int sk;
47 sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
48 if (sk < 0)
49 test_error("socket()");
51 test_enable_repair(sk);
52 test_sock_restore(sk, img, saddr, daddr, dport);
53 if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0, daddr, -1, 100, 100))
54 test_error("setsockopt(TCP_AO_ADD_KEY)");
55 test_ao_restore(sk, ao_img);
57 if (test_get_tcp_ao_counters(sk, cnt))
58 test_error("test_get_tcp_ao_counters()");
60 test_disable_repair(sk);
61 test_sock_state_free(img);
62 return sk;
65 static void *server_fn(void *arg)
67 uint64_t before_good, after_good, after_bad;
68 struct tcp_ao_counters ao1, ao2;
69 struct tcp_sock_state img;
70 struct tcp_ao_repair ao_img;
71 sockaddr_af saddr;
72 ssize_t bytes;
73 int sk, lsk;
75 lsk = test_listen_socket(this_ip_addr, test_server_port, 1);
77 if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
78 test_error("setsockopt(TCP_AO_ADD_KEY)");
80 synchronize_threads(); /* 1: MKT added => connect() */
82 if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
83 test_error("test_wait_fd()");
85 sk = accept(lsk, NULL, NULL);
86 if (sk < 0)
87 test_error("accept()");
89 synchronize_threads(); /* 2: accepted => send data */
90 close(lsk);
92 bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
93 if (bytes != quota) {
94 if (bytes > 0)
95 test_fail("server served: %zd", bytes);
96 else
97 test_fail("server returned: %zd", bytes);
98 goto out;
101 before_good = netstat_get_one("TCPAOGood", NULL);
103 synchronize_threads(); /* 3: restore the connection on another port */
105 test_enable_repair(sk);
106 test_sock_checkpoint(sk, &img, &saddr);
107 test_ao_checkpoint(sk, &ao_img);
108 test_kill_sk(sk);
109 #ifdef IPV6_TEST
110 saddr.sin6_port = htons(ntohs(saddr.sin6_port) + 1);
111 #else
112 saddr.sin_port = htons(ntohs(saddr.sin_port) + 1);
113 #endif
114 test_adjust_seqs(&img, &ao_img, true);
115 synchronize_threads(); /* 4: dump finished */
116 sk = test_sk_restore(&img, &ao_img, &saddr, this_ip_dest,
117 client_new_port, &ao1);
119 trace_ao_event_sne_expect(TCP_AO_SND_SNE_UPDATE, this_ip_addr,
120 this_ip_dest, test_server_port + 1, client_new_port, 1);
121 trace_ao_event_sne_expect(TCP_AO_SND_SNE_UPDATE, this_ip_dest,
122 this_ip_addr, client_new_port, test_server_port + 1, 1);
123 trace_ao_event_sne_expect(TCP_AO_RCV_SNE_UPDATE, this_ip_addr,
124 this_ip_dest, test_server_port + 1, client_new_port, 1);
125 trace_ao_event_sne_expect(TCP_AO_RCV_SNE_UPDATE, this_ip_dest,
126 this_ip_addr, client_new_port, test_server_port + 1, 1);
127 synchronize_threads(); /* 5: verify the connection during SEQ-number rollover */
128 bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
129 if (bytes != quota) {
130 if (bytes > 0)
131 test_fail("server served: %zd", bytes);
132 else
133 test_fail("server returned: %zd", bytes);
134 } else {
135 test_ok("server alive");
138 synchronize_threads(); /* 6: verify counters after SEQ-number rollover */
139 if (test_get_tcp_ao_counters(sk, &ao2))
140 test_error("test_get_tcp_ao_counters()");
141 after_good = netstat_get_one("TCPAOGood", NULL);
143 test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD);
145 if (after_good <= before_good) {
146 test_fail("TCPAOGood counter did not increase: %" PRIu64 " <= %" PRIu64,
147 after_good, before_good);
148 } else {
149 test_ok("TCPAOGood counter increased %" PRIu64 " => %" PRIu64,
150 before_good, after_good);
152 after_bad = netstat_get_one("TCPAOBad", NULL);
153 if (after_bad)
154 test_fail("TCPAOBad counter is non-zero: %" PRIu64, after_bad);
155 else
156 test_ok("TCPAOBad counter didn't increase");
157 test_enable_repair(sk);
158 test_ao_checkpoint(sk, &ao_img);
159 if (ao_img.snd_sne && ao_img.rcv_sne) {
160 test_ok("SEQ extension incremented: %u/%u",
161 ao_img.snd_sne, ao_img.rcv_sne);
162 } else {
163 test_fail("SEQ extension was not incremented: %u/%u",
164 ao_img.snd_sne, ao_img.rcv_sne);
167 synchronize_threads(); /* 6: verified => closed */
168 out:
169 close(sk);
170 return NULL;
173 static void *client_fn(void *arg)
175 uint64_t before_good, after_good, after_bad;
176 struct tcp_ao_counters ao1, ao2;
177 struct tcp_sock_state img;
178 struct tcp_ao_repair ao_img;
179 sockaddr_af saddr;
180 int sk;
182 sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
183 if (sk < 0)
184 test_error("socket()");
186 if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
187 test_error("setsockopt(TCP_AO_ADD_KEY)");
189 synchronize_threads(); /* 1: MKT added => connect() */
190 if (test_connect_socket(sk, this_ip_dest, test_server_port) <= 0)
191 test_error("failed to connect()");
193 synchronize_threads(); /* 2: accepted => send data */
194 if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC)) {
195 test_fail("pre-migrate verify failed");
196 return NULL;
199 before_good = netstat_get_one("TCPAOGood", NULL);
201 synchronize_threads(); /* 3: restore the connection on another port */
202 test_enable_repair(sk);
203 test_sock_checkpoint(sk, &img, &saddr);
204 test_ao_checkpoint(sk, &ao_img);
205 test_kill_sk(sk);
206 #ifdef IPV6_TEST
207 client_new_port = ntohs(saddr.sin6_port) + 1;
208 saddr.sin6_port = htons(ntohs(saddr.sin6_port) + 1);
209 #else
210 client_new_port = ntohs(saddr.sin_port) + 1;
211 saddr.sin_port = htons(ntohs(saddr.sin_port) + 1);
212 #endif
213 test_adjust_seqs(&img, &ao_img, false);
214 synchronize_threads(); /* 4: dump finished */
215 sk = test_sk_restore(&img, &ao_img, &saddr, this_ip_dest,
216 test_server_port + 1, &ao1);
218 synchronize_threads(); /* 5: verify the connection during SEQ-number rollover */
219 if (test_client_verify(sk, msg_len, nr_packets, TEST_TIMEOUT_SEC))
220 test_fail("post-migrate verify failed");
221 else
222 test_ok("post-migrate connection alive");
224 synchronize_threads(); /* 5: verify counters after SEQ-number rollover */
225 if (test_get_tcp_ao_counters(sk, &ao2))
226 test_error("test_get_tcp_ao_counters()");
227 after_good = netstat_get_one("TCPAOGood", NULL);
229 test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD);
231 if (after_good <= before_good) {
232 test_fail("TCPAOGood counter did not increase: %" PRIu64 " <= %" PRIu64,
233 after_good, before_good);
234 } else {
235 test_ok("TCPAOGood counter increased %" PRIu64 " => %" PRIu64,
236 before_good, after_good);
238 after_bad = netstat_get_one("TCPAOBad", NULL);
239 if (after_bad)
240 test_fail("TCPAOBad counter is non-zero: %" PRIu64, after_bad);
241 else
242 test_ok("TCPAOBad counter didn't increase");
244 synchronize_threads(); /* 6: verified => closed */
245 close(sk);
247 synchronize_threads(); /* don't race to exit: let server exit() */
248 return NULL;
251 int main(int argc, char *argv[])
253 test_init(8, server_fn, client_fn);
254 return 0;