MPTCP: an overlooked new feature in Go 1.21

Original link:https://colobu.com/2023/07/03/mptcp-a-go-1-21-new-feature/

Go 1.21 will be released in two or three months. Many students have summarized the new features of Go 1.21 to create momentum for the arrival of the new Go version. However, I have not seen any students specifically introduce Go 1.21 as a new network library. An added feature, so I will create a new article to introduce it.

Regarding the new feature of MPTCP, there is an issue ( #56539 ) for follow-up and discussion. It is an extension to TCP’s single path, defined by the RFC8684 specification.

The Multipath Transmission Control Protocol (Multipath TCP, MPTCP for short) is a protocol at the transport layer designed to enhance the traditional single-path TCP protocol so that it can simultaneously transmit data on multiple network paths. MPTCP allows simultaneous use of multiple paths for data transmission, providing higher bandwidth, better load balancing, and higher reliability.
The traditional TCP protocol is designed for a single path, which transmits data over a single connection between peers. By introducing additional functions, MPTCP enables a TCP connection to run on multiple network paths at the same time.
MPTCP works as follows:

  1. Connection establishment : The connection establishment process of MPTCP is similar to that of traditional TCP, but during the initial handshake, the two parties will exchange capability options to determine whether MPTCP is supported.
  2. Subflow establishment : Once the MPTCP connection is established, it can start multiple subflows (subflows), each subflow transmits data through a different network path. These sub-flows can be identified by different IP addresses and port numbers.
  3. Path management : MPTCP uses a path management mechanism to select and manage multiple network paths. It can select the path according to the quality, delay, bandwidth and other indicators of the path, and dynamically adjust the use of the path according to the network conditions.
  4. Data transfer : MPTCP splits data into appropriately sized chunks and sends them on different sub-streams. The receiving end will reassemble the data according to the serial number of the data block and the substream to which the data block belongs.

Advantages of MPTCP include:

  • Bandwidth enhancement : MPTCP can utilize the bandwidth of multiple paths at the same time, thus providing higher overall bandwidth.
  • Load balancing : MPTCP can dynamically adjust data transmission according to path quality and available bandwidth to achieve load balancing and improve network resource utilization.
  • Fault tolerance : Since data can be transmitted through multiple paths, MPTCP can provide better fault tolerance. Even if one path fails, data can still be transmitted over other available paths.
  • Mobility support : MPTCP can maintain the connection when the mobile device switches networks without re-establishing the connection, providing a smoother mobile experience.

MPTCP has become a standardized protocol, and it is widely used in multipath transmission scenarios, such as internal communication in data centers , wireless networks , and mobile networks .

For example, Apple’s official documentation states:

iOS supports Multipath TCP (MPTCP) and allows an iPhone or iPad to establish a backup TCP connection to a target host over a cellular data connection.
iPhones and iPads use MPTCP with an active cellular data connection to establish two connections:

  • Primary TCP connection over Wi-Fi
  • Alternate connection via cellular data

If Wi-Fi is unavailable or unresponsive, iOS uses a cellular data connection.
https://support.apple.com/zh-cn/HT201373

The official help document of Little Red Riding Hood also gives a special introduction to MPTCP.

MPTCP is widely supported in the Linux kernel and has been part of the Linux kernel. ChatGPT said that since the Linux kernel version 3.6, MPTCP has been included in the mainline kernel, and users can configure and use MPTCP functions, but the MPTCP community website says that MPTCP v1 is only supported in 5.6.
Linux distributions such as Ubuntu, Fedora, and Debian usually include MPTCP support by default. Since Linux 5.19, MPTCP includes the following features:

  • Support setting IPPROTO_MPTCP protocol in socket system call
  • Fallback from MPTCP to TCP if peer or intermediate device does not support MPTCP
  • Path management using in-kernel or userspace path managers
  • Also use socket options for TCP sockets
  • Debugging features, including MIB counters, diagnostic support (using the ss command), and tracepoints

Through the efforts of Go community and MPTCP community students, a convenient way to support MPTCP was finally found and implemented in Go version 1.21. In summary, it is the following four methods.

For TCP client, you can set and check whether MPTCP is supported by the following methods:


1
2

func (*Dialer) SetMultipathTCP(enabled bool )
func (*Dialer) MultipathTCP() bool

For TCP server, you can set and check whether MPTCP is supported by the following methods:


1
2

func (*ListenConfig) SetMultipathTCP(enabled bool )
func (*ListenConfig) MultipathTCP() bool

Therefore, for a system, both the client and the server need to be set to ensure that MPTCP works.

I demonstrate how to use MPTCP with a simple example.

The server-side code is as follows, enable mptcp for Listener, and the connection established with the client may support mptcp, or degenerate into ordinary tcp:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

package main
import (
“context”
“errors”
“flag”
“fmt”
“io”
“net”
)
var (
addr = flag. String( “addr” , “:8080” , “service address” )
)
func main() {
flag. Parse()
lc := &net.ListenConfig{}
if lc.MultipathTCP() { // mptcp is disabled by default
panic ( “MultipathTCP should be off by default” )
}
lc.SetMultipathTCP( true ) // Actively enable mptcp
ln, err := lc.Listen(context.Background(), “tcp” , *addr) // normal tcp listening
if err != nil {
panic (err)
}
for {
conn, err := ln. Accept()
if err != nil {
panic (err)
}
go func () {
defer conn. Close()
isMultipathTCP, err := conn.(*net.TCPConn).MultipathTCP() // Check whether the connection supports mptcp
fmt.Printf( “accepted connection from %s with mptcp: %t, err: %v\n” , conn.RemoteAddr(), isMultipathTCP, err)
for {
buf := make ([] byte , 1024 )
n, err := conn. Read(buf)
if err != nil {
if errors.Is(err, io.EOF) {
return
}
panic (err)
}
if _, err := conn.Write(buf[:n]); err != nil {
panic (err)
}
}
}()
}
}

The client code is as follows. We enable mptcp for the dialer, and check whether the established connection really supports mptcp, because if the client or server does not support mptcp, it will degenerate into ordinary tcp:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

package main
import (
“flag”
“fmt”
“net”
“time”
)
var (
addr = flag. String( “addr” , “127.0.0.1:8080” , “service address” )
)
func main() {
flag. Parse()
d := &net.Dialer{}
if d.MultipathTCP() { // Disabled by default
panic ( “MultipathTCP should be off by default” )
}
d.SetMultipathTCP( true ) // active enable
if !d.MultipathTCP() { // use mptcp when dial has been set
panic ( “MultipathTCP is not on after having been forced to on” )
}
c, err := d.Dial( “tcp” , *addr)
if err != nil {
panic (err)
}
defer c.Close()
tcp, ok := c.(*net.TCPConn)
if !ok {
panic ( “struct is not a TCPConn” )
}
mptcp, err := tcp.MultipathTCP() // Whether the established connection really supports mptcp
if err != nil {
panic (err)
}
fmt.Printf( “outgoing connection from %s with mptcp: %t\n” , *addr, mptcp)
if !mptcp { // does not support mptcp, panic
panic ( “outgoing connection is not with MPTCP” )
}
for {
snt := [] byte ( “MPTCP TEST” )
if _, err := c.Write(snt); err != nil {
panic (err)
}
b := make ([] byte , len (snt))
if _, err := c.Read(b); err != nil {
panic (err)
}
fmt. Println( string (b))
time. Sleep(time. Second)
}
}

This article is transferred from:https://colobu.com/2023/07/03/mptcp-a-go-1-21-new-feature/
This site is only for collection, and the copyright belongs to the original author.