From: Willem de Bruijn <will...@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 <will...@google.com> --- tools/testing/selftests/net/psock_tpacket.c | 125 +++++++++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) 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); -- 2.15.0.531.g2ccb3012c9-goog