xref: /freebsd/contrib/tcpdump/print-arista.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
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