Back to home page

OSCL-LXR

 
 

    


0001 #include <errno.h>
0002 #include <error.h>
0003 #include <getopt.h>
0004 #include <stdbool.h>
0005 #include <stdio.h>
0006 #include <stdlib.h>
0007 #include <string.h>
0008 #include <unistd.h>
0009 
0010 #include <sys/time.h>
0011 #include <sys/socket.h>
0012 #include <sys/select.h>
0013 #include <sys/ioctl.h>
0014 #include <arpa/inet.h>
0015 #include <net/if.h>
0016 
0017 #include <asm/types.h>
0018 #include <linux/net_tstamp.h>
0019 #include <linux/errqueue.h>
0020 
0021 #include "../kselftest.h"
0022 
0023 struct options {
0024     int so_timestamp;
0025     int so_timestampns;
0026     int so_timestamping;
0027 };
0028 
0029 struct tstamps {
0030     bool tstamp;
0031     bool tstampns;
0032     bool swtstamp;
0033     bool hwtstamp;
0034 };
0035 
0036 struct socket_type {
0037     char *friendly_name;
0038     int type;
0039     int protocol;
0040     bool enabled;
0041 };
0042 
0043 struct test_case {
0044     struct options sockopt;
0045     struct tstamps expected;
0046     bool enabled;
0047     bool warn_on_fail;
0048 };
0049 
0050 struct sof_flag {
0051     int mask;
0052     char *name;
0053 };
0054 
0055 static struct sof_flag sof_flags[] = {
0056 #define SOF_FLAG(f) { f, #f }
0057     SOF_FLAG(SOF_TIMESTAMPING_SOFTWARE),
0058     SOF_FLAG(SOF_TIMESTAMPING_RX_SOFTWARE),
0059     SOF_FLAG(SOF_TIMESTAMPING_RX_HARDWARE),
0060 };
0061 
0062 static struct socket_type socket_types[] = {
0063     { "ip",     SOCK_RAW,   IPPROTO_EGP },
0064     { "udp",    SOCK_DGRAM, IPPROTO_UDP },
0065     { "tcp",    SOCK_STREAM,    IPPROTO_TCP },
0066 };
0067 
0068 static struct test_case test_cases[] = {
0069     { {}, {} },
0070     {
0071         { .so_timestamp = 1 },
0072         { .tstamp = true }
0073     },
0074     {
0075         { .so_timestampns = 1 },
0076         { .tstampns = true }
0077     },
0078     {
0079         { .so_timestamp = 1, .so_timestampns = 1 },
0080         { .tstampns = true }
0081     },
0082     {
0083         { .so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE },
0084         {}
0085     },
0086     {
0087         /* Loopback device does not support hw timestamps. */
0088         { .so_timestamping = SOF_TIMESTAMPING_RX_HARDWARE },
0089         {}
0090     },
0091     {
0092         { .so_timestamping = SOF_TIMESTAMPING_SOFTWARE },
0093         .warn_on_fail = true
0094     },
0095     {
0096         { .so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE
0097             | SOF_TIMESTAMPING_RX_HARDWARE },
0098         {}
0099     },
0100     {
0101         { .so_timestamping = SOF_TIMESTAMPING_SOFTWARE
0102             | SOF_TIMESTAMPING_RX_SOFTWARE },
0103         { .swtstamp = true }
0104     },
0105     {
0106         { .so_timestamp = 1, .so_timestamping = SOF_TIMESTAMPING_SOFTWARE
0107             | SOF_TIMESTAMPING_RX_SOFTWARE },
0108         { .tstamp = true, .swtstamp = true }
0109     },
0110 };
0111 
0112 static struct option long_options[] = {
0113     { "list_tests", no_argument, 0, 'l' },
0114     { "test_num", required_argument, 0, 'n' },
0115     { "op_size", required_argument, 0, 's' },
0116     { "tcp", no_argument, 0, 't' },
0117     { "udp", no_argument, 0, 'u' },
0118     { "ip", no_argument, 0, 'i' },
0119     { "strict", no_argument, 0, 'S' },
0120     { "ipv4", no_argument, 0, '4' },
0121     { "ipv6", no_argument, 0, '6' },
0122     { NULL, 0, NULL, 0 },
0123 };
0124 
0125 static int next_port = 19999;
0126 static int op_size = 10 * 1024;
0127 
0128 void print_test_case(struct test_case *t)
0129 {
0130     int f = 0;
0131 
0132     printf("sockopts {");
0133     if (t->sockopt.so_timestamp)
0134         printf(" SO_TIMESTAMP ");
0135     if (t->sockopt.so_timestampns)
0136         printf(" SO_TIMESTAMPNS ");
0137     if (t->sockopt.so_timestamping) {
0138         printf(" SO_TIMESTAMPING: {");
0139         for (f = 0; f < ARRAY_SIZE(sof_flags); f++)
0140             if (t->sockopt.so_timestamping & sof_flags[f].mask)
0141                 printf(" %s |", sof_flags[f].name);
0142         printf("}");
0143     }
0144     printf("} expected cmsgs: {");
0145     if (t->expected.tstamp)
0146         printf(" SCM_TIMESTAMP ");
0147     if (t->expected.tstampns)
0148         printf(" SCM_TIMESTAMPNS ");
0149     if (t->expected.swtstamp || t->expected.hwtstamp) {
0150         printf(" SCM_TIMESTAMPING {");
0151         if (t->expected.swtstamp)
0152             printf("0");
0153         if (t->expected.swtstamp && t->expected.hwtstamp)
0154             printf(",");
0155         if (t->expected.hwtstamp)
0156             printf("2");
0157         printf("}");
0158     }
0159     printf("}\n");
0160 }
0161 
0162 void do_send(int src)
0163 {
0164     int r;
0165     char *buf = malloc(op_size);
0166 
0167     memset(buf, 'z', op_size);
0168     r = write(src, buf, op_size);
0169     if (r < 0)
0170         error(1, errno, "Failed to sendmsg");
0171 
0172     free(buf);
0173 }
0174 
0175 bool do_recv(int rcv, int read_size, struct tstamps expected)
0176 {
0177     const int CMSG_SIZE = 1024;
0178 
0179     struct scm_timestamping *ts;
0180     struct tstamps actual = {};
0181     char cmsg_buf[CMSG_SIZE];
0182     struct iovec recv_iov;
0183     struct cmsghdr *cmsg;
0184     bool failed = false;
0185     struct msghdr hdr;
0186     int flags = 0;
0187     int r;
0188 
0189     memset(&hdr, 0, sizeof(hdr));
0190     hdr.msg_iov = &recv_iov;
0191     hdr.msg_iovlen = 1;
0192     recv_iov.iov_base = malloc(read_size);
0193     recv_iov.iov_len = read_size;
0194 
0195     hdr.msg_control = cmsg_buf;
0196     hdr.msg_controllen = sizeof(cmsg_buf);
0197 
0198     r = recvmsg(rcv, &hdr, flags);
0199     if (r < 0)
0200         error(1, errno, "Failed to recvmsg");
0201     if (r != read_size)
0202         error(1, 0, "Only received %d bytes of payload.", r);
0203 
0204     if (hdr.msg_flags & (MSG_TRUNC | MSG_CTRUNC))
0205         error(1, 0, "Message was truncated.");
0206 
0207     for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL;
0208          cmsg = CMSG_NXTHDR(&hdr, cmsg)) {
0209         if (cmsg->cmsg_level != SOL_SOCKET)
0210             error(1, 0, "Unexpected cmsg_level %d",
0211                   cmsg->cmsg_level);
0212         switch (cmsg->cmsg_type) {
0213         case SCM_TIMESTAMP:
0214             actual.tstamp = true;
0215             break;
0216         case SCM_TIMESTAMPNS:
0217             actual.tstampns = true;
0218             break;
0219         case SCM_TIMESTAMPING:
0220             ts = (struct scm_timestamping *)CMSG_DATA(cmsg);
0221             actual.swtstamp = !!ts->ts[0].tv_sec;
0222             if (ts->ts[1].tv_sec != 0)
0223                 error(0, 0, "ts[1] should not be set.");
0224             actual.hwtstamp = !!ts->ts[2].tv_sec;
0225             break;
0226         default:
0227             error(1, 0, "Unexpected cmsg_type %d", cmsg->cmsg_type);
0228         }
0229     }
0230 
0231 #define VALIDATE(field) \
0232     do { \
0233         if (expected.field != actual.field) { \
0234             if (expected.field) \
0235                 error(0, 0, "Expected " #field " to be set."); \
0236             else \
0237                 error(0, 0, \
0238                       "Expected " #field " to not be set."); \
0239             failed = true; \
0240         } \
0241     } while (0)
0242 
0243     VALIDATE(tstamp);
0244     VALIDATE(tstampns);
0245     VALIDATE(swtstamp);
0246     VALIDATE(hwtstamp);
0247 #undef VALIDATE
0248 
0249     free(recv_iov.iov_base);
0250 
0251     return failed;
0252 }
0253 
0254 void config_so_flags(int rcv, struct options o)
0255 {
0256     int on = 1;
0257 
0258     if (setsockopt(rcv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
0259         error(1, errno, "Failed to enable SO_REUSEADDR");
0260 
0261     if (o.so_timestamp &&
0262         setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMP,
0263                &o.so_timestamp, sizeof(o.so_timestamp)) < 0)
0264         error(1, errno, "Failed to enable SO_TIMESTAMP");
0265 
0266     if (o.so_timestampns &&
0267         setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPNS,
0268                &o.so_timestampns, sizeof(o.so_timestampns)) < 0)
0269         error(1, errno, "Failed to enable SO_TIMESTAMPNS");
0270 
0271     if (o.so_timestamping &&
0272         setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPING,
0273                &o.so_timestamping, sizeof(o.so_timestamping)) < 0)
0274         error(1, errno, "Failed to set SO_TIMESTAMPING");
0275 }
0276 
0277 bool run_test_case(struct socket_type *s, int test_num, char ip_version,
0278            bool strict)
0279 {
0280     union {
0281         struct sockaddr_in6 addr6;
0282         struct sockaddr_in addr4;
0283         struct sockaddr addr_un;
0284     } addr;
0285     int read_size = op_size;
0286     int src, dst, rcv, port;
0287     socklen_t addr_size;
0288     bool failed = false;
0289 
0290     port = (s->type == SOCK_RAW) ? 0 : next_port++;
0291     memset(&addr, 0, sizeof(addr));
0292     if (ip_version == '4') {
0293         addr.addr4.sin_family = AF_INET;
0294         addr.addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
0295         addr.addr4.sin_port = htons(port);
0296         addr_size = sizeof(addr.addr4);
0297         if (s->type == SOCK_RAW)
0298             read_size += 20;  /* for IPv4 header */
0299     } else {
0300         addr.addr6.sin6_family = AF_INET6;
0301         addr.addr6.sin6_addr = in6addr_loopback;
0302         addr.addr6.sin6_port = htons(port);
0303         addr_size = sizeof(addr.addr6);
0304     }
0305     printf("Starting testcase %d over ipv%c...\n", test_num, ip_version);
0306     src = socket(addr.addr_un.sa_family, s->type,
0307              s->protocol);
0308     if (src < 0)
0309         error(1, errno, "Failed to open src socket");
0310 
0311     dst = socket(addr.addr_un.sa_family, s->type,
0312              s->protocol);
0313     if (dst < 0)
0314         error(1, errno, "Failed to open dst socket");
0315 
0316     if (bind(dst, &addr.addr_un, addr_size) < 0)
0317         error(1, errno, "Failed to bind to port %d", port);
0318 
0319     if (s->type == SOCK_STREAM && (listen(dst, 1) < 0))
0320         error(1, errno, "Failed to listen");
0321 
0322     if (connect(src, &addr.addr_un, addr_size) < 0)
0323         error(1, errno, "Failed to connect");
0324 
0325     if (s->type == SOCK_STREAM) {
0326         rcv = accept(dst, NULL, NULL);
0327         if (rcv < 0)
0328             error(1, errno, "Failed to accept");
0329         close(dst);
0330     } else {
0331         rcv = dst;
0332     }
0333 
0334     config_so_flags(rcv, test_cases[test_num].sockopt);
0335     usleep(20000); /* setsockopt for SO_TIMESTAMPING is asynchronous */
0336     do_send(src);
0337 
0338     failed = do_recv(rcv, read_size, test_cases[test_num].expected);
0339 
0340     close(rcv);
0341     close(src);
0342 
0343     if (failed) {
0344         printf("FAILURE in testcase %d over ipv%c ", test_num,
0345                ip_version);
0346         print_test_case(&test_cases[test_num]);
0347         if (!strict && test_cases[test_num].warn_on_fail)
0348             failed = false;
0349     }
0350     return failed;
0351 }
0352 
0353 int main(int argc, char **argv)
0354 {
0355     bool all_protocols = true;
0356     bool all_tests = true;
0357     bool cfg_ipv4 = false;
0358     bool cfg_ipv6 = false;
0359     bool strict = false;
0360     int arg_index = 0;
0361     int failures = 0;
0362     int s, t, opt;
0363 
0364     while ((opt = getopt_long(argc, argv, "", long_options,
0365                   &arg_index)) != -1) {
0366         switch (opt) {
0367         case 'l':
0368             for (t = 0; t < ARRAY_SIZE(test_cases); t++) {
0369                 printf("%d\t", t);
0370                 print_test_case(&test_cases[t]);
0371             }
0372             return 0;
0373         case 'n':
0374             t = atoi(optarg);
0375             if (t >= ARRAY_SIZE(test_cases))
0376                 error(1, 0, "Invalid test case: %d", t);
0377             all_tests = false;
0378             test_cases[t].enabled = true;
0379             break;
0380         case 's':
0381             op_size = atoi(optarg);
0382             break;
0383         case 't':
0384             all_protocols = false;
0385             socket_types[2].enabled = true;
0386             break;
0387         case 'u':
0388             all_protocols = false;
0389             socket_types[1].enabled = true;
0390             break;
0391         case 'i':
0392             all_protocols = false;
0393             socket_types[0].enabled = true;
0394             break;
0395         case 'S':
0396             strict = true;
0397             break;
0398         case '4':
0399             cfg_ipv4 = true;
0400             break;
0401         case '6':
0402             cfg_ipv6 = true;
0403             break;
0404         default:
0405             error(1, 0, "Failed to parse parameters.");
0406         }
0407     }
0408 
0409     for (s = 0; s < ARRAY_SIZE(socket_types); s++) {
0410         if (!all_protocols && !socket_types[s].enabled)
0411             continue;
0412 
0413         printf("Testing %s...\n", socket_types[s].friendly_name);
0414         for (t = 0; t < ARRAY_SIZE(test_cases); t++) {
0415             if (!all_tests && !test_cases[t].enabled)
0416                 continue;
0417             if (cfg_ipv4 || !cfg_ipv6)
0418                 if (run_test_case(&socket_types[s], t, '4',
0419                           strict))
0420                     failures++;
0421             if (cfg_ipv6 || !cfg_ipv4)
0422                 if (run_test_case(&socket_types[s], t, '6',
0423                           strict))
0424                     failures++;
0425         }
0426     }
0427     if (!failures)
0428         printf("PASSED.\n");
0429     return failures;
0430 }