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