X-Git-Url: https://git.tcpdump.org/tcpdump/blobdiff_plain/4aac37f04316b37b73b99bdcdbfa97347bb2fe51..refs/heads/master:/print-arista.c diff --git a/print-arista.c b/print-arista.c index e4c761b3..0ec04889 100644 --- a/print-arista.c +++ b/print-arista.c @@ -2,87 +2,156 @@ /* \summary: EtherType protocol for Arista Networks printer */ -#ifdef HAVE_CONFIG_H #include -#endif #include "netdissect-stdinc.h" -#include - #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; }