개요
MPTCP는 TCP의 확장버전으로 기존의 TCP를 사용하는 Application의 변경을 하지 않고 MPTCP를 사용할 수 있도록 한다.
아래의 그림에서 확인할 수 있듯이 MPTCP는 각 각의 개별 TCP 연결을 Subflow로 사용한다. 또한, 각 Subflow에서 송수신되는 Data들은 MPTCP Stack에서 분배 및 재결합된다. (분배는 송신 시, 재결합은 수신 시)
각 Subflow는 각 각의 IP Stack을 거치게 됨으로 서로 다른 경로(WIFI, Cellular 등)를 통해 전송되는 것을 알 수 있다.
MPTCP Packet
MPTCP Packet은 TCP Option 필드에 부착된다.
TCP Option 필드의 하위에는 Kind, Length, Subtype이라는 필드가 존재한다. 세 필드의 역할은 다음과 같다.
- Kind : TCP Option 종류 (Ex. MSS, Timestamps, SACK, MPTCP 등)
- Length : TCP Option 패킷의 길이
- Subtype : TCP Option 에서 사용하는 메시지의 종류 (Ex. MPTCP의 경우 : MP_CAPABLE, MP_JOIN, ADD_ADDR 등)
MPTCP는 기본적으로 10진수 30의 값을 TCP Option의 Kind 필드에 고정적으로 담으며 Length와 Subtype은 MPTCP의 Signal마다 가변적으로 적용된다.
앞서 설명하였듯이 MPTCP Packet은 TCP Option 필드에 부착된다.
또한, MPTCP Packet은 TCP Option의 하위 필드인 Kind 필드에 10진수 30값(16진수 1E)으로 고정한다.
해당 Kind 값을 통해 Source와 Destination은 MPTCP 패킷임을 알 수 있다.
MPTCP Subtype Table
이번에는 MPTCP에서 사용하는 여러 Subtype들을 살펴보도록 한다.
- MP_CAPABLE
: 가장 초기 MPTCP Connection을 연결할 때 사용하는 Subtype - MP_JOIN
: 새로운 MPTCP의 Subflow를 연결할 때 사용하는 Subtype - DSS
: 여러 Subflow에서 수신된 정렬되지 않은 데이터들을 MPTCP Layer에서 재결합하기 위해 사용하는 Subtype - ADD_ADDR
: 연결을 위한 것이 아닌 잠재적인 NIC의 Address를 알려주기 위해 사용하는 Subtype - REMOVE_ADDR
: 잠재적인 NIC의 Address를 삭제요청하기 위해 사용하는 Subtype - MP_PRIO
: 현재 연결된 Subtype의 우선순위를 변경하기 위해 사용하는 Subtype (Backup, Primary) - MP_FAIL
: MPTCP Connection에 문제가 발생하여 TCP Connection으로 Fall-Back 하기 위해 사용하는 Subtype
MP_CAPABLE
초기 MPTCP 연결은 하나의 Subflow의 SYN, SYN/ACK, ACK 패킷을 통해 진행된다.
그리고 3-way handshake와 더불어 MPTCP의 MP_CAPABLE 옵션이 3개의 패킷(SYN, SYN/ACK, ACK)에 함께 부착된다.
MPTCP 초기 연결 시에 두 호스트 간에는 암호화 알고리즘을 활용해 Key를 나눠 갖는다.
현재 [RFC6824] 규격에 따르면 기본적인 암호화 알고리즘은 SHA1을 사용한다.
이 Key의 목적은 MPTCP Connection을 인증하고 새로운 Subflow를 Connection에 추가할 때 사용한다.
위 그림은 초기 연결 시 사용되는 패킷의 포캣이다. 이 패킷의 필드들은 다음과 같은 의미를 가진다.
- Kind
: MPTCP를 의미하는 0x1E 값으로 고정된다. - Length
: 초기 연결 시에는 0x0C나 0x14값으로 고정된다. SYN, SYN/ACK일 때 0x0C로 고정되며, ACK일 땐 0x14로 고정된다. - Subtype
: MP_CAPABLE을 나타내는 0x0으로 고정된다. - Version
: 현재 MPTCP의 버전을 나타낸다. - A Flag
: Checksum 사용 여부 (1-사용/0-미사용)를 나타낸다. 다시 말해, SYN에서 A를 1로 설정한 뒤 보내게 되면 Sender측은 Checksum 사용을 원한다고 표현한 것이다. 만약, SYN/ACK에서 A가 0으로 설정되었다면 Receiver 측은 Checksum을 사용하지 않는다는 의미이다. 결론적으로 마지막 ACK 패킷의 A Flag 값을 통해서 이 Connection에서의 Checksum 사용 여부를 알 수 있게 된다. - B Flag
: 확장성 Flag를 나타내며, MPTCP의 확장판 버전이 존재할 시 사용되는 Flag이다. 즉, 확장된 MPTCP 버전이라면 해당 Flag가 1로 설정된다. - C~H Flag
: 암호화 알고리즘 협상 Flag이다. 현재는 H만 1로 설정하여 알고리즘을 협상하며, H Flag는 HMAC-SHA1 암호화 알고리즘을 나타낸다. 이것을 통해 MPTCP Connection을 인증하고 새로운 Subflow를 생성할 수 있기 때문에 반드시 암호화 알고리즘은 협상되어야 한다. - Sender Key
: 암호화 알고리즘을 통해 생성된 Sender Key 값 - Receiver Key
: 암호화 알고리즘을 통해 생성된 Receiver Key 값
** SYN에서는 Sender Key만 확인되며, SYN/ACK에서는 Receiver Key만 확인된다. 마지막 ACK에서 Sender와 Receiver 측의 두 Key값을 모두 확인할 수 있다. 또한, 이 세개의 Key값은 SHA-1에서 생성된 가장 중요하지 않은 64bit로 구성된다. (세 패킷의 MP_CAPABLE Length 필드 값이 다른 이유)
MP_JOIN
MPTCP Connection이 MP_CAPABLE 교환으로 초기 연결이 완료되었으면 추가 Subflow를 Connection에 추가할 수 있게 된다. 또한, ADD_ADDR Singal을 통해 사용 가능한 주소를 미리 수신 측과 교환한 이후에 새 Subflow 연결을 수행할 수 있다. (Address ID 사전교환)
새 Subflow는 일반적인 TCP 3-Way Handshake와 다르게 4-Way Handshake(SYN -> SYN+ACK -> ACK -> ACK)로 진행된다. (연결을 수행하는 측에서 마지막 ACK까지 수신받아야 새로운 Subflow 연결이 완료되는 것이다.)
또한, 4-Way Handsahke 시에 사용되는 패킷과 함께 "MP_JOIN"을 사용하여서 새로운 Subflow를 Connection에 인식시킨다.
새로운 연결하는 Subflow를 인증하기 위해 MP_CAPABLE 때에 사용되었던 Key 정보를 사용한다.
위 그림은 MPTCP의 새 Subflow 연결 요청(SYN)할 때 사용되는 패킷의 포맷이다. 이 패킷의 필드들은 다음과 같은 의미를 가진다.
- Kind
: MPTCP를 의미하는 0x1E 값으로 고정된다. - Length
: 새 Subflow의 연결 요청(SYN + MP_JOIN) 패킷의 길이를 나타낸다. - Subtype
: MP_JOIN을 나타내는 0x1 값으로 고정된다. - B flag
: 새로 연결할 Subflow를 Backup으로 할지 Primary로 할지 설정하는 Flag이다. (Backup = 1, Primary = 0)
: B Flag의 왼쪽 3bit는 0으로 고정된다. - Address ID
: Subflow의 Address ID를 나타내며 이 값은 ADD_ADDR을 통해 사전에 교환된 상태이다.
: 양측의 Host는 사전 교환된 Address ID와 IP Address를 미리 매핑 시켜 놓는다.
: 초기 MP_CAPABLE에서 사용된 Subflow의 Address ID 값은 default로 0이다.
: 이 필드의 목적은 IP 헤더가 Middleboxes(NAT 등)에 의해 변경되더라도 패킷의 Source 주소 식별을 가능케 한다. - Receiver's Token
: MPTCP Connection 식별, 초기 연결할 때 생성된 32Bit Token(Host-A인 경우 Host-B에서 생성된 Token) - Sender's Random Number
: Reply Attack을 방지하기 위한 임의 번호(Nonce)
위 그림은 MPTCP의 새 Subflow 연결 요청 응답(SYN/ACK)할 때 사용되는 패킷의 포맷이다. 이 패킷의 필드들은 다음과 같은 의미를 가진다.
- Length
: 새 Subflow의 연결 요청 응답(SYN/ACK + MP_JOIN) 패킷의 길이를 나타낸다. - Sender's Truncated HMAC
: SYN + MP_JOIN을 받은 수신자는 송신 측의 HMAC(가장 왼쪽 64bit)로 응답한다. - Sender's Random Number
: SYN + MP_JOIN을 받은 수신자는 송신 측의 HMAC와 함께 임의 번호(Nonce)로 응답한다.
위 그림은 MPTCP의 새 Subflow 연결이 완료(ACK) 되었을 때 사용되는 패킷의 포맷이다. 이 패킷의 필드들은 다음과 같은 의미를 가진다.
- Length
: 새 Subflow의 연결 완료(ACK + MP_JOIN) 패킷의 길이를 나타낸다. - Sender's HMAC
: 연결 요청 측의 인증 정보를 담는 필드이다.
: 연결 수락 측에서 ACK + MP_JOIN 패킷을 전송하면 연결 요청 측의 Subflow가 PRE_ESTABLISHED 상태가 되고, 이후 ACK를 수신한 경우에 연결 요청 측의 Subflow가 ESTABLISHED(= fully_established) 상태로 전환된다. (**4-way)
** 만약 MP_JOIN Signal을 연결 수락 측에서 거부하거나 정상적인 인증(Token) 값이 아니라면 해당 Subflow(TCP Session)는 RST Packet을 통해 닫힌다.
DSS
Sender Application에서 하나의 입력 Data Stream을 가져와 이것을 하나 이상의 Subflow로 분할하며, 그것을 다시 조립하고 순서대로 Receiver Applicaton에 전달될 수 있도록 MPTCP는 Data Sequence Signal(DSS)을 사용한다.
위 그림은 MPTCP의 데이터 송수신시 사용되는 패킷의 포맷이다. 이 패킷의 필드는 다음과 같은 의미를 가진다.
- Kind
: MPTCP를 의미하는 0x1E 값으로 고정된다. - Length
: DSS 패킷의 길이를 나타낸다. - Subtype
: DSS를 나타내는 0x2로 고정된다. - (reserved)
: 총 6bit로 padding 역할을 한다. 즉, 0으로 해당 6bit를 채운다. - F Flag
: DATA_FIN을 나타내는 Flag
: MPTCP Connection에서 더이상 보낼 Data가 없음을 의미한다. (Subflow-Level이 아닌 Connection-Level로 이해)
: DATA_FIN은 최종 한 Byte를 차지한다. 다시 말해, 보낼 Data가 10Byte라면 DATA_FIN을 포함해서 총 Data 크기는 11Byte가 되는 것이다. - m Flag
: 해당 Flag가 1로 설정되었다면, Data Sequence Number 필드가 8Byte 길이임을 의미한다. (M Flag가 1로 설정되었을 경우) - M Flag
: 해당 Flag가 1로 설정되었다면, 해당 패킷에 Data Sequence Number, Subflow Sequnece Number, Data-Level Length, Checksum이 존재함을 의미한다. - a Flag
: 해당 Flag가 1로 설정되었다면, Data ACK 필드가 8Byte 길이임을 의미한다. (A Flag가 1로 설정되었을 경우) - A Flag
: 해당 Flag가 1로 설정되었다면, 해당 패킷에 Data ACK가 존재함을 의미한다. - Data ACK
: MPTCP Connection-level의 ACK이다. 이 ACK는 표준 TCP의 누적(Cumulative) ACK와 동일한 역할을 수행한다. 또한, 다음 수신할 DSN(Data Sequence Number)을 지정한다.
: Data ACK는 Data와 모든 MPTCP 신호(MP_CAPABLE, MP_JOIN 등)가 Remote 단에서 수신되고 승인되었음을 증명한다. - DSN (Data Seqeunce Number)
: DSN은 0으로 시작할 수 없으며, 블라인드 세션에서 가로채기 더 어렵게 하기 위해 SHA-1 해시의 최소 64bit로 설정된다. (초기 DSN 값)
: 송신단에서 전송하는 Applicaiton Data의 시작 데이터를 나타낸다. - Subflow Sequence Number
: 각 Subflow에서 관리하는 필드이다.
: 각 Subflow에서 보내는 Data의 시작 위치를 나타내며, 해당 필드는 DSN에 의해 매핑되어 재조립된다. - Data-level Length
: MPTCP Connection에 의해서 전송되는 Data의 길이를 나타낸다.
: 예를 들어, 송신할 때 DSN이 80, Data-level Length가 10이라면 수신단에서는 Data ACK를 90으로 설정하고 다음 Data를 요청하게 된다.
: 만약 위와 같은 송신 패킷에 DATA_FIN이 설정된 경우라면 Data-level Length가 11이 되고 Data ACK는 91로 응답할 것이다. - Checksum
: MPTCP의 Data를 감지할 때 사용하는 것이 아닌, Middleboxes(NAT 등)에 의해 Payload가 조정되었는지 감지하는데 사용된다.
: 만약 조정되었다면 MPTCP를 유지할 수 없음으로 일반 TCP로 Fall-back 된다.
DATA_FIN
Applicaiton 이 소켓으로 close()를 호출할 때, 이것은 더 이상 전송할 데이터가 없음을 의미한다.
MPTCP는 이때 DATA_FIN을 발생시킨다. (DSS의 'F' Flag)
기본적으로 Host는 작동 중인 모든 Subflow를 닫아서는 안된다.
즉, 모든 Outstanding Data(송신측에서 Data를 보냈지만 아직 ACK되지 않은 Data들)가 DATA_ACKed가 되어야지만 모든 Subflow를 닫을 수 있다.
위에서 설명한 대로 개별 Subflow는 표준 TCP FIN으로 종료된다.
모든 Subflow가 FIN 교환으로 닫혔지만 DATA_FIN이 수신 및 승인되지 않은 경우 MPTCP Connection은 Timeout 후에만 닫힐 수 있다.
이는 MPTCP Stack이 Subflow와 Connection Level에서 모두 TIME_WAIT 상태를 갖는다는 것을 의미한다.
따라서, 새로운 Subflow를 다시 설정하기 전에 모든 Subflow에서 연결이 끊기는 "Break-Before-Make" 시나리오가 허용된다.
실제 MPTCP 패킷 캡쳐
www.multipath-tcp.org에서 제공되는 MPTCP Kernel을 Linux PC에 올린 뒤 Echo 테스트를 진행해보았다.
테스트는 하나의 Server와 하나의 Client를 두었으며, 테스트 구조는 다음 그림과 같다.
MPTCP Connection에는 하나의 Subflow만을 포함시켜 진행하였다.
아래에 캡쳐된 패킷들의 MPTCP 신호의 시간적 순서는 다음과 같다.
(1)MP_CAPABLE -> (2)ADD_ADDR -> (3)DSS -> (4)MP_JOIN -> (5)DATA_FIN
(1)MP_CAPABLE
(2)ADD_ADDR
(3)DSS
(4)MP_JOIN
(5)DATA_FIN
Ref
- A. Ford, C. Raiciu, M. Handley, and O. Bonaventure, “TCP Extensions for Multipath Operation with Multiple Addresses.” IETF RFC 6824, April 2013.
'Linux > MPTCP' 카테고리의 다른 글
MPTCP OFO 패킷 큐 사이즈 측정 (in Linux kernel) (0) | 2022.01.11 |
---|---|
MPTCP 설치 for Linux (Debian, RaspberryPi) (0) | 2021.12.07 |
MPTCP Path Manager : Netlink PM (0) | 2021.09.06 |
1. MPTCP 개념 (0) | 2021.07.09 |