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