xref: /netbsd-src/external/bsd/tcpdump/dist/print-geneve.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
13d25ea14Schristos /*
23d25ea14Schristos  * Copyright (c) 2014 VMware, Inc. All Rights Reserved.
33d25ea14Schristos  *
43d25ea14Schristos  * Jesse Gross <jesse@nicira.com>
53d25ea14Schristos  *
63d25ea14Schristos  * Redistribution and use in source and binary forms, with or without
73d25ea14Schristos  * modification, are permitted provided that: (1) source code
83d25ea14Schristos  * distributions retain the above copyright notice and this paragraph
93d25ea14Schristos  * in its entirety, and (2) distributions including binary code include
103d25ea14Schristos  * the above copyright notice and this paragraph in its entirety in
113d25ea14Schristos  * the documentation or other materials provided with the distribution.
123d25ea14Schristos  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
133d25ea14Schristos  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
143d25ea14Schristos  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
153d25ea14Schristos  * FOR A PARTICULAR PURPOSE.
163d25ea14Schristos  */
173d25ea14Schristos 
18fdccd7e4Schristos #include <sys/cdefs.h>
19fdccd7e4Schristos #ifndef lint
20*26ba0b50Schristos __RCSID("$NetBSD: print-geneve.c,v 1.5 2024/09/02 16:15:31 christos Exp $");
21fdccd7e4Schristos #endif
22fdccd7e4Schristos 
23dc860a36Sspz /* \summary: Generic Network Virtualization Encapsulation (Geneve) printer */
24dc860a36Sspz 
25c74ad251Schristos #include <config.h>
263d25ea14Schristos 
27c74ad251Schristos #include "netdissect-stdinc.h"
283d25ea14Schristos 
29784088dfSchristos #include "netdissect.h"
303d25ea14Schristos #include "extract.h"
313d25ea14Schristos #include "ethertype.h"
323d25ea14Schristos 
333d25ea14Schristos /*
34784088dfSchristos  * Geneve header, draft-ietf-nvo3-geneve
353d25ea14Schristos  *
363d25ea14Schristos  *    0                   1                   2                   3
373d25ea14Schristos  *    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
383d25ea14Schristos  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
393d25ea14Schristos  *    |Ver|  Opt Len  |O|C|    Rsvd.  |          Protocol Type        |
403d25ea14Schristos  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
413d25ea14Schristos  *    |        Virtual Network Identifier (VNI)       |    Reserved   |
423d25ea14Schristos  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433d25ea14Schristos  *    |                    Variable Length Options                    |
443d25ea14Schristos  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
453d25ea14Schristos  *
463d25ea14Schristos  * Options:
473d25ea14Schristos  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
483d25ea14Schristos  *    |          Option Class         |      Type     |R|R|R| Length  |
493d25ea14Schristos  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
503d25ea14Schristos  *    |                      Variable Option Data                     |
513d25ea14Schristos  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
523d25ea14Schristos  */
533d25ea14Schristos 
543d25ea14Schristos #define VER_SHIFT 6
553d25ea14Schristos #define HDR_OPTS_LEN_MASK 0x3F
563d25ea14Schristos 
573d25ea14Schristos #define FLAG_OAM      (1 << 7)
583d25ea14Schristos #define FLAG_CRITICAL (1 << 6)
593d25ea14Schristos #define FLAG_R1       (1 << 5)
603d25ea14Schristos #define FLAG_R2       (1 << 4)
613d25ea14Schristos #define FLAG_R3       (1 << 3)
623d25ea14Schristos #define FLAG_R4       (1 << 2)
633d25ea14Schristos #define FLAG_R5       (1 << 1)
643d25ea14Schristos #define FLAG_R6       (1 << 0)
653d25ea14Schristos 
663d25ea14Schristos #define OPT_TYPE_CRITICAL (1 << 7)
673d25ea14Schristos #define OPT_LEN_MASK 0x1F
683d25ea14Schristos 
693d25ea14Schristos static const struct tok geneve_flag_values[] = {
703d25ea14Schristos         { FLAG_OAM, "O" },
713d25ea14Schristos         { FLAG_CRITICAL, "C" },
723d25ea14Schristos         { FLAG_R1, "R1" },
733d25ea14Schristos         { FLAG_R2, "R2" },
743d25ea14Schristos         { FLAG_R3, "R3" },
753d25ea14Schristos         { FLAG_R4, "R4" },
763d25ea14Schristos         { FLAG_R5, "R5" },
773d25ea14Schristos         { FLAG_R6, "R6" },
783d25ea14Schristos         { 0, NULL }
793d25ea14Schristos };
803d25ea14Schristos 
813d25ea14Schristos static const char *
823d25ea14Schristos format_opt_class(uint16_t opt_class)
833d25ea14Schristos {
84784088dfSchristos     switch (opt_class) {
85784088dfSchristos     case 0x0100:
86784088dfSchristos         return "Linux";
87784088dfSchristos     case 0x0101:
88784088dfSchristos         return "Open vSwitch";
89784088dfSchristos     case 0x0102:
90784088dfSchristos         return "Open Virtual Networking (OVN)";
91784088dfSchristos     case 0x0103:
92784088dfSchristos         return "In-band Network Telemetry (INT)";
93784088dfSchristos     case 0x0104:
94784088dfSchristos         return "VMware";
95784088dfSchristos     default:
96784088dfSchristos         if (opt_class <= 0x00ff)
973d25ea14Schristos             return "Standard";
98784088dfSchristos         else if (opt_class >= 0xfff0)
993d25ea14Schristos             return "Experimental";
100784088dfSchristos     }
101784088dfSchristos 
1023d25ea14Schristos     return "Unknown";
1033d25ea14Schristos }
1043d25ea14Schristos 
1053d25ea14Schristos static void
1063d25ea14Schristos geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len)
1073d25ea14Schristos {
1083d25ea14Schristos     const char *sep = "";
1093d25ea14Schristos 
1103d25ea14Schristos     while (len > 0) {
1113d25ea14Schristos         uint16_t opt_class;
1123d25ea14Schristos         uint8_t opt_type;
1133d25ea14Schristos         uint8_t opt_len;
1143d25ea14Schristos 
115c74ad251Schristos         ND_PRINT("%s", sep);
1163d25ea14Schristos         sep = ", ";
1173d25ea14Schristos 
118c74ad251Schristos         opt_class = GET_BE_U_2(bp);
119c74ad251Schristos         opt_type = GET_U_1(bp + 2);
120c74ad251Schristos         opt_len = 4 + ((GET_U_1(bp + 3) & OPT_LEN_MASK) * 4);
1213d25ea14Schristos 
122c74ad251Schristos         ND_PRINT("class %s (0x%x) type 0x%x%s len %u",
1233d25ea14Schristos                   format_opt_class(opt_class), opt_class, opt_type,
124c74ad251Schristos                   opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len);
1253d25ea14Schristos 
1263d25ea14Schristos         if (opt_len > len) {
127c74ad251Schristos             ND_PRINT(" [bad length]");
1283d25ea14Schristos             return;
1293d25ea14Schristos         }
1303d25ea14Schristos 
1313d25ea14Schristos         if (ndo->ndo_vflag > 1 && opt_len > 4) {
132784088dfSchristos             const uint32_t *data = (const uint32_t *)(bp + 4);
1333d25ea14Schristos             int i;
1343d25ea14Schristos 
135c74ad251Schristos             ND_PRINT(" data");
1363d25ea14Schristos 
1373d25ea14Schristos             for (i = 4; i < opt_len; i += 4) {
138c74ad251Schristos                 ND_PRINT(" %08x", GET_BE_U_4(data));
139784088dfSchristos                 data++;
1403d25ea14Schristos             }
1413d25ea14Schristos         }
1423d25ea14Schristos 
1433d25ea14Schristos         bp += opt_len;
1443d25ea14Schristos         len -= opt_len;
1453d25ea14Schristos     }
1463d25ea14Schristos }
1473d25ea14Schristos 
1483d25ea14Schristos void
1493d25ea14Schristos geneve_print(netdissect_options *ndo, const u_char *bp, u_int len)
1503d25ea14Schristos {
1513d25ea14Schristos     uint8_t ver_opt;
152784088dfSchristos     u_int version;
1533d25ea14Schristos     uint8_t flags;
1543d25ea14Schristos     uint16_t prot;
1553d25ea14Schristos     uint32_t vni;
1563d25ea14Schristos     uint8_t reserved;
1573d25ea14Schristos     u_int opts_len;
1583d25ea14Schristos 
159c74ad251Schristos     ndo->ndo_protocol = "geneve";
160c74ad251Schristos     ND_PRINT("Geneve");
1613d25ea14Schristos 
162c74ad251Schristos     if (len < 8) {
163c74ad251Schristos         ND_PRINT(" [length %u < 8]", len);
164c74ad251Schristos         nd_print_invalid(ndo);
165c74ad251Schristos         return;
166c74ad251Schristos     }
1673d25ea14Schristos 
168c74ad251Schristos     ND_TCHECK_8(bp);
169c74ad251Schristos 
170c74ad251Schristos     ver_opt = GET_U_1(bp);
1713d25ea14Schristos     bp += 1;
1723d25ea14Schristos     len -= 1;
1733d25ea14Schristos 
1743d25ea14Schristos     version = ver_opt >> VER_SHIFT;
1753d25ea14Schristos     if (version != 0) {
176c74ad251Schristos         ND_PRINT(" ERROR: unknown-version %u", version);
1773d25ea14Schristos         return;
1783d25ea14Schristos     }
1793d25ea14Schristos 
180c74ad251Schristos     flags = GET_U_1(bp);
1813d25ea14Schristos     bp += 1;
1823d25ea14Schristos     len -= 1;
1833d25ea14Schristos 
184c74ad251Schristos     prot = GET_BE_U_2(bp);
1853d25ea14Schristos     bp += 2;
1863d25ea14Schristos     len -= 2;
1873d25ea14Schristos 
188c74ad251Schristos     vni = GET_BE_U_3(bp);
1893d25ea14Schristos     bp += 3;
1903d25ea14Schristos     len -= 3;
1913d25ea14Schristos 
192c74ad251Schristos     reserved = GET_U_1(bp);
1933d25ea14Schristos     bp += 1;
1943d25ea14Schristos     len -= 1;
1953d25ea14Schristos 
196c74ad251Schristos     ND_PRINT(", Flags [%s]",
197c74ad251Schristos               bittok2str_nosep(geneve_flag_values, "none", flags));
198c74ad251Schristos     ND_PRINT(", vni 0x%x", vni);
1993d25ea14Schristos 
2003d25ea14Schristos     if (reserved)
201c74ad251Schristos         ND_PRINT(", rsvd 0x%x", reserved);
2023d25ea14Schristos 
2033d25ea14Schristos     if (ndo->ndo_eflag)
204c74ad251Schristos         ND_PRINT(", proto %s (0x%04x)",
205c74ad251Schristos                   tok2str(ethertype_values, "unknown", prot), prot);
2063d25ea14Schristos 
2073d25ea14Schristos     opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4;
2083d25ea14Schristos 
2093d25ea14Schristos     if (len < opts_len) {
210c74ad251Schristos         ND_PRINT(" truncated-geneve - %u bytes missing",
211c74ad251Schristos                   opts_len - len);
2123d25ea14Schristos         return;
2133d25ea14Schristos     }
2143d25ea14Schristos 
215c74ad251Schristos     ND_TCHECK_LEN(bp, opts_len);
2163d25ea14Schristos 
2173d25ea14Schristos     if (opts_len > 0) {
218c74ad251Schristos         ND_PRINT(", options [");
2193d25ea14Schristos 
2203d25ea14Schristos         if (ndo->ndo_vflag)
2213d25ea14Schristos             geneve_opts_print(ndo, bp, opts_len);
2223d25ea14Schristos         else
223c74ad251Schristos             ND_PRINT("%u bytes", opts_len);
2243d25ea14Schristos 
225c74ad251Schristos         ND_PRINT("]");
2263d25ea14Schristos     }
2273d25ea14Schristos 
2283d25ea14Schristos     bp += opts_len;
2293d25ea14Schristos     len -= opts_len;
2303d25ea14Schristos 
2313d25ea14Schristos     if (ndo->ndo_vflag < 1)
232c74ad251Schristos         ND_PRINT(": ");
2333d25ea14Schristos     else
234c74ad251Schristos         ND_PRINT("\n\t");
2353d25ea14Schristos 
236c74ad251Schristos     if (ethertype_print(ndo, prot, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL) == 0) {
2373d25ea14Schristos         if (prot == ETHERTYPE_TEB)
238c74ad251Schristos             ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
2393d25ea14Schristos         else
240c74ad251Schristos             ND_PRINT("geneve-proto-0x%x", prot);
2413d25ea14Schristos     }
2423d25ea14Schristos 
2433d25ea14Schristos     return;
2443d25ea14Schristos 
2453d25ea14Schristos trunc:
246c74ad251Schristos     nd_print_trunc(ndo);
2473d25ea14Schristos }
248