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 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 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