2019-05-18 21:18:30 +08:00
|
|
|
// Copyright (c) 2018 Arista Networks, Inc. All rights reserved.
|
|
|
|
|
2019-05-23 17:20:16 +08:00
|
|
|
/* \summary: EtherType protocol for Arista Networks printer */
|
|
|
|
|
2020-04-26 07:48:36 +08:00
|
|
|
#include <config.h>
|
2019-05-18 21:18:30 +08:00
|
|
|
|
2019-09-02 18:08:23 +08:00
|
|
|
#include "netdissect-stdinc.h"
|
2019-05-18 21:18:30 +08:00
|
|
|
|
|
|
|
#include "netdissect.h"
|
|
|
|
#include "extract.h"
|
|
|
|
|
2022-04-14 22:49:11 +08:00
|
|
|
/*
|
|
|
|
|
|
|
|
From Bill Fenner:
|
|
|
|
|
|
|
|
The Arista timestamp header consists of the following fields:
|
|
|
|
1. The Arista ethertype (0xd28b)
|
|
|
|
2. A 2-byte subtype field; 0x01 indicates the timestamp header
|
|
|
|
3. A 2-byte version field, described below.
|
|
|
|
4. A 48-bit or 64-bit timestamp field, depending on the contents of the version field
|
|
|
|
|
|
|
|
This header is then followed by the original ethertype and the remainder of the original packet.
|
|
|
|
|
|
|
|
0 1 2 3
|
|
|
|
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
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
| dst mac |
|
|
|
|
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
| | |
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
|
|
|
|
| src mac |
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
| ethertype 0xd28b | subtype 0x1 |
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
| version | |
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
|
|
|
|
| timestamp... |
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
|
|
|
|
The two-byte version value is split into 3 fields:
|
|
|
|
1. The timescale in use. Currently assigned values include:
|
|
|
|
0 = TAI
|
|
|
|
1 = UTC
|
|
|
|
2. The timestamp format and length. Currently assigned values include:
|
|
|
|
1 = 64-bit timestamp
|
|
|
|
2 = 48-bit timestamp
|
|
|
|
3. The hardware info
|
|
|
|
0 = R/R2 series
|
|
|
|
1 = R3 series
|
|
|
|
|
|
|
|
0 1
|
|
|
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
| timescale | format|hw info|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
|
2022-06-22 05:48:26 +08:00
|
|
|
|
|
|
|
See also: https://www.arista.com/assets/data/pdf/Whitepapers/Overview_Arista_Timestamps.pdf
|
|
|
|
|
2022-04-14 22:49:11 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#define ARISTA_SUBTYPE_TIMESTAMP 0x0001
|
|
|
|
static const struct tok subtype_str[] = {
|
|
|
|
{ ARISTA_SUBTYPE_TIMESTAMP, "Timestamp" },
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct tok ts_timescale_str[] = {
|
|
|
|
{ 0, "TAI" },
|
|
|
|
{ 1, "UTC" },
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
#define FORMAT_64BIT 0x1
|
|
|
|
#define FORMAT_48BIT 0x2
|
|
|
|
static const struct tok ts_format_str[] = {
|
|
|
|
{ FORMAT_64BIT, "64-bit" },
|
|
|
|
{ FORMAT_48BIT, "48-bit" },
|
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct tok hw_info_str[] = {
|
|
|
|
{ 0, "R/R2" },
|
|
|
|
{ 1, "R3" },
|
2019-06-21 13:54:58 +08:00
|
|
|
{ 0, NULL }
|
|
|
|
};
|
|
|
|
|
2024-03-11 00:24:40 +08:00
|
|
|
#define MAX_VALID_NS 999999999U
|
|
|
|
#define BOGUS_NS_STR "(bogus ns!)"
|
|
|
|
|
2019-06-21 13:54:58 +08:00
|
|
|
static inline void
|
2024-03-11 00:24:40 +08:00
|
|
|
arista_print_date_hms_time(netdissect_options *ndo, const uint32_t seconds,
|
|
|
|
const uint32_t nanoseconds)
|
2019-06-21 13:54:58 +08:00
|
|
|
{
|
2024-03-11 00:24:40 +08:00
|
|
|
const time_t ts = seconds;
|
Have a common routine for converting dates and times to strings.
Have a routine that takes a buffer, a strftime format, and a struct tm *
as arguments, and:
* checks whether the struct tm * is null and, if so, returns a string
indicating that the date and time couldn't be converted;
* otherwise, passes it to strftime(), along with the buffer and the
format argument and, if strftime() returns 0, meaning the string didn't
fit into the buffer and thus that the buffer's contents are undefined,
returns a string indicating that the date and time didn't fit into the
buffer;
* otherwise, returns a pointer to the buffer.
Call that routine instead of directly calling strftime() in printers;
that prevents printing a buffer with undefined data if the buffer isn't
big enough for the string.
Also, when generating file names using an strftime format, check the
return value of strftime() to make sure the buffer didn't overflow.
2023-01-31 15:03:16 +08:00
|
|
|
char buf[sizeof("-yyyyyyyyyy-mm-dd hh:mm:ss")];
|
2019-06-21 13:54:58 +08:00
|
|
|
|
Have a common routine for converting dates and times to strings.
Have a routine that takes a buffer, a strftime format, and a struct tm *
as arguments, and:
* checks whether the struct tm * is null and, if so, returns a string
indicating that the date and time couldn't be converted;
* otherwise, passes it to strftime(), along with the buffer and the
format argument and, if strftime() returns 0, meaning the string didn't
fit into the buffer and thus that the buffer's contents are undefined,
returns a string indicating that the date and time didn't fit into the
buffer;
* otherwise, returns a pointer to the buffer.
Call that routine instead of directly calling strftime() in printers;
that prevents printing a buffer with undefined data if the buffer isn't
big enough for the string.
Also, when generating file names using an strftime format, check the
return value of strftime() to make sure the buffer didn't overflow.
2023-01-31 15:03:16 +08:00
|
|
|
ND_PRINT("%s.%09u",
|
|
|
|
nd_format_time(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
|
|
|
|
gmtime(&ts)), nanoseconds);
|
2024-03-11 00:24:40 +08:00
|
|
|
if (nanoseconds > MAX_VALID_NS)
|
|
|
|
ND_PRINT(" " BOGUS_NS_STR);
|
2019-06-21 13:54:58 +08:00
|
|
|
}
|
2019-05-18 21:18:30 +08:00
|
|
|
|
|
|
|
int
|
2019-05-23 17:20:16 +08:00
|
|
|
arista_ethertype_print(netdissect_options *ndo, const u_char *bp, u_int len _U_)
|
2019-05-18 21:18:30 +08:00
|
|
|
{
|
|
|
|
uint16_t subTypeId;
|
|
|
|
u_short bytesConsumed = 0;
|
|
|
|
|
|
|
|
ndo->ndo_protocol = "arista";
|
|
|
|
|
|
|
|
subTypeId = GET_BE_U_2(bp);
|
|
|
|
bp += 2;
|
2022-04-14 22:49:11 +08:00
|
|
|
bytesConsumed += 2;
|
2019-05-18 21:18:30 +08:00
|
|
|
|
2022-04-14 22:49:11 +08:00
|
|
|
ND_PRINT("SubType %s (0x%04x), ",
|
|
|
|
tok2str(subtype_str, "Unknown", subTypeId),
|
|
|
|
subTypeId);
|
2019-05-18 21:18:30 +08:00
|
|
|
|
|
|
|
// TapAgg Header Timestamping
|
|
|
|
if (subTypeId == ARISTA_SUBTYPE_TIMESTAMP) {
|
2024-03-11 00:24:40 +08:00
|
|
|
uint32_t seconds;
|
2022-04-14 22:49:11 +08:00
|
|
|
uint32_t nanoseconds;
|
|
|
|
uint8_t ts_timescale = GET_U_1(bp);
|
|
|
|
bp += 1;
|
|
|
|
bytesConsumed += 1;
|
|
|
|
ND_PRINT("Timescale %s (%u), ",
|
|
|
|
tok2str(ts_timescale_str, "Unknown", ts_timescale),
|
|
|
|
ts_timescale);
|
|
|
|
|
|
|
|
uint8_t ts_format = GET_U_1(bp) >> 4;
|
|
|
|
uint8_t hw_info = GET_U_1(bp) & 0x0f;
|
|
|
|
bp += 1;
|
|
|
|
bytesConsumed += 1;
|
|
|
|
|
2019-05-18 21:18:30 +08:00
|
|
|
// Timestamp has 32-bit lsb in nanosec and remaining msb in sec
|
2022-04-14 22:49:11 +08:00
|
|
|
ND_PRINT("Format %s (%u), HwInfo %s (%u), Timestamp ",
|
|
|
|
tok2str(ts_format_str, "Unknown", ts_format),
|
|
|
|
ts_format,
|
|
|
|
tok2str(hw_info_str, "Unknown", hw_info),
|
|
|
|
hw_info);
|
|
|
|
switch (ts_format) {
|
|
|
|
case FORMAT_64BIT:
|
2019-06-21 13:54:58 +08:00
|
|
|
seconds = GET_BE_U_4(bp);
|
|
|
|
nanoseconds = GET_BE_U_4(bp + 4);
|
|
|
|
arista_print_date_hms_time(ndo, seconds, nanoseconds);
|
2022-04-14 22:49:11 +08:00
|
|
|
bytesConsumed += 8;
|
2019-05-18 21:18:30 +08:00
|
|
|
break;
|
2022-04-14 22:49:11 +08:00
|
|
|
case FORMAT_48BIT:
|
|
|
|
seconds = GET_BE_U_2(bp);
|
|
|
|
nanoseconds = GET_BE_U_4(bp + 2);
|
2024-03-11 00:24:40 +08:00
|
|
|
ND_PRINT("%u.%09u", seconds, nanoseconds);
|
|
|
|
if (nanoseconds > MAX_VALID_NS)
|
|
|
|
ND_PRINT(" " BOGUS_NS_STR);
|
2022-04-14 22:49:11 +08:00
|
|
|
bytesConsumed += 6;
|
2019-05-18 21:18:30 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
2022-04-14 22:49:11 +08:00
|
|
|
ND_PRINT(": ");
|
2019-05-18 21:18:30 +08:00
|
|
|
return bytesConsumed;
|
|
|
|
}
|