seq-ext.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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 connection 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. const unsigned int nr_packets = 1000;
  13. const unsigned int msg_len = 1000;
  14. const unsigned int quota = nr_packets * msg_len;
  15. unsigned int client_new_port;
  16. /* Move them closer to roll-over */
  17. static void test_adjust_seqs(struct tcp_sock_state *img,
  18. struct tcp_ao_repair *ao_img,
  19. bool server)
  20. {
  21. uint32_t new_seq1, new_seq2;
  22. /* make them roll-over during quota, but on different segments */
  23. if (server) {
  24. new_seq1 = ((uint32_t)-1) - msg_len;
  25. new_seq2 = ((uint32_t)-1) - (quota - 2 * msg_len);
  26. } else {
  27. new_seq1 = ((uint32_t)-1) - (quota - 2 * msg_len);
  28. new_seq2 = ((uint32_t)-1) - msg_len;
  29. }
  30. img->in.seq = new_seq1;
  31. img->trw.snd_wl1 = img->in.seq - msg_len;
  32. img->out.seq = new_seq2;
  33. img->trw.rcv_wup = img->in.seq;
  34. }
  35. static int test_sk_restore(struct tcp_sock_state *img,
  36. struct tcp_ao_repair *ao_img, sockaddr_af *saddr,
  37. const union tcp_addr daddr, unsigned int dport,
  38. struct tcp_counters *cnt)
  39. {
  40. int sk;
  41. sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
  42. if (sk < 0)
  43. test_error("socket()");
  44. test_enable_repair(sk);
  45. test_sock_restore(sk, img, saddr, daddr, dport);
  46. if (test_add_repaired_key(sk, DEFAULT_TEST_PASSWORD, 0, daddr, -1, 100, 100))
  47. test_error("setsockopt(TCP_AO_ADD_KEY)");
  48. test_ao_restore(sk, ao_img);
  49. if (test_get_tcp_counters(sk, cnt))
  50. test_error("test_get_tcp_counters()");
  51. test_disable_repair(sk);
  52. test_sock_state_free(img);
  53. return sk;
  54. }
  55. static void *server_fn(void *arg)
  56. {
  57. uint64_t before_good, after_good, after_bad;
  58. struct tcp_counters cnt1, cnt2;
  59. struct tcp_sock_state img;
  60. struct tcp_ao_repair ao_img;
  61. sockaddr_af saddr;
  62. ssize_t bytes;
  63. int sk, lsk;
  64. lsk = test_listen_socket(this_ip_addr, test_server_port, 1);
  65. if (test_add_key(lsk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
  66. test_error("setsockopt(TCP_AO_ADD_KEY)");
  67. synchronize_threads(); /* 1: MKT added => connect() */
  68. if (test_wait_fd(lsk, TEST_TIMEOUT_SEC, 0))
  69. test_error("test_wait_fd()");
  70. sk = accept(lsk, NULL, NULL);
  71. if (sk < 0)
  72. test_error("accept()");
  73. synchronize_threads(); /* 2: accepted => send data */
  74. close(lsk);
  75. bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
  76. if (bytes != quota) {
  77. if (bytes > 0)
  78. test_fail("server served: %zd", bytes);
  79. else
  80. test_fail("server returned: %zd", bytes);
  81. goto out;
  82. }
  83. before_good = netstat_get_one("TCPAOGood", NULL);
  84. synchronize_threads(); /* 3: restore the connection on another port */
  85. test_enable_repair(sk);
  86. test_sock_checkpoint(sk, &img, &saddr);
  87. test_ao_checkpoint(sk, &ao_img);
  88. test_kill_sk(sk);
  89. #ifdef IPV6_TEST
  90. saddr.sin6_port = htons(ntohs(saddr.sin6_port) + 1);
  91. #else
  92. saddr.sin_port = htons(ntohs(saddr.sin_port) + 1);
  93. #endif
  94. test_adjust_seqs(&img, &ao_img, true);
  95. synchronize_threads(); /* 4: dump finished */
  96. sk = test_sk_restore(&img, &ao_img, &saddr, this_ip_dest,
  97. client_new_port, &cnt1);
  98. trace_ao_event_sne_expect(TCP_AO_SND_SNE_UPDATE, this_ip_addr,
  99. this_ip_dest, test_server_port + 1, client_new_port, 1);
  100. trace_ao_event_sne_expect(TCP_AO_SND_SNE_UPDATE, this_ip_dest,
  101. this_ip_addr, client_new_port, test_server_port + 1, 1);
  102. trace_ao_event_sne_expect(TCP_AO_RCV_SNE_UPDATE, this_ip_addr,
  103. this_ip_dest, test_server_port + 1, client_new_port, 1);
  104. trace_ao_event_sne_expect(TCP_AO_RCV_SNE_UPDATE, this_ip_dest,
  105. this_ip_addr, client_new_port, test_server_port + 1, 1);
  106. synchronize_threads(); /* 5: verify the connection during SEQ-number rollover */
  107. bytes = test_server_run(sk, quota, TEST_TIMEOUT_SEC);
  108. if (bytes != quota) {
  109. if (bytes > 0)
  110. test_fail("server served: %zd", bytes);
  111. else
  112. test_fail("server returned: %zd", bytes);
  113. } else {
  114. test_ok("server alive");
  115. }
  116. synchronize_threads(); /* 6: verify counters after SEQ-number rollover */
  117. if (test_get_tcp_counters(sk, &cnt2))
  118. test_error("test_get_tcp_counters()");
  119. after_good = netstat_get_one("TCPAOGood", NULL);
  120. test_assert_counters(NULL, &cnt1, &cnt2, TEST_CNT_GOOD);
  121. if (after_good <= before_good) {
  122. test_fail("TCPAOGood counter did not increase: %" PRIu64 " <= %" PRIu64,
  123. after_good, before_good);
  124. } else {
  125. test_ok("TCPAOGood counter increased %" PRIu64 " => %" PRIu64,
  126. before_good, after_good);
  127. }
  128. after_bad = netstat_get_one("TCPAOBad", NULL);
  129. if (after_bad)
  130. test_fail("TCPAOBad counter is non-zero: %" PRIu64, after_bad);
  131. else
  132. test_ok("TCPAOBad counter didn't increase");
  133. test_enable_repair(sk);
  134. test_ao_checkpoint(sk, &ao_img);
  135. if (ao_img.snd_sne && ao_img.rcv_sne) {
  136. test_ok("SEQ extension incremented: %u/%u",
  137. ao_img.snd_sne, ao_img.rcv_sne);
  138. } else {
  139. test_fail("SEQ extension was not incremented: %u/%u",
  140. ao_img.snd_sne, ao_img.rcv_sne);
  141. }
  142. synchronize_threads(); /* 6: verified => closed */
  143. out:
  144. close(sk);
  145. return NULL;
  146. }
  147. static void *client_fn(void *arg)
  148. {
  149. uint64_t before_good, after_good, after_bad;
  150. struct tcp_counters cnt1, cnt2;
  151. struct tcp_sock_state img;
  152. struct tcp_ao_repair ao_img;
  153. sockaddr_af saddr;
  154. int sk;
  155. sk = socket(test_family, SOCK_STREAM, IPPROTO_TCP);
  156. if (sk < 0)
  157. test_error("socket()");
  158. if (test_add_key(sk, DEFAULT_TEST_PASSWORD, this_ip_dest, -1, 100, 100))
  159. test_error("setsockopt(TCP_AO_ADD_KEY)");
  160. synchronize_threads(); /* 1: MKT added => connect() */
  161. if (test_connect_socket(sk, this_ip_dest, test_server_port) <= 0)
  162. test_error("failed to connect()");
  163. synchronize_threads(); /* 2: accepted => send data */
  164. if (test_client_verify(sk, msg_len, nr_packets)) {
  165. test_fail("pre-migrate verify failed");
  166. return NULL;
  167. }
  168. before_good = netstat_get_one("TCPAOGood", NULL);
  169. synchronize_threads(); /* 3: restore the connection on another port */
  170. test_enable_repair(sk);
  171. test_sock_checkpoint(sk, &img, &saddr);
  172. test_ao_checkpoint(sk, &ao_img);
  173. test_kill_sk(sk);
  174. #ifdef IPV6_TEST
  175. client_new_port = ntohs(saddr.sin6_port) + 1;
  176. saddr.sin6_port = htons(ntohs(saddr.sin6_port) + 1);
  177. #else
  178. client_new_port = ntohs(saddr.sin_port) + 1;
  179. saddr.sin_port = htons(ntohs(saddr.sin_port) + 1);
  180. #endif
  181. test_adjust_seqs(&img, &ao_img, false);
  182. synchronize_threads(); /* 4: dump finished */
  183. sk = test_sk_restore(&img, &ao_img, &saddr, this_ip_dest,
  184. test_server_port + 1, &cnt1);
  185. synchronize_threads(); /* 5: verify the connection during SEQ-number rollover */
  186. if (test_client_verify(sk, msg_len, nr_packets))
  187. test_fail("post-migrate verify failed");
  188. else
  189. test_ok("post-migrate connection alive");
  190. synchronize_threads(); /* 5: verify counters after SEQ-number rollover */
  191. if (test_get_tcp_counters(sk, &cnt2))
  192. test_error("test_get_tcp_counters()");
  193. after_good = netstat_get_one("TCPAOGood", NULL);
  194. test_assert_counters(NULL, &cnt1, &cnt2, TEST_CNT_GOOD);
  195. if (after_good <= before_good) {
  196. test_fail("TCPAOGood counter did not increase: %" PRIu64 " <= %" PRIu64,
  197. after_good, before_good);
  198. } else {
  199. test_ok("TCPAOGood counter increased %" PRIu64 " => %" PRIu64,
  200. before_good, after_good);
  201. }
  202. after_bad = netstat_get_one("TCPAOBad", NULL);
  203. if (after_bad)
  204. test_fail("TCPAOBad counter is non-zero: %" PRIu64, after_bad);
  205. else
  206. test_ok("TCPAOBad counter didn't increase");
  207. synchronize_threads(); /* 6: verified => closed */
  208. close(sk);
  209. synchronize_threads(); /* don't race to exit: let server exit() */
  210. return NULL;
  211. }
  212. int main(int argc, char *argv[])
  213. {
  214. test_init(8, server_fn, client_fn);
  215. return 0;
  216. }