mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-22 12:33:59 +08:00
selftests: mptcp: add MPTCP_FULL_INFO testcase
Add a testcase explicitly triggering the newly introduce MPTCP_FULL_INFO getsockopt. Link: https://github.com/multipath-tcp/mptcp_net-next/issues/388 Signed-off-by: Paolo Abeni <pabeni@redhat.com> Reviewed-by: Matthieu Baerts <matthieu.baerts@tessares.net> Co-developed-by: Matthieu Baerts <matthieu.baerts@tessares.net> Signed-off-by: Matthieu Baerts <matthieu.baerts@tessares.net> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
492432074e
commit
aa723d5b35
@ -86,9 +86,38 @@ struct mptcp_subflow_addrs {
|
||||
#define MPTCP_SUBFLOW_ADDRS 3
|
||||
#endif
|
||||
|
||||
#ifndef MPTCP_FULL_INFO
|
||||
struct mptcp_subflow_info {
|
||||
__u32 id;
|
||||
struct mptcp_subflow_addrs addrs;
|
||||
};
|
||||
|
||||
struct mptcp_full_info {
|
||||
__u32 size_tcpinfo_kernel; /* must be 0, set by kernel */
|
||||
__u32 size_tcpinfo_user;
|
||||
__u32 size_sfinfo_kernel; /* must be 0, set by kernel */
|
||||
__u32 size_sfinfo_user;
|
||||
__u32 num_subflows; /* must be 0, set by kernel (real subflow count) */
|
||||
__u32 size_arrays_user; /* max subflows that userspace is interested in;
|
||||
* the buffers at subflow_info/tcp_info
|
||||
* are respectively at least:
|
||||
* size_arrays * size_sfinfo_user
|
||||
* size_arrays * size_tcpinfo_user
|
||||
* bytes wide
|
||||
*/
|
||||
__aligned_u64 subflow_info;
|
||||
__aligned_u64 tcp_info;
|
||||
struct mptcp_info mptcp_info;
|
||||
};
|
||||
|
||||
#define MPTCP_FULL_INFO 4
|
||||
#endif
|
||||
|
||||
struct so_state {
|
||||
struct mptcp_info mi;
|
||||
struct mptcp_info last_sample;
|
||||
struct tcp_info tcp_info;
|
||||
struct mptcp_subflow_addrs addrs;
|
||||
uint64_t mptcpi_rcv_delta;
|
||||
uint64_t tcpi_rcv_delta;
|
||||
bool pkt_stats_avail;
|
||||
@ -370,6 +399,8 @@ static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t
|
||||
olen -= sizeof(struct mptcp_subflow_data);
|
||||
assert(olen == ti.d.size_user);
|
||||
|
||||
s->tcp_info = ti.ti[0];
|
||||
|
||||
if (ti.ti[0].tcpi_bytes_sent == w &&
|
||||
ti.ti[0].tcpi_bytes_received == r)
|
||||
goto done;
|
||||
@ -391,7 +422,7 @@ done:
|
||||
do_getsockopt_bogus_sf_data(fd, MPTCP_TCPINFO);
|
||||
}
|
||||
|
||||
static void do_getsockopt_subflow_addrs(int fd)
|
||||
static void do_getsockopt_subflow_addrs(struct so_state *s, int fd)
|
||||
{
|
||||
struct sockaddr_storage remote, local;
|
||||
socklen_t olen, rlen, llen;
|
||||
@ -439,6 +470,7 @@ static void do_getsockopt_subflow_addrs(int fd)
|
||||
|
||||
assert(memcmp(&local, &addrs.addr[0].ss_local, sizeof(local)) == 0);
|
||||
assert(memcmp(&remote, &addrs.addr[0].ss_remote, sizeof(remote)) == 0);
|
||||
s->addrs = addrs.addr[0];
|
||||
|
||||
memset(&addrs, 0, sizeof(addrs));
|
||||
|
||||
@ -459,13 +491,70 @@ static void do_getsockopt_subflow_addrs(int fd)
|
||||
do_getsockopt_bogus_sf_data(fd, MPTCP_SUBFLOW_ADDRS);
|
||||
}
|
||||
|
||||
static void do_getsockopt_mptcp_full_info(struct so_state *s, int fd)
|
||||
{
|
||||
size_t data_size = sizeof(struct mptcp_full_info);
|
||||
struct mptcp_subflow_info sfinfo[2];
|
||||
struct tcp_info tcp_info[2];
|
||||
struct mptcp_full_info mfi;
|
||||
socklen_t olen;
|
||||
int ret;
|
||||
|
||||
memset(&mfi, 0, data_size);
|
||||
memset(tcp_info, 0, sizeof(tcp_info));
|
||||
memset(sfinfo, 0, sizeof(sfinfo));
|
||||
|
||||
mfi.size_tcpinfo_user = sizeof(struct tcp_info);
|
||||
mfi.size_sfinfo_user = sizeof(struct mptcp_subflow_info);
|
||||
mfi.size_arrays_user = 2;
|
||||
mfi.subflow_info = (unsigned long)&sfinfo[0];
|
||||
mfi.tcp_info = (unsigned long)&tcp_info[0];
|
||||
olen = data_size;
|
||||
|
||||
ret = getsockopt(fd, SOL_MPTCP, MPTCP_FULL_INFO, &mfi, &olen);
|
||||
if (ret < 0) {
|
||||
if (errno == EOPNOTSUPP) {
|
||||
perror("MPTCP_FULL_INFO test skipped");
|
||||
return;
|
||||
}
|
||||
xerror("getsockopt MPTCP_FULL_INFO");
|
||||
}
|
||||
|
||||
assert(olen <= data_size);
|
||||
assert(mfi.size_tcpinfo_kernel > 0);
|
||||
assert(mfi.size_tcpinfo_user ==
|
||||
MIN(mfi.size_tcpinfo_kernel, sizeof(struct tcp_info)));
|
||||
assert(mfi.size_sfinfo_kernel > 0);
|
||||
assert(mfi.size_sfinfo_user ==
|
||||
MIN(mfi.size_sfinfo_kernel, sizeof(struct mptcp_subflow_info)));
|
||||
assert(mfi.num_subflows == 1);
|
||||
|
||||
/* Tolerate future extension to mptcp_info struct and running newer
|
||||
* test on top of older kernel.
|
||||
* Anyway any kernel supporting MPTCP_FULL_INFO must at least include
|
||||
* the following in mptcp_info.
|
||||
*/
|
||||
assert(olen > (socklen_t)__builtin_offsetof(struct mptcp_full_info, tcp_info));
|
||||
assert(mfi.mptcp_info.mptcpi_subflows == 0);
|
||||
assert(mfi.mptcp_info.mptcpi_bytes_sent == s->last_sample.mptcpi_bytes_sent);
|
||||
assert(mfi.mptcp_info.mptcpi_bytes_received == s->last_sample.mptcpi_bytes_received);
|
||||
|
||||
assert(sfinfo[0].id == 1);
|
||||
assert(tcp_info[0].tcpi_bytes_sent == s->tcp_info.tcpi_bytes_sent);
|
||||
assert(tcp_info[0].tcpi_bytes_received == s->tcp_info.tcpi_bytes_received);
|
||||
assert(!memcmp(&sfinfo->addrs, &s->addrs, sizeof(struct mptcp_subflow_addrs)));
|
||||
}
|
||||
|
||||
static void do_getsockopts(struct so_state *s, int fd, size_t r, size_t w)
|
||||
{
|
||||
do_getsockopt_mptcp_info(s, fd, w);
|
||||
|
||||
do_getsockopt_tcp_info(s, fd, r, w);
|
||||
|
||||
do_getsockopt_subflow_addrs(fd);
|
||||
do_getsockopt_subflow_addrs(s, fd);
|
||||
|
||||
if (r)
|
||||
do_getsockopt_mptcp_full_info(s, fd);
|
||||
}
|
||||
|
||||
static void connect_one_server(int fd, int pipefd)
|
||||
|
Loading…
Reference in New Issue
Block a user