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

Reply via email to