diff mbox series

[net-next,RFC] selftests: test timestamps in psock_tpacket

Message ID 20171130015207.43554-1-willemdebruijn.kernel@gmail.com
State RFC, archived
Headers show
Series [net-next,RFC] selftests: test timestamps in psock_tpacket | expand

Commit Message

Willem de Bruijn Nov. 30, 2017, 1:52 a.m. UTC
From: Willem de Bruijn <willemb@google.com>

Packet rings can return timestamps. Optionally test this path.

Verify that the returned values are sane.
Also test new timestamp modes skip and ns64.

Signed-off-by: Willem de Bruijn <willemb@google.com>
---
 tools/testing/selftests/net/psock_tpacket.c | 125 +++++++++++++++++++++++++++-
 1 file changed, 124 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/tools/testing/selftests/net/psock_tpacket.c b/tools/testing/selftests/net/psock_tpacket.c
index 7f6cd9fdacf3..5af11016a5de 100644
--- a/tools/testing/selftests/net/psock_tpacket.c
+++ b/tools/testing/selftests/net/psock_tpacket.c
@@ -36,6 +36,7 @@ 
  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -57,6 +58,7 @@ 
 #include <net/if.h>
 #include <inttypes.h>
 #include <poll.h>
+#include <sys/time.h>
 
 #include "psock_lib.h"
 
@@ -75,6 +77,19 @@ 
 #define NUM_PACKETS		100
 #define ALIGN_8(x)		(((x) + 8 - 1) & ~(8 - 1))
 
+const uint64_t tstamp_bound_ns64 = 1000UL * 1000 * 1000;
+
+enum cfg_tstamp_type {
+	tstype_none,
+	tstype_default,
+	tstype_skip,
+	tstype_ns64
+};
+
+static enum cfg_tstamp_type cfg_tstamp;
+
+static uint64_t tstamp_start_ns64;
+
 struct ring {
 	struct iovec *rd;
 	uint8_t *mm_space;
@@ -150,6 +165,43 @@  static void test_payload(void *pay, size_t len)
 	}
 }
 
+static void test_tstamp(uint32_t sec, uint32_t nsec)
+{
+	uint64_t tstamp_ns64;
+
+	if (!cfg_tstamp)
+		return;
+
+	if (cfg_tstamp == tstype_skip) {
+		if (sec || nsec) {
+			fprintf(stderr, "%s: unexpected tstamp %u:%u\n",
+				__func__, sec, nsec);
+			exit(1);
+		}
+		return;
+	}
+
+	if (cfg_tstamp == tstype_ns64)
+		tstamp_ns64 = (((uint64_t) sec) << 32) | nsec;
+	else
+		tstamp_ns64 = (sec * 1000UL * 1000 * 1000) + nsec;
+
+	if (tstamp_ns64 < tstamp_start_ns64) {
+		fprintf(stderr, "tstamp: %lu lowerbound=%lu under=%lu\n",
+				tstamp_ns64, tstamp_start_ns64,
+				tstamp_start_ns64 - tstamp_ns64);
+		exit(1);
+	}
+	if (tstamp_ns64 > tstamp_start_ns64 + tstamp_bound_ns64) {
+		fprintf(stderr, "tstamp: %lu upperbound=%lu over=%lu\n",
+				tstamp_ns64,
+				tstamp_start_ns64 + tstamp_bound_ns64,
+				tstamp_ns64 - (tstamp_start_ns64 +
+					       tstamp_bound_ns64));
+		exit(1);
+	}
+}
+
 static void create_payload(void *pay, size_t *len)
 {
 	int i;
@@ -256,12 +308,18 @@  static void walk_v1_v2_rx(int sock, struct ring *ring)
 			case TPACKET_V1:
 				test_payload((uint8_t *) ppd.raw + ppd.v1->tp_h.tp_mac,
 					     ppd.v1->tp_h.tp_snaplen);
+				test_tstamp(ppd.v1->tp_h.tp_sec,
+					    cfg_tstamp == tstype_ns64 ?
+					    ppd.v1->tp_h.tp_usec :
+					    ppd.v1->tp_h.tp_usec * 1000);
 				total_bytes += ppd.v1->tp_h.tp_snaplen;
 				break;
 
 			case TPACKET_V2:
 				test_payload((uint8_t *) ppd.raw + ppd.v2->tp_h.tp_mac,
 					     ppd.v2->tp_h.tp_snaplen);
+				test_tstamp(ppd.v2->tp_h.tp_sec,
+					    ppd.v2->tp_h.tp_nsec);
 				total_bytes += ppd.v2->tp_h.tp_snaplen;
 				break;
 			}
