1*f4924aecSJason Xing #include <linux/net_tstamp.h>
2*f4924aecSJason Xing #include <sys/time.h>
3*f4924aecSJason Xing #include <linux/errqueue.h>
4*f4924aecSJason Xing #include "test_progs.h"
5*f4924aecSJason Xing #include "network_helpers.h"
6*f4924aecSJason Xing #include "net_timestamping.skel.h"
7*f4924aecSJason Xing
8*f4924aecSJason Xing #define CG_NAME "/net-timestamping-test"
9*f4924aecSJason Xing #define NSEC_PER_SEC 1000000000LL
10*f4924aecSJason Xing
11*f4924aecSJason Xing static const char addr4_str[] = "127.0.0.1";
12*f4924aecSJason Xing static const char addr6_str[] = "::1";
13*f4924aecSJason Xing static struct net_timestamping *skel;
14*f4924aecSJason Xing static const int cfg_payload_len = 30;
15*f4924aecSJason Xing static struct timespec usr_ts;
16*f4924aecSJason Xing static u64 delay_tolerance_nsec = 10000000000; /* 10 seconds */
17*f4924aecSJason Xing int SK_TS_SCHED;
18*f4924aecSJason Xing int SK_TS_TXSW;
19*f4924aecSJason Xing int SK_TS_ACK;
20*f4924aecSJason Xing
timespec_to_ns64(struct timespec * ts)21*f4924aecSJason Xing static int64_t timespec_to_ns64(struct timespec *ts)
22*f4924aecSJason Xing {
23*f4924aecSJason Xing return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec;
24*f4924aecSJason Xing }
25*f4924aecSJason Xing
validate_key(int tskey,int tstype)26*f4924aecSJason Xing static void validate_key(int tskey, int tstype)
27*f4924aecSJason Xing {
28*f4924aecSJason Xing static int expected_tskey = -1;
29*f4924aecSJason Xing
30*f4924aecSJason Xing if (tstype == SCM_TSTAMP_SCHED)
31*f4924aecSJason Xing expected_tskey = cfg_payload_len - 1;
32*f4924aecSJason Xing
33*f4924aecSJason Xing ASSERT_EQ(expected_tskey, tskey, "tskey mismatch");
34*f4924aecSJason Xing
35*f4924aecSJason Xing expected_tskey = tskey;
36*f4924aecSJason Xing }
37*f4924aecSJason Xing
validate_timestamp(struct timespec * cur,struct timespec * prev)38*f4924aecSJason Xing static void validate_timestamp(struct timespec *cur, struct timespec *prev)
39*f4924aecSJason Xing {
40*f4924aecSJason Xing int64_t cur_ns, prev_ns;
41*f4924aecSJason Xing
42*f4924aecSJason Xing cur_ns = timespec_to_ns64(cur);
43*f4924aecSJason Xing prev_ns = timespec_to_ns64(prev);
44*f4924aecSJason Xing
45*f4924aecSJason Xing ASSERT_LT(cur_ns - prev_ns, delay_tolerance_nsec, "latency");
46*f4924aecSJason Xing }
47*f4924aecSJason Xing
test_socket_timestamp(struct scm_timestamping * tss,int tstype,int tskey)48*f4924aecSJason Xing static void test_socket_timestamp(struct scm_timestamping *tss, int tstype,
49*f4924aecSJason Xing int tskey)
50*f4924aecSJason Xing {
51*f4924aecSJason Xing static struct timespec prev_ts;
52*f4924aecSJason Xing
53*f4924aecSJason Xing validate_key(tskey, tstype);
54*f4924aecSJason Xing
55*f4924aecSJason Xing switch (tstype) {
56*f4924aecSJason Xing case SCM_TSTAMP_SCHED:
57*f4924aecSJason Xing validate_timestamp(&tss->ts[0], &usr_ts);
58*f4924aecSJason Xing SK_TS_SCHED += 1;
59*f4924aecSJason Xing break;
60*f4924aecSJason Xing case SCM_TSTAMP_SND:
61*f4924aecSJason Xing validate_timestamp(&tss->ts[0], &prev_ts);
62*f4924aecSJason Xing SK_TS_TXSW += 1;
63*f4924aecSJason Xing break;
64*f4924aecSJason Xing case SCM_TSTAMP_ACK:
65*f4924aecSJason Xing validate_timestamp(&tss->ts[0], &prev_ts);
66*f4924aecSJason Xing SK_TS_ACK += 1;
67*f4924aecSJason Xing break;
68*f4924aecSJason Xing }
69*f4924aecSJason Xing
70*f4924aecSJason Xing prev_ts = tss->ts[0];
71*f4924aecSJason Xing }
72*f4924aecSJason Xing
test_recv_errmsg_cmsg(struct msghdr * msg)73*f4924aecSJason Xing static void test_recv_errmsg_cmsg(struct msghdr *msg)
74*f4924aecSJason Xing {
75*f4924aecSJason Xing struct sock_extended_err *serr = NULL;
76*f4924aecSJason Xing struct scm_timestamping *tss = NULL;
77*f4924aecSJason Xing struct cmsghdr *cm;
78*f4924aecSJason Xing
79*f4924aecSJason Xing for (cm = CMSG_FIRSTHDR(msg);
80*f4924aecSJason Xing cm && cm->cmsg_len;
81*f4924aecSJason Xing cm = CMSG_NXTHDR(msg, cm)) {
82*f4924aecSJason Xing if (cm->cmsg_level == SOL_SOCKET &&
83*f4924aecSJason Xing cm->cmsg_type == SCM_TIMESTAMPING) {
84*f4924aecSJason Xing tss = (void *)CMSG_DATA(cm);
85*f4924aecSJason Xing } else if ((cm->cmsg_level == SOL_IP &&
86*f4924aecSJason Xing cm->cmsg_type == IP_RECVERR) ||
87*f4924aecSJason Xing (cm->cmsg_level == SOL_IPV6 &&
88*f4924aecSJason Xing cm->cmsg_type == IPV6_RECVERR) ||
89*f4924aecSJason Xing (cm->cmsg_level == SOL_PACKET &&
90*f4924aecSJason Xing cm->cmsg_type == PACKET_TX_TIMESTAMP)) {
91*f4924aecSJason Xing serr = (void *)CMSG_DATA(cm);
92*f4924aecSJason Xing ASSERT_EQ(serr->ee_origin, SO_EE_ORIGIN_TIMESTAMPING,
93*f4924aecSJason Xing "cmsg type");
94*f4924aecSJason Xing }
95*f4924aecSJason Xing
96*f4924aecSJason Xing if (serr && tss)
97*f4924aecSJason Xing test_socket_timestamp(tss, serr->ee_info,
98*f4924aecSJason Xing serr->ee_data);
99*f4924aecSJason Xing }
100*f4924aecSJason Xing }
101*f4924aecSJason Xing
socket_recv_errmsg(int fd)102*f4924aecSJason Xing static bool socket_recv_errmsg(int fd)
103*f4924aecSJason Xing {
104*f4924aecSJason Xing static char ctrl[1024 /* overprovision*/];
105*f4924aecSJason Xing char data[cfg_payload_len];
106*f4924aecSJason Xing static struct msghdr msg;
107*f4924aecSJason Xing struct iovec entry;
108*f4924aecSJason Xing int n = 0;
109*f4924aecSJason Xing
110*f4924aecSJason Xing memset(&msg, 0, sizeof(msg));
111*f4924aecSJason Xing memset(&entry, 0, sizeof(entry));
112*f4924aecSJason Xing memset(ctrl, 0, sizeof(ctrl));
113*f4924aecSJason Xing
114*f4924aecSJason Xing entry.iov_base = data;
115*f4924aecSJason Xing entry.iov_len = cfg_payload_len;
116*f4924aecSJason Xing msg.msg_iov = &entry;
117*f4924aecSJason Xing msg.msg_iovlen = 1;
118*f4924aecSJason Xing msg.msg_name = NULL;
119*f4924aecSJason Xing msg.msg_namelen = 0;
120*f4924aecSJason Xing msg.msg_control = ctrl;
121*f4924aecSJason Xing msg.msg_controllen = sizeof(ctrl);
122*f4924aecSJason Xing
123*f4924aecSJason Xing n = recvmsg(fd, &msg, MSG_ERRQUEUE);
124*f4924aecSJason Xing if (n == -1)
125*f4924aecSJason Xing ASSERT_EQ(errno, EAGAIN, "recvmsg MSG_ERRQUEUE");
126*f4924aecSJason Xing
127*f4924aecSJason Xing if (n >= 0)
128*f4924aecSJason Xing test_recv_errmsg_cmsg(&msg);
129*f4924aecSJason Xing
130*f4924aecSJason Xing return n == -1;
131*f4924aecSJason Xing }
132*f4924aecSJason Xing
test_socket_timestamping(int fd)133*f4924aecSJason Xing static void test_socket_timestamping(int fd)
134*f4924aecSJason Xing {
135*f4924aecSJason Xing while (!socket_recv_errmsg(fd));
136*f4924aecSJason Xing
137*f4924aecSJason Xing ASSERT_EQ(SK_TS_SCHED, 1, "SCM_TSTAMP_SCHED");
138*f4924aecSJason Xing ASSERT_EQ(SK_TS_TXSW, 1, "SCM_TSTAMP_SND");
139*f4924aecSJason Xing ASSERT_EQ(SK_TS_ACK, 1, "SCM_TSTAMP_ACK");
140*f4924aecSJason Xing
141*f4924aecSJason Xing SK_TS_SCHED = 0;
142*f4924aecSJason Xing SK_TS_TXSW = 0;
143*f4924aecSJason Xing SK_TS_ACK = 0;
144*f4924aecSJason Xing }
145*f4924aecSJason Xing
test_tcp(int family,bool enable_socket_timestamping)146*f4924aecSJason Xing static void test_tcp(int family, bool enable_socket_timestamping)
147*f4924aecSJason Xing {
148*f4924aecSJason Xing struct net_timestamping__bss *bss;
149*f4924aecSJason Xing char buf[cfg_payload_len];
150*f4924aecSJason Xing int sfd = -1, cfd = -1;
151*f4924aecSJason Xing unsigned int sock_opt;
152*f4924aecSJason Xing struct netns_obj *ns;
153*f4924aecSJason Xing int cg_fd;
154*f4924aecSJason Xing int ret;
155*f4924aecSJason Xing
156*f4924aecSJason Xing cg_fd = test__join_cgroup(CG_NAME);
157*f4924aecSJason Xing if (!ASSERT_OK_FD(cg_fd, "join cgroup"))
158*f4924aecSJason Xing return;
159*f4924aecSJason Xing
160*f4924aecSJason Xing ns = netns_new("net_timestamping_ns", true);
161*f4924aecSJason Xing if (!ASSERT_OK_PTR(ns, "create ns"))
162*f4924aecSJason Xing goto out;
163*f4924aecSJason Xing
164*f4924aecSJason Xing skel = net_timestamping__open_and_load();
165*f4924aecSJason Xing if (!ASSERT_OK_PTR(skel, "open and load skel"))
166*f4924aecSJason Xing goto out;
167*f4924aecSJason Xing
168*f4924aecSJason Xing if (!ASSERT_OK(net_timestamping__attach(skel), "attach skel"))
169*f4924aecSJason Xing goto out;
170*f4924aecSJason Xing
171*f4924aecSJason Xing skel->links.skops_sockopt =
172*f4924aecSJason Xing bpf_program__attach_cgroup(skel->progs.skops_sockopt, cg_fd);
173*f4924aecSJason Xing if (!ASSERT_OK_PTR(skel->links.skops_sockopt, "attach cgroup"))
174*f4924aecSJason Xing goto out;
175*f4924aecSJason Xing
176*f4924aecSJason Xing bss = skel->bss;
177*f4924aecSJason Xing memset(bss, 0, sizeof(*bss));
178*f4924aecSJason Xing
179*f4924aecSJason Xing skel->bss->monitored_pid = getpid();
180*f4924aecSJason Xing
181*f4924aecSJason Xing sfd = start_server(family, SOCK_STREAM,
182*f4924aecSJason Xing family == AF_INET6 ? addr6_str : addr4_str, 0, 0);
183*f4924aecSJason Xing if (!ASSERT_OK_FD(sfd, "start_server"))
184*f4924aecSJason Xing goto out;
185*f4924aecSJason Xing
186*f4924aecSJason Xing cfd = connect_to_fd(sfd, 0);
187*f4924aecSJason Xing if (!ASSERT_OK_FD(cfd, "connect_to_fd_server"))
188*f4924aecSJason Xing goto out;
189*f4924aecSJason Xing
190*f4924aecSJason Xing if (enable_socket_timestamping) {
191*f4924aecSJason Xing sock_opt = SOF_TIMESTAMPING_SOFTWARE |
192*f4924aecSJason Xing SOF_TIMESTAMPING_OPT_ID |
193*f4924aecSJason Xing SOF_TIMESTAMPING_TX_SCHED |
194*f4924aecSJason Xing SOF_TIMESTAMPING_TX_SOFTWARE |
195*f4924aecSJason Xing SOF_TIMESTAMPING_TX_ACK;
196*f4924aecSJason Xing ret = setsockopt(cfd, SOL_SOCKET, SO_TIMESTAMPING,
197*f4924aecSJason Xing (char *) &sock_opt, sizeof(sock_opt));
198*f4924aecSJason Xing if (!ASSERT_OK(ret, "setsockopt SO_TIMESTAMPING"))
199*f4924aecSJason Xing goto out;
200*f4924aecSJason Xing
201*f4924aecSJason Xing ret = clock_gettime(CLOCK_REALTIME, &usr_ts);
202*f4924aecSJason Xing if (!ASSERT_OK(ret, "get user time"))
203*f4924aecSJason Xing goto out;
204*f4924aecSJason Xing }
205*f4924aecSJason Xing
206*f4924aecSJason Xing ret = write(cfd, buf, sizeof(buf));
207*f4924aecSJason Xing if (!ASSERT_EQ(ret, sizeof(buf), "send to server"))
208*f4924aecSJason Xing goto out;
209*f4924aecSJason Xing
210*f4924aecSJason Xing if (enable_socket_timestamping)
211*f4924aecSJason Xing test_socket_timestamping(cfd);
212*f4924aecSJason Xing
213*f4924aecSJason Xing ASSERT_EQ(bss->nr_active, 1, "nr_active");
214*f4924aecSJason Xing ASSERT_EQ(bss->nr_snd, 2, "nr_snd");
215*f4924aecSJason Xing ASSERT_EQ(bss->nr_sched, 1, "nr_sched");
216*f4924aecSJason Xing ASSERT_EQ(bss->nr_txsw, 1, "nr_txsw");
217*f4924aecSJason Xing ASSERT_EQ(bss->nr_ack, 1, "nr_ack");
218*f4924aecSJason Xing
219*f4924aecSJason Xing out:
220*f4924aecSJason Xing if (sfd >= 0)
221*f4924aecSJason Xing close(sfd);
222*f4924aecSJason Xing if (cfd >= 0)
223*f4924aecSJason Xing close(cfd);
224*f4924aecSJason Xing net_timestamping__destroy(skel);
225*f4924aecSJason Xing netns_free(ns);
226*f4924aecSJason Xing close(cg_fd);
227*f4924aecSJason Xing }
228*f4924aecSJason Xing
test_net_timestamping(void)229*f4924aecSJason Xing void test_net_timestamping(void)
230*f4924aecSJason Xing {
231*f4924aecSJason Xing if (test__start_subtest("INET4: bpf timestamping"))
232*f4924aecSJason Xing test_tcp(AF_INET, false);
233*f4924aecSJason Xing if (test__start_subtest("INET4: bpf and socket timestamping"))
234*f4924aecSJason Xing test_tcp(AF_INET, true);
235*f4924aecSJason Xing if (test__start_subtest("INET6: bpf timestamping"))
236*f4924aecSJason Xing test_tcp(AF_INET6, false);
237*f4924aecSJason Xing if (test__start_subtest("INET6: bpf and socket timestamping"))
238*f4924aecSJason Xing test_tcp(AF_INET6, true);
239*f4924aecSJason Xing }
240