Branch data Line data Source code
1 : : #include <netinet/tcp.h>
2 : : #include <sys/ioctl.h>
3 : : #include <linux/sockios.h>
4 : : #include <unistd.h>
5 : : #include <stdlib.h>
6 : : #include <sys/mman.h>
7 : : #include <string.h>
8 : :
9 : : #include "cr_options.h"
10 : : #include "util.h"
11 : : #include "list.h"
12 : : #include "log.h"
13 : : #include "asm/types.h"
14 : : #include "files.h"
15 : : #include "sockets.h"
16 : : #include "sk-inet.h"
17 : : #include "netfilter.h"
18 : : #include "image.h"
19 : : #include "namespaces.h"
20 : : #include "xmalloc.h"
21 : : #include "config.h"
22 : : #include "cr-show.h"
23 : : #include "kerndat.h"
24 : :
25 : : #include "protobuf.h"
26 : : #include "protobuf/tcp-stream.pb-c.h"
27 : :
28 : : #ifndef CONFIG_HAS_TCP_REPAIR
29 : : /*
30 : : * It's been reported that both tcp_repair_opt
31 : : * and TCP_ enum already shipped in netinet/tcp.h
32 : : * system header by some distros thus we need a
33 : : * test if we can use predefined ones or provide
34 : : * our own.
35 : : */
36 : : struct tcp_repair_opt {
37 : : u32 opt_code;
38 : : u32 opt_val;
39 : : };
40 : :
41 : : enum {
42 : : TCP_NO_QUEUE,
43 : : TCP_RECV_QUEUE,
44 : : TCP_SEND_QUEUE,
45 : : TCP_QUEUES_NR,
46 : : };
47 : : #endif
48 : :
49 : : #ifndef TCP_TIMESTAMP
50 : : #define TCP_TIMESTAMP 24
51 : : #endif
52 : :
53 : : #ifndef TCPOPT_SACK_PERM
54 : : #define TCPOPT_SACK_PERM TCPOPT_SACK_PERMITTED
55 : : #endif
56 : :
57 : : static LIST_HEAD(cpt_tcp_repair_sockets);
58 : : static LIST_HEAD(rst_tcp_repair_sockets);
59 : :
60 : 74 : static int tcp_repair_on(int fd)
61 : : {
62 : 74 : int ret, aux = 1;
63 : :
64 : 74 : ret = setsockopt(fd, SOL_TCP, TCP_REPAIR, &aux, sizeof(aux));
65 [ - + ]: 74 : if (ret < 0)
66 : 0 : pr_perror("Can't turn TCP repair mode ON");
67 : :
68 : 74 : return ret;
69 : : }
70 : :
71 : 24 : static int refresh_inet_sk(struct inet_sk_desc *sk)
72 : : {
73 : : int size;
74 : : struct tcp_info info;
75 : :
76 [ - + ]: 24 : if (dump_opt(sk->rfd, SOL_TCP, TCP_INFO, &info)) {
77 : 0 : pr_perror("Failed to obtain TCP_INFO");
78 : 0 : return -1;
79 : : }
80 : :
81 [ - + ]: 24 : switch (info.tcpi_state) {
82 : : case TCP_ESTABLISHED:
83 : : case TCP_CLOSE:
84 : : break;
85 : : default:
86 : 0 : pr_err("Unknown state %d\n", sk->state);
87 : 0 : return -1;
88 : : }
89 : :
90 [ - + ]: 24 : if (ioctl(sk->rfd, SIOCOUTQ, &size) == -1) {
91 : 0 : pr_perror("Unable to get size of snd queue");
92 : 0 : return -1;
93 : : }
94 : :
95 : 24 : sk->wqlen = size;
96 : :
97 [ - + ]: 24 : if (ioctl(sk->rfd, SIOCOUTQNSD, &size) == -1) {
98 : 0 : pr_perror("Unable to get size of unsent data");
99 : 0 : return -1;
100 : : }
101 : :
102 : 24 : sk->uwqlen = size;
103 : :
104 [ - + ]: 24 : if (ioctl(sk->rfd, SIOCINQ, &size) == -1) {
105 : 0 : pr_perror("Unable to get size of recv queue");
106 : 0 : return -1;
107 : : }
108 : :
109 : 24 : sk->rqlen = size;
110 : :
111 : 24 : return 0;
112 : : }
113 : :
114 : 24 : static int tcp_repair_establised(int fd, struct inet_sk_desc *sk)
115 : : {
116 : : int ret;
117 : :
118 : 24 : pr_info("\tTurning repair on for socket %x\n", sk->sd.ino);
119 : : /*
120 : : * Keep the socket open in criu till the very end. In
121 : : * case we close this fd after one task fd dumping and
122 : : * fail we'll have to turn repair mode off
123 : : */
124 : 24 : sk->rfd = dup(fd);
125 [ - + ]: 24 : if (sk->rfd < 0) {
126 : 0 : pr_perror("Can't save socket fd for repair");
127 : 0 : goto err1;
128 : : }
129 : :
130 [ + - ]: 24 : if (!(root_ns_mask & CLONE_NEWNET)) {
131 : 24 : ret = nf_lock_connection(sk);
132 [ + - ]: 24 : if (ret < 0)
133 : : goto err2;
134 : : }
135 : :
136 : 24 : ret = tcp_repair_on(sk->rfd);
137 [ + - ]: 24 : if (ret < 0)
138 : : goto err3;
139 : :
140 : 24 : list_add_tail(&sk->rlist, &cpt_tcp_repair_sockets);
141 : :
142 : 24 : ret = refresh_inet_sk(sk);
143 [ - + ]: 24 : if (ret < 0)
144 : : goto err1;
145 : :
146 : : return 0;
147 : :
148 : : err3:
149 [ # # ]: 0 : if (!(root_ns_mask & CLONE_NEWNET))
150 : 0 : nf_unlock_connection(sk);
151 : : err2:
152 : 0 : close(sk->rfd);
153 : : err1:
154 : : return -1;
155 : : }
156 : :
157 : 0 : static void tcp_unlock_one(struct inet_sk_desc *sk)
158 : : {
159 : : int ret;
160 : :
161 : : list_del(&sk->rlist);
162 : :
163 [ # # ]: 0 : if (!(root_ns_mask & CLONE_NEWNET)) {
164 : 0 : ret = nf_unlock_connection(sk);
165 [ # # ]: 0 : if (ret < 0)
166 : 0 : pr_perror("Failed to unlock TCP connection");
167 : : }
168 : :
169 : 0 : tcp_repair_off(sk->rfd);
170 : :
171 : : /*
172 : : * tcp_repair_off modifies SO_REUSEADDR so
173 : : * don't forget to restore original value.
174 : : */
175 : 0 : restore_opt(sk->rfd, SOL_SOCKET, SO_REUSEADDR, &sk->cpt_reuseaddr);
176 : :
177 : 0 : close(sk->rfd);
178 : 0 : }
179 : :
180 : 448 : void cpt_unlock_tcp_connections(void)
181 : : {
182 : : struct inet_sk_desc *sk, *n;
183 : :
184 [ - + ]: 448 : list_for_each_entry_safe(sk, n, &cpt_tcp_repair_sockets, rlist)
185 : 0 : tcp_unlock_one(sk);
186 : 448 : }
187 : :
188 : : /*
189 : : * TCP queues sequences and their relations to the code below
190 : : *
191 : : * output queue
192 : : * net <----------------------------- sk
193 : : * ^ ^ ^ seq >>
194 : : * snd_una snd_nxt write_seq
195 : : *
196 : : * input queue
197 : : * net -----------------------------> sk
198 : : * << seq ^ ^
199 : : * rcv_nxt copied_seq
200 : : *
201 : : *
202 : : * inq_len = rcv_nxt - copied_seq = SIOCINQ
203 : : * outq_len = write_seq - snd_una = SIOCOUTQ
204 : : * inq_seq = rcv_nxt
205 : : * outq_seq = write_seq
206 : : *
207 : : * On restore kernel moves the option we configure with setsockopt,
208 : : * thus we should advance them on the _len value in restore_tcp_seqs.
209 : : *
210 : : */
211 : :
212 : 48 : static int tcp_stream_get_queue(int sk, int queue_id,
213 : : u32 *seq, u32 len, char **bufp)
214 : : {
215 : : int ret, aux;
216 : : socklen_t auxl;
217 : : char *buf;
218 : :
219 : 48 : pr_debug("\tSet repair queue %d\n", queue_id);
220 : 48 : aux = queue_id;
221 : 48 : auxl = sizeof(aux);
222 : 48 : ret = setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &aux, auxl);
223 [ + - ]: 48 : if (ret < 0)
224 : : goto err_sopt;
225 : :
226 : 48 : pr_debug("\tGet queue seq\n");
227 : 48 : auxl = sizeof(*seq);
228 : 48 : ret = getsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, seq, &auxl);
229 [ + - ]: 48 : if (ret < 0)
230 : : goto err_sopt;
231 : :
232 : 48 : pr_info("\t`- seq %u len %u\n", *seq, len);
233 : :
234 [ + + ]: 48 : if (len) {
235 : : /*
236 : : * Try to grab one byte more from the queue to
237 : : * make sure there are len bytes for real
238 : : */
239 [ - + ]: 13 : buf = xmalloc(len + 1);
240 [ + - ]: 13 : if (!buf)
241 : : goto err_buf;
242 : :
243 : 13 : pr_debug("\tReading queue (%d bytes)\n", len);
244 : 13 : ret = recv(sk, buf, len + 1, MSG_PEEK | MSG_DONTWAIT);
245 [ + - ]: 13 : if (ret != len)
246 : : goto err_recv;
247 : : } else
248 : : buf = NULL;
249 : :
250 : 48 : *bufp = buf;
251 : 48 : return 0;
252 : :
253 : : err_sopt:
254 : 0 : pr_perror("\tsockopt failed");
255 : : err_buf:
256 : : return -1;
257 : :
258 : : err_recv:
259 : 0 : pr_perror("\trecv failed (%d, want %d, errno %d)", ret, len, errno);
260 [ # # ]: 0 : xfree(buf);
261 : : goto err_buf;
262 : : }
263 : :
264 : 24 : static int tcp_stream_get_options(int sk, TcpStreamEntry *tse)
265 : : {
266 : : int ret;
267 : : socklen_t auxl;
268 : : struct tcp_info ti;
269 : : int val;
270 : :
271 : 24 : auxl = sizeof(ti);
272 : 24 : ret = getsockopt(sk, SOL_TCP, TCP_INFO, &ti, &auxl);
273 [ + - ]: 24 : if (ret < 0)
274 : : goto err_sopt;
275 : :
276 : 24 : auxl = sizeof(tse->mss_clamp);
277 : 24 : ret = getsockopt(sk, SOL_TCP, TCP_MAXSEG, &tse->mss_clamp, &auxl);
278 [ + - ]: 24 : if (ret < 0)
279 : : goto err_sopt;
280 : :
281 : 24 : tse->opt_mask = ti.tcpi_options;
282 [ + - ]: 24 : if (ti.tcpi_options & TCPI_OPT_WSCALE) {
283 : 24 : tse->snd_wscale = ti.tcpi_snd_wscale;
284 : 24 : tse->rcv_wscale = ti.tcpi_rcv_wscale;
285 : 24 : tse->has_rcv_wscale = true;
286 : : }
287 : :
288 [ + - ]: 24 : if (ti.tcpi_options & TCPI_OPT_TIMESTAMPS) {
289 : 24 : auxl = sizeof(val);
290 : 24 : ret = getsockopt(sk, SOL_TCP, TCP_TIMESTAMP, &val, &auxl);
291 [ + - ]: 24 : if (ret < 0)
292 : : goto err_sopt;
293 : :
294 : 24 : tse->has_timestamp = true;
295 : 24 : tse->timestamp = val;
296 : : }
297 : :
298 [ + - ]: 24 : pr_info("\toptions: mss_clamp %x wscale %x tstamp %d sack %d\n",
299 : : (int)tse->mss_clamp,
300 : : ti.tcpi_options & TCPI_OPT_WSCALE ? (int)tse->snd_wscale : -1,
301 : : ti.tcpi_options & TCPI_OPT_TIMESTAMPS ? 1 : 0,
302 : : ti.tcpi_options & TCPI_OPT_SACK ? 1 : 0);
303 : :
304 : 24 : return 0;
305 : :
306 : : err_sopt:
307 : 0 : pr_perror("\tsockopt failed");
308 : 0 : return -1;
309 : : }
310 : :
311 : 24 : static int dump_tcp_conn_state(struct inet_sk_desc *sk)
312 : : {
313 : : int ret, img_fd, aux;
314 : 24 : TcpStreamEntry tse = TCP_STREAM_ENTRY__INIT;
315 : : char *in_buf, *out_buf;
316 : :
317 : : /*
318 : : * Read queue
319 : : */
320 : :
321 : 24 : pr_info("Reading inq for socket\n");
322 : 24 : tse.inq_len = sk->rqlen;
323 : 24 : ret = tcp_stream_get_queue(sk->rfd, TCP_RECV_QUEUE,
324 : : &tse.inq_seq, tse.inq_len, &in_buf);
325 [ + - ]: 24 : if (ret < 0)
326 : : goto err_in;
327 : :
328 : : /*
329 : : * Write queue
330 : : */
331 : :
332 : 24 : pr_info("Reading outq for socket\n");
333 : 24 : tse.outq_len = sk->wqlen;
334 : 24 : tse.unsq_len = sk->uwqlen;
335 : 24 : tse.has_unsq_len = true;
336 : 24 : ret = tcp_stream_get_queue(sk->rfd, TCP_SEND_QUEUE,
337 : : &tse.outq_seq, tse.outq_len, &out_buf);
338 [ + - ]: 24 : if (ret < 0)
339 : : goto err_out;
340 : :
341 : : /*
342 : : * Initial options
343 : : */
344 : :
345 : 24 : pr_info("Reading options for socket\n");
346 : 24 : ret = tcp_stream_get_options(sk->rfd, &tse);
347 [ + - ]: 24 : if (ret < 0)
348 : : goto err_opt;
349 : :
350 : : /*
351 : : * TCP socket options
352 : : */
353 : :
354 [ + - ]: 24 : if (dump_opt(sk->rfd, SOL_TCP, TCP_NODELAY, &aux))
355 : : goto err_opt;
356 : :
357 [ - + ]: 24 : if (aux) {
358 : 0 : tse.has_nodelay = true;
359 : 0 : tse.nodelay = true;
360 : : }
361 : :
362 [ + - ]: 24 : if (dump_opt(sk->rfd, SOL_TCP, TCP_CORK, &aux))
363 : : goto err_opt;
364 : :
365 [ - + ]: 24 : if (aux) {
366 : 0 : tse.has_cork = true;
367 : 0 : tse.cork = true;
368 : : }
369 : :
370 : : /*
371 : : * Push the stuff to image
372 : : */
373 : :
374 : 24 : img_fd = open_image(CR_FD_TCP_STREAM, O_DUMP, sk->sd.ino);
375 [ + - ]: 24 : if (img_fd < 0)
376 : : goto err_img;
377 : :
378 : 24 : ret = pb_write_one(img_fd, &tse, PB_TCP_STREAM);
379 [ + - ]: 24 : if (ret < 0)
380 : : goto err_iw;
381 : :
382 [ + + ]: 24 : if (in_buf) {
383 : 9 : ret = write_img_buf(img_fd, in_buf, tse.inq_len);
384 [ + - ]: 9 : if (ret < 0)
385 : : goto err_iw;
386 : : }
387 : :
388 [ + + ]: 24 : if (out_buf) {
389 : 4 : ret = write_img_buf(img_fd, out_buf, tse.outq_len);
390 [ + - ]: 4 : if (ret < 0)
391 : : goto err_iw;
392 : : }
393 : :
394 : 24 : pr_info("Done\n");
395 : : err_iw:
396 : 24 : close(img_fd);
397 : : err_img:
398 : : err_opt:
399 [ + + ]: 24 : xfree(out_buf);
400 : : err_out:
401 [ + + ]: 24 : xfree(in_buf);
402 : : err_in:
403 : 24 : return ret;
404 : : }
405 : :
406 : 58 : int dump_one_tcp(int fd, struct inet_sk_desc *sk)
407 : : {
408 [ + + ]: 58 : if (sk->state != TCP_ESTABLISHED)
409 : : return 0;
410 : :
411 : 24 : pr_info("Dumping TCP connection\n");
412 : :
413 [ + - ]: 24 : if (tcp_repair_establised(fd, sk))
414 : : return -1;
415 : :
416 [ + - ]: 24 : if (dump_tcp_conn_state(sk))
417 : : return -1;
418 : :
419 : : /*
420 : : * Socket is left in repair mode, so that at the end it's just
421 : : * closed and the connection is silently terminated
422 : : */
423 : 24 : return 0;
424 : : }
425 : :
426 : 48 : static int set_tcp_queue_seq(int sk, int queue, u32 seq)
427 : : {
428 : 48 : pr_debug("\tSetting %d queue seq to %u\n", queue, seq);
429 : :
430 [ - + ]: 48 : if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)) < 0) {
431 : 0 : pr_perror("Can't set repair queue");
432 : 0 : return -1;
433 : : }
434 : :
435 [ - + ]: 48 : if (setsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, &seq, sizeof(seq)) < 0) {
436 : 0 : pr_perror("Can't set queue seq");
437 : 0 : return -1;
438 : : }
439 : :
440 : : return 0;
441 : : }
442 : :
443 : 24 : static int restore_tcp_seqs(int sk, TcpStreamEntry *tse)
444 : : {
445 [ + - ]: 24 : if (set_tcp_queue_seq(sk, TCP_RECV_QUEUE,
446 : 24 : tse->inq_seq - tse->inq_len))
447 : : return -1;
448 [ + - ]: 24 : if (set_tcp_queue_seq(sk, TCP_SEND_QUEUE,
449 : 24 : tse->outq_seq - tse->outq_len))
450 : : return -1;
451 : :
452 : 24 : return 0;
453 : : }
454 : :
455 : 16 : static int __send_tcp_queue(int sk, int queue, u32 len, int imgfd)
456 : : {
457 : : int ret, err = -1;
458 : : int off, max;
459 : : char *buf;
460 : :
461 [ - + ]: 16 : buf = xmalloc(len);
462 [ + - ]: 16 : if (!buf)
463 : : return -1;
464 : :
465 [ + - ]: 16 : if (read_img_buf(imgfd, buf, len) < 0)
466 : : goto err;
467 : :
468 [ + + ]: 16 : max = (queue == TCP_SEND_QUEUE) ? tcp_max_wshare : tcp_max_rshare;
469 : : off = 0;
470 [ + + ]: 34 : while (len) {
471 : 18 : int chunk = (len > max ? max : len);
472 : :
473 : 18 : ret = send(sk, buf + off, chunk, 0);
474 [ - + ]: 18 : if (ret != chunk) {
475 : 0 : pr_perror("Can't restore %d queue data (%d), want (%d:%d)",
476 : : queue, ret, chunk, len);
477 : 0 : goto err;
478 : : }
479 : 18 : off += chunk;
480 : 18 : len -= chunk;
481 : : }
482 : :
483 : : err = 0;
484 : : err:
485 [ + - ]: 16 : xfree(buf);
486 : :
487 : 16 : return err;
488 : : }
489 : :
490 : 12 : static int send_tcp_queue(int sk, int queue, u32 len, int imgfd)
491 : : {
492 : 12 : pr_debug("\tRestoring TCP %d queue data %u bytes\n", queue, len);
493 : :
494 [ - + ]: 12 : if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)) < 0) {
495 : 0 : pr_perror("Can't set repair queue");
496 : 0 : return -1;
497 : : }
498 : :
499 : 12 : return __send_tcp_queue(sk, queue, len, imgfd);
500 : : }
501 : :
502 : 24 : static int restore_tcp_queues(int sk, TcpStreamEntry *tse, int fd)
503 : : {
504 : : u32 len;
505 : :
506 [ + - ]: 24 : if (restore_prepare_socket(sk))
507 : : return -1;
508 : :
509 : 24 : len = tse->inq_len;
510 [ + + ][ + - ]: 24 : if (len && send_tcp_queue(sk, TCP_RECV_QUEUE, len, fd))
511 : : return -1;
512 : :
513 : : /*
514 : : * All data in a write buffer can be divided on two parts sent
515 : : * but not yet acknowledged data and unsent data.
516 : : * The TCP stack must know which data have been sent, because
517 : : * acknowledgment can be received for them. These data must be
518 : : * restored in repair mode.
519 : : */
520 : 24 : len = tse->outq_len - tse->unsq_len;
521 [ + + ][ + - ]: 24 : if (len && send_tcp_queue(sk, TCP_SEND_QUEUE, len, fd))
522 : : return -1;
523 : :
524 : : /*
525 : : * The second part of data have never been sent to outside, so
526 : : * they can be restored without any tricks.
527 : : */
528 : 24 : len = tse->unsq_len;
529 : 24 : tcp_repair_off(sk);
530 [ + + ][ + - ]: 24 : if (len && __send_tcp_queue(sk, TCP_SEND_QUEUE, len, fd))
531 : : return -1;
532 [ + - ]: 24 : if (tcp_repair_on(sk))
533 : : return -1;
534 : :
535 : 24 : return 0;
536 : : }
537 : :
538 : 24 : static int restore_tcp_opts(int sk, TcpStreamEntry *tse)
539 : : {
540 : : struct tcp_repair_opt opts[4];
541 : : int onr = 0;
542 : :
543 : 24 : pr_debug("\tRestoring TCP options\n");
544 : :
545 [ + - ]: 24 : if (tse->opt_mask & TCPI_OPT_SACK) {
546 : 24 : pr_debug("\t\tWill turn SAK on\n");
547 : 24 : opts[onr].opt_code = TCPOPT_SACK_PERM;
548 : 24 : opts[onr].opt_val = 0;
549 : : onr++;
550 : : }
551 : :
552 [ + - ]: 24 : if (tse->opt_mask & TCPI_OPT_WSCALE) {
553 : 24 : pr_debug("\t\tWill set snd_wscale to %u\n", tse->snd_wscale);
554 : 24 : pr_debug("\t\tWill set rcv_wscale to %u\n", tse->rcv_wscale);
555 : 24 : opts[onr].opt_code = TCPOPT_WINDOW;
556 : 24 : opts[onr].opt_val = tse->snd_wscale + (tse->rcv_wscale << 16);
557 : 24 : onr++;
558 : : }
559 : :
560 [ + - ]: 24 : if (tse->opt_mask & TCPI_OPT_TIMESTAMPS) {
561 : 24 : pr_debug("\t\tWill turn timestamps on\n");
562 : 24 : opts[onr].opt_code = TCPOPT_TIMESTAMP;
563 : 24 : opts[onr].opt_val = 0;
564 : 24 : onr++;
565 : : }
566 : :
567 : 24 : pr_debug("Will set mss clamp to %u\n", tse->mss_clamp);
568 : 24 : opts[onr].opt_code = TCPOPT_MAXSEG;
569 : 24 : opts[onr].opt_val = tse->mss_clamp;
570 : 24 : onr++;
571 : :
572 [ - + ]: 24 : if (setsockopt(sk, SOL_TCP, TCP_REPAIR_OPTIONS,
573 : : opts, onr * sizeof(struct tcp_repair_opt)) < 0) {
574 : 0 : pr_perror("Can't repair options");
575 : 0 : return -1;
576 : : }
577 : :
578 [ + - ]: 24 : if (tse->has_timestamp) {
579 [ - + ]: 24 : if (setsockopt(sk, SOL_TCP, TCP_TIMESTAMP,
580 : 24 : &tse->timestamp, sizeof(tse->timestamp)) < 0) {
581 : 0 : pr_perror("Can't set timestamp");
582 : 0 : return -1;
583 : : }
584 : : }
585 : :
586 : : return 0;
587 : : }
588 : :
589 : 24 : static int restore_tcp_conn_state(int sk, struct inet_sk_info *ii)
590 : : {
591 : : int ifd, aux;
592 : : TcpStreamEntry *tse;
593 : :
594 : 24 : pr_info("Restoring TCP connection id %x ino %x\n", ii->ie->id, ii->ie->ino);
595 : :
596 : 24 : ifd = open_image(CR_FD_TCP_STREAM, O_RSTR, ii->ie->ino);
597 [ + - ]: 24 : if (ifd < 0)
598 : : goto err;
599 : :
600 [ + - ]: 24 : if (pb_read_one(ifd, &tse, PB_TCP_STREAM) < 0)
601 : : goto err_c;
602 : :
603 [ + - ]: 24 : if (restore_tcp_seqs(sk, tse))
604 : : goto err_c;
605 : :
606 [ + - ]: 24 : if (inet_bind(sk, ii))
607 : : goto err_c;
608 : :
609 [ + - ]: 24 : if (inet_connect(sk, ii))
610 : : goto err_c;
611 : :
612 [ + - ]: 24 : if (restore_tcp_opts(sk, tse))
613 : : goto err_c;
614 : :
615 [ + - ]: 24 : if (restore_tcp_queues(sk, tse, ifd))
616 : : goto err_c;
617 : :
618 [ - + ][ # # ]: 24 : if (tse->has_nodelay && tse->nodelay) {
619 : 0 : aux = 1;
620 [ # # ]: 0 : if (restore_opt(sk, SOL_TCP, TCP_NODELAY, &aux))
621 : : goto err_c;
622 : : }
623 : :
624 [ - + ][ # # ]: 24 : if (tse->has_cork && tse->cork) {
625 : 0 : aux = 1;
626 [ # # ]: 0 : if (restore_opt(sk, SOL_TCP, TCP_CORK, &aux))
627 : : goto err_c;
628 : : }
629 : :
630 : 24 : tcp_stream_entry__free_unpacked(tse, NULL);
631 : 24 : close(ifd);
632 : 24 : return 0;
633 : :
634 : : err_c:
635 : 0 : tcp_stream_entry__free_unpacked(tse, NULL);
636 : 0 : close(ifd);
637 : : err:
638 : : return -1;
639 : : }
640 : :
641 : : /*
642 : : * rst_tcp_socks contains sockets in repair mode,
643 : : * which will be off in restorer before resuming.
644 : : */
645 : : struct rst_tcp_sock *rst_tcp_socks = NULL;
646 : : int rst_tcp_socks_nr = 0;
647 : :
648 : 24 : int rst_tcp_socks_add(int fd, bool reuseaddr)
649 : : {
650 : : struct rst_tcp_sock *cur;
651 : :
652 : 24 : rst_tcp_socks_nr++;
653 [ - + ]: 24 : rst_tcp_socks = xrealloc(rst_tcp_socks, rst_tcp_socks_len());
654 [ + - ]: 24 : if (!rst_tcp_socks)
655 : : return -1;
656 : :
657 : 24 : pr_debug("Schedule %d socket for repair off\n", fd);
658 : 24 : cur = &rst_tcp_socks[rst_tcp_socks_nr - 1];
659 : 24 : cur->sk = fd;
660 : 24 : cur->reuseaddr = reuseaddr;
661 : :
662 : 24 : return 0;
663 : : }
664 : :
665 : 24 : int restore_one_tcp(int fd, struct inet_sk_info *ii)
666 : : {
667 : 24 : pr_info("Restoring TCP connection\n");
668 : :
669 [ + - ]: 24 : if (tcp_repair_on(fd))
670 : : return -1;
671 : :
672 [ + - ]: 24 : if (restore_tcp_conn_state(fd, ii))
673 : : return -1;
674 : :
675 : 24 : return 0;
676 : : }
677 : :
678 : 56 : void tcp_locked_conn_add(struct inet_sk_info *ii)
679 : : {
680 : 56 : list_add_tail(&ii->rlist, &rst_tcp_repair_sockets);
681 : 56 : }
682 : :
683 : 448 : void rst_unlock_tcp_connections(void)
684 : : {
685 : : struct inet_sk_info *ii;
686 : :
687 : : /* Network will be unlocked by network-unlock scripts */
688 [ + + ]: 448 : if (root_ns_mask & CLONE_NEWNET)
689 : 448 : return;
690 : :
691 [ + + ]: 258 : list_for_each_entry(ii, &rst_tcp_repair_sockets, rlist)
692 : 24 : nf_unlock_connection_info(ii);
693 : : }
694 : :
695 : 2 : int check_tcp(void)
696 : : {
697 : : socklen_t optlen;
698 : : int sk, ret;
699 : : int val;
700 : :
701 : 2 : sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
702 [ - + ]: 2 : if (sk < 0) {
703 : 0 : pr_perror("Can't create TCP socket :(");
704 : 0 : return -1;
705 : : }
706 : :
707 : 2 : ret = tcp_repair_on(sk);
708 [ + - ]: 2 : if (ret)
709 : : goto out;
710 : :
711 : 2 : optlen = sizeof(val);
712 : 2 : ret = getsockopt(sk, SOL_TCP, TCP_TIMESTAMP, &val, &optlen);
713 [ - + ]: 2 : if (ret)
714 : 0 : pr_perror("Can't get TCP_TIMESTAMP");
715 : :
716 : : out:
717 : 2 : close(sk);
718 : :
719 : 2 : return ret;
720 : : }
721 : :
722 : 0 : void show_tcp_stream(int fd, void *obj)
723 : : {
724 : : TcpStreamEntry *e = obj;
725 [ # # ]: 0 : if (opts.show_pages_content) {
726 : 0 : pr_msg("In-queue:");
727 : 0 : print_image_data(fd, e->inq_len, 1);
728 : 0 : pr_msg("Out-queue:");
729 : 0 : print_image_data(fd, e->outq_len, 1);
730 : : }
731 : 0 : }
|