@@ -572,6 +630,7 @@  static void __v3_walk_block(struct block_desc *pbd, const int block_num)
 			bytes_with_padding += ALIGN_8(ppd->tp_snaplen + ppd->tp_mac);
 
 		test_payload((uint8_t *) ppd + ppd->tp_mac, ppd->tp_snaplen);
+		test_tstamp(ppd->tp_sec, ppd->tp_nsec);
 
 		status_bar_update();
 		total_packets++;
@@ -766,6 +825,38 @@  static void unmap_ring(int sock, struct ring *ring)
 	free(ring->rd);
 }
 
+static void setup_tstamp(int sock)
+{
+	struct timeval tv;
+	int one = 1;
+
+	gettimeofday(&tv, NULL);
+	tstamp_start_ns64 = (tv.tv_sec * 1000UL * 1000 * 1000) +
+			    (tv.tv_usec * 1000UL);
+
+/* TODO: remove before submit: temporary */
+#ifndef PACKET_SKIPTIMESTAMP
+#define PACKET_SKIPTIMESTAMP	23
+#endif
+#ifndef PACKET_TIMESTAMP_NS64
+#define PACKET_TIMESTAMP_NS64	24
+#endif
+
+	if (cfg_tstamp == tstype_skip) {
+		if (setsockopt(sock, SOL_PACKET, PACKET_SKIPTIMESTAMP,
+			       &one, sizeof(one))) {
+			perror("setsockopt skiptimestamp");
+			exit(1);
+		}
+	} else if (cfg_tstamp == tstype_ns64) {
+		if (setsockopt(sock, SOL_PACKET, PACKET_TIMESTAMP_NS64,
+			       &one, sizeof(one))) {
+			perror("setsockopt timestamp ns64");
+			exit(1);
+		}
+	}
+}
+
 static int test_kernel_bit_width(void)
 {
 	char in[512], *ptr;
@@ -829,6 +920,8 @@  static int test_tpacket(int version, int type)
 	}
 
 	sock = pfsocket(version);
+	if (cfg_tstamp)
+		setup_tstamp(sock);
 	memset(&ring, 0, sizeof(ring));
 	setup_ring(sock, &ring, version, type);
 	mmap_ring(sock, &ring);
@@ -841,10 +934,40 @@  static int test_tpacket(int version, int type)
 	return 0;
 }
 
-int main(void)
+static void usage(const char *filepath)
+{
+	fprintf(stderr, "Usage: %s [-t <default|skip|ns64>]\n", filepath);
+	exit(1);
+}
+
+static void parse_opts(int argc, char **argv)
+{
+	int c;
+
+	while ((c = getopt(argc, argv, "t:")) != -1) {
+		switch (c) {
+		case 't':
+			if (!strcmp(optarg, "default"))
+				cfg_tstamp = tstype_default;
+			else if (!strcmp(optarg, "skip"))
+				cfg_tstamp = tstype_skip;
+			else if (!strcmp(optarg, "ns64"))
+				cfg_tstamp = tstype_ns64;
+			else
+				usage(argv[0]);
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+}
+
+int main(int argc, char **argv)
 {
 	int ret = 0;
 
+	parse_opts(argc, argv);
+
 	ret |= test_tpacket(TPACKET_V1, PACKET_RX_RING);
 	ret |= test_tpacket(TPACKET_V1, PACKET_TX_RING);