1 // Copyright (c) 2018 Arista Networks, Inc. All rights reserved.
3 /* \summary: EtherType protocol for Arista Networks printer */
9 #include "netdissect-stdinc.h"
11 #include "netdissect.h"
18 The Arista timestamp header consists of the following fields:
19 1. The Arista ethertype (0xd28b)
20 2. A 2-byte subtype field; 0x01 indicates the timestamp header
21 3. A 2-byte version field, described below.
22 4. A 48-bit or 64-bit timestamp field, depending on the contents of the version field
24 This header is then followed by the original ethertype and the remainder of the original packet.
27 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
28 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
34 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 | ethertype 0xd28b | subtype 0x1 |
36 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
40 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 The two-byte version value is split into 3 fields:
43 1. The timescale in use. Currently assigned values include:
46 2. The timestamp format and length. Currently assigned values include:
54 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
55 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 | timescale | format|hw info|
57 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60 See also: https://www.arista.com/assets/data/pdf/Whitepapers/Overview_Arista_Timestamps.pdf
64 #define ARISTA_SUBTYPE_TIMESTAMP 0x0001
65 static const struct tok subtype_str[] = {
66 { ARISTA_SUBTYPE_TIMESTAMP, "Timestamp" },
70 static const struct tok ts_timescale_str[] = {
76 #define FORMAT_64BIT 0x1
77 #define FORMAT_48BIT 0x2
78 static const struct tok ts_format_str[] = {
79 { FORMAT_64BIT, "64-bit" },
80 { FORMAT_48BIT, "48-bit" },
84 static const struct tok hw_info_str[] = {
91 arista_print_date_hms_time(netdissect_options *ndo, uint32_t seconds,
95 char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss")];
97 ts = seconds + (nanoseconds / 1000000000);
98 nanoseconds %= 1000000000;
100 nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
101 gmtime(&ts)), nanoseconds);
105 arista_ethertype_print(netdissect_options *ndo, const u_char *bp, u_int len _U_)
108 u_short bytesConsumed = 0;
110 ndo->ndo_protocol = "arista";
112 subTypeId = GET_BE_U_2(bp);
116 ND_PRINT("SubType %s (0x%04x), ",
117 tok2str(subtype_str, "Unknown", subTypeId),
120 // TapAgg Header Timestamping
121 if (subTypeId == ARISTA_SUBTYPE_TIMESTAMP) {
123 uint32_t nanoseconds;
124 uint8_t ts_timescale = GET_U_1(bp);
127 ND_PRINT("Timescale %s (%u), ",
128 tok2str(ts_timescale_str, "Unknown", ts_timescale),
131 uint8_t ts_format = GET_U_1(bp) >> 4;
132 uint8_t hw_info = GET_U_1(bp) & 0x0f;
136 // Timestamp has 32-bit lsb in nanosec and remaining msb in sec
137 ND_PRINT("Format %s (%u), HwInfo %s (%u), Timestamp ",
138 tok2str(ts_format_str, "Unknown", ts_format),
140 tok2str(hw_info_str, "Unknown", hw_info),
144 seconds = GET_BE_U_4(bp);
145 nanoseconds = GET_BE_U_4(bp + 4);
146 arista_print_date_hms_time(ndo, seconds, nanoseconds);
150 seconds = GET_BE_U_2(bp);
151 nanoseconds = GET_BE_U_4(bp + 2);
152 seconds += nanoseconds / 1000000000;
153 nanoseconds %= 1000000000;
154 ND_PRINT("%" PRIu64 ".%09u", seconds, nanoseconds);
164 return bytesConsumed;