]> The Tcpdump Group git mirrors - tcpdump/blob - print-arista.c
63bf9dd80d0d8b73321a7fab6ad46c7fe00f69e3
[tcpdump] / print-arista.c
1 // Copyright (c) 2018 Arista Networks, Inc. All rights reserved.
2
3 /* \summary: EtherType protocol for Arista Networks printer */
4
5 #ifdef HAVE_CONFIG_H
6 #include <config.h>
7 #endif
8
9 #include "netdissect-stdinc.h"
10
11 #include "netdissect.h"
12 #include "extract.h"
13
14 /*
15
16 From Bill Fenner:
17
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
23
24 This header is then followed by the original ethertype and the remainder of the original packet.
25
26 0 1 2 3
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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29 | dst mac |
30 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31 | | |
32 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
33 | src mac |
34 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 | ethertype 0xd28b | subtype 0x1 |
36 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 | version | |
38 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
39 | timestamp... |
40 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41
42 The two-byte version value is split into 3 fields:
43 1. The timescale in use. Currently assigned values include:
44 0 = TAI
45 1 = UTC
46 2. The timestamp format and length. Currently assigned values include:
47 1 = 64-bit timestamp
48 2 = 48-bit timestamp
49 3. The hardware info
50 0 = R/R2 series
51 1 = R3 series
52
53 0 1
54 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
55 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 | timescale | format|hw info|
57 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58
59
60 See also: https://www.arista.com/assets/data/pdf/Whitepapers/Overview_Arista_Timestamps.pdf
61
62 */
63
64 #define ARISTA_SUBTYPE_TIMESTAMP 0x0001
65 static const struct tok subtype_str[] = {
66 { ARISTA_SUBTYPE_TIMESTAMP, "Timestamp" },
67 { 0, NULL }
68 };
69
70 static const struct tok ts_timescale_str[] = {
71 { 0, "TAI" },
72 { 1, "UTC" },
73 { 0, NULL }
74 };
75
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" },
81 { 0, NULL }
82 };
83
84 static const struct tok hw_info_str[] = {
85 { 0, "R/R2" },
86 { 1, "R3" },
87 { 0, NULL }
88 };
89
90 #define MAX_VALID_NS 999999999U
91 #define BOGUS_NS_STR "(bogus ns!)"
92
93 static inline void
94 arista_print_date_hms_time(netdissect_options *ndo, const uint32_t seconds,
95 const uint32_t nanoseconds)
96 {
97 const time_t ts = seconds;
98 char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss")];
99
100 ND_PRINT("%s.%09u",
101 nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
102 gmtime(&ts)), nanoseconds);
103 if (nanoseconds > MAX_VALID_NS)
104 ND_PRINT(" " BOGUS_NS_STR);
105 }
106
107 int
108 arista_ethertype_print(netdissect_options *ndo, const u_char *bp, u_int len _U_)
109 {
110 uint16_t subTypeId;
111 u_short bytesConsumed = 0;
112
113 ndo->ndo_protocol = "arista";
114
115 subTypeId = GET_BE_U_2(bp);
116 bp += 2;
117 bytesConsumed += 2;
118
119 ND_PRINT("SubType %s (0x%04x), ",
120 tok2str(subtype_str, "Unknown", subTypeId),
121 subTypeId);
122
123 // TapAgg Header Timestamping
124 if (subTypeId == ARISTA_SUBTYPE_TIMESTAMP) {
125 uint32_t seconds;
126 uint32_t nanoseconds;
127 uint8_t ts_timescale = GET_U_1(bp);
128 bp += 1;
129 bytesConsumed += 1;
130 ND_PRINT("Timescale %s (%u), ",
131 tok2str(ts_timescale_str, "Unknown", ts_timescale),
132 ts_timescale);
133
134 uint8_t ts_format = GET_U_1(bp) >> 4;
135 uint8_t hw_info = GET_U_1(bp) & 0x0f;
136 bp += 1;
137 bytesConsumed += 1;
138
139 // Timestamp has 32-bit lsb in nanosec and remaining msb in sec
140 ND_PRINT("Format %s (%u), HwInfo %s (%u), Timestamp ",
141 tok2str(ts_format_str, "Unknown", ts_format),
142 ts_format,
143 tok2str(hw_info_str, "Unknown", hw_info),
144 hw_info);
145 switch (ts_format) {
146 case FORMAT_64BIT:
147 seconds = GET_BE_U_4(bp);
148 nanoseconds = GET_BE_U_4(bp + 4);
149 arista_print_date_hms_time(ndo, seconds, nanoseconds);
150 bytesConsumed += 8;
151 break;
152 case FORMAT_48BIT:
153 seconds = GET_BE_U_2(bp);
154 nanoseconds = GET_BE_U_4(bp + 2);
155 ND_PRINT("%u.%09u", seconds, nanoseconds);
156 if (nanoseconds > MAX_VALID_NS)
157 ND_PRINT(" " BOGUS_NS_STR);
158 bytesConsumed += 6;
159 break;
160 default:
161 return -1;
162 }
163 } else {
164 return -1;
165 }
166 ND_PRINT(": ");
167 return bytesConsumed;
168 }