~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/net/tcp_ao/lib/repair.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* This is over-simplified TCP_REPAIR for TCP_ESTABLISHED sockets
  3  * It tests that TCP-AO enabled connection can be restored.
  4  * For the proper socket repair see:
  5  * https://github.com/checkpoint-restore/criu/blob/criu-dev/soccr/soccr.h
  6  */
  7 #include <fcntl.h>
  8 #include <linux/sockios.h>
  9 #include <sys/ioctl.h>
 10 #include "aolib.h"
 11 
 12 #ifndef TCPOPT_MAXSEG
 13 # define TCPOPT_MAXSEG          2
 14 #endif
 15 #ifndef TCPOPT_WINDOW
 16 # define TCPOPT_WINDOW          3
 17 #endif
 18 #ifndef TCPOPT_SACK_PERMITTED
 19 # define TCPOPT_SACK_PERMITTED  4
 20 #endif
 21 #ifndef TCPOPT_TIMESTAMP
 22 # define TCPOPT_TIMESTAMP       8
 23 #endif
 24 
 25 enum {
 26         TCP_ESTABLISHED = 1,
 27         TCP_SYN_SENT,
 28         TCP_SYN_RECV,
 29         TCP_FIN_WAIT1,
 30         TCP_FIN_WAIT2,
 31         TCP_TIME_WAIT,
 32         TCP_CLOSE,
 33         TCP_CLOSE_WAIT,
 34         TCP_LAST_ACK,
 35         TCP_LISTEN,
 36         TCP_CLOSING,    /* Now a valid state */
 37         TCP_NEW_SYN_RECV,
 38 
 39         TCP_MAX_STATES  /* Leave at the end! */
 40 };
 41 
 42 static void test_sock_checkpoint_queue(int sk, int queue, int qlen,
 43                                        struct tcp_sock_queue *q)
 44 {
 45         socklen_t len;
 46         int ret;
 47 
 48         if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)))
 49                 test_error("setsockopt(TCP_REPAIR_QUEUE)");
 50 
 51         len = sizeof(q->seq);
 52         ret = getsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, &q->seq, &len);
 53         if (ret || len != sizeof(q->seq))
 54                 test_error("getsockopt(TCP_QUEUE_SEQ): %d", (int)len);
 55 
 56         if (!qlen) {
 57                 q->buf = NULL;
 58                 return;
 59         }
 60 
 61         q->buf = malloc(qlen);
 62         if (q->buf == NULL)
 63                 test_error("malloc()");
 64         ret = recv(sk, q->buf, qlen, MSG_PEEK | MSG_DONTWAIT);
 65         if (ret != qlen)
 66                 test_error("recv(%d): %d", qlen, ret);
 67 }
 68 
 69 void __test_sock_checkpoint(int sk, struct tcp_sock_state *state,
 70                             void *addr, size_t addr_size)
 71 {
 72         socklen_t len = sizeof(state->info);
 73         int ret;
 74 
 75         memset(state, 0, sizeof(*state));
 76 
 77         ret = getsockopt(sk, SOL_TCP, TCP_INFO, &state->info, &len);
 78         if (ret || len != sizeof(state->info))
 79                 test_error("getsockopt(TCP_INFO): %d", (int)len);
 80 
 81         len = addr_size;
 82         if (getsockname(sk, addr, &len) || len != addr_size)
 83                 test_error("getsockname(): %d", (int)len);
 84 
 85         len = sizeof(state->trw);
 86         ret = getsockopt(sk, SOL_TCP, TCP_REPAIR_WINDOW, &state->trw, &len);
 87         if (ret || len != sizeof(state->trw))
 88                 test_error("getsockopt(TCP_REPAIR_WINDOW): %d", (int)len);
 89 
 90         if (ioctl(sk, SIOCOUTQ, &state->outq_len))
 91                 test_error("ioctl(SIOCOUTQ)");
 92 
 93         if (ioctl(sk, SIOCOUTQNSD, &state->outq_nsd_len))
 94                 test_error("ioctl(SIOCOUTQNSD)");
 95         test_sock_checkpoint_queue(sk, TCP_SEND_QUEUE, state->outq_len, &state->out);
 96 
 97         if (ioctl(sk, SIOCINQ, &state->inq_len))
 98                 test_error("ioctl(SIOCINQ)");
 99         test_sock_checkpoint_queue(sk, TCP_RECV_QUEUE, state->inq_len, &state->in);
100 
101         if (state->info.tcpi_state == TCP_CLOSE)
102                 state->outq_len = state->outq_nsd_len = 0;
103 
104         len = sizeof(state->mss);
105         ret = getsockopt(sk, SOL_TCP, TCP_MAXSEG, &state->mss, &len);
106         if (ret || len != sizeof(state->mss))
107                 test_error("getsockopt(TCP_MAXSEG): %d", (int)len);
108 
109         len = sizeof(state->timestamp);
110         ret = getsockopt(sk, SOL_TCP, TCP_TIMESTAMP, &state->timestamp, &len);
111         if (ret || len != sizeof(state->timestamp))
112                 test_error("getsockopt(TCP_TIMESTAMP): %d", (int)len);
113 }
114 
115 void test_ao_checkpoint(int sk, struct tcp_ao_repair *state)
116 {
117         socklen_t len = sizeof(*state);
118         int ret;
119 
120         memset(state, 0, sizeof(*state));
121 
122         ret = getsockopt(sk, SOL_TCP, TCP_AO_REPAIR, state, &len);
123         if (ret || len != sizeof(*state))
124                 test_error("getsockopt(TCP_AO_REPAIR): %d", (int)len);
125 }
126 
127 static void test_sock_restore_seq(int sk, int queue, uint32_t seq)
128 {
129         if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)))
130                 test_error("setsockopt(TCP_REPAIR_QUEUE)");
131 
132         if (setsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, &seq, sizeof(seq)))
133                 test_error("setsockopt(TCP_QUEUE_SEQ)");
134 }
135 
136 static void test_sock_restore_queue(int sk, int queue, void *buf, int len)
137 {
138         int chunk = len;
139         size_t off = 0;
140 
141         if (len == 0)
142                 return;
143 
144         if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)))
145                 test_error("setsockopt(TCP_REPAIR_QUEUE)");
146 
147         do {
148                 int ret;
149 
150                 ret = send(sk, buf + off, chunk, 0);
151                 if (ret <= 0) {
152                         if (chunk > 1024) {
153                                 chunk >>= 1;
154                                 continue;
155                         }
156                         test_error("send()");
157                 }
158                 off += ret;
159                 len -= ret;
160         } while (len > 0);
161 }
162 
163 void __test_sock_restore(int sk, const char *device,
164                          struct tcp_sock_state *state,
165                          void *saddr, void *daddr, size_t addr_size)
166 {
167         struct tcp_repair_opt opts[4];
168         unsigned int opt_nr = 0;
169         long flags;
170 
171         if (bind(sk, saddr, addr_size))
172                 test_error("bind()");
173 
174         flags = fcntl(sk, F_GETFL);
175         if ((flags < 0) || (fcntl(sk, F_SETFL, flags | O_NONBLOCK) < 0))
176                 test_error("fcntl()");
177 
178         test_sock_restore_seq(sk, TCP_RECV_QUEUE, state->in.seq - state->inq_len);
179         test_sock_restore_seq(sk, TCP_SEND_QUEUE, state->out.seq - state->outq_len);
180 
181         if (device != NULL && setsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE,
182                                          device, strlen(device) + 1))
183                 test_error("setsockopt(SO_BINDTODEVICE, %s)", device);
184 
185         if (connect(sk, daddr, addr_size))
186                 test_error("connect()");
187 
188         if (state->info.tcpi_options & TCPI_OPT_SACK) {
189                 opts[opt_nr].opt_code = TCPOPT_SACK_PERMITTED;
190                 opts[opt_nr].opt_val = 0;
191                 opt_nr++;
192         }
193         if (state->info.tcpi_options & TCPI_OPT_WSCALE) {
194                 opts[opt_nr].opt_code = TCPOPT_WINDOW;
195                 opts[opt_nr].opt_val = state->info.tcpi_snd_wscale +
196                                 (state->info.tcpi_rcv_wscale << 16);
197                 opt_nr++;
198         }
199         if (state->info.tcpi_options & TCPI_OPT_TIMESTAMPS) {
200                 opts[opt_nr].opt_code = TCPOPT_TIMESTAMP;
201                 opts[opt_nr].opt_val = 0;
202                 opt_nr++;
203         }
204         opts[opt_nr].opt_code = TCPOPT_MAXSEG;
205         opts[opt_nr].opt_val = state->mss;
206         opt_nr++;
207 
208         if (setsockopt(sk, SOL_TCP, TCP_REPAIR_OPTIONS, opts, opt_nr * sizeof(opts[0])))
209                 test_error("setsockopt(TCP_REPAIR_OPTIONS)");
210 
211         if (state->info.tcpi_options & TCPI_OPT_TIMESTAMPS) {
212                 if (setsockopt(sk, SOL_TCP, TCP_TIMESTAMP,
213                                &state->timestamp, opt_nr * sizeof(opts[0])))
214                         test_error("setsockopt(TCP_TIMESTAMP)");
215         }
216         test_sock_restore_queue(sk, TCP_RECV_QUEUE, state->in.buf, state->inq_len);
217         test_sock_restore_queue(sk, TCP_SEND_QUEUE, state->out.buf, state->outq_len);
218         if (setsockopt(sk, SOL_TCP, TCP_REPAIR_WINDOW, &state->trw, sizeof(state->trw)))
219                 test_error("setsockopt(TCP_REPAIR_WINDOW)");
220 }
221 
222 void test_ao_restore(int sk, struct tcp_ao_repair *state)
223 {
224         if (setsockopt(sk, SOL_TCP, TCP_AO_REPAIR, state, sizeof(*state)))
225                 test_error("setsockopt(TCP_AO_REPAIR)");
226 }
227 
228 void test_sock_state_free(struct tcp_sock_state *state)
229 {
230         free(state->out.buf);
231         free(state->in.buf);
232 }
233 
234 void test_enable_repair(int sk)
235 {
236         int val = TCP_REPAIR_ON;
237 
238         if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &val, sizeof(val)))
239                 test_error("setsockopt(TCP_REPAIR)");
240 }
241 
242 void test_disable_repair(int sk)
243 {
244         int val = TCP_REPAIR_OFF_NO_WP;
245 
246         if (setsockopt(sk, SOL_TCP, TCP_REPAIR, &val, sizeof(val)))
247                 test_error("setsockopt(TCP_REPAIR)");
248 }
249 
250 void test_kill_sk(int sk)
251 {
252         test_enable_repair(sk);
253         close(sk);
254 }
255 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php