Skip to content

Commit c11c590

Browse files
Florian Westphaldavem330
authored andcommitted
mptcp: add MPTCP_SUBFLOW_ADDRS getsockopt support
This retrieves the address pairs of all subflows currently active for a given mptcp connection. It re-uses the same meta-header as for MPTCP_TCPINFO. A new structure is provided to hold the subflow address data: struct mptcp_subflow_addrs { union { __kernel_sa_family_t sa_family; struct sockaddr sa_local; struct sockaddr_in sin_local; struct sockaddr_in6 sin6_local; struct sockaddr_storage ss_local; }; union { struct sockaddr sa_remote; struct sockaddr_in sin_remote; struct sockaddr_in6 sin6_remote; struct sockaddr_storage ss_remote; }; }; Usage of the new getsockopt is very similar to MPTCP_TCPINFO one. Userspace allocates a 'struct mptcp_subflow_data', followed by one or more 'struct mptcp_subflow_addrs', then inits the mptcp_subflow_data structure as follows: struct mptcp_subflow_addrs *sf_addr; struct mptcp_subflow_data *addr; socklen_t olen = sizeof(*addr) + (8 * sizeof(*sf_addr)); addr = malloc(olen); addr->size_subflow_data = sizeof(*addr); addr->num_subflows = 0; addr->size_kernel = 0; addr->size_user = sizeof(struct mptcp_subflow_addrs); sf_addr = (struct mptcp_subflow_addrs *)(addr + 1); and then retrieves the endpoint addresses via: ret = getsockopt(fd, SOL_MPTCP, MPTCP_SUBFLOW_ADDRS, addr, &olen); If the call succeeds, kernel will have added up to 8 endpoint addresses after the 'mptcp_subflow_data' header. Userspace needs to re-check 'olen' value to detect how many bytes have been filled in by the kernel. Userspace can check addr->num_subflows to discover when there were more subflows that available data space. Co-developed-by: Matthieu Baerts <[email protected]> Signed-off-by: Matthieu Baerts <[email protected]> Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Mat Martineau <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 06f15ce commit c11c590

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

include/uapi/linux/mptcp.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
#include <linux/const.h>
66
#include <linux/types.h>
7+
#include <linux/in.h> /* for sockaddr_in */
8+
#include <linux/in6.h> /* for sockaddr_in6 */
9+
#include <linux/socket.h> /* for sockaddr_storage and sa_family */
10+
11+
#ifndef __KERNEL__
12+
#include <sys/socket.h> /* for struct sockaddr */
13+
#endif
714

815
#define MPTCP_SUBFLOW_FLAG_MCAP_REM _BITUL(0)
916
#define MPTCP_SUBFLOW_FLAG_MCAP_LOC _BITUL(1)
@@ -200,8 +207,25 @@ struct mptcp_subflow_data {
200207
__u32 size_user; /* size of one element in data[] */
201208
} __attribute__((aligned(8)));
202209

210+
struct mptcp_subflow_addrs {
211+
union {
212+
__kernel_sa_family_t sa_family;
213+
struct sockaddr sa_local;
214+
struct sockaddr_in sin_local;
215+
struct sockaddr_in6 sin6_local;
216+
struct __kernel_sockaddr_storage ss_local;
217+
};
218+
union {
219+
struct sockaddr sa_remote;
220+
struct sockaddr_in sin_remote;
221+
struct sockaddr_in6 sin6_remote;
222+
struct __kernel_sockaddr_storage ss_remote;
223+
};
224+
};
225+
203226
/* MPTCP socket options */
204227
#define MPTCP_INFO 1
205228
#define MPTCP_TCPINFO 2
229+
#define MPTCP_SUBFLOW_ADDRS 3
206230

207231
#endif /* _UAPI_MPTCP_H */

net/mptcp/sockopt.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,95 @@ static int mptcp_getsockopt_tcpinfo(struct mptcp_sock *msk, char __user *optval,
840840
return 0;
841841
}
842842

