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