概念

比如docker等容器在不同的机器之间无缝迁移(可能由于调度,维护,交割等原因),是常见的需求场景
但是又希望不能中断服务,因此各种虚拟机和容器的热迁移就得到很多关注。
linux也在3.5版本中引入TCP_REPAIR socket选项来支持热迁移

获取状态及还原

当需要迁移的时候,为迁移的socket进入repair模式

setsockopt设置TCP_PREPAIR选项
进入repair模式的要求:

  • 需要CAP_NET_ADMIN, 用户命名空间需要有网络管理能力
  • socket处于CLOSE状态或ESTABLISHED状态

从内核读取缓存数据

内核缓存区中未发送或未被确认的数据,或者未被应用程序读取的数据
setsockopt设置TCP_REPAIR_QUEUE选项的值分别为TCP_SEND_QUEUE和TCP_RECV_QUEUE, 从两个缓存中读取数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
int flags, int *addr_len)
{
...
if (unlikely(tp->repair)) {
err = -EPERM;
if (!(flags & MSG_PEEK)) //只支持peek方式
goto out;
if (tp->repair_queue == TCP_SEND_QUEUE) //从发送队列中读取
err = tcp_peek_sndq(sk, msg, len);
goto out;
err = -EINVAL;
if (tp->repair_queue == TCP_NO_QUEUE)
goto out;
//正常的peek流程,peek接收队列数据
/* 'common' recv queue MSG_PEEK-ing */
}
...
}

迁移完,把这些数据还原到对应的socket缓存中,通过send()接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
{
...
if (unlikely(tp->repair)) {
if (tp->repair_queue == TCP_RECV_QUEUE) {
copied = tcp_send_rcvq(sk, msg, size); //放到接收队列
goto out_nopush;
}
err = -EINVAL;
if (tp->repair_queue == TCP_NO_QUEUE)
goto out_err;
//TCP_SEND_QUEUE, 正常模式处理
/* 'common' sending to sendq */
}
...
//正常的copy到内核发送缓存,准备发送的处理过程
...
}

读取和还原tcp协商信息

当握手的时候,会用tcp扩展选项来协商支持的情况,比如sack,timestamp,wscale等
getsockopt TCP_REPAIR_OPTIONS选项来获取这些值, 迁移之后setsockopt还原这些值

读取和还原序号

1
2
3
4
5
6
7
8
case TCP_QUEUE_SEQ:
if (tp->repair_queue == TCP_SEND_QUEUE)
val = tp->write_seq;
else if (tp->repair_queue == TCP_RECV_QUEUE)
val = tp->rcv_nxt;
else
return -EINVAL;
break;

读取和还原MSS

1
2
3
4
5
6
7
case TCP_MAXSEG:
val = tp->mss_cache;
if (!val && ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)))
val = tp->rx_opt.user_mss;
if (tp->repair)
val = tp->rx_opt.mss_clamp;
break;

读取和还原滑动窗口信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
case TCP_REPAIR_WINDOW: {
struct tcp_repair_window opt;
if (get_user(len, optlen))
return -EFAULT;
if (len != sizeof(opt))
return -EINVAL;
if (!tp->repair)
return -EPERM;
opt.snd_wl1 = tp->snd_wl1;
opt.snd_wnd = tp->snd_wnd;
opt.max_window = tp->max_window;
opt.rcv_wnd = tp->rcv_wnd;
opt.rcv_wup = tp->rcv_wup;
if (copy_to_user(optval, &opt, len))
return -EFAULT;
return 0;
}

静默关闭连接

close()将静默关闭,不会发送FIN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
void tcp_close(struct sock *sk, long timeout)
{
if (unlikely(tcp_sk(sk)->repair)) {
sk->sk_prot->disconnect(sk, 0);
} else if (data_was_unread) {
/* Unread data was tossed, zap the connection. */
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE);
tcp_set_state(sk, TCP_CLOSE);
tcp_send_active_reset(sk, sk->sk_allocation);
} else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
/* Check zero linger _after_ checking for unread data. */
sk->sk_prot->disconnect(sk, 0);
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA);
} else if (tcp_close_state(sk)) {
tcp_send_fin(sk);
}
...
}
int tcp_disconnect(struct sock *sk, int flags)
{
struct inet_sock *inet = inet_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
int err = 0;
int old_state = sk->sk_state;
if (old_state != TCP_CLOSE)
tcp_set_state(sk, TCP_CLOSE);
/* ABORT function of RFC793 */
if (old_state == TCP_LISTEN) {
inet_csk_listen_stop(sk);
} else if (unlikely(tp->repair)) {
sk->sk_err = ECONNABORTED;
}
...
}

还原连接

connect()直接进入ESTABLISH状态, 然后setsockopt各个状态选项,再用send()两个缓存到对应内核队列中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int tcp_connect(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *buff;
int err;
tcp_connect_init(sk);//初始化tcp配置,选项,滑动窗口等
if (unlikely(tp->repair)) {
tcp_finish_connect(sk, NULL); //repair模式直接进入TCP_ESTABLISHED状态
return 0;
}
...
//发送握手包
}