843+
static void mptcp_get_sub_addrs(const struct sock *sk, struct mptcp_subflow_addrs *a)
844+
{
845+
struct inet_sock *inet = inet_sk(sk);
846+
847+
memset(a, 0, sizeof(*a));
848+
849+
if (sk->sk_family == AF_INET) {
850+
a->sin_local.sin_family = AF_INET;
851+
a->sin_local.sin_port = inet->inet_sport;
852+
a->sin_local.sin_addr.s_addr = inet->inet_rcv_saddr;
853+
854+
if (!a->sin_local.sin_addr.s_addr)
855+
a->sin_local.sin_addr.s_addr = inet->inet_saddr;
856+
857+
a->sin_remote.sin_family = AF_INET;
858+
a->sin_remote.sin_port = inet->inet_dport;
859+
a->sin_remote.sin_addr.s_addr = inet->inet_daddr;
860+
#if IS_ENABLED(CONFIG_IPV6)
861+
} else if (sk->sk_family == AF_INET6) {
862+
const struct ipv6_pinfo *np = inet6_sk(sk);
863+
864+
a->sin6_local.sin6_family = AF_INET6;
865+
a->sin6_local.sin6_port = inet->inet_sport;
866+
867+
if (ipv6_addr_any(&sk->sk_v6_rcv_saddr))
868+
a->sin6_local.sin6_addr = np->saddr;
869+
else
870+
a->sin6_local.sin6_addr = sk->sk_v6_rcv_saddr;
871+
872+
a->sin6_remote.sin6_family = AF_INET6;
873+
a->sin6_remote.sin6_port = inet->inet_dport;
874+
a->sin6_remote.sin6_addr = sk->sk_v6_daddr;
875+
#endif
876+
}
877+
}
878+
879+
static int mptcp_getsockopt_subflow_addrs(struct mptcp_sock *msk, char __user *optval,
880+
int __user *optlen)
881+
{
882+
struct sock *sk = &msk->sk.icsk_inet.sk;
883+
struct mptcp_subflow_context *subflow;
884+
unsigned int sfcount = 0, copied = 0;
885+
struct mptcp_subflow_data sfd;
886+
char __user *addrptr;
887+
int len;
888+
889+
len = mptcp_get_subflow_data(&sfd, optval, optlen);
890+
if (len < 0)
891+
return len;
892+
893+
sfd.size_kernel = sizeof(struct mptcp_subflow_addrs);
894+
sfd.size_user = min_t(unsigned int, sfd.size_user,
895+
sizeof(struct mptcp_subflow_addrs));
896+
897+
addrptr = optval + sfd.size_subflow_data;
898+
899+
lock_sock(sk);
900+
901+
mptcp_for_each_subflow(msk, subflow) {
902+
struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
903+
904+
++sfcount;
905+
906+
if (len && len >= sfd.size_user) {
907+
struct mptcp_subflow_addrs a;
908+
909+
mptcp_get_sub_addrs(ssk, &a);
910+
911+
if (copy_to_user(addrptr, &a, sfd.size_user)) {
912+
release_sock(sk);
913+
return -EFAULT;
914+
}
915+
916+
addrptr += sfd.size_user;
917+
copied += sfd.size_user;
918+
len -= sfd.size_user;
919+
}
920+
}
921+
922+
release_sock(sk);
923+
924+
sfd.num_subflows = sfcount;
925+
926+
if (mptcp_put_subflow_data(&sfd, optval, copied, optlen))
927+
return -EFAULT;
928+
929+
return 0;
930+
}
931+
843932
static int mptcp_getsockopt_sol_tcp(struct mptcp_sock *msk, int optname,
844933
char __user *optval, int __user *optlen)
845934
{
@@ -862,6 +951,8 @@ static int mptcp_getsockopt_sol_mptcp(struct mptcp_sock *msk, int optname,
862951
return mptcp_getsockopt_info(msk, optval, optlen);
863952
case MPTCP_TCPINFO:
864953
return mptcp_getsockopt_tcpinfo(msk, optval, optlen);
954+
case MPTCP_SUBFLOW_ADDRS:
955+
return mptcp_getsockopt_subflow_addrs(msk, optval, optlen);
865956
}
866957

867958
return -EOPNOTSUPP;

0 commit comments

Comments
 (0)