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