]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-arista.c
zfs: merge openzfs/zfs@8a7407012
[FreeBSD/FreeBSD.git] / contrib / 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 }