Home | History | Annotate | Line # | Download | only in dist
      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