原文来自:http://www.cnhalo.net/2016/09/13/linux-tcp-repair/

资料

TCP connection repair
CRIU

linux tcp repair及tcp热迁移相关推荐

  1. TCP套接口热迁移REPAIR模式

    要实现TCP套接口的热迁移,必须能够实现在迁移之前保存套接口的当前状态,迁移之后还原套接口的状态.Linux内核中为支持TCP套接口热迁移实现了REPAIR模式以及相关的操作.迁移流程如下,首先启用R ...

  2. 数据连接linux网络编程之TCP/IP基础(四):TCP连接的建立和断开、滑动窗口

    在写这篇文章之前,xxx已经写过了几篇关于改数据连接主题的文章,想要了解的朋友可以去翻一下之前的文章 一.TCP段格式: TCP的段格式如下图所示 源端口号与目标端口号 源端口号和目标端口号,加上IP ...

  3. Linux内核中影响tcp三次握手的一些协议配置

    在Linux的发行版本中,都存在一个/proc/目录,有的也称它为Proc文件系统.在 /proc 虚拟文件系统中存在一些可调节的内核参数.这个文件系统中的每个文件都表示一个或多个参数,它们可以通过 ...

  4. 【Linux网络编程】TCP网络编程中connect listen和accept三者之间的关系

    00. 目录 文章目录 00. 目录 01. TCP服务端和客户端流程 02. connect函数 03. listen函数 04. 三次握手 05. accept函数 06. 附录 01. TCP服 ...

  5. 【Linux网络编程】TCP编程

    00. 目录 文章目录 00. 目录 01. TCP概述 02. TCP特点 03. TCP中CS架构 04. TCP相关函数 05. TCP服务端示例 06. TCP客户端示例 07. 附录 01. ...

  6. 【Linux网络编程】TCP网络编程中connect()、listen()和accept()三者之间的关系

    基于 TCP 的网络编程开发分为服务器端和客户端两部分,常见的核心步骤和流程如下: connect()函数 对于客户端的 connect() 函数,该函数的功能为客户端主动连接服务器,建立连接是通过三 ...

  7. 优化Linux下的内核TCP参数来提高服务器负载能力

    提高服务器的负载能力,是一个永恒的话题.在一台服务器CPU和内存资源额定有限的情况下,最大的压榨服务器的性能,是最终的目的.要提高Linux系统下的负载能力,可以先启用Apache的Worker模式, ...

  8. Linux集群和自动化维1.4.2 优化Linux下的内核TCP参数以提高系统性能

    1.4.2 优化Linux下的内核TCP参数以提高系统性能 内核的优化跟服务器的优化一样,应本着稳定安全的原则.下面以Squid服务器为例来说明,待客户端与服务器端建立TCP/IP连接后就会关闭Soc ...

  9. android linux网络连接,Android和Linux服务器之间的TCP连接

    我正在编写一个代码,需要每秒从Android移动设备向台式计算机(linux服务器)发送数据.由于数据经常发送,通过Http命中无法实现(因为会消耗时间),所以Tcp通信似乎是更好的选择,因为andr ...

最新文章

  1. 你的组织为自动化测试做好准备了吗?
  2. 使用QT制作桌面小工具(一)
  3. [云炬ThinkPython阅读笔记]2.1 赋值语句
  4. Python的matplotlib(2)
  5. Effective Java之抛出与抽象相应的异常(六十一)
  6. UE4学习-创建基于C++的场景
  7. linux命令 dstat,关于linux:每天学一个-Linux-命令103dstat
  8. 把编译时间加入到目标文件
  9. [转]iis7.5+win2008 出现 HTTP Error 503. The service is unavailable.
  10. 小白学深度之LSTM长短期记忆神经网络——深度AI科普团队
  11. c语言文本格式自动对齐,c语言文件读取原始数据是1、2列是按相同的一起排列命名为Yi- 爱问知识人...
  12. 谷歌地图 街景 api_Google使街景在地图中更加突出
  13. 超50万人推荐的神奇兼实用App,个个精品,打死也不能错过
  14. 《云计算架构技术与实践》连载(2):1.2 云计算的发展趋势
  15. 产品经理经常面临的系统须知大拷问
  16. 计算机音乐说散就散,说散就散(精彩音乐汇)
  17. 区块链源代码分析(1)
  18. 根据QQ号获取昵称和头像
  19. 正交单位矩阵 matlab,05-06线性代数试卷及答案
  20. 2022年汽车零部件行业前景

热门文章

  1. 100个python算法超详细讲解:邮票组合
  2. 给服务器添加硬盘,Ubuntu挂载硬盘
  3. 无线吸尘器软件魔鬼细节
  4. 设计数据密集型应用——数据系统的未来
  5. 希望C语言能够给我铺路
  6. 家庭亲情网,要取消几个号码怎么取消
  7. google play直接下载apk安装包文件教程(blynk)
  8. iOS中 HeathKit框架学习 步数统计等 韩俊强的博客
  9. 单片机 -AD电压检测调试遇到的坑,请避让!
  10. Pod 一直停留在 Terminating 状态,我等得花儿都谢了~