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.
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
,
23 uint32_t new_seq1
, new_seq2
;
25 /* make them roll-over during quota, but on different segments */
27 new_seq1
= ((uint32_t)-1) - msg_len
;
28 new_seq2
= ((uint32_t)-1) - (quota
- 2 * msg_len
);
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
)
47 sk
= socket(test_family
, SOCK_STREAM
, IPPROTO_TCP
);
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
);
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
;
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
);
87 test_error("accept()");
89 synchronize_threads(); /* 2: accepted => send data */
92 bytes
= test_server_run(sk
, quota
, TEST_TIMEOUT_SEC
);
95 test_fail("server served: %zd", bytes
);
97 test_fail("server returned: %zd", bytes
);
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
);
110 saddr
.sin6_port
= htons(ntohs(saddr
.sin6_port
) + 1);
112 saddr
.sin_port
= htons(ntohs(saddr
.sin_port
) + 1);
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
) {
131 test_fail("server served: %zd", bytes
);
133 test_fail("server returned: %zd", bytes
);
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
);
149 test_ok("TCPAOGood counter increased %" PRIu64
" => %" PRIu64
,
150 before_good
, after_good
);
152 after_bad
= netstat_get_one("TCPAOBad", NULL
);
154 test_fail("TCPAOBad counter is non-zero: %" PRIu64
, after_bad
);
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
);
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 */
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
;
182 sk
= socket(test_family
, SOCK_STREAM
, IPPROTO_TCP
);
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");
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
);
207 client_new_port
= ntohs(saddr
.sin6_port
) + 1;
208 saddr
.sin6_port
= htons(ntohs(saddr
.sin6_port
) + 1);
210 client_new_port
= ntohs(saddr
.sin_port
) + 1;
211 saddr
.sin_port
= htons(ntohs(saddr
.sin_port
) + 1);
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");
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
);
235 test_ok("TCPAOGood counter increased %" PRIu64
" => %" PRIu64
,
236 before_good
, after_good
);
238 after_bad
= netstat_get_one("TCPAOBad", NULL
);
240 test_fail("TCPAOBad counter is non-zero: %" PRIu64
, after_bad
);
242 test_ok("TCPAOBad counter didn't increase");
244 synchronize_threads(); /* 6: verified => closed */
247 synchronize_threads(); /* don't race to exit: let server exit() */
251 int main(int argc
, char *argv
[])
253 test_init(8, server_fn
, client_fn
);