kk Blog —— 通用基础


date [-d @int|str] [+%s|"+%F %T"]
netstat -ltunp
sar -n DEV 1

MPTCP_OPTION

解析见 mptcp_parse_options()

MPTCP_SUB_CAPABLE

1
2
3
4
5
#define MPTCP_SUB_CAPABLE                       0
#define MPTCP_SUB_LEN_CAPABLE_SYN               12
#define MPTCP_SUB_LEN_CAPABLE_SYN_ALIGN         12
#define MPTCP_SUB_LEN_CAPABLE_ACK               20
#define MPTCP_SUB_LEN_CAPABLE_ACK_ALIGN         20

最初的三次握手时用

MPTCP_SUB_JOIN

1
2
3
4
5
6
7
#define MPTCP_SUB_JOIN                  1
#define MPTCP_SUB_LEN_JOIN_SYN          12
#define MPTCP_SUB_LEN_JOIN_SYN_ALIGN    12
#define MPTCP_SUB_LEN_JOIN_SYNACK       16
#define MPTCP_SUB_LEN_JOIN_SYNACK_ALIGN 16
#define MPTCP_SUB_LEN_JOIN_ACK          24
#define MPTCP_SUB_LEN_JOIN_ACK_ALIGN    24

第二次、第三次、。。。握手时用

MPTCP_SUB_DSS

1
#define MPTCP_SUB_DSS           2

MPTCP_SUB_ADD_ADDR, MPTCP_SUB_REMOVE_ADDR

1
2
3
4
5
6
7
8
9
10
11
12
#define MPTCP_SUB_ADD_ADDR              3
#define MPTCP_SUB_LEN_ADD_ADDR4         8
#define MPTCP_SUB_LEN_ADD_ADDR4_VER1    16
#define MPTCP_SUB_LEN_ADD_ADDR6         20
#define MPTCP_SUB_LEN_ADD_ADDR6_VER1    28
#define MPTCP_SUB_LEN_ADD_ADDR4_ALIGN   8
#define MPTCP_SUB_LEN_ADD_ADDR4_ALIGN_VER1      16
#define MPTCP_SUB_LEN_ADD_ADDR6_ALIGN   20
#define MPTCP_SUB_LEN_ADD_ADDR6_ALIGN_VER1      28

#define MPTCP_SUB_REMOVE_ADDR   4
#define MPTCP_SUB_LEN_REMOVE_ADDR       4

fullmesh 模式通告ip

MPTCP_SUB_PRIO

1
2
3
4
#define MPTCP_SUB_PRIO          5
#define MPTCP_SUB_LEN_PRIO      3
#define MPTCP_SUB_LEN_PRIO_ADDR 4
#define MPTCP_SUB_LEN_PRIO_ALIGN        4

./ip/ip link set dev enp0s3 multipath off/on/backup

backup命令就是将该接口设置为backup模式,并且会通过PRIO option通知对方,两边会标记low_prio、rcv_low_prio。但目前所有pm都没有用到low_prio。

MPTCP_SUB_FAIL

1
2
3
#define MPTCP_SUB_FAIL          6
#define MPTCP_SUB_LEN_FAIL      12 
#define MPTCP_SUB_LEN_FAIL_ALIGN        12

MPTCP_SUB_FCLOSE

1
2
3
#define MPTCP_SUB_FCLOSE        7
#define MPTCP_SUB_LEN_FCLOSE    12
#define MPTCP_SUB_LEN_FCLOSE_ALIGN      12

MPTCP_VERSION

mptcp_version

只有两个版本 v0、v1

v1: 在option=MPTCP_SUB_ADD_ADDR 时需要加密,收包时在 mptcp_handle_add_addr 验证。

v0: 没有加密

mptcp建连过程

创建 socket

1
2
3
4
5
6
7
inet_create
	tcp_v4_init_sock
		tcp_init_sock
			mptcp_init_tcp_sock {
				if (!mptcp_init_failed && sysctl_mptcp_enabled == MPTCP_SYSCTL)
					mptcp_enable_sock(sk);
			}

所以listen之后再设置mptcp_enable=0,需要restart才能生效

发送syn

只加 option

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
tcp_connect {
	tcp_connect_init {
		tp->request_mptcp = 1;
	}
	tcp_transmit_skb
		tcp_syn_options
			mptcp_syn_options {
				if (is_master_tp(tp)) {
					opts->mptcp_options |= OPTION_MP_CAPABLE | OPTION_TYPE_SYN;
					...
				} else {
					opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_SYN;
				}
			}
}

接收syn, 发送synack

只加 option

1
2
3
4
5
6
7
8
9
tcp_synack_options
	mptcp_synack_options {
		/* MPCB not yet set - thus it's a new MPTCP-session */
		if (!mtreq->is_sub) {
			opts->mptcp_options |= OPTION_MP_CAPABLE | OPTION_TYPE_SYNACK;
		} else {
			opts->mptcp_options |= OPTION_MP_JOIN | OPTION_TYPE_SYNACK;
		}
	}

接收synack

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
tcp_v4_do_rcv {
	sk->sk_state == TCP_SYN_SENT

	tcp_rcv_state_process {
		queued = tcp_rcv_synsent_state_process(sk, skb, th, len) {

			if (tp->request_mptcp || mptcp(tp)) {
				ret = mptcp_rcv_synsent_state_process(sk, &sk, skb, &mopt);
				// 这个会创建出一个新的sk叫master_sk,原来的sk改为meta_sk
				// master_sk 和 meta_sk 的五元组一样,meta_sk 从hash表中删去,master_sk 加入hash表
				// 也就是说,和应用层通信的是meta_sk,tcp通信用master_sk
			}

			tcp_set_state(sk, TCP_ESTABLISHED);

			tcp_send_ack(sk) {
				mptcp_established_options {
					if (unlikely(tp->mptcp->include_mpc)) {
						opts->mptcp_options |= OPTION_MP_CAPABLE | OPTION_TYPE_ACK;
					}
			}
		}
		if (is_meta_sk(sk)) {
			mptcp_update_metasocket(tp->meta_sk);
			// 客户端建连成功
		}
	}
}

接收ack

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
tcp_child_process {
	tcp_rcv_state_process {

		if (!tcp_validate_incoming(sk, skb, th, 0))
			return 0;

		/* step 5: check the ACK field */
		if (th->ack) {
			int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0;

			switch (sk->sk_state) {
				case TCP_SYN_RECV:

				tcp_set_state(sk, TCP_ESTABLISHED);

			}

			case TCP_ESTABLISHED:
				tcp_data_queue(sk, skb);
				queued = 1;
				break;
			}

		}

		if (mptcp(tp)) {
			if (is_master_tp(tp)) {
				mptcp_update_metasocket(mptcp_meta_sk(sk));
				// 服务端建连成功
			}
	}