aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/networking/timestamping
diff options
context:
space:
mode:
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/.gitignore4
-rw-r--r--tools/testing/selftests/networking/timestamping/Makefile11
-rw-r--r--tools/testing/selftests/networking/timestamping/config2
-rw-r--r--tools/testing/selftests/networking/timestamping/rxtimestamp.c390
-rwxr-xr-xtools/testing/selftests/networking/timestamping/txtimestamp.sh57
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