Skip to content

Commit

Permalink
info: fallback: MPTCP_INFO_FLAG_FALLBACK is never set
Browse files Browse the repository at this point in the history
When calling getsockopt(MPTCP_INFO), MPTCP_INFO_FLAG_FALLBACK will never
be set. Instead the syscall will return an error, for both the client
and the server side.

MPTCP_INFO_FLAG_FALLBACK will only be set when listing MPTCP connections
via the Netlink API (hence the confusion).

We can simplify the examples now:
- getsockopt(MPTCP_INFO) for both the client and server, kernels >= 5.16
- getsockopt(SO_PROTOCOL) for the server only, only check the client
  request, kernels < 5.16

Signed-off-by: Matthieu Baerts (NGI0) <[email protected]>
  • Loading branch information
matttbe committed May 6, 2024
1 parent 5238136 commit e67074d
Showing 1 changed file with 21 additions and 48 deletions.
69 changes: 21 additions & 48 deletions mptcp-info.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,9 @@ therefore recommended to use these last two fields.
Since kernel v5.16, `getsockopt(MPTCP_INFO)` can be used to check if an
MPTCP connection fell back to TCP. If this `getsockopt()` call returns `-1`,
and `errno` is set to `EOPNOTSUPP` (v4) or `ENOPROTOOPT` (v6), it means the
MPTCP connection has fallen back to TCP at some point. In case of a client
(`connect()`), or for a server to check if an established connection has later
fallen back to TCP (should be rare), it is also required to check if the
`mptcpi_flags` field from the `mptcp_info` structure has the
`MPTCP_INFO_FLAG_FALLBACK` bit (`0x1`) set.
and `errno` is set to `EOPNOTSUPP` (v4) or `ENOPROTOOPT` (v6), it either means:
- the MPTCP connection has fallen back to TCP at some point
- or the kernel is older than v5.16.
{: .warning}
On kernels < v5.16, `getsockopt(MPTCP_INFO)` will always fail, and `errno` will
Expand All @@ -290,24 +287,29 @@ the protocol will be set to `IPPROTO_MPTCP`. This can be used on kernels < 5.16
too.
<details markdown="block">
<summary>Example in C (<b>client only</b>) </summary>
<summary>Example in C (client or server) </summary>
{: .warning}
**Client only**: It requires **kernel >= 5.16**
Requires **kernel >= 5.16**: it works with clients and servers, and for fallback
that would have happened after the establishment of the connection (should be
rare).
```c
#define MPTCP_INFO 1
#define MPTCP_INFO_FLAG_FALLBACK 1
bool socket_is_mptcp(int client_fd)
bool socket_is_mptcp(int accept_fd)
{
socklen_t len = sizeof(struct mptcp_info);
struct mptcp_info info = { 0 };
socklen_t len = 0:
/* kernel < 5.16 will always fail with errno set to EOPNOTSUPP (v4) or ENOPROTOOPT (v6) */
if (kernel_version_lower(5, 16))
return true; /* This method cannot be used: check the next example */
if (getsockopt(client_fd, SOL_MPTCP, MPTCP_INFO, &info, &len) < 0) {
perror("kernel < v5.16: we cannot tell (workaround: use NetLink or ss -Mi)");
return true;
if (getsockopt(accept_fd, SOL_MPTCP, MPTCP_INFO, NULL, &len) < 0) {
if (errno != EOPNOTSUPP && errno != ENOPROTOOPT)
perror("getsockopt(MPTCP_INFO)"); /* Should not happen */
return false; /* A fallback happened */
}
return (info.mptcpi_flags & MPTCP_INFO_FLAG_FALLBACK) == 0;
return true;
}
```
</details> {: .ctsm}
Expand All @@ -316,7 +318,9 @@ bool socket_is_mptcp(int client_fd)
<summary>Example in C (<b>server only</b>: MPTCP requested?) </summary>

{: .warning}
**Server only**: it **only** checks if the client requested to use MPTCP
**Server only**: it **only** checks if the client requested to use MPTCP. Note
that even if it should be rare, a fallback can happened later during the
connection.

```c
bool client_requested_mptcp(int accept_fd)
Expand All @@ -333,37 +337,6 @@ bool client_requested_mptcp(int accept_fd)
```
</details> {: .ctsm}
<details markdown="block">
<summary>Example in C (<b>server only</b>: full solution) </summary>
{: .warning}
**Server only**: Requires **kernel >= 5.16**, it also checks for fallback
that would have happened after the establishment of the connection (should be
rare)
```c
#define MPTCP_INFO 1
#define MPTCP_INFO_FLAG_FALLBACK 1
bool socket_is_mptcp(int accept_fd)
{
socklen_t len = sizeof(struct mptcp_info);
struct mptcp_info info = { 0 };
/* kernel < 5.16 will always fail with errno set to EOPNOTSUPP (v4) or ENOPROTOOPT (v6) */
if (kernel_version_lower(5, 16))
return true; /* This method cannot be used: check the next example */
if (getsockopt(accept_fd, SOL_MPTCP, MPTCP_INFO, &info, &len) < 0) {
if (errno != EOPNOTSUPP && errno != ENOPROTOOPT)
perror("getsockopt(MPTCP_INFO)"); /* Should not happen */
return false; /* The client didn't ask to use MPTCP */
}
/* The connection has been established in MPTCP, check for fallback later (rare) */
return (info.mptcpi_flags & MPTCP_INFO_FLAG_FALLBACK) == 0;
}
```
</details> {: .ctsm}

<details markdown="block">
<summary>Example in Go </summary>
Call [`MultipathTCP()`](https://pkg.go.dev/net#TCPConn.MultipathTCP) on
Expand Down

0 comments on commit e67074d

Please sign in to comment.