]> The Tcpdump Group git mirrors - tcpdump/blob - print-arista.c
Arista: Refine the output format and print HwInfo.
[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
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 static inline void
89 arista_print_date_hms_time(netdissect_options *ndo, uint32_t seconds,
90 uint32_t nanoseconds)
91 {
92 time_t ts;
93 struct tm *tm;
94 char buf[BUFSIZE];
95
96 ts = seconds + (nanoseconds / 1000000000);
97 nanoseconds %= 1000000000;
98 if (NULL == (tm = gmtime(&ts)))
99 ND_PRINT("gmtime() error");
100 else if (0 == strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm))
101 ND_PRINT("strftime() error");
102 else
103 ND_PRINT("%s.%09u", buf, nanoseconds);
104 }
105
106 int
107 arista_ethertype_print(netdissect_options *ndo, const u_char *bp, u_int len _U_)
108 {
109 uint16_t subTypeId;
110 u_short bytesConsumed = 0;
111
112 ndo->ndo_protocol = "arista";
113
114 subTypeId = GET_BE_U_2(bp);
115 bp += 2;
116 bytesConsumed += 2;
117
118 ND_PRINT("SubType %s (0x%04x), ",
119 tok2str(subtype_str, "Unknown", subTypeId),
120 subTypeId);
121
122 // TapAgg Header Timestamping
123 if (subTypeId == ARISTA_SUBTYPE_TIMESTAMP) {
124 uint64_t seconds;
125 uint32_t nanoseconds;
126 uint8_t ts_timescale = GET_U_1(bp);
127 bp += 1;
128 bytesConsumed += 1;
129 ND_PRINT("Timescale %s (%u), ",
130 tok2str(ts_timescale_str, "Unknown", ts_timescale),
131 ts_timescale);
132
133 uint8_t ts_format = GET_U_1(bp) >> 4;
134 uint8_t hw_info = GET_U_1(bp) & 0x0f;
135 bp += 1;
136 bytesConsumed += 1;
137
138 // Timestamp has 32-bit lsb in nanosec and remaining msb in sec
139 ND_PRINT("Format %s (%u), HwInfo %s (%u), Timestamp ",
140 tok2str(ts_format_str, "Unknown", ts_format),
141 ts_format,
142 tok2str(hw_info_str, "Unknown", hw_info),
143 hw_info);
144 switch (ts_format) {
145 case FORMAT_64BIT:
146 seconds = GET_BE_U_4(bp);
147 nanoseconds = GET_BE_U_4(bp + 4);
148 arista_print_date_hms_time(ndo, seconds, nanoseconds);
149 bytesConsumed += 8;
150 break;
151 case FORMAT_48BIT:
152 seconds = GET_BE_U_2(bp);
153 nanoseconds = GET_BE_U_4(bp + 2);
154 seconds += nanoseconds / 1000000000;
155 nanoseconds %= 1000000000;
156 ND_PRINT("%" PRIu64 ".%09u", seconds, nanoseconds);
157 bytesConsumed += 6;
158 break;
159 default:
160 return -1;
161 }
162 } else {
163 return -1;
164 }
165 ND_PRINT(": ");
166 return bytesConsumed;
167 }