Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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"
 12
 13const unsigned int nr_packets = 1000;
 14const unsigned int msg_len = 1000;
 15const unsigned int quota = nr_packets * msg_len;
 16unsigned int client_new_port;
 17
 18/* Move them closer to roll-over */
 19static void test_adjust_seqs(struct tcp_sock_state *img,
 20			     struct tcp_ao_repair *ao_img,
 21			     bool server)
 22{
 23	uint32_t new_seq1, new_seq2;
 24
 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;
 32	}
 33
 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;
 38}
 39
 40static 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)
 44{
 45	int sk;
 46
 47	sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
 48	if (sk < 0)
 49		test_error("socket()");
 50
 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);
 56
 57	if (test_get_tcp_ao_counters(sk, cnt))
 58		test_error("test_get_tcp_ao_counters()");
 59
 60	test_disable_repair(sk);
 61	test_sock_state_free(img);
 62	return sk;
 63}
 64
 65static void *server_fn(void *arg)
 66{
 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;
 74
 75	lsk = test_listen_socket(this_ip_addr, test_server_port, 1);
 76
 77	if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
 78		test_error("setsockopt(TCP_AO_ADD_KEY)");
 79
 80	synchronize_threads(); /* 1: MKT added => connect() */
 81
 82	if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
 83		test_error("test_wait_fd()");
 84
 85	sk = accept(lsk, NULL, NULL);
 86	if (sk < 0)
 87		test_error("accept()");
 88
 89	synchronize_threads(); /* 2: accepted => send data */
 90	close(lsk);
 91
 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;
 99	}
100
101	before_good = netstat_get_one("TCPAOGood", NULL);
102
103	synchronize_threads(); /* 3: restore the connection on another port */
104
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);
118
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");
136	}
137
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);
142
143	test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD);
144
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);
151	}
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);
165	}
166
167	synchronize_threads(); /* 6: verified => closed */
168out:
169	close(sk);
170	return NULL;
171}
172
173static void *client_fn(void *arg)
174{
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;
181
182	sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
183	if (sk < 0)
184		test_error("socket()");
185
186	if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
187		test_error("setsockopt(TCP_AO_ADD_KEY)");
188
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()");
192
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;
197	}
198
199	before_good = netstat_get_one("TCPAOGood", NULL);
200
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);
217
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");
223
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);
228
229	test_tcp_ao_counters_cmp(NULL, &ao1, &ao2, TEST_CNT_GOOD);
230
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);
237	}
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");
243
244	synchronize_threads(); /* 6: verified => closed */
245	close(sk);
246
247	synchronize_threads(); /* don't race to exit: let server exit() */
248	return NULL;
249}
250
251int main(int argc, char *argv[])
252{
253	test_init(8, server_fn, client_fn);
254	return 0;
255}