*/
/* \summary: Generic Network Virtualization Encapsulation (Geneve) printer */
+/* specification: RFC 8926 */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include <config.h>
-#include <netdissect-stdinc.h>
+#include "netdissect-stdinc.h"
+#define ND_LONGJMP_FROM_TCHECK
#include "netdissect.h"
#include "extract.h"
#include "ethertype.h"
/*
- * Geneve header, draft-ietf-nvo3-geneve
+ * Geneve header:
*
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Virtual Network Identifier (VNI) | Reserved |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Variable Length Options |
+ * | |
+ * ~ Variable-Length Options ~
+ * | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Options:
+ * 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Option Class | Type |R|R|R| Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | Variable Option Data |
+ * | |
+ * ~ Variable-Length Option Data ~
+ * | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
};
static const char *
-format_opt_class(uint16_t opt_class)
+format_opt_class(const uint16_t opt_class)
{
switch (opt_class) {
case 0x0100:
return "In-band Network Telemetry (INT)";
case 0x0104:
return "VMware";
+ case 0x0105:
+ case 0x0108:
+ case 0x0109:
+ case 0x010A:
+ case 0x010B:
+ case 0x010C:
+ case 0x010D:
+ case 0x010E:
+ case 0x010F:
+ case 0x0110:
+ return "Amazon";
+ case 0x0106:
+ case 0x0130:
+ case 0x0131:
+ return "Cisco";
+ case 0x0107:
+ return "Oracle";
+ case 0x0111:
+ case 0x0112:
+ case 0x0113:
+ case 0x0114:
+ case 0x0115:
+ case 0x0116:
+ case 0x0117:
+ case 0x0118:
+ return "IBM";
+ case 0x0119:
+ case 0x011A:
+ case 0x011B:
+ case 0x011C:
+ case 0x011D:
+ case 0x011E:
+ case 0x011F:
+ case 0x0120:
+ case 0x0121:
+ case 0x0122:
+ case 0x0123:
+ case 0x0124:
+ case 0x0125:
+ case 0x0126:
+ case 0x0127:
+ case 0x0128:
+ return "Ericsson";
+ case 0x0129:
+ return "Oxide";
+ case 0x0132:
+ case 0x0133:
+ case 0x0134:
+ case 0x0135:
+ return "Google";
+ case 0x0136:
+ return "InfoQuick";
default:
if (opt_class <= 0x00ff)
return "Standard";
return "Unknown";
}
-static void
+static unsigned
geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len)
{
const char *sep = "";
- while (len > 0) {
+ while (len != 0) {
uint16_t opt_class;
uint8_t opt_type;
uint8_t opt_len;
- ND_PRINT((ndo, "%s", sep));
+ ND_ICHECKMSG_U("remaining options length", len, <, 4);
+ ND_PRINT("%s", sep);
sep = ", ";
- opt_class = EXTRACT_BE_U_2(bp);
- opt_type = EXTRACT_U_1(bp + 2);
- opt_len = 4 + ((EXTRACT_U_1(bp + 3) & OPT_LEN_MASK) * 4);
+ opt_class = GET_BE_U_2(bp);
+ opt_type = GET_U_1(bp + 2);
+ opt_len = 4 + ((GET_U_1(bp + 3) & OPT_LEN_MASK) * 4);
- ND_PRINT((ndo, "class %s (0x%x) type 0x%x%s len %u",
+ ND_PRINT("class %s (0x%x) type 0x%x%s len %u",
format_opt_class(opt_class), opt_class, opt_type,
- opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len));
+ opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len);
if (opt_len > len) {
- ND_PRINT((ndo, " [bad length]"));
- return;
+ ND_PRINT(" [bad length]");
+ goto invalid;
}
if (ndo->ndo_vflag > 1 && opt_len > 4) {
const uint32_t *data = (const uint32_t *)(bp + 4);
int i;
- ND_PRINT((ndo, " data"));
+ ND_PRINT(" data");
for (i = 4; i < opt_len; i += 4) {
- ND_PRINT((ndo, " %08x", EXTRACT_BE_U_4(data)));
+ ND_PRINT(" %08x", GET_BE_U_4(data));
data++;
}
- }
+ } else
+ ND_TCHECK_LEN(bp, opt_len);
bp += opt_len;
len -= opt_len;
}
+ return 1;
+invalid:
+ ND_TCHECK_LEN(bp, len);
+ return 0;
}
void
uint8_t reserved;
u_int opts_len;
- ND_PRINT((ndo, "Geneve"));
+ ndo->ndo_protocol = "geneve";
+ ND_PRINT("Geneve");
- ND_TCHECK_8(bp);
+ ND_ICHECK_U(len, <, 8);
- ver_opt = EXTRACT_U_1(bp);
+ ver_opt = GET_U_1(bp);
bp += 1;
len -= 1;
version = ver_opt >> VER_SHIFT;
if (version != 0) {
- ND_PRINT((ndo, " ERROR: unknown-version %u", version));
- return;
+ ND_PRINT(" ERROR: unknown-version %u", version);
+ goto invalid;
}
- flags = EXTRACT_U_1(bp);
+ flags = GET_U_1(bp);
bp += 1;
len -= 1;
- prot = EXTRACT_BE_U_2(bp);
+ prot = GET_BE_U_2(bp);
bp += 2;
len -= 2;
- vni = EXTRACT_BE_U_3(bp);
+ vni = GET_BE_U_3(bp);
bp += 3;
len -= 3;
- reserved = EXTRACT_U_1(bp);
+ reserved = GET_U_1(bp);
bp += 1;
len -= 1;
- ND_PRINT((ndo, ", Flags [%s]",
- bittok2str_nosep(geneve_flag_values, "none", flags)));
- ND_PRINT((ndo, ", vni 0x%x", vni));
+ ND_PRINT(", Flags [%s]",
+ bittok2str_nosep(geneve_flag_values, "none", flags));
+ ND_PRINT(", vni 0x%x", vni);
if (reserved)
- ND_PRINT((ndo, ", rsvd 0x%x", reserved));
+ ND_PRINT(", rsvd 0x%x", reserved);
if (ndo->ndo_eflag)
- ND_PRINT((ndo, ", proto %s (0x%04x)",
- tok2str(ethertype_values, "unknown", prot), prot));
+ ND_PRINT(", proto %s (0x%04x)",
+ tok2str(ethertype_values, "unknown", prot), prot);
opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4;
if (len < opts_len) {
- ND_PRINT((ndo, " truncated-geneve - %u bytes missing",
- opts_len - len));
- return;
+ ND_PRINT(" (opts_len %u > %u", opts_len, len);
+ goto invalid;
}
- ND_TCHECK_LEN(bp, opts_len);
-
if (opts_len > 0) {
- ND_PRINT((ndo, ", options ["));
-
- if (ndo->ndo_vflag)
- geneve_opts_print(ndo, bp, opts_len);
- else
- ND_PRINT((ndo, "%u bytes", opts_len));
+ ND_PRINT(", options [");
+
+ if (ndo->ndo_vflag) {
+ if (! geneve_opts_print(ndo, bp, opts_len))
+ goto invalid;
+ } else {
+ ND_TCHECK_LEN(bp, opts_len);
+ ND_PRINT("%u bytes", opts_len);
+ }
- ND_PRINT((ndo, "]"));
+ ND_PRINT("]");
}
bp += opts_len;
len -= opts_len;
if (ndo->ndo_vflag < 1)
- ND_PRINT((ndo, ": "));
+ ND_PRINT(": ");
else
- ND_PRINT((ndo, "\n\t"));
+ ND_PRINT("\n\t");
- if (ethertype_print(ndo, prot, bp, len, ndo->ndo_snapend - bp, NULL, NULL) == 0) {
+ if (ethertype_print(ndo, prot, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL) == 0) {
if (prot == ETHERTYPE_TEB)
- ether_print(ndo, bp, len, ndo->ndo_snapend - bp, NULL, NULL);
- else
- ND_PRINT((ndo, "geneve-proto-0x%x", prot));
+ ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
+ else {
+ ND_PRINT("geneve-proto-0x%x", prot);
+ ND_TCHECK_LEN(bp, len);
+ }
}
return;
-trunc:
- ND_PRINT((ndo, " [|geneve]"));
+invalid:
+ nd_print_invalid(ndo);
}