diff options
Diffstat (limited to '')
-rw-r--r-- | tools/testing/selftests/net/hwtstamp_config.c (renamed from tools/testing/selftests/networking/timestamping/hwtstamp_config.c) | 0 | ||||
-rw-r--r-- | tools/testing/selftests/net/timestamping.c (renamed from tools/testing/selftests/networking/timestamping/timestamping.c) | 112 | ||||
-rw-r--r-- | tools/testing/selftests/net/txtimestamp.c (renamed from tools/testing/selftests/networking/timestamping/txtimestamp.c) | 193 | ||||
-rw-r--r-- | tools/testing/selftests/networking/timestamping/.gitignore | 4 | ||||
-rw-r--r-- | tools/testing/selftests/networking/timestamping/Makefile | 11 | ||||
-rw-r--r-- | tools/testing/selftests/networking/timestamping/config | 2 | ||||
-rw-r--r-- | tools/testing/selftests/networking/timestamping/rxtimestamp.c | 390 | ||||
-rwxr-xr-x | tools/testing/selftests/networking/timestamping/txtimestamp.sh | 57 |
8 files changed, 246 insertions, 523 deletions
diff --git a/tools/testing/selftests/networking/timestamping/hwtstamp_config.c b/tools/testing/selftests/net/hwtstamp_config.c index e1fdee841021..e1fdee841021 100644 --- a/tools/testing/selftests/networking/timestamping/hwtstamp_config.c +++ b/tools/testing/selftests/net/hwtstamp_config.c diff --git a/tools/testing/selftests/networking/timestamping/timestamping.c b/tools/testing/selftests/net/timestamping.c index aca3491174a1..044bc0e9ed81 100644 --- a/tools/testing/selftests/networking/timestamping/timestamping.c +++ b/tools/testing/selftests/net/timestamping.c @@ -47,7 +47,7 @@ static void usage(const char *error) { if (error) printf("invalid option: %s\n", error); - printf("timestamping interface option*\n\n" + printf("timestamping <interface> [bind_phc_index] [option]*\n\n" "Options:\n" " IP_MULTICAST_LOOP - looping outgoing multicasts\n" " SO_TIMESTAMP - normal software time stamping, ms resolution\n" @@ -58,8 +58,10 @@ static void usage(const char *error) " SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n" " SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n" " SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n" + " SOF_TIMESTAMPING_BIND_PHC - request to bind a PHC of PTP vclock\n" " SIOCGSTAMP - check last socket time stamp\n" - " SIOCGSTAMPNS - more accurate socket time stamp\n"); + " SIOCGSTAMPNS - more accurate socket time stamp\n" + " PTPV2 - use PTPv2 messages\n"); exit(1); } @@ -115,13 +117,28 @@ static const unsigned char sync[] = { 0x00, 0x00, 0x00, 0x00 }; -static void sendpacket(int sock, struct sockaddr *addr, socklen_t addr_len) +static const unsigned char sync_v2[] = { + 0x00, 0x02, 0x00, 0x2C, + 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, + 0xFE, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, +}; + +static void sendpacket(int sock, struct sockaddr *addr, socklen_t addr_len, int ptpv2) { + size_t sync_len = ptpv2 ? sizeof(sync_v2) : sizeof(sync); + const void *sync_p = ptpv2 ? sync_v2 : sync; struct timeval now; int res; - res = sendto(sock, sync, sizeof(sync), 0, - addr, addr_len); + res = sendto(sock, sync_p, sync_len, 0, addr, addr_len); gettimeofday(&now, 0); if (res < 0) printf("%s: %s\n", "send", strerror(errno)); @@ -134,9 +151,11 @@ static void sendpacket(int sock, struct sockaddr *addr, socklen_t addr_len) static void printpacket(struct msghdr *msg, int res, char *data, int sock, int recvmsg_flags, - int siocgstamp, int siocgstampns) + int siocgstamp, int siocgstampns, int ptpv2) { struct sockaddr_in *from_addr = (struct sockaddr_in *)msg->msg_name; + size_t sync_len = ptpv2 ? sizeof(sync_v2) : sizeof(sync); + const void *sync_p = ptpv2 ? sync_v2 : sync; struct cmsghdr *cmsg; struct timeval tv; struct timespec ts; @@ -210,10 +229,9 @@ static void printpacket(struct msghdr *msg, int res, "probably SO_EE_ORIGIN_TIMESTAMPING" #endif ); - if (res < sizeof(sync)) + if (res < sync_len) printf(" => truncated data?!"); - else if (!memcmp(sync, data + res - sizeof(sync), - sizeof(sync))) + else if (!memcmp(sync_p, data + res - sync_len, sync_len)) printf(" => GOT OUR DATA BACK (HURRAY!)"); break; } @@ -257,7 +275,7 @@ static void printpacket(struct msghdr *msg, int res, } static void recvpacket(int sock, int recvmsg_flags, - int siocgstamp, int siocgstampns) + int siocgstamp, int siocgstampns, int ptpv2) { char data[256]; struct msghdr msg; @@ -288,18 +306,18 @@ static void recvpacket(int sock, int recvmsg_flags, } else { printpacket(&msg, res, data, sock, recvmsg_flags, - siocgstamp, siocgstampns); + siocgstamp, siocgstampns, ptpv2); } } int main(int argc, char **argv) { - int so_timestamping_flags = 0; int so_timestamp = 0; int so_timestampns = 0; int siocgstamp = 0; int siocgstampns = 0; int ip_multicast_loop = 0; + int ptpv2 = 0; char *interface; int i; int enabled = 1; @@ -307,18 +325,31 @@ int main(int argc, char **argv) struct ifreq device; struct ifreq hwtstamp; struct hwtstamp_config hwconfig, hwconfig_requested; + struct so_timestamping so_timestamping_get = { 0, 0 }; + struct so_timestamping so_timestamping = { 0, 0 }; struct sockaddr_in addr; struct ip_mreq imr; struct in_addr iaddr; int val; socklen_t len; struct timeval next; + size_t if_len; if (argc < 2) usage(0); interface = argv[1]; + if_len = strlen(interface); + if (if_len >= IFNAMSIZ) { + printf("interface name exceeds IFNAMSIZ\n"); + exit(1); + } - for (i = 2; i < argc; i++) { + if (argc >= 3 && sscanf(argv[2], "%d", &so_timestamping.bind_phc) == 1) + val = 3; + else + val = 2; + + for (i = val; i < argc; i++) { if (!strcasecmp(argv[i], "SO_TIMESTAMP")) so_timestamp = 1; else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS")) @@ -329,18 +360,22 @@ int main(int argc, char **argv) siocgstampns = 1; else if (!strcasecmp(argv[i], "IP_MULTICAST_LOOP")) ip_multicast_loop = 1; + else if (!strcasecmp(argv[i], "PTPV2")) + ptpv2 = 1; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_HARDWARE")) - so_timestamping_flags |= SOF_TIMESTAMPING_TX_HARDWARE; + so_timestamping.flags |= SOF_TIMESTAMPING_TX_HARDWARE; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_SOFTWARE")) - so_timestamping_flags |= SOF_TIMESTAMPING_TX_SOFTWARE; + so_timestamping.flags |= SOF_TIMESTAMPING_TX_SOFTWARE; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_HARDWARE")) - so_timestamping_flags |= SOF_TIMESTAMPING_RX_HARDWARE; + so_timestamping.flags |= SOF_TIMESTAMPING_RX_HARDWARE; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_SOFTWARE")) - so_timestamping_flags |= SOF_TIMESTAMPING_RX_SOFTWARE; + so_timestamping.flags |= SOF_TIMESTAMPING_RX_SOFTWARE; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE")) - so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE; + so_timestamping.flags |= SOF_TIMESTAMPING_SOFTWARE; else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RAW_HARDWARE")) - so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE; + so_timestamping.flags |= SOF_TIMESTAMPING_RAW_HARDWARE; + else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_BIND_PHC")) + so_timestamping.flags |= SOF_TIMESTAMPING_BIND_PHC; else usage(argv[i]); } @@ -350,19 +385,20 @@ int main(int argc, char **argv) bail("socket"); memset(&device, 0, sizeof(device)); - strncpy(device.ifr_name, interface, sizeof(device.ifr_name)); + memcpy(device.ifr_name, interface, if_len + 1); if (ioctl(sock, SIOCGIFADDR, &device) < 0) bail("getting interface IP address"); memset(&hwtstamp, 0, sizeof(hwtstamp)); - strncpy(hwtstamp.ifr_name, interface, sizeof(hwtstamp.ifr_name)); + memcpy(hwtstamp.ifr_name, interface, if_len + 1); hwtstamp.ifr_data = (void *)&hwconfig; memset(&hwconfig, 0, sizeof(hwconfig)); hwconfig.tx_type = - (so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ? + (so_timestamping.flags & SOF_TIMESTAMPING_TX_HARDWARE) ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; hwconfig.rx_filter = - (so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ? + (so_timestamping.flags & SOF_TIMESTAMPING_RX_HARDWARE) ? + ptpv2 ? HWTSTAMP_FILTER_PTP_V2_L4_SYNC : HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE; hwconfig_requested = hwconfig; if (ioctl(sock, SIOCSHWTSTAMP, &hwtstamp) < 0) { @@ -386,6 +422,9 @@ int main(int argc, char **argv) sizeof(struct sockaddr_in)) < 0) bail("bind"); + if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, if_len)) + bail("bind device"); + /* set multicast group for outgoing packets */ inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */ addr.sin_addr = iaddr; @@ -417,10 +456,9 @@ int main(int argc, char **argv) &enabled, sizeof(enabled)) < 0) bail("setsockopt SO_TIMESTAMPNS"); - if (so_timestamping_flags && - setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, - &so_timestamping_flags, - sizeof(so_timestamping_flags)) < 0) + if (so_timestamping.flags && + setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &so_timestamping, + sizeof(so_timestamping)) < 0) bail("setsockopt SO_TIMESTAMPING"); /* request IP_PKTINFO for debugging purposes */ @@ -441,14 +479,18 @@ int main(int argc, char **argv) else printf("SO_TIMESTAMPNS %d\n", val); - if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &val, &len) < 0) { + len = sizeof(so_timestamping_get); + if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &so_timestamping_get, + &len) < 0) { printf("%s: %s\n", "getsockopt SO_TIMESTAMPING", strerror(errno)); } else { - printf("SO_TIMESTAMPING %d\n", val); - if (val != so_timestamping_flags) - printf(" not the expected value %d\n", - so_timestamping_flags); + printf("SO_TIMESTAMPING flags %d, bind phc %d\n", + so_timestamping_get.flags, so_timestamping_get.bind_phc); + if (so_timestamping_get.flags != so_timestamping.flags || + so_timestamping_get.bind_phc != so_timestamping.bind_phc) + printf(" not expected, flags %d, bind phc %d\n", + so_timestamping.flags, so_timestamping.bind_phc); } /* send packets forever every five seconds */ @@ -490,16 +532,16 @@ int main(int argc, char **argv) printf("has error\n"); recvpacket(sock, 0, siocgstamp, - siocgstampns); + siocgstampns, ptpv2); recvpacket(sock, MSG_ERRQUEUE, siocgstamp, - siocgstampns); + siocgstampns, ptpv2); } } else { /* write one packet */ sendpacket(sock, (struct sockaddr *)&addr, - sizeof(addr)); + sizeof(addr), ptpv2); next.tv_sec += 5; continue; } diff --git a/tools/testing/selftests/networking/timestamping/txtimestamp.c b/tools/testing/selftests/net/txtimestamp.c index 7e386be47120..10f2fde3686b 100644 --- a/tools/testing/selftests/networking/timestamping/txtimestamp.c +++ b/tools/testing/selftests/net/txtimestamp.c @@ -26,6 +26,7 @@ #include <inttypes.h> #include <linux/errqueue.h> #include <linux/if_ether.h> +#include <linux/if_packet.h> #include <linux/ipv6.h> #include <linux/net_tstamp.h> #include <netdb.h> @@ -34,13 +35,13 @@ #include <netinet/ip.h> #include <netinet/udp.h> #include <netinet/tcp.h> -#include <netpacket/packet.h> #include <poll.h> #include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/epoll.h> #include <sys/ioctl.h> #include <sys/select.h> #include <sys/socket.h> @@ -49,6 +50,10 @@ #include <time.h> #include <unistd.h> +#define NSEC_PER_USEC 1000L +#define USEC_PER_SEC 1000000L +#define NSEC_PER_SEC 1000000000LL + /* command line parameters */ static int cfg_proto = SOCK_STREAM; static int cfg_ipproto = IPPROTO_TCP; @@ -59,14 +64,19 @@ static int cfg_payload_len = 10; static int cfg_poll_timeout = 100; static int cfg_delay_snd; static int cfg_delay_ack; +static int cfg_delay_tolerance_usec = 500; static bool cfg_show_payload; static bool cfg_do_pktinfo; +static bool cfg_busy_poll; +static int cfg_sleep_usec = 50 * 1000; static bool cfg_loop_nodata; -static bool cfg_no_delay; static bool cfg_use_cmsg; static bool cfg_use_pf_packet; +static bool cfg_use_epoll; +static bool cfg_epollet; static bool cfg_do_listen; static uint16_t dest_port = 9000; +static bool cfg_print_nsec; static struct sockaddr_in daddr; static struct sockaddr_in6 daddr6; @@ -75,11 +85,48 @@ static struct timespec ts_usr; static int saved_tskey = -1; static int saved_tskey_type = -1; +struct timing_event { + int64_t min; + int64_t max; + int64_t total; + int count; +}; + +static struct timing_event usr_enq; +static struct timing_event usr_snd; +static struct timing_event usr_ack; + static bool test_failed; +static int64_t timespec_to_ns64(struct timespec *ts) +{ + return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec; +} + static int64_t timespec_to_us64(struct timespec *ts) { - return ts->tv_sec * 1000 * 1000 + ts->tv_nsec / 1000; + return ts->tv_sec * USEC_PER_SEC + ts->tv_nsec / NSEC_PER_USEC; +} + +static void init_timing_event(struct timing_event *te) +{ + te->min = INT64_MAX; + te->max = 0; + te->total = 0; + te->count = 0; +} + +static void add_timing_event(struct timing_event *te, + struct timespec *t_start, struct timespec *t_end) +{ + int64_t ts_delta = timespec_to_ns64(t_end) - timespec_to_ns64(t_start); + + te->count++; + if (ts_delta < te->min) + te->min = ts_delta; + if (ts_delta > te->max) + te->max = ts_delta; + te->total += ts_delta; } static void validate_key(int tskey, int tstype) @@ -106,32 +153,51 @@ static void validate_key(int tskey, int tstype) static void validate_timestamp(struct timespec *cur, int min_delay) { - int max_delay = min_delay + 500 /* processing time upper bound */; int64_t cur64, start64; + int max_delay; cur64 = timespec_to_us64(cur); start64 = timespec_to_us64(&ts_usr); + max_delay = min_delay + cfg_delay_tolerance_usec; if (cur64 < start64 + min_delay || cur64 > start64 + max_delay) { - fprintf(stderr, "ERROR: delay %lu expected between %d and %d\n", + fprintf(stderr, "ERROR: %" PRId64 " us expected between %d and %d\n", cur64 - start64, min_delay, max_delay); test_failed = true; } } +static void __print_ts_delta_formatted(int64_t ts_delta) +{ + if (cfg_print_nsec) + fprintf(stderr, "%" PRId64 " ns", ts_delta); + else + fprintf(stderr, "%" PRId64 " us", ts_delta / NSEC_PER_USEC); +} + static void __print_timestamp(const char *name, struct timespec *cur, uint32_t key, int payload_len) { + int64_t ts_delta; + if (!(cur->tv_sec | cur->tv_nsec)) return; - fprintf(stderr, " %s: %lu s %lu us (seq=%u, len=%u)", - name, cur->tv_sec, cur->tv_nsec / 1000, - key, payload_len); - - if (cur != &ts_usr) - fprintf(stderr, " (USR %+" PRId64 " us)", - timespec_to_us64(cur) - timespec_to_us64(&ts_usr)); + if (cfg_print_nsec) + fprintf(stderr, " %s: %lu s %lu ns (seq=%u, len=%u)", + name, cur->tv_sec, cur->tv_nsec, + key, payload_len); + else + fprintf(stderr, " %s: %lu s %lu us (seq=%u, len=%u)", + name, cur->tv_sec, cur->tv_nsec / NSEC_PER_USEC, + key, payload_len); + + if (cur != &ts_usr) { + ts_delta = timespec_to_ns64(cur) - timespec_to_ns64(&ts_usr); + fprintf(stderr, " (USR +"); + __print_ts_delta_formatted(ts_delta); + fprintf(stderr, ")"); + } fprintf(stderr, "\n"); } @@ -155,14 +221,17 @@ static void print_timestamp(struct scm_timestamping *tss, int tstype, case SCM_TSTAMP_SCHED: tsname = " ENQ"; validate_timestamp(&tss->ts[0], 0); + add_timing_event(&usr_enq, &ts_usr, &tss->ts[0]); break; case SCM_TSTAMP_SND: tsname = " SND"; validate_timestamp(&tss->ts[0], cfg_delay_snd); + add_timing_event(&usr_snd, &ts_usr, &tss->ts[0]); break; case SCM_TSTAMP_ACK: tsname = " ACK"; validate_timestamp(&tss->ts[0], cfg_delay_ack); + add_timing_event(&usr_ack, &ts_usr, &tss->ts[0]); break; default: error(1, 0, "unknown timestamp type: %u", @@ -171,6 +240,21 @@ static void print_timestamp(struct scm_timestamping *tss, int tstype, __print_timestamp(tsname, &tss->ts[0], tskey, payload_len); } +static void print_timing_event(char *name, struct timing_event *te) +{ + if (!te->count) + return; + + fprintf(stderr, " %s: count=%d", name, te->count); + fprintf(stderr, ", avg="); + __print_ts_delta_formatted((int64_t)(te->total / te->count)); + fprintf(stderr, ", min="); + __print_ts_delta_formatted(te->min); + fprintf(stderr, ", max="); + __print_ts_delta_formatted(te->max); + fprintf(stderr, "\n"); +} + /* TODO: convert to check_and_print payload once API is stable */ static void print_payload(char *data, int len) { @@ -198,6 +282,17 @@ static void print_pktinfo(int family, int ifindex, void *saddr, void *daddr) daddr ? inet_ntop(family, daddr, da, sizeof(da)) : "unknown"); } +static void __epoll(int epfd) +{ + struct epoll_event events; + int ret; + + memset(&events, 0, sizeof(events)); + ret = epoll_wait(epfd, &events, 1, cfg_poll_timeout); + if (ret != 1) + error(1, errno, "epoll_wait"); +} + static void __poll(int fd) { struct pollfd pollfd; @@ -391,17 +486,21 @@ static void do_test(int family, unsigned int report_opt) struct msghdr msg; struct iovec iov; char *buf; - int fd, i, val = 1, total_len; + int fd, i, val = 1, total_len, epfd = 0; + + init_timing_event(&usr_enq); + init_timing_event(&usr_snd); + init_timing_event(&usr_ack); total_len = cfg_payload_len; if (cfg_use_pf_packet || cfg_proto == SOCK_RAW) { total_len += sizeof(struct udphdr); - if (cfg_use_pf_packet || cfg_ipproto == IPPROTO_RAW) + if (cfg_use_pf_packet || cfg_ipproto == IPPROTO_RAW) { if (family == PF_INET) total_len += sizeof(struct iphdr); else total_len += sizeof(struct ipv6hdr); - + } /* special case, only rawv6_sendmsg: * pass proto in sin6_port if not connected * also see ANK comment in net/ipv4/raw.c @@ -418,6 +517,20 @@ static void do_test(int family, unsigned int report_opt) if (fd < 0) error(1, errno, "socket"); + if (cfg_use_epoll) { + struct epoll_event ev; + + memset(&ev, 0, sizeof(ev)); + ev.data.fd = fd; + if (cfg_epollet) + ev.events |= EPOLLET; + epfd = epoll_create(1); + if (epfd <= 0) + error(1, errno, "epoll_create"); + if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev)) + error(1, errno, "epoll_ctl"); + } + /* reset expected key on each new socket */ saved_tskey = -1; @@ -525,19 +638,28 @@ static void do_test(int family, unsigned int report_opt) error(1, errno, "send"); /* wait for all errors to be queued, else ACKs arrive OOO */ - if (!cfg_no_delay) - usleep(50 * 1000); + if (cfg_sleep_usec) + usleep(cfg_sleep_usec); - __poll(fd); + if (!cfg_busy_poll) { + if (cfg_use_epoll) + __epoll(epfd); + else + __poll(fd); + } while (!recv_errmsg(fd)) {} } + print_timing_event("USR-ENQ", &usr_enq); + print_timing_event("USR-SND", &usr_snd); + print_timing_event("USR-ACK", &usr_ack); + if (close(fd)) error(1, errno, "close"); free(buf); - usleep(100 * 1000); + usleep(100 * NSEC_PER_USEC); } static void __attribute__((noreturn)) usage(const char *filepath) @@ -547,18 +669,23 @@ static void __attribute__((noreturn)) usage(const char *filepath) " -4: only IPv4\n" " -6: only IPv6\n" " -h: show this message\n" + " -b: busy poll to read from error queue\n" " -c N: number of packets for each test\n" " -C: use cmsg to set tstamp recording options\n" - " -D: no delay between packets\n" - " -F: poll() waits forever for an event\n" + " -e: use level-triggered epoll() instead of poll()\n" + " -E: use event-triggered epoll() instead of poll()\n" + " -F: poll()/epoll() waits forever for an event\n" " -I: request PKTINFO\n" " -l N: send N bytes at a time\n" " -L listen on hostname and port\n" " -n: set no-payload option\n" + " -N: print timestamps and durations in nsec (instead of usec)\n" " -p N: connect to port N\n" " -P: use PF_PACKET\n" " -r: use raw\n" " -R: use raw (IP_HDRINCL)\n" + " -S N: usec to sleep before reading error queue\n" + " -t N: tolerance (usec) for timestamp validation\n" " -u: use udp\n" " -v: validate SND delay (usec)\n" " -V: validate ACK delay (usec)\n" @@ -572,7 +699,8 @@ static void parse_opt(int argc, char **argv) int proto_count = 0; int c; - while ((c = getopt(argc, argv, "46c:CDFhIl:Lnp:PrRuv:V:x")) != -1) { + while ((c = getopt(argc, argv, + "46bc:CeEFhIl:LnNp:PrRS:t:uv:V:x")) != -1) { switch (c) { case '4': do_ipv6 = 0; @@ -580,15 +708,21 @@ static void parse_opt(int argc, char **argv) case '6': do_ipv4 = 0; break; + case 'b': + cfg_busy_poll = true; + break; case 'c': cfg_num_pkts = strtoul(optarg, NULL, 10); break; case 'C': cfg_use_cmsg = true; break; - case 'D': - cfg_no_delay = true; + case 'e': + cfg_use_epoll = true; break; + case 'E': + cfg_use_epoll = true; + cfg_epollet = true; case 'F': cfg_poll_timeout = -1; break; @@ -604,6 +738,9 @@ static void parse_opt(int argc, char **argv) case 'n': cfg_loop_nodata = true; break; + case 'N': + cfg_print_nsec = true; + break; case 'p': dest_port = strtoul(optarg, NULL, 10); break; @@ -623,6 +760,12 @@ static void parse_opt(int argc, char **argv) cfg_proto = SOCK_RAW; cfg_ipproto = IPPROTO_RAW; break; + case 'S': + cfg_sleep_usec = strtoul(optarg, NULL, 10); + break; + case 't': + cfg_delay_tolerance_usec = strtoul(optarg, NULL, 10); + break; case 'u': proto_count++; cfg_proto = SOCK_DGRAM; @@ -653,6 +796,8 @@ static void parse_opt(int argc, char **argv) error(1, 0, "pass -P, -r, -R or -u, not multiple"); if (cfg_do_pktinfo && cfg_use_pf_packet) error(1, 0, "cannot ask for pktinfo over pf_packet"); + if (cfg_busy_poll && cfg_use_epoll) + error(1, 0, "pass epoll or busy_poll, not both"); if (optind != argc - 1) error(1, 0, "missing required hostname argument"); diff --git a/tools/testing/selftests/networking/timestamping/.gitignore b/tools/testing/selftests/networking/timestamping/.gitignore deleted file mode 100644 index d9355035e746..000000000000 --- a/tools/testing/selftests/networking/timestamping/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -timestamping -rxtimestamp -txtimestamp -hwtstamp_config diff --git a/tools/testing/selftests/networking/timestamping/Makefile b/tools/testing/selftests/networking/timestamping/Makefile deleted file mode 100644 index 1de8bd8ccf5d..000000000000 --- a/tools/testing/selftests/networking/timestamping/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -CFLAGS += -I../../../../../usr/include - -TEST_GEN_FILES := hwtstamp_config rxtimestamp timestamping txtimestamp -TEST_PROGS := txtimestamp.sh - -all: $(TEST_PROGS) - -top_srcdir = ../../../../.. -KSFT_KHDR_INSTALL := 1 -include ../../lib.mk diff --git a/tools/testing/selftests/networking/timestamping/config b/tools/testing/selftests/networking/timestamping/config deleted file mode 100644 index a13e3169b0a4..000000000000 --- a/tools/testing/selftests/networking/timestamping/config +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_IFB=y -CONFIG_NET_SCH_NETEM=y diff --git a/tools/testing/selftests/networking/timestamping/rxtimestamp.c b/tools/testing/selftests/networking/timestamping/rxtimestamp.c deleted file mode 100644 index 6dee9e636a95..000000000000 --- a/tools/testing/selftests/networking/timestamping/rxtimestamp.c +++ /dev/null @@ -1,390 +0,0 @@ -#include <errno.h> -#include <error.h> -#include <getopt.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <sys/time.h> -#include <sys/socket.h> -#include <sys/select.h> -#include <sys/ioctl.h> -#include <arpa/inet.h> -#include <net/if.h> - -#include <asm/types.h> -#include <linux/net_tstamp.h> -#include <linux/errqueue.h> - -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - -struct options { - int so_timestamp; - int so_timestampns; - int so_timestamping; -}; - -struct tstamps { - bool tstamp; - bool tstampns; - bool swtstamp; - bool hwtstamp; -}; - -struct socket_type { - char *friendly_name; - int type; - int protocol; - bool enabled; -}; - -struct test_case { - struct options sockopt; - struct tstamps expected; - bool enabled; -}; - -struct sof_flag { - int mask; - char *name; -}; - -static struct sof_flag sof_flags[] = { -#define SOF_FLAG(f) { f, #f } - SOF_FLAG(SOF_TIMESTAMPING_SOFTWARE), - SOF_FLAG(SOF_TIMESTAMPING_RX_SOFTWARE), - SOF_FLAG(SOF_TIMESTAMPING_RX_HARDWARE), -}; - -static struct socket_type socket_types[] = { - { "ip", SOCK_RAW, IPPROTO_EGP }, - { "udp", SOCK_DGRAM, IPPROTO_UDP }, - { "tcp", SOCK_STREAM, IPPROTO_TCP }, -}; - -static struct test_case test_cases[] = { - { {}, {} }, - { - { so_timestamp: 1 }, - { tstamp: true } - }, - { - { so_timestampns: 1 }, - { tstampns: true } - }, - { - { so_timestamp: 1, so_timestampns: 1 }, - { tstampns: true } - }, - { - { so_timestamping: SOF_TIMESTAMPING_RX_SOFTWARE }, - {} - }, - { - /* Loopback device does not support hw timestamps. */ - { so_timestamping: SOF_TIMESTAMPING_RX_HARDWARE }, - {} - }, - { - { so_timestamping: SOF_TIMESTAMPING_SOFTWARE }, - {} - }, - { - { so_timestamping: SOF_TIMESTAMPING_RX_SOFTWARE - | SOF_TIMESTAMPING_RX_HARDWARE }, - {} - }, - { - { so_timestamping: SOF_TIMESTAMPING_SOFTWARE - | SOF_TIMESTAMPING_RX_SOFTWARE }, - { swtstamp: true } - }, - { - { so_timestamp: 1, so_timestamping: SOF_TIMESTAMPING_SOFTWARE - | SOF_TIMESTAMPING_RX_SOFTWARE }, - { tstamp: true, swtstamp: true } - }, -}; - -static struct option long_options[] = { - { "list_tests", no_argument, 0, 'l' }, - { "test_num", required_argument, 0, 'n' }, - { "op_size", required_argument, 0, 's' }, - { "tcp", no_argument, 0, 't' }, - { "udp", no_argument, 0, 'u' }, - { "ip", no_argument, 0, 'i' }, -}; - -static int next_port = 19999; -static int op_size = 10 * 1024; - -void print_test_case(struct test_case *t) -{ - int f = 0; - - printf("sockopts {"); - if (t->sockopt.so_timestamp) - printf(" SO_TIMESTAMP "); - if (t->sockopt.so_timestampns) - printf(" SO_TIMESTAMPNS "); - if (t->sockopt.so_timestamping) { - printf(" SO_TIMESTAMPING: {"); - for (f = 0; f < ARRAY_SIZE(sof_flags); f++) - if (t->sockopt.so_timestamping & sof_flags[f].mask) - printf(" %s |", sof_flags[f].name); - printf("}"); - } - printf("} expected cmsgs: {"); - if (t->expected.tstamp) - printf(" SCM_TIMESTAMP "); - if (t->expected.tstampns) - printf(" SCM_TIMESTAMPNS "); - if (t->expected.swtstamp || t->expected.hwtstamp) { - printf(" SCM_TIMESTAMPING {"); - if (t->expected.swtstamp) - printf("0"); - if (t->expected.swtstamp && t->expected.hwtstamp) - printf(","); - if (t->expected.hwtstamp) - printf("2"); - printf("}"); - } - printf("}\n"); -} - -void do_send(int src) -{ - int r; - char *buf = malloc(op_size); - - memset(buf, 'z', op_size); - r = write(src, buf, op_size); - if (r < 0) - error(1, errno, "Failed to sendmsg"); - - free(buf); -} - -bool do_recv(int rcv, int read_size, struct tstamps expected) -{ - const int CMSG_SIZE = 1024; - - struct scm_timestamping *ts; - struct tstamps actual = {}; - char cmsg_buf[CMSG_SIZE]; - struct iovec recv_iov; - struct cmsghdr *cmsg; - bool failed = false; - struct msghdr hdr; - int flags = 0; - int r; - - memset(&hdr, 0, sizeof(hdr)); - hdr.msg_iov = &recv_iov; - hdr.msg_iovlen = 1; - recv_iov.iov_base = malloc(read_size); - recv_iov.iov_len = read_size; - - hdr.msg_control = cmsg_buf; - hdr.msg_controllen = sizeof(cmsg_buf); - - r = recvmsg(rcv, &hdr, flags); - if (r < 0) - error(1, errno, "Failed to recvmsg"); - if (r != read_size) - error(1, 0, "Only received %d bytes of payload.", r); - - if (hdr.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) - error(1, 0, "Message was truncated."); - - for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL; - cmsg = CMSG_NXTHDR(&hdr, cmsg)) { - if (cmsg->cmsg_level != SOL_SOCKET) - error(1, 0, "Unexpected cmsg_level %d", - cmsg->cmsg_level); - switch (cmsg->cmsg_type) { - case SCM_TIMESTAMP: - actual.tstamp = true; - break; - case SCM_TIMESTAMPNS: - actual.tstampns = true; - break; - case SCM_TIMESTAMPING: - ts = (struct scm_timestamping *)CMSG_DATA(cmsg); - actual.swtstamp = !!ts->ts[0].tv_sec; - if (ts->ts[1].tv_sec != 0) - error(0, 0, "ts[1] should not be set."); - actual.hwtstamp = !!ts->ts[2].tv_sec; - break; - default: - error(1, 0, "Unexpected cmsg_type %d", cmsg->cmsg_type); - } - } - -#define VALIDATE(field) \ - do { \ - if (expected.field != actual.field) { \ - if (expected.field) \ - error(0, 0, "Expected " #field " to be set."); \ - else \ - error(0, 0, \ - "Expected " #field " to not be set."); \ - failed = true; \ - } \ - } while (0) - - VALIDATE(tstamp); - VALIDATE(tstampns); - VALIDATE(swtstamp); - VALIDATE(hwtstamp); -#undef VALIDATE - - free(recv_iov.iov_base); - - return failed; -} - -void config_so_flags(int rcv, struct options o) -{ - int on = 1; - - if (setsockopt(rcv, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - error(1, errno, "Failed to enable SO_REUSEADDR"); - - if (o.so_timestamp && - setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMP, - &o.so_timestamp, sizeof(o.so_timestamp)) < 0) - error(1, errno, "Failed to enable SO_TIMESTAMP"); - - if (o.so_timestampns && - setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPNS, - &o.so_timestampns, sizeof(o.so_timestampns)) < 0) - error(1, errno, "Failed to enable SO_TIMESTAMPNS"); - - if (o.so_timestamping && - setsockopt(rcv, SOL_SOCKET, SO_TIMESTAMPING, - &o.so_timestamping, sizeof(o.so_timestamping)) < 0) - error(1, errno, "Failed to set SO_TIMESTAMPING"); -} - -bool run_test_case(struct socket_type s, struct test_case t) -{ - int port = (s.type == SOCK_RAW) ? 0 : next_port++; - int read_size = op_size; - struct sockaddr_in addr; - bool failed = false; - int src, dst, rcv; - - src = socket(AF_INET, s.type, s.protocol); - if (src < 0) - error(1, errno, "Failed to open src socket"); - - dst = socket(AF_INET, s.type, s.protocol); - if (dst < 0) - error(1, errno, "Failed to open dst socket"); - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - addr.sin_port = htons(port); - - if (bind(dst, (struct sockaddr *)&addr, sizeof(addr)) < 0) - error(1, errno, "Failed to bind to port %d", port); - - if (s.type == SOCK_STREAM && (listen(dst, 1) < 0)) - error(1, errno, "Failed to listen"); - - if (connect(src, (struct sockaddr *)&addr, sizeof(addr)) < 0) - error(1, errno, "Failed to connect"); - - if (s.type == SOCK_STREAM) { - rcv = accept(dst, NULL, NULL); - if (rcv < 0) - error(1, errno, "Failed to accept"); - close(dst); - } else { - rcv = dst; - } - - config_so_flags(rcv, t.sockopt); - usleep(20000); /* setsockopt for SO_TIMESTAMPING is asynchronous */ - do_send(src); - - if (s.type == SOCK_RAW) - read_size += 20; /* for IP header */ - failed = do_recv(rcv, read_size, t.expected); - - close(rcv); - close(src); - - return failed; -} - -int main(int argc, char **argv) -{ - bool all_protocols = true; - bool all_tests = true; - int arg_index = 0; - int failures = 0; - int s, t; - char opt; - - while ((opt = getopt_long(argc, argv, "", long_options, - &arg_index)) != -1) { - switch (opt) { - case 'l': - for (t = 0; t < ARRAY_SIZE(test_cases); t++) { - printf("%d\t", t); - print_test_case(&test_cases[t]); - } - return 0; - case 'n': - t = atoi(optarg); - if (t >= ARRAY_SIZE(test_cases)) - error(1, 0, "Invalid test case: %d", t); - all_tests = false; - test_cases[t].enabled = true; - break; - case 's': - op_size = atoi(optarg); - break; - case 't': - all_protocols = false; - socket_types[2].enabled = true; - break; - case 'u': - all_protocols = false; - socket_types[1].enabled = true; - break; - case 'i': - all_protocols = false; - socket_types[0].enabled = true; - break; - default: - error(1, 0, "Failed to parse parameters."); - } - } - - for (s = 0; s < ARRAY_SIZE(socket_types); s++) { - if (!all_protocols && !socket_types[s].enabled) - continue; - - printf("Testing %s...\n", socket_types[s].friendly_name); - for (t = 0; t < ARRAY_SIZE(test_cases); t++) { - if (!all_tests && !test_cases[t].enabled) - continue; - - printf("Starting testcase %d...\n", t); - if (run_test_case(socket_types[s], test_cases[t])) { - failures++; - printf("FAILURE in test case "); - print_test_case(&test_cases[t]); - } - } - } - if (!failures) - printf("PASSED.\n"); - return failures; -} diff --git a/tools/testing/selftests/networking/timestamping/txtimestamp.sh b/tools/testing/selftests/networking/timestamping/txtimestamp.sh deleted file mode 100755 index df0d86ca72b7..000000000000 --- a/tools/testing/selftests/networking/timestamping/txtimestamp.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/bash -# SPDX-License-Identifier: GPL-2.0 -# -# Send packets with transmit timestamps over loopback with netem -# Verify that timestamps correspond to netem delay - -set -e - -setup() { - # set 1ms delay on lo egress - tc qdisc add dev lo root netem delay 1ms - - # set 2ms delay on ifb0 egress - modprobe ifb - ip link add ifb_netem0 type ifb - ip link set dev ifb_netem0 up - tc qdisc add dev ifb_netem0 root netem delay 2ms - - # redirect lo ingress through ifb0 egress - tc qdisc add dev lo handle ffff: ingress - tc filter add dev lo parent ffff: \ - u32 match mark 0 0xffff \ - action mirred egress redirect dev ifb_netem0 -} - -run_test_v4v6() { - # SND will be delayed 1000us - # ACK will be delayed 6000us: 1 + 2 ms round-trip - local -r args="$@ -v 1000 -V 6000" - - ./txtimestamp ${args} -4 -L 127.0.0.1 - ./txtimestamp ${args} -6 -L ::1 -} - -run_test_tcpudpraw() { - local -r args=$@ - - run_test_v4v6 ${args} # tcp - run_test_v4v6 ${args} -u # udp - run_test_v4v6 ${args} -r # raw - run_test_v4v6 ${args} -R # raw (IPPROTO_RAW) - run_test_v4v6 ${args} -P # pf_packet -} - -run_test_all() { - run_test_tcpudpraw # setsockopt - run_test_tcpudpraw -C # cmsg - run_test_tcpudpraw -n # timestamp w/o data -} - -if [[ "$(ip netns identify)" == "root" ]]; then - ../../net/in_netns.sh $0 $@ -else - setup - run_test_all - echo "OK. All tests passed" -fi |