diff options
author | Jian Yang <jianyang@google.com> | 2020-03-25 13:32:07 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2020-03-29 21:48:30 -0700 |
commit | 5ef5c90e3cb3ae1ce7bebddaeb8e8f44309950f7 (patch) | |
tree | d025c25e717a13808070791ccf8110c645c4b4a6 /tools/testing/selftests/networking | |
parent | ARM: dts: apalis-imx6qdl: use rgmii-id instead of rgmii (diff) | |
download | linux-dev-5ef5c90e3cb3ae1ce7bebddaeb8e8f44309950f7.tar.xz linux-dev-5ef5c90e3cb3ae1ce7bebddaeb8e8f44309950f7.zip |
selftests: move timestamping selftests to net folder
For historical reasons, there are several timestamping selftest targets
in selftests/networking/timestamping. Move them to the standard
directory for networking tests: selftests/net.
Signed-off-by: Jian Yang <jianyang@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Acked-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'tools/testing/selftests/networking')
8 files changed, 0 insertions, 2049 deletions
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/hwtstamp_config.c b/tools/testing/selftests/networking/timestamping/hwtstamp_config.c deleted file mode 100644 index e1fdee841021..000000000000 --- a/tools/testing/selftests/networking/timestamping/hwtstamp_config.c +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* Test program for SIOC{G,S}HWTSTAMP - * Copyright 2013 Solarflare Communications - * Author: Ben Hutchings - */ - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <sys/socket.h> -#include <sys/ioctl.h> - -#include <linux/if.h> -#include <linux/net_tstamp.h> -#include <linux/sockios.h> - -static int -lookup_value(const char **names, int size, const char *name) -{ - int value; - - for (value = 0; value < size; value++) - if (names[value] && strcasecmp(names[value], name) == 0) - return value; - - return -1; -} - -static const char * -lookup_name(const char **names, int size, int value) -{ - return (value >= 0 && value < size) ? names[value] : NULL; -} - -static void list_names(FILE *f, const char **names, int size) -{ - int value; - - for (value = 0; value < size; value++) - if (names[value]) - fprintf(f, " %s\n", names[value]); -} - -static const char *tx_types[] = { -#define TX_TYPE(name) [HWTSTAMP_TX_ ## name] = #name - TX_TYPE(OFF), - TX_TYPE(ON), - TX_TYPE(ONESTEP_SYNC) -#undef TX_TYPE -}; -#define N_TX_TYPES ((int)(sizeof(tx_types) / sizeof(tx_types[0]))) - -static const char *rx_filters[] = { -#define RX_FILTER(name) [HWTSTAMP_FILTER_ ## name] = #name - RX_FILTER(NONE), - RX_FILTER(ALL), - RX_FILTER(SOME), - RX_FILTER(PTP_V1_L4_EVENT), - RX_FILTER(PTP_V1_L4_SYNC), - RX_FILTER(PTP_V1_L4_DELAY_REQ), - RX_FILTER(PTP_V2_L4_EVENT), - RX_FILTER(PTP_V2_L4_SYNC), - RX_FILTER(PTP_V2_L4_DELAY_REQ), - RX_FILTER(PTP_V2_L2_EVENT), - RX_FILTER(PTP_V2_L2_SYNC), - RX_FILTER(PTP_V2_L2_DELAY_REQ), - RX_FILTER(PTP_V2_EVENT), - RX_FILTER(PTP_V2_SYNC), - RX_FILTER(PTP_V2_DELAY_REQ), -#undef RX_FILTER -}; -#define N_RX_FILTERS ((int)(sizeof(rx_filters) / sizeof(rx_filters[0]))) - -static void usage(void) -{ - fputs("Usage: hwtstamp_config if_name [tx_type rx_filter]\n" - "tx_type is any of (case-insensitive):\n", - stderr); - list_names(stderr, tx_types, N_TX_TYPES); - fputs("rx_filter is any of (case-insensitive):\n", stderr); - list_names(stderr, rx_filters, N_RX_FILTERS); -} - -int main(int argc, char **argv) -{ - struct ifreq ifr; - struct hwtstamp_config config; - const char *name; - int sock; - - if ((argc != 2 && argc != 4) || (strlen(argv[1]) >= IFNAMSIZ)) { - usage(); - return 2; - } - - if (argc == 4) { - config.flags = 0; - config.tx_type = lookup_value(tx_types, N_TX_TYPES, argv[2]); - config.rx_filter = lookup_value(rx_filters, N_RX_FILTERS, argv[3]); - if (config.tx_type < 0 || config.rx_filter < 0) { - usage(); - return 2; - } - } - - sock = socket(AF_INET, SOCK_DGRAM, 0); - if (sock < 0) { - perror("socket"); - return 1; - } - - strcpy(ifr.ifr_name, argv[1]); - ifr.ifr_data = (caddr_t)&config; - - if (ioctl(sock, (argc == 2) ? SIOCGHWTSTAMP : SIOCSHWTSTAMP, &ifr)) { - perror("ioctl"); - return 1; - } - - printf("flags = %#x\n", config.flags); - name = lookup_name(tx_types, N_TX_TYPES, config.tx_type); - if (name) - printf("tx_type = %s\n", name); - else - printf("tx_type = %d\n", config.tx_type); - name = lookup_name(rx_filters, N_RX_FILTERS, config.rx_filter); - if (name) - printf("rx_filter = %s\n", name); - else - printf("rx_filter = %d\n", config.rx_filter); - - return 0; -} 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/timestamping.c b/tools/testing/selftests/networking/timestamping/timestamping.c deleted file mode 100644 index aca3491174a1..000000000000 --- a/tools/testing/selftests/networking/timestamping/timestamping.c +++ /dev/null @@ -1,509 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * This program demonstrates how the various time stamping features in - * the Linux kernel work. It emulates the behavior of a PTP - * implementation in stand-alone master mode by sending PTPv1 Sync - * multicasts once every second. It looks for similar packets, but - * beyond that doesn't actually implement PTP. - * - * Outgoing packets are time stamped with SO_TIMESTAMPING with or - * without hardware support. - * - * Incoming packets are time stamped with SO_TIMESTAMPING with or - * without hardware support, SIOCGSTAMP[NS] (per-socket time stamp) and - * SO_TIMESTAMP[NS]. - * - * Copyright (C) 2009 Intel Corporation. - * Author: Patrick Ohly <patrick.ohly@intel.com> - */ - -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <string.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> -#include <linux/sockios.h> - -#ifndef SO_TIMESTAMPING -# define SO_TIMESTAMPING 37 -# define SCM_TIMESTAMPING SO_TIMESTAMPING -#endif - -#ifndef SO_TIMESTAMPNS -# define SO_TIMESTAMPNS 35 -#endif - -static void usage(const char *error) -{ - if (error) - printf("invalid option: %s\n", error); - printf("timestamping interface option*\n\n" - "Options:\n" - " IP_MULTICAST_LOOP - looping outgoing multicasts\n" - " SO_TIMESTAMP - normal software time stamping, ms resolution\n" - " SO_TIMESTAMPNS - more accurate software time stamping\n" - " SOF_TIMESTAMPING_TX_HARDWARE - hardware time stamping of outgoing packets\n" - " SOF_TIMESTAMPING_TX_SOFTWARE - software fallback for outgoing packets\n" - " SOF_TIMESTAMPING_RX_HARDWARE - hardware time stamping of incoming packets\n" - " 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" - " SIOCGSTAMP - check last socket time stamp\n" - " SIOCGSTAMPNS - more accurate socket time stamp\n"); - exit(1); -} - -static void bail(const char *error) -{ - printf("%s: %s\n", error, strerror(errno)); - exit(1); -} - -static const unsigned char sync[] = { - 0x00, 0x01, 0x00, 0x01, - 0x5f, 0x44, 0x46, 0x4c, - 0x54, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, - - /* fake uuid */ - 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, - - 0x00, 0x01, 0x00, 0x37, - 0x00, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0x00, - 0x49, 0x05, 0xcd, 0x01, - 0x29, 0xb1, 0x8d, 0xb0, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, - - /* fake uuid */ - 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, - - 0x00, 0x00, 0x00, 0x37, - 0x00, 0x00, 0x00, 0x04, - 0x44, 0x46, 0x4c, 0x54, - 0x00, 0x00, 0xf0, 0x60, - 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0xf0, 0x60, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, - 0x44, 0x46, 0x4c, 0x54, - 0x00, 0x01, - - /* fake uuid */ - 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, - - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 -}; - -static void sendpacket(int sock, struct sockaddr *addr, socklen_t addr_len) -{ - struct timeval now; - int res; - - res = sendto(sock, sync, sizeof(sync), 0, - addr, addr_len); - gettimeofday(&now, 0); - if (res < 0) - printf("%s: %s\n", "send", strerror(errno)); - else - printf("%ld.%06ld: sent %d bytes\n", - (long)now.tv_sec, (long)now.tv_usec, - res); -} - -static void printpacket(struct msghdr *msg, int res, - char *data, - int sock, int recvmsg_flags, - int siocgstamp, int siocgstampns) -{ - struct sockaddr_in *from_addr = (struct sockaddr_in *)msg->msg_name; - struct cmsghdr *cmsg; - struct timeval tv; - struct timespec ts; - struct timeval now; - - gettimeofday(&now, 0); - - printf("%ld.%06ld: received %s data, %d bytes from %s, %zu bytes control messages\n", - (long)now.tv_sec, (long)now.tv_usec, - (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular", - res, - inet_ntoa(from_addr->sin_addr), - msg->msg_controllen); - for (cmsg = CMSG_FIRSTHDR(msg); - cmsg; - cmsg = CMSG_NXTHDR(msg, cmsg)) { - printf(" cmsg len %zu: ", cmsg->cmsg_len); - switch (cmsg->cmsg_level) { - case SOL_SOCKET: - printf("SOL_SOCKET "); - switch (cmsg->cmsg_type) { - case SO_TIMESTAMP: { - struct timeval *stamp = - (struct timeval *)CMSG_DATA(cmsg); - printf("SO_TIMESTAMP %ld.%06ld", - (long)stamp->tv_sec, - (long)stamp->tv_usec); - break; - } - case SO_TIMESTAMPNS: { - struct timespec *stamp = - (struct timespec *)CMSG_DATA(cmsg); - printf("SO_TIMESTAMPNS %ld.%09ld", - (long)stamp->tv_sec, - (long)stamp->tv_nsec); - break; - } - case SO_TIMESTAMPING: { - struct timespec *stamp = - (struct timespec *)CMSG_DATA(cmsg); - printf("SO_TIMESTAMPING "); - printf("SW %ld.%09ld ", - (long)stamp->tv_sec, - (long)stamp->tv_nsec); - stamp++; - /* skip deprecated HW transformed */ - stamp++; - printf("HW raw %ld.%09ld", - (long)stamp->tv_sec, - (long)stamp->tv_nsec); - break; - } - default: - printf("type %d", cmsg->cmsg_type); - break; - } - break; - case IPPROTO_IP: - printf("IPPROTO_IP "); - switch (cmsg->cmsg_type) { - case IP_RECVERR: { - struct sock_extended_err *err = - (struct sock_extended_err *)CMSG_DATA(cmsg); - printf("IP_RECVERR ee_errno '%s' ee_origin %d => %s", - strerror(err->ee_errno), - err->ee_origin, -#ifdef SO_EE_ORIGIN_TIMESTAMPING - err->ee_origin == SO_EE_ORIGIN_TIMESTAMPING ? - "bounced packet" : "unexpected origin" -#else - "probably SO_EE_ORIGIN_TIMESTAMPING" -#endif - ); - if (res < sizeof(sync)) - printf(" => truncated data?!"); - else if (!memcmp(sync, data + res - sizeof(sync), - sizeof(sync))) - printf(" => GOT OUR DATA BACK (HURRAY!)"); - break; - } - case IP_PKTINFO: { - struct in_pktinfo *pktinfo = - (struct in_pktinfo *)CMSG_DATA(cmsg); - printf("IP_PKTINFO interface index %u", - pktinfo->ipi_ifindex); - break; - } - default: - printf("type %d", cmsg->cmsg_type); - break; - } - break; - default: - printf("level %d type %d", - cmsg->cmsg_level, - cmsg->cmsg_type); - break; - } - printf("\n"); - } - - if (siocgstamp) { - if (ioctl(sock, SIOCGSTAMP, &tv)) - printf(" %s: %s\n", "SIOCGSTAMP", strerror(errno)); - else - printf("SIOCGSTAMP %ld.%06ld\n", - (long)tv.tv_sec, - (long)tv.tv_usec); - } - if (siocgstampns) { - if (ioctl(sock, SIOCGSTAMPNS, &ts)) - printf(" %s: %s\n", "SIOCGSTAMPNS", strerror(errno)); - else - printf("SIOCGSTAMPNS %ld.%09ld\n", - (long)ts.tv_sec, - (long)ts.tv_nsec); - } -} - -static void recvpacket(int sock, int recvmsg_flags, - int siocgstamp, int siocgstampns) -{ - char data[256]; - struct msghdr msg; - struct iovec entry; - struct sockaddr_in from_addr; - struct { - struct cmsghdr cm; - char control[512]; - } control; - int res; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = &entry; - msg.msg_iovlen = 1; - entry.iov_base = data; - entry.iov_len = sizeof(data); - msg.msg_name = (caddr_t)&from_addr; - msg.msg_namelen = sizeof(from_addr); - msg.msg_control = &control; - msg.msg_controllen = sizeof(control); - - res = recvmsg(sock, &msg, recvmsg_flags|MSG_DONTWAIT); - if (res < 0) { - printf("%s %s: %s\n", - "recvmsg", - (recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular", - strerror(errno)); - } else { - printpacket(&msg, res, data, - sock, recvmsg_flags, - siocgstamp, siocgstampns); - } -} - -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; - char *interface; - int i; - int enabled = 1; - int sock; - struct ifreq device; - struct ifreq hwtstamp; - struct hwtstamp_config hwconfig, hwconfig_requested; - struct sockaddr_in addr; - struct ip_mreq imr; - struct in_addr iaddr; - int val; - socklen_t len; - struct timeval next; - - if (argc < 2) - usage(0); - interface = argv[1]; - - for (i = 2; i < argc; i++) { - if (!strcasecmp(argv[i], "SO_TIMESTAMP")) - so_timestamp = 1; - else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS")) - so_timestampns = 1; - else if (!strcasecmp(argv[i], "SIOCGSTAMP")) - siocgstamp = 1; - else if (!strcasecmp(argv[i], "SIOCGSTAMPNS")) - siocgstampns = 1; - else if (!strcasecmp(argv[i], "IP_MULTICAST_LOOP")) - ip_multicast_loop = 1; - else if (!strcasecmp(argv[i], "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; - else if (!strcasecmp(argv[i], "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; - else if (!strcasecmp(argv[i], "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; - else - usage(argv[i]); - } - - sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sock < 0) - bail("socket"); - - memset(&device, 0, sizeof(device)); - strncpy(device.ifr_name, interface, sizeof(device.ifr_name)); - 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)); - hwtstamp.ifr_data = (void *)&hwconfig; - memset(&hwconfig, 0, sizeof(hwconfig)); - hwconfig.tx_type = - (so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ? - HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; - hwconfig.rx_filter = - (so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ? - HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE; - hwconfig_requested = hwconfig; - if (ioctl(sock, SIOCSHWTSTAMP, &hwtstamp) < 0) { - if ((errno == EINVAL || errno == ENOTSUP) && - hwconfig_requested.tx_type == HWTSTAMP_TX_OFF && - hwconfig_requested.rx_filter == HWTSTAMP_FILTER_NONE) - printf("SIOCSHWTSTAMP: disabling hardware time stamping not possible\n"); - else - bail("SIOCSHWTSTAMP"); - } - printf("SIOCSHWTSTAMP: tx_type %d requested, got %d; rx_filter %d requested, got %d\n", - hwconfig_requested.tx_type, hwconfig.tx_type, - hwconfig_requested.rx_filter, hwconfig.rx_filter); - - /* bind to PTP port */ - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(INADDR_ANY); - addr.sin_port = htons(319 /* PTP event port */); - if (bind(sock, - (struct sockaddr *)&addr, - sizeof(struct sockaddr_in)) < 0) - bail("bind"); - - /* set multicast group for outgoing packets */ - inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */ - addr.sin_addr = iaddr; - imr.imr_multiaddr.s_addr = iaddr.s_addr; - imr.imr_interface.s_addr = - ((struct sockaddr_in *)&device.ifr_addr)->sin_addr.s_addr; - if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, - &imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0) - bail("set multicast"); - - /* join multicast group, loop our own packet */ - if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &imr, sizeof(struct ip_mreq)) < 0) - bail("join multicast group"); - - if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, - &ip_multicast_loop, sizeof(enabled)) < 0) { - bail("loop multicast"); - } - - /* set socket options for time stamping */ - if (so_timestamp && - setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, - &enabled, sizeof(enabled)) < 0) - bail("setsockopt SO_TIMESTAMP"); - - if (so_timestampns && - setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS, - &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) - bail("setsockopt SO_TIMESTAMPING"); - - /* request IP_PKTINFO for debugging purposes */ - if (setsockopt(sock, SOL_IP, IP_PKTINFO, - &enabled, sizeof(enabled)) < 0) - printf("%s: %s\n", "setsockopt IP_PKTINFO", strerror(errno)); - - /* verify socket options */ - len = sizeof(val); - if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, &len) < 0) - printf("%s: %s\n", "getsockopt SO_TIMESTAMP", strerror(errno)); - else - printf("SO_TIMESTAMP %d\n", val); - - if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS, &val, &len) < 0) - printf("%s: %s\n", "getsockopt SO_TIMESTAMPNS", - strerror(errno)); - else - printf("SO_TIMESTAMPNS %d\n", val); - - if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &val, &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); - } - - /* send packets forever every five seconds */ - gettimeofday(&next, 0); - next.tv_sec = (next.tv_sec + 1) / 5 * 5; - next.tv_usec = 0; - while (1) { - struct timeval now; - struct timeval delta; - long delta_us; - int res; - fd_set readfs, errorfs; - - gettimeofday(&now, 0); - delta_us = (long)(next.tv_sec - now.tv_sec) * 1000000 + - (long)(next.tv_usec - now.tv_usec); - if (delta_us > 0) { - /* continue waiting for timeout or data */ - delta.tv_sec = delta_us / 1000000; - delta.tv_usec = delta_us % 1000000; - - FD_ZERO(&readfs); - FD_ZERO(&errorfs); - FD_SET(sock, &readfs); - FD_SET(sock, &errorfs); - printf("%ld.%06ld: select %ldus\n", - (long)now.tv_sec, (long)now.tv_usec, - delta_us); - res = select(sock + 1, &readfs, 0, &errorfs, &delta); - gettimeofday(&now, 0); - printf("%ld.%06ld: select returned: %d, %s\n", - (long)now.tv_sec, (long)now.tv_usec, - res, - res < 0 ? strerror(errno) : "success"); - if (res > 0) { - if (FD_ISSET(sock, &readfs)) - printf("ready for reading\n"); - if (FD_ISSET(sock, &errorfs)) - printf("has error\n"); - recvpacket(sock, 0, - siocgstamp, - siocgstampns); - recvpacket(sock, MSG_ERRQUEUE, - siocgstamp, - siocgstampns); - } - } else { - /* write one packet */ - sendpacket(sock, - (struct sockaddr *)&addr, - sizeof(addr)); - next.tv_sec += 5; - continue; - } - } - - return 0; -} diff --git a/tools/testing/selftests/networking/timestamping/txtimestamp.c b/tools/testing/selftests/networking/timestamping/txtimestamp.c deleted file mode 100644 index 011b0da6b033..000000000000 --- a/tools/testing/selftests/networking/timestamping/txtimestamp.c +++ /dev/null @@ -1,916 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright 2014 Google Inc. - * Author: willemb@google.com (Willem de Bruijn) - * - * Test software tx timestamping, including - * - * - SCHED, SND and ACK timestamps - * - RAW, UDP and TCP - * - IPv4 and IPv6 - * - various packet sizes (to test GSO and TSO) - * - * Consult the command line arguments for help on running - * the various testcases. - * - * This test requires a dummy TCP server. - * A simple `nc6 [-u] -l -p $DESTPORT` will do - */ - -#define _GNU_SOURCE - -#include <arpa/inet.h> -#include <asm/types.h> -#include <error.h> -#include <errno.h> -#include <inttypes.h> -#include <linux/errqueue.h> -#include <linux/if_ether.h> -#include <linux/ipv6.h> -#include <linux/net_tstamp.h> -#include <netdb.h> -#include <net/if.h> -#include <netinet/in.h> -#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> -#include <sys/time.h> -#include <sys/types.h> -#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; -static int cfg_num_pkts = 4; -static int do_ipv4 = 1; -static int do_ipv6 = 1; -static int cfg_payload_len = 10; -static int cfg_poll_timeout = 100; -static int cfg_delay_snd; -static int cfg_delay_ack; -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_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; -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 * 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) -{ - int stepsize; - - /* compare key for each subsequent request - * must only test for one type, the first one requested - */ - if (saved_tskey == -1) - saved_tskey_type = tstype; - else if (saved_tskey_type != tstype) - return; - - stepsize = cfg_proto == SOCK_STREAM ? cfg_payload_len : 1; - if (tskey != saved_tskey + stepsize) { - fprintf(stderr, "ERROR: key %d, expected %d\n", - tskey, saved_tskey + stepsize); - test_failed = true; - } - - saved_tskey = tskey; -} - -static void validate_timestamp(struct timespec *cur, int min_delay) -{ - int max_delay = min_delay + 500 /* processing time upper bound */; - int64_t cur64, start64; - - cur64 = timespec_to_us64(cur); - start64 = timespec_to_us64(&ts_usr); - - if (cur64 < start64 + min_delay || cur64 > start64 + max_delay) { - fprintf(stderr, "ERROR: %lu 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, "%lu ns", ts_delta); - else - fprintf(stderr, "%lu 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; - - 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"); -} - -static void print_timestamp_usr(void) -{ - if (clock_gettime(CLOCK_REALTIME, &ts_usr)) - error(1, errno, "clock_gettime"); - - __print_timestamp(" USR", &ts_usr, 0, 0); -} - -static void print_timestamp(struct scm_timestamping *tss, int tstype, - int tskey, int payload_len) -{ - const char *tsname; - - validate_key(tskey, tstype); - - switch (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", - 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) -{ - int i; - - if (!len) - return; - - if (len > 70) - len = 70; - - fprintf(stderr, "payload: "); - for (i = 0; i < len; i++) - fprintf(stderr, "%02hhx ", data[i]); - fprintf(stderr, "\n"); -} - -static void print_pktinfo(int family, int ifindex, void *saddr, void *daddr) -{ - char sa[INET6_ADDRSTRLEN], da[INET6_ADDRSTRLEN]; - - fprintf(stderr, " pktinfo: ifindex=%u src=%s dst=%s\n", - ifindex, - saddr ? inet_ntop(family, saddr, sa, sizeof(sa)) : "unknown", - 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; - int ret; - - memset(&pollfd, 0, sizeof(pollfd)); - pollfd.fd = fd; - ret = poll(&pollfd, 1, cfg_poll_timeout); - if (ret != 1) - error(1, errno, "poll"); -} - -static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len) -{ - struct sock_extended_err *serr = NULL; - struct scm_timestamping *tss = NULL; - struct cmsghdr *cm; - int batch = 0; - - for (cm = CMSG_FIRSTHDR(msg); - cm && cm->cmsg_len; - cm = CMSG_NXTHDR(msg, cm)) { - if (cm->cmsg_level == SOL_SOCKET && - cm->cmsg_type == SCM_TIMESTAMPING) { - tss = (void *) CMSG_DATA(cm); - } else if ((cm->cmsg_level == SOL_IP && - cm->cmsg_type == IP_RECVERR) || - (cm->cmsg_level == SOL_IPV6 && - cm->cmsg_type == IPV6_RECVERR) || - (cm->cmsg_level == SOL_PACKET && - cm->cmsg_type == PACKET_TX_TIMESTAMP)) { - serr = (void *) CMSG_DATA(cm); - if (serr->ee_errno != ENOMSG || - serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) { - fprintf(stderr, "unknown ip error %d %d\n", - serr->ee_errno, - serr->ee_origin); - serr = NULL; - } - } else if (cm->cmsg_level == SOL_IP && - cm->cmsg_type == IP_PKTINFO) { - struct in_pktinfo *info = (void *) CMSG_DATA(cm); - print_pktinfo(AF_INET, info->ipi_ifindex, - &info->ipi_spec_dst, &info->ipi_addr); - } else if (cm->cmsg_level == SOL_IPV6 && - cm->cmsg_type == IPV6_PKTINFO) { - struct in6_pktinfo *info6 = (void *) CMSG_DATA(cm); - print_pktinfo(AF_INET6, info6->ipi6_ifindex, - NULL, &info6->ipi6_addr); - } else - fprintf(stderr, "unknown cmsg %d,%d\n", - cm->cmsg_level, cm->cmsg_type); - - if (serr && tss) { - print_timestamp(tss, serr->ee_info, serr->ee_data, - payload_len); - serr = NULL; - tss = NULL; - batch++; - } - } - - if (batch > 1) - fprintf(stderr, "batched %d timestamps\n", batch); -} - -static int recv_errmsg(int fd) -{ - static char ctrl[1024 /* overprovision*/]; - static struct msghdr msg; - struct iovec entry; - static char *data; - int ret = 0; - - data = malloc(cfg_payload_len); - if (!data) - error(1, 0, "malloc"); - - memset(&msg, 0, sizeof(msg)); - memset(&entry, 0, sizeof(entry)); - memset(ctrl, 0, sizeof(ctrl)); - - entry.iov_base = data; - entry.iov_len = cfg_payload_len; - msg.msg_iov = &entry; - msg.msg_iovlen = 1; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = ctrl; - msg.msg_controllen = sizeof(ctrl); - - ret = recvmsg(fd, &msg, MSG_ERRQUEUE); - if (ret == -1 && errno != EAGAIN) - error(1, errno, "recvmsg"); - - if (ret >= 0) { - __recv_errmsg_cmsg(&msg, ret); - if (cfg_show_payload) - print_payload(data, cfg_payload_len); - } - - free(data); - return ret == -1; -} - -static uint16_t get_ip_csum(const uint16_t *start, int num_words, - unsigned long sum) -{ - int i; - - for (i = 0; i < num_words; i++) - sum += start[i]; - - while (sum >> 16) - sum = (sum & 0xFFFF) + (sum >> 16); - - return ~sum; -} - -static uint16_t get_udp_csum(const struct udphdr *udph, int alen) -{ - unsigned long pseudo_sum, csum_len; - const void *csum_start = udph; - - pseudo_sum = htons(IPPROTO_UDP); - pseudo_sum += udph->len; - - /* checksum ip(v6) addresses + udp header + payload */ - csum_start -= alen * 2; - csum_len = ntohs(udph->len) + alen * 2; - - return get_ip_csum(csum_start, csum_len >> 1, pseudo_sum); -} - -static int fill_header_ipv4(void *p) -{ - struct iphdr *iph = p; - - memset(iph, 0, sizeof(*iph)); - - iph->ihl = 5; - iph->version = 4; - iph->ttl = 2; - iph->saddr = daddr.sin_addr.s_addr; /* set for udp csum calc */ - iph->daddr = daddr.sin_addr.s_addr; - iph->protocol = IPPROTO_UDP; - - /* kernel writes saddr, csum, len */ - - return sizeof(*iph); -} - -static int fill_header_ipv6(void *p) -{ - struct ipv6hdr *ip6h = p; - - memset(ip6h, 0, sizeof(*ip6h)); - - ip6h->version = 6; - ip6h->payload_len = htons(sizeof(struct udphdr) + cfg_payload_len); - ip6h->nexthdr = IPPROTO_UDP; - ip6h->hop_limit = 64; - - ip6h->saddr = daddr6.sin6_addr; - ip6h->daddr = daddr6.sin6_addr; - - /* kernel does not write saddr in case of ipv6 */ - - return sizeof(*ip6h); -} - -static void fill_header_udp(void *p, bool is_ipv4) -{ - struct udphdr *udph = p; - - udph->source = ntohs(dest_port + 1); /* spoof */ - udph->dest = ntohs(dest_port); - udph->len = ntohs(sizeof(*udph) + cfg_payload_len); - udph->check = 0; - - udph->check = get_udp_csum(udph, is_ipv4 ? sizeof(struct in_addr) : - sizeof(struct in6_addr)); -} - -static void do_test(int family, unsigned int report_opt) -{ - char control[CMSG_SPACE(sizeof(uint32_t))]; - struct sockaddr_ll laddr; - unsigned int sock_opt; - struct cmsghdr *cmsg; - struct msghdr msg; - struct iovec iov; - char *buf; - 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 (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 - */ - daddr6.sin6_port = htons(cfg_ipproto); - } - - buf = malloc(total_len); - if (!buf) - error(1, 0, "malloc"); - - fd = socket(cfg_use_pf_packet ? PF_PACKET : family, - cfg_proto, cfg_ipproto); - 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; - - if (cfg_proto == SOCK_STREAM) { - if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, - (char*) &val, sizeof(val))) - error(1, 0, "setsockopt no nagle"); - - if (family == PF_INET) { - if (connect(fd, (void *) &daddr, sizeof(daddr))) - error(1, errno, "connect ipv4"); - } else { - if (connect(fd, (void *) &daddr6, sizeof(daddr6))) - error(1, errno, "connect ipv6"); - } - } - - if (cfg_do_pktinfo) { - if (family == AF_INET6) { - if (setsockopt(fd, SOL_IPV6, IPV6_RECVPKTINFO, - &val, sizeof(val))) - error(1, errno, "setsockopt pktinfo ipv6"); - } else { - if (setsockopt(fd, SOL_IP, IP_PKTINFO, - &val, sizeof(val))) - error(1, errno, "setsockopt pktinfo ipv4"); - } - } - - sock_opt = SOF_TIMESTAMPING_SOFTWARE | - SOF_TIMESTAMPING_OPT_CMSG | - SOF_TIMESTAMPING_OPT_ID; - - if (!cfg_use_cmsg) - sock_opt |= report_opt; - - if (cfg_loop_nodata) - sock_opt |= SOF_TIMESTAMPING_OPT_TSONLY; - - if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, - (char *) &sock_opt, sizeof(sock_opt))) - error(1, 0, "setsockopt timestamping"); - - for (i = 0; i < cfg_num_pkts; i++) { - memset(&msg, 0, sizeof(msg)); - memset(buf, 'a' + i, total_len); - - if (cfg_use_pf_packet || cfg_proto == SOCK_RAW) { - int off = 0; - - if (cfg_use_pf_packet || cfg_ipproto == IPPROTO_RAW) { - if (family == PF_INET) - off = fill_header_ipv4(buf); - else - off = fill_header_ipv6(buf); - } - - fill_header_udp(buf + off, family == PF_INET); - } - - print_timestamp_usr(); - - iov.iov_base = buf; - iov.iov_len = total_len; - - if (cfg_proto != SOCK_STREAM) { - if (cfg_use_pf_packet) { - memset(&laddr, 0, sizeof(laddr)); - - laddr.sll_family = AF_PACKET; - laddr.sll_ifindex = 1; - laddr.sll_protocol = htons(family == AF_INET ? ETH_P_IP : ETH_P_IPV6); - laddr.sll_halen = ETH_ALEN; - - msg.msg_name = (void *)&laddr; - msg.msg_namelen = sizeof(laddr); - } else if (family == PF_INET) { - msg.msg_name = (void *)&daddr; - msg.msg_namelen = sizeof(daddr); - } else { - msg.msg_name = (void *)&daddr6; - msg.msg_namelen = sizeof(daddr6); - } - } - - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - if (cfg_use_cmsg) { - memset(control, 0, sizeof(control)); - - msg.msg_control = control; - msg.msg_controllen = sizeof(control); - - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SO_TIMESTAMPING; - cmsg->cmsg_len = CMSG_LEN(sizeof(uint32_t)); - - *((uint32_t *) CMSG_DATA(cmsg)) = report_opt; - } - - val = sendmsg(fd, &msg, 0); - if (val != total_len) - error(1, errno, "send"); - - /* wait for all errors to be queued, else ACKs arrive OOO */ - if (cfg_sleep_usec) - usleep(cfg_sleep_usec); - - 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 * NSEC_PER_USEC); -} - -static void __attribute__((noreturn)) usage(const char *filepath) -{ - fprintf(stderr, "\nUsage: %s [options] hostname\n" - "\nwhere options are:\n" - " -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" - " -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" - " -u: use udp\n" - " -v: validate SND delay (usec)\n" - " -V: validate ACK delay (usec)\n" - " -x: show payload (up to 70 bytes)\n", - filepath); - exit(1); -} - -static void parse_opt(int argc, char **argv) -{ - int proto_count = 0; - int c; - - while ((c = getopt(argc, argv, - "46bc:CeEFhIl:LnNp:PrRS:uv:V:x")) != -1) { - switch (c) { - case '4': - do_ipv6 = 0; - break; - 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 'e': - cfg_use_epoll = true; - break; - case 'E': - cfg_use_epoll = true; - cfg_epollet = true; - case 'F': - cfg_poll_timeout = -1; - break; - case 'I': - cfg_do_pktinfo = true; - break; - case 'l': - cfg_payload_len = strtoul(optarg, NULL, 10); - break; - case 'L': - cfg_do_listen = true; - break; - case 'n': - cfg_loop_nodata = true; - break; - case 'N': - cfg_print_nsec = true; - break; - case 'p': - dest_port = strtoul(optarg, NULL, 10); - break; - case 'P': - proto_count++; - cfg_use_pf_packet = true; - cfg_proto = SOCK_DGRAM; - cfg_ipproto = 0; - break; - case 'r': - proto_count++; - cfg_proto = SOCK_RAW; - cfg_ipproto = IPPROTO_UDP; - break; - case 'R': - proto_count++; - cfg_proto = SOCK_RAW; - cfg_ipproto = IPPROTO_RAW; - break; - case 'S': - cfg_sleep_usec = strtoul(optarg, NULL, 10); - break; - case 'u': - proto_count++; - cfg_proto = SOCK_DGRAM; - cfg_ipproto = IPPROTO_UDP; - break; - case 'v': - cfg_delay_snd = strtoul(optarg, NULL, 10); - break; - case 'V': - cfg_delay_ack = strtoul(optarg, NULL, 10); - break; - case 'x': - cfg_show_payload = true; - break; - case 'h': - default: - usage(argv[0]); - } - } - - if (!cfg_payload_len) - error(1, 0, "payload may not be nonzero"); - if (cfg_proto != SOCK_STREAM && cfg_payload_len > 1472) - error(1, 0, "udp packet might exceed expected MTU"); - if (!do_ipv4 && !do_ipv6) - error(1, 0, "pass -4 or -6, not both"); - if (proto_count > 1) - 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"); -} - -static void resolve_hostname(const char *hostname) -{ - struct addrinfo hints = { .ai_family = do_ipv4 ? AF_INET : AF_INET6 }; - struct addrinfo *addrs, *cur; - int have_ipv4 = 0, have_ipv6 = 0; - -retry: - if (getaddrinfo(hostname, NULL, &hints, &addrs)) - error(1, errno, "getaddrinfo"); - - cur = addrs; - while (cur && !have_ipv4 && !have_ipv6) { - if (!have_ipv4 && cur->ai_family == AF_INET) { - memcpy(&daddr, cur->ai_addr, sizeof(daddr)); - daddr.sin_port = htons(dest_port); - have_ipv4 = 1; - } - else if (!have_ipv6 && cur->ai_family == AF_INET6) { - memcpy(&daddr6, cur->ai_addr, sizeof(daddr6)); - daddr6.sin6_port = htons(dest_port); - have_ipv6 = 1; - } - cur = cur->ai_next; - } - if (addrs) - freeaddrinfo(addrs); - - if (do_ipv6 && hints.ai_family != AF_INET6) { - hints.ai_family = AF_INET6; - goto retry; - } - - do_ipv4 &= have_ipv4; - do_ipv6 &= have_ipv6; -} - -static void do_listen(int family, void *addr, int alen) -{ - int fd, type; - - type = cfg_proto == SOCK_RAW ? SOCK_DGRAM : cfg_proto; - - fd = socket(family, type, 0); - if (fd == -1) - error(1, errno, "socket rx"); - - if (bind(fd, addr, alen)) - error(1, errno, "bind rx"); - - if (type == SOCK_STREAM && listen(fd, 10)) - error(1, errno, "listen rx"); - - /* leave fd open, will be closed on process exit. - * this enables connect() to succeed and avoids icmp replies - */ -} - -static void do_main(int family) -{ - fprintf(stderr, "family: %s %s\n", - family == PF_INET ? "INET" : "INET6", - cfg_use_pf_packet ? "(PF_PACKET)" : ""); - - fprintf(stderr, "test SND\n"); - do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE); - - fprintf(stderr, "test ENQ\n"); - do_test(family, SOF_TIMESTAMPING_TX_SCHED); - - fprintf(stderr, "test ENQ + SND\n"); - do_test(family, SOF_TIMESTAMPING_TX_SCHED | - SOF_TIMESTAMPING_TX_SOFTWARE); - - if (cfg_proto == SOCK_STREAM) { - fprintf(stderr, "\ntest ACK\n"); - do_test(family, SOF_TIMESTAMPING_TX_ACK); - - fprintf(stderr, "\ntest SND + ACK\n"); - do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE | - SOF_TIMESTAMPING_TX_ACK); - - fprintf(stderr, "\ntest ENQ + SND + ACK\n"); - do_test(family, SOF_TIMESTAMPING_TX_SCHED | - SOF_TIMESTAMPING_TX_SOFTWARE | - SOF_TIMESTAMPING_TX_ACK); - } -} - -const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" }; - -int main(int argc, char **argv) -{ - if (argc == 1) - usage(argv[0]); - - parse_opt(argc, argv); - resolve_hostname(argv[argc - 1]); - - fprintf(stderr, "protocol: %s\n", sock_names[cfg_proto]); - fprintf(stderr, "payload: %u\n", cfg_payload_len); - fprintf(stderr, "server port: %u\n", dest_port); - fprintf(stderr, "\n"); - - if (do_ipv4) { - if (cfg_do_listen) - do_listen(PF_INET, &daddr, sizeof(daddr)); - do_main(PF_INET); - } - - if (do_ipv6) { - if (cfg_do_listen) - do_listen(PF_INET6, &daddr6, sizeof(daddr6)); - do_main(PF_INET6); - } - - return test_failed; -} diff --git a/tools/testing/selftests/networking/timestamping/txtimestamp.sh b/tools/testing/selftests/networking/timestamping/txtimestamp.sh deleted file mode 100755 index 70a8cda7fd53..000000000000 --- a/tools/testing/selftests/networking/timestamping/txtimestamp.sh +++ /dev/null @@ -1,82 +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() { - setup - run_test_tcpudpraw # setsockopt - run_test_tcpudpraw -C # cmsg - run_test_tcpudpraw -n # timestamp w/o data - echo "OK. All tests passed" -} - -run_test_one() { - setup - ./txtimestamp $@ -} - -usage() { - echo "Usage: $0 [ -r | --run ] <txtimestamp args> | [ -h | --help ]" - echo " (no args) Run all tests" - echo " -r|--run Run an individual test with arguments" - echo " -h|--help Help" -} - -main() { - if [[ $# -eq 0 ]]; then - run_test_all - else - if [[ "$1" = "-r" || "$1" == "--run" ]]; then - shift - run_test_one $@ - else - usage - fi - fi -} - -if [[ "$(ip netns identify)" == "root" ]]; then - ../../net/in_netns.sh $0 $@ -else - main $@ -fi |