]> The Tcpdump Group git mirrors - tcpdump/blob - print-arista.c
CONTRIBUTION: mention the nd_ types.
[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 static inline void
91 arista_print_date_hms_time(netdissect_options *ndo, uint32_t seconds,
92 uint32_t nanoseconds)
93 {
94 time_t ts;
95 char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss")];
96
97 ts = seconds + (nanoseconds / 1000000000);
98 nanoseconds %= 1000000000;
99 ND_PRINT("%s.%09u",
100 nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
101 gmtime(&ts)), nanoseconds);
102 }
103
104 int
105 arista_ethertype_print(netdissect_options *ndo, const u_char *bp, u_int len _U_)
106 {
107 uint16_t subTypeId;
108 u_short bytesConsumed = 0;
109
110 ndo->ndo_protocol = "arista";
111
112 subTypeId = GET_BE_U_2(bp);
113 bp += 2;
114 bytesConsumed += 2;
115
116 ND_PRINT("SubType %s (0x%04x), ",
117 tok2str(subtype_str, "Unknown", subTypeId),
118 subTypeId);
119
120 // TapAgg Header Timestamping
121 if (subTypeId == ARISTA_SUBTYPE_TIMESTAMP) {
122 uint64_t seconds;
123 uint32_t nanoseconds;
124 uint8_t ts_timescale = GET_U_1(bp);
125 bp += 1;
126 bytesConsumed += 1;
127 ND_PRINT("Timescale %s (%u), ",
128 tok2str(ts_timescale_str, "Unknown", ts_timescale),
129 ts_timescale);
130
131 uint8_t ts_format = GET_U_1(bp) >> 4;
132 uint8_t hw_info = GET_U_1(bp) & 0x0f;
133 bp += 1;
134 bytesConsumed += 1;
135
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),
139 ts_format,
140 tok2str(hw_info_str, "Unknown", hw_info),
141 hw_info);
142 switch (ts_format) {
143 case FORMAT_64BIT:
144 seconds = GET_BE_U_4(bp);
145 nanoseconds = GET_BE_U_4(bp + 4);
146 arista_print_date_hms_time(ndo, seconds, nanoseconds);
147 bytesConsumed += 8;
148 break;
149 case FORMAT_48BIT:
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);
155 bytesConsumed += 6;
156 break;
157 default:
158 return -1;
159 }
160 } else {
161 return -1;
162 }
163 ND_PRINT(": ");
164 return bytesConsumed;
165 }