Skip to content

Commit 5bf259e

Browse files
devnexenintel-lab-lkp
authored andcommitted
selftests: mptcp: cover RECVERR and MSG_ERRQUEUE
Add MPTCP selftest coverage for RECVERR sockopt round-trips and parent-socket MSG_ERRQUEUE delivery. Enable TX software timestamping, send data over an MPTCP socket, wait for POLLERR, and verify that recvmsg(MSG_ERRQUEUE) returns timestamping metadata on the MPTCP parent socket. Signed-off-by: David Carlier <devnexen@gmail.com> Assisted-by: Codex:gpt-5
1 parent 49cad7d commit 5bf259e

1 file changed

Lines changed: 152 additions & 0 deletions

File tree

tools/testing/selftests/net/mptcp/mptcp_sockopt.c

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,17 @@
2626

2727
#include <linux/tcp.h>
2828
#include <linux/compiler.h>
29+
#include <linux/errqueue.h>
30+
#include <linux/net_tstamp.h>
31+
32+
#include <poll.h>
2933

3034
static int pf = AF_INET;
3135

36+
#ifndef SCM_TIMESTAMPING
37+
#define SCM_TIMESTAMPING SO_TIMESTAMPING
38+
#endif
39+
3240
#ifndef IPPROTO_MPTCP
3341
#define IPPROTO_MPTCP 262
3442
#endif
@@ -128,6 +136,9 @@ struct so_state {
128136
#define MIN(a, b) ((a) < (b) ? (a) : (b))
129137
#endif
130138

139+
static void enable_tx_timestamping(int fd);
140+
static void test_msg_errqueue_timestamping(int fd);
141+
131142
static void __noreturn die_perror(const char *msg)
132143
{
133144
perror(msg);
@@ -598,13 +609,17 @@ static void connect_one_server(int fd, int pipefd)
598609

599610
assert(strncmp(buf2, "xmit", 4) == 0);
600611

612+
enable_tx_timestamping(fd);
613+
601614
ret = write(fd, buf, len);
602615
if (ret < 0)
603616
die_perror("write");
604617

605618
if (ret != (ssize_t)len)
606619
xerror("short write");
607620

621+
test_msg_errqueue_timestamping(fd);
622+
608623
total = 0;
609624
do {
610625
ret = read(fd, buf2 + total, sizeof(buf2) - total);
@@ -769,6 +784,142 @@ static void test_ip_tos_sockopt(int fd)
769784
xerror("expect socklen_t == -1");
770785
}
771786

787+
static void test_ip_recverr_sockopt(int fd)
788+
{
789+
struct iovec iov = {
790+
.iov_base = &(char){ 0 },
791+
.iov_len = 1,
792+
};
793+
struct msghdr msg = {
794+
.msg_iov = &iov,
795+
.msg_iovlen = 1,
796+
};
797+
int one = 1, zero = 0, val = -1;
798+
socklen_t s = sizeof(val);
799+
int level, optname, r;
800+
801+
switch (pf) {
802+
case AF_INET:
803+
level = SOL_IP;
804+
optname = IP_RECVERR;
805+
break;
806+
case AF_INET6:
807+
level = SOL_IPV6;
808+
optname = IPV6_RECVERR;
809+
break;
810+
default:
811+
xerror("Unknown pf %d\n", pf);
812+
}
813+
814+
r = setsockopt(fd, level, optname, &one, sizeof(one));
815+
if (r)
816+
die_perror("setsockopt recverr on");
817+
818+
r = getsockopt(fd, level, optname, &val, &s);
819+
if (r)
820+
die_perror("getsockopt recverr on");
821+
if (s != sizeof(val) || val != one)
822+
xerror("recverr on mismatch val=%d len=%u", val, s);
823+
824+
r = recvmsg(fd, &msg, MSG_ERRQUEUE | MSG_DONTWAIT);
825+
if (r != -1 || errno != EAGAIN)
826+
xerror("expected empty errqueue to return EAGAIN, ret=%d errno=%d", r, errno);
827+
828+
r = setsockopt(fd, level, optname, &zero, sizeof(zero));
829+
if (r)
830+
die_perror("setsockopt recverr off");
831+
832+
val = -1;
833+
s = sizeof(val);
834+
r = getsockopt(fd, level, optname, &val, &s);
835+
if (r)
836+
die_perror("getsockopt recverr off");
837+
if (s != sizeof(val) || val != zero)
838+
xerror("recverr off mismatch val=%d len=%u", val, s);
839+
}
840+
841+
static void enable_tx_timestamping(int fd)
842+
{
843+
int val = SOF_TIMESTAMPING_SOFTWARE |
844+
SOF_TIMESTAMPING_TX_SOFTWARE |
845+
SOF_TIMESTAMPING_OPT_TSONLY;
846+
int ret;
847+
848+
ret = setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING_OLD,
849+
&val, sizeof(val));
850+
if (ret)
851+
die_perror("setsockopt SO_TIMESTAMPING");
852+
}
853+
854+
static void test_msg_errqueue_timestamping(int fd)
855+
{
856+
char ctrl[512] = { 0 };
857+
char data[32] = { 0 };
858+
struct iovec iov = {
859+
.iov_base = data,
860+
.iov_len = sizeof(data),
861+
};
862+
struct msghdr msg = {
863+
.msg_iov = &iov,
864+
.msg_iovlen = 1,
865+
.msg_control = ctrl,
866+
.msg_controllen = sizeof(ctrl),
867+
};
868+
struct pollfd pfd = {
869+
.fd = fd,
870+
.events = POLLERR,
871+
};
872+
struct cmsghdr *cm;
873+
struct scm_timestamping *tss = NULL;
874+
struct sock_extended_err *serr = NULL;
875+
int ret, i;
876+
877+
for (i = 0; i < 10; i++) {
878+
ret = poll(&pfd, 1, 1000);
879+
if (ret < 0)
880+
die_perror("poll errqueue");
881+
if (ret == 0)
882+
continue;
883+
if (!(pfd.revents & POLLERR))
884+
xerror("expected POLLERR, got revents %#x", pfd.revents);
885+
break;
886+
}
887+
888+
if (i == 10)
889+
xerror("timed out waiting for MSG_ERRQUEUE event");
890+
891+
ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
892+
if (ret < 0)
893+
die_perror("recvmsg timestamping errqueue");
894+
if (!(msg.msg_flags & MSG_ERRQUEUE))
895+
xerror("expected MSG_ERRQUEUE in msg_flags, got %#x",
896+
msg.msg_flags);
897+
898+
for (cm = CMSG_FIRSTHDR(&msg); cm; cm = CMSG_NXTHDR(&msg, cm)) {
899+
if (cm->cmsg_level == SOL_SOCKET &&
900+
cm->cmsg_type == SCM_TIMESTAMPING)
901+
tss = (void *)CMSG_DATA(cm);
902+
if ((cm->cmsg_level == SOL_IP &&
903+
cm->cmsg_type == IP_RECVERR) ||
904+
(cm->cmsg_level == SOL_IPV6 &&
905+
cm->cmsg_type == IPV6_RECVERR))
906+
serr = (void *)CMSG_DATA(cm);
907+
}
908+
909+
if (!tss)
910+
xerror("missing SCM_TIMESTAMPING cmsg");
911+
if (!serr)
912+
xerror("missing sock_extended_err cmsg");
913+
if (serr->ee_errno != ENOMSG ||
914+
serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING)
915+
xerror("unexpected timestamping err ee_errno=%u ee_origin=%u",
916+
serr->ee_errno, serr->ee_origin);
917+
if (!tss->ts[0].tv_sec && !tss->ts[0].tv_nsec &&
918+
!tss->ts[1].tv_sec && !tss->ts[1].tv_nsec &&
919+
!tss->ts[2].tv_sec && !tss->ts[2].tv_nsec)
920+
xerror("all timestamp slots are zero");
921+
}
922+
772923
static int client(int pipefd)
773924
{
774925
int fd = -1;
@@ -787,6 +938,7 @@ static int client(int pipefd)
787938
}
788939

789940
test_ip_tos_sockopt(fd);
941+
test_ip_recverr_sockopt(fd);
790942

791943
connect_one_server(fd, pipefd);
792944

0 commit comments

Comments
 (0)