]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-arista.c
CI: Add warning exemptions for Sun C (suncc-5.15) on Solaris 10
[tcpdump] / print-arista.c
index 26720d3a1fb1e8512bb26633c6d710493c5aa4a5..0ec04889b6a212a5c34af18daace66c935a8d047 100644 (file)
 
 /* \summary: EtherType protocol for Arista Networks printer */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <config.h>
 
 #include "netdissect-stdinc.h"
 
-#include <string.h>
-
 #include "netdissect.h"
 #include "extract.h"
-#include "addrtoname.h"
+#include "timeval-operations.h"
+
+/*
+
+From Bill Fenner:
+
+The Arista timestamp header consists of the following fields:
+1. The Arista ethertype (0xd28b)
+2. A 2-byte subtype field; 0x01 indicates the timestamp header
+3. A 2-byte version field, described below.
+4. A 48-bit or 64-bit timestamp field, depending on the contents of the version field
+
+This header is then followed by the original ethertype and the remainder of the original packet.
+
+ 0                   1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                            dst mac                            |
++                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|                               |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                            src mac                            |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|        ethertype 0xd28b       |          subtype 0x1          |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|            version            |                               |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               +
+|                          timestamp...                         |
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+The two-byte version value is split into 3 fields:
+1. The timescale in use.  Currently assigned values include:
+    0 = TAI
+    1 = UTC
+2. The timestamp format and length.  Currently assigned values include:
+    1 = 64-bit timestamp
+    2 = 48-bit timestamp
+3. The hardware info
+    0 = R/R2 series
+    1 = R3 series
+
+ 0                   1
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|   timescale   | format|hw info|
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+See also: https://www.arista.com/assets/data/pdf/Whitepapers/Overview_Arista_Timestamps.pdf
+
+*/
 
-#define ARISTA_SUBTYPE_TIMESTAMP 0x01
+#define ARISTA_SUBTYPE_TIMESTAMP 0x0001
+static const struct tok subtype_str[] = {
+       { ARISTA_SUBTYPE_TIMESTAMP, "Timestamp" },
+       { 0, NULL }
+};
 
-#define ARISTA_TIMESTAMP_64_TAI 0x0010
-#define ARISTA_TIMESTAMP_64_UTC 0x0110
-#define ARISTA_TIMESTAMP_48_TAI 0x0020
-#define ARISTA_TIMESTAMP_48_UTC 0x0120
+static const struct tok ts_timescale_str[] = {
+       { 0, "TAI" },
+       { 1, "UTC" },
+       { 0, NULL }
+};
 
-static const struct tok ts_version_name[] = {
-       { ARISTA_TIMESTAMP_64_TAI, "TAI(64-bit)" },
-       { ARISTA_TIMESTAMP_64_UTC, "UTC(64-bit)" },
-       { ARISTA_TIMESTAMP_48_TAI, "TAI(48-bit)" },
-       { ARISTA_TIMESTAMP_48_UTC, "UTC(48-bit)" },
+#define FORMAT_64BIT 0x1
+#define FORMAT_48BIT 0x2
+static const struct tok ts_format_str[] = {
+       { FORMAT_64BIT, "64-bit" },
+       { FORMAT_48BIT, "48-bit" },
+       { 0, NULL }
+};
+
+static const struct tok hw_info_str[] = {
+       { 0, "R/R2" },
+       { 1, "R3" },
        { 0, NULL }
 };
 
 static inline void
-arista_print_date_hms_time(netdissect_options *ndo, uint32_t seconds,
-               uint32_t nanoseconds)
+arista_print_date_hms_time(netdissect_options *ndo, const uint32_t seconds,
+               const uint32_t nanoseconds)
 {
-       time_t ts;
-       struct tm *tm;
-       char buf[BUFSIZE];
-
-       ts = seconds + (nanoseconds / 1000000000);
-       if (NULL == (tm = gmtime(&ts)))
-               ND_PRINT(": gmtime() error");
-       else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm))
-               ND_PRINT(": strftime() error");
-       else
-               ND_PRINT(": %s, %09u ns, ", buf, nanoseconds);
+       const time_t ts = seconds;
+       char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss")];
+
+       ND_PRINT("%s.%09u",
+           nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
+              gmtime(&ts)), nanoseconds);
+       if (nanoseconds > ND_NANO_PER_SEC - 1)
+               ND_PRINT(" " ND_INVALID_NANO_SEC_STR);
 }
 
 int
 arista_ethertype_print(netdissect_options *ndo, const u_char *bp, u_int len _U_)
 {
        uint16_t subTypeId;
-       uint16_t version;
        u_short bytesConsumed = 0;
-       u_short size = 0;
-       uint32_t seconds, nanoseconds;
 
        ndo->ndo_protocol = "arista";
 
        subTypeId = GET_BE_U_2(bp);
        bp += 2;
-       version = GET_BE_U_2(bp);
-       bp += 2;
-       bytesConsumed += 4;
+       bytesConsumed += 2;
 
-       ND_PRINT("SubType: 0x%1x, Version: 0x%04x, ", subTypeId, version);
+       ND_PRINT("SubType %s (0x%04x), ",
+                tok2str(subtype_str, "Unknown", subTypeId),
+                subTypeId);
 
        // TapAgg Header Timestamping
        if (subTypeId == ARISTA_SUBTYPE_TIMESTAMP) {
+               uint32_t seconds;
+               uint32_t nanoseconds;
+               uint8_t ts_timescale = GET_U_1(bp);
+               bp += 1;
+               bytesConsumed += 1;
+               ND_PRINT("Timescale %s (%u), ",
+                        tok2str(ts_timescale_str, "Unknown", ts_timescale),
+                        ts_timescale);
+
+               uint8_t ts_format = GET_U_1(bp) >> 4;
+               uint8_t hw_info = GET_U_1(bp) & 0x0f;
+               bp += 1;
+               bytesConsumed += 1;
+
                // Timestamp has 32-bit lsb in nanosec and remaining msb in sec
-               ND_PRINT("Timestamp %s", tok2str(ts_version_name,
-                                       "Unknown timestamp Version 0x%04x ", version));
-               switch (version) {
-               case ARISTA_TIMESTAMP_64_TAI:
-               case ARISTA_TIMESTAMP_64_UTC:
+               ND_PRINT("Format %s (%u), HwInfo %s (%u), Timestamp ",
+                        tok2str(ts_format_str, "Unknown", ts_format),
+                        ts_format,
+                        tok2str(hw_info_str, "Unknown", hw_info),
+                        hw_info);
+               switch (ts_format) {
+               case FORMAT_64BIT:
                        seconds = GET_BE_U_4(bp);
                        nanoseconds = GET_BE_U_4(bp + 4);
                        arista_print_date_hms_time(ndo, seconds, nanoseconds);
-                       bytesConsumed += size + 8;
+                       bytesConsumed += 8;
                        break;
-               case ARISTA_TIMESTAMP_48_TAI:
-               case ARISTA_TIMESTAMP_48_UTC:
-                       ND_PRINT(": Seconds %u,", GET_BE_U_2(bp));
-                       ND_PRINT(" Nanoseconds %u, ", GET_BE_U_4(bp + 2));
-                       bytesConsumed += size + 6;
+               case FORMAT_48BIT:
+                       seconds = GET_BE_U_2(bp);
+                       nanoseconds = GET_BE_U_4(bp + 2);
+                       ND_PRINT("%u.%09u", seconds, nanoseconds);
+                       if (nanoseconds > ND_NANO_PER_SEC - 1)
+                               ND_PRINT(" " ND_INVALID_NANO_SEC_STR);
+                       bytesConsumed += 6;
                        break;
                default:
                        return -1;
@@ -90,5 +159,6 @@ arista_ethertype_print(netdissect_options *ndo, const u_char *bp, u_int len _U_)
        } else {
                return -1;
        }
+       ND_PRINT(": ");
        return bytesConsumed;
 }