xref: /freebsd/contrib/tcpdump/print-geneve.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
18bdc5a62SPatrick Kelsey /*
28bdc5a62SPatrick Kelsey  * Copyright (c) 2014 VMware, Inc. All Rights Reserved.
38bdc5a62SPatrick Kelsey  *
48bdc5a62SPatrick Kelsey  * Jesse Gross <jesse@nicira.com>
58bdc5a62SPatrick Kelsey  *
68bdc5a62SPatrick Kelsey  * Redistribution and use in source and binary forms, with or without
78bdc5a62SPatrick Kelsey  * modification, are permitted provided that: (1) source code
88bdc5a62SPatrick Kelsey  * distributions retain the above copyright notice and this paragraph
98bdc5a62SPatrick Kelsey  * in its entirety, and (2) distributions including binary code include
108bdc5a62SPatrick Kelsey  * the above copyright notice and this paragraph in its entirety in
118bdc5a62SPatrick Kelsey  * the documentation or other materials provided with the distribution.
128bdc5a62SPatrick Kelsey  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
138bdc5a62SPatrick Kelsey  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
148bdc5a62SPatrick Kelsey  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
158bdc5a62SPatrick Kelsey  * FOR A PARTICULAR PURPOSE.
168bdc5a62SPatrick Kelsey  */
178bdc5a62SPatrick Kelsey 
183340d773SGleb Smirnoff /* \summary: Generic Network Virtualization Encapsulation (Geneve) printer */
193340d773SGleb Smirnoff 
20*ee67461eSJoseph Mingrone #include <config.h>
218bdc5a62SPatrick Kelsey 
22*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
238bdc5a62SPatrick Kelsey 
243340d773SGleb Smirnoff #include "netdissect.h"
258bdc5a62SPatrick Kelsey #include "extract.h"
268bdc5a62SPatrick Kelsey #include "ethertype.h"
278bdc5a62SPatrick Kelsey 
288bdc5a62SPatrick Kelsey /*
293340d773SGleb Smirnoff  * Geneve header, draft-ietf-nvo3-geneve
308bdc5a62SPatrick Kelsey  *
318bdc5a62SPatrick Kelsey  *    0                   1                   2                   3
328bdc5a62SPatrick Kelsey  *    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
338bdc5a62SPatrick Kelsey  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
348bdc5a62SPatrick Kelsey  *    |Ver|  Opt Len  |O|C|    Rsvd.  |          Protocol Type        |
358bdc5a62SPatrick Kelsey  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368bdc5a62SPatrick Kelsey  *    |        Virtual Network Identifier (VNI)       |    Reserved   |
378bdc5a62SPatrick Kelsey  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
388bdc5a62SPatrick Kelsey  *    |                    Variable Length Options                    |
398bdc5a62SPatrick Kelsey  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
408bdc5a62SPatrick Kelsey  *
418bdc5a62SPatrick Kelsey  * Options:
428bdc5a62SPatrick Kelsey  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
438bdc5a62SPatrick Kelsey  *    |          Option Class         |      Type     |R|R|R| Length  |
448bdc5a62SPatrick Kelsey  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
458bdc5a62SPatrick Kelsey  *    |                      Variable Option Data                     |
468bdc5a62SPatrick Kelsey  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
478bdc5a62SPatrick Kelsey  */
488bdc5a62SPatrick Kelsey 
498bdc5a62SPatrick Kelsey #define VER_SHIFT 6
508bdc5a62SPatrick Kelsey #define HDR_OPTS_LEN_MASK 0x3F
518bdc5a62SPatrick Kelsey 
528bdc5a62SPatrick Kelsey #define FLAG_OAM      (1 << 7)
538bdc5a62SPatrick Kelsey #define FLAG_CRITICAL (1 << 6)
548bdc5a62SPatrick Kelsey #define FLAG_R1       (1 << 5)
558bdc5a62SPatrick Kelsey #define FLAG_R2       (1 << 4)
568bdc5a62SPatrick Kelsey #define FLAG_R3       (1 << 3)
578bdc5a62SPatrick Kelsey #define FLAG_R4       (1 << 2)
588bdc5a62SPatrick Kelsey #define FLAG_R5       (1 << 1)
598bdc5a62SPatrick Kelsey #define FLAG_R6       (1 << 0)
608bdc5a62SPatrick Kelsey 
618bdc5a62SPatrick Kelsey #define OPT_TYPE_CRITICAL (1 << 7)
628bdc5a62SPatrick Kelsey #define OPT_LEN_MASK 0x1F
638bdc5a62SPatrick Kelsey 
648bdc5a62SPatrick Kelsey static const struct tok geneve_flag_values[] = {
658bdc5a62SPatrick Kelsey         { FLAG_OAM, "O" },
668bdc5a62SPatrick Kelsey         { FLAG_CRITICAL, "C" },
678bdc5a62SPatrick Kelsey         { FLAG_R1, "R1" },
688bdc5a62SPatrick Kelsey         { FLAG_R2, "R2" },
698bdc5a62SPatrick Kelsey         { FLAG_R3, "R3" },
708bdc5a62SPatrick Kelsey         { FLAG_R4, "R4" },
718bdc5a62SPatrick Kelsey         { FLAG_R5, "R5" },
728bdc5a62SPatrick Kelsey         { FLAG_R6, "R6" },
738bdc5a62SPatrick Kelsey         { 0, NULL }
748bdc5a62SPatrick Kelsey };
758bdc5a62SPatrick Kelsey 
768bdc5a62SPatrick Kelsey static const char *
format_opt_class(uint16_t opt_class)778bdc5a62SPatrick Kelsey format_opt_class(uint16_t opt_class)
788bdc5a62SPatrick Kelsey {
793340d773SGleb Smirnoff     switch (opt_class) {
803340d773SGleb Smirnoff     case 0x0100:
813340d773SGleb Smirnoff         return "Linux";
823340d773SGleb Smirnoff     case 0x0101:
833340d773SGleb Smirnoff         return "Open vSwitch";
843340d773SGleb Smirnoff     case 0x0102:
853340d773SGleb Smirnoff         return "Open Virtual Networking (OVN)";
863340d773SGleb Smirnoff     case 0x0103:
873340d773SGleb Smirnoff         return "In-band Network Telemetry (INT)";
883340d773SGleb Smirnoff     case 0x0104:
893340d773SGleb Smirnoff         return "VMware";
903340d773SGleb Smirnoff     default:
913340d773SGleb Smirnoff         if (opt_class <= 0x00ff)
928bdc5a62SPatrick Kelsey             return "Standard";
933340d773SGleb Smirnoff         else if (opt_class >= 0xfff0)
948bdc5a62SPatrick Kelsey             return "Experimental";
953340d773SGleb Smirnoff     }
963340d773SGleb Smirnoff 
978bdc5a62SPatrick Kelsey     return "Unknown";
988bdc5a62SPatrick Kelsey }
998bdc5a62SPatrick Kelsey 
1008bdc5a62SPatrick Kelsey static void
geneve_opts_print(netdissect_options * ndo,const u_char * bp,u_int len)1018bdc5a62SPatrick Kelsey geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len)
1028bdc5a62SPatrick Kelsey {
1038bdc5a62SPatrick Kelsey     const char *sep = "";
1048bdc5a62SPatrick Kelsey 
1058bdc5a62SPatrick Kelsey     while (len > 0) {
1068bdc5a62SPatrick Kelsey         uint16_t opt_class;
1078bdc5a62SPatrick Kelsey         uint8_t opt_type;
1088bdc5a62SPatrick Kelsey         uint8_t opt_len;
1098bdc5a62SPatrick Kelsey 
110*ee67461eSJoseph Mingrone         ND_PRINT("%s", sep);
1118bdc5a62SPatrick Kelsey         sep = ", ";
1128bdc5a62SPatrick Kelsey 
113*ee67461eSJoseph Mingrone         opt_class = GET_BE_U_2(bp);
114*ee67461eSJoseph Mingrone         opt_type = GET_U_1(bp + 2);
115*ee67461eSJoseph Mingrone         opt_len = 4 + ((GET_U_1(bp + 3) & OPT_LEN_MASK) * 4);
1168bdc5a62SPatrick Kelsey 
117*ee67461eSJoseph Mingrone         ND_PRINT("class %s (0x%x) type 0x%x%s len %u",
1188bdc5a62SPatrick Kelsey                   format_opt_class(opt_class), opt_class, opt_type,
119*ee67461eSJoseph Mingrone                   opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len);
1208bdc5a62SPatrick Kelsey 
1218bdc5a62SPatrick Kelsey         if (opt_len > len) {
122*ee67461eSJoseph Mingrone             ND_PRINT(" [bad length]");
1238bdc5a62SPatrick Kelsey             return;
1248bdc5a62SPatrick Kelsey         }
1258bdc5a62SPatrick Kelsey 
1268bdc5a62SPatrick Kelsey         if (ndo->ndo_vflag > 1 && opt_len > 4) {
1273340d773SGleb Smirnoff             const uint32_t *data = (const uint32_t *)(bp + 4);
1288bdc5a62SPatrick Kelsey             int i;
1298bdc5a62SPatrick Kelsey 
130*ee67461eSJoseph Mingrone             ND_PRINT(" data");
1318bdc5a62SPatrick Kelsey 
1328bdc5a62SPatrick Kelsey             for (i = 4; i < opt_len; i += 4) {
133*ee67461eSJoseph Mingrone                 ND_PRINT(" %08x", GET_BE_U_4(data));
1343340d773SGleb Smirnoff                 data++;
1358bdc5a62SPatrick Kelsey             }
1368bdc5a62SPatrick Kelsey         }
1378bdc5a62SPatrick Kelsey 
1388bdc5a62SPatrick Kelsey         bp += opt_len;
1398bdc5a62SPatrick Kelsey         len -= opt_len;
1408bdc5a62SPatrick Kelsey     }
1418bdc5a62SPatrick Kelsey }
1428bdc5a62SPatrick Kelsey 
1438bdc5a62SPatrick Kelsey void
geneve_print(netdissect_options * ndo,const u_char * bp,u_int len)1448bdc5a62SPatrick Kelsey geneve_print(netdissect_options *ndo, const u_char *bp, u_int len)
1458bdc5a62SPatrick Kelsey {
1468bdc5a62SPatrick Kelsey     uint8_t ver_opt;
1473340d773SGleb Smirnoff     u_int version;
1488bdc5a62SPatrick Kelsey     uint8_t flags;
1498bdc5a62SPatrick Kelsey     uint16_t prot;
1508bdc5a62SPatrick Kelsey     uint32_t vni;
1518bdc5a62SPatrick Kelsey     uint8_t reserved;
1528bdc5a62SPatrick Kelsey     u_int opts_len;
1538bdc5a62SPatrick Kelsey 
154*ee67461eSJoseph Mingrone     ndo->ndo_protocol = "geneve";
155*ee67461eSJoseph Mingrone     ND_PRINT("Geneve");
1568bdc5a62SPatrick Kelsey 
157*ee67461eSJoseph Mingrone     if (len < 8) {
158*ee67461eSJoseph Mingrone         ND_PRINT(" [length %u < 8]", len);
159*ee67461eSJoseph Mingrone         nd_print_invalid(ndo);
160*ee67461eSJoseph Mingrone         return;
161*ee67461eSJoseph Mingrone     }
1628bdc5a62SPatrick Kelsey 
163*ee67461eSJoseph Mingrone     ND_TCHECK_8(bp);
164*ee67461eSJoseph Mingrone 
165*ee67461eSJoseph Mingrone     ver_opt = GET_U_1(bp);
1668bdc5a62SPatrick Kelsey     bp += 1;
1678bdc5a62SPatrick Kelsey     len -= 1;
1688bdc5a62SPatrick Kelsey 
1698bdc5a62SPatrick Kelsey     version = ver_opt >> VER_SHIFT;
1708bdc5a62SPatrick Kelsey     if (version != 0) {
171*ee67461eSJoseph Mingrone         ND_PRINT(" ERROR: unknown-version %u", version);
1728bdc5a62SPatrick Kelsey         return;
1738bdc5a62SPatrick Kelsey     }
1748bdc5a62SPatrick Kelsey 
175*ee67461eSJoseph Mingrone     flags = GET_U_1(bp);
1768bdc5a62SPatrick Kelsey     bp += 1;
1778bdc5a62SPatrick Kelsey     len -= 1;
1788bdc5a62SPatrick Kelsey 
179*ee67461eSJoseph Mingrone     prot = GET_BE_U_2(bp);
1808bdc5a62SPatrick Kelsey     bp += 2;
1818bdc5a62SPatrick Kelsey     len -= 2;
1828bdc5a62SPatrick Kelsey 
183*ee67461eSJoseph Mingrone     vni = GET_BE_U_3(bp);
1848bdc5a62SPatrick Kelsey     bp += 3;
1858bdc5a62SPatrick Kelsey     len -= 3;
1868bdc5a62SPatrick Kelsey 
187*ee67461eSJoseph Mingrone     reserved = GET_U_1(bp);
1888bdc5a62SPatrick Kelsey     bp += 1;
1898bdc5a62SPatrick Kelsey     len -= 1;
1908bdc5a62SPatrick Kelsey 
191*ee67461eSJoseph Mingrone     ND_PRINT(", Flags [%s]",
192*ee67461eSJoseph Mingrone               bittok2str_nosep(geneve_flag_values, "none", flags));
193*ee67461eSJoseph Mingrone     ND_PRINT(", vni 0x%x", vni);
1948bdc5a62SPatrick Kelsey 
1958bdc5a62SPatrick Kelsey     if (reserved)
196*ee67461eSJoseph Mingrone         ND_PRINT(", rsvd 0x%x", reserved);
1978bdc5a62SPatrick Kelsey 
1988bdc5a62SPatrick Kelsey     if (ndo->ndo_eflag)
199*ee67461eSJoseph Mingrone         ND_PRINT(", proto %s (0x%04x)",
200*ee67461eSJoseph Mingrone                   tok2str(ethertype_values, "unknown", prot), prot);
2018bdc5a62SPatrick Kelsey 
2028bdc5a62SPatrick Kelsey     opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4;
2038bdc5a62SPatrick Kelsey 
2048bdc5a62SPatrick Kelsey     if (len < opts_len) {
205*ee67461eSJoseph Mingrone         ND_PRINT(" truncated-geneve - %u bytes missing",
206*ee67461eSJoseph Mingrone                   opts_len - len);
2078bdc5a62SPatrick Kelsey         return;
2088bdc5a62SPatrick Kelsey     }
2098bdc5a62SPatrick Kelsey 
210*ee67461eSJoseph Mingrone     ND_TCHECK_LEN(bp, opts_len);
2118bdc5a62SPatrick Kelsey 
2128bdc5a62SPatrick Kelsey     if (opts_len > 0) {
213*ee67461eSJoseph Mingrone         ND_PRINT(", options [");
2148bdc5a62SPatrick Kelsey 
2158bdc5a62SPatrick Kelsey         if (ndo->ndo_vflag)
2168bdc5a62SPatrick Kelsey             geneve_opts_print(ndo, bp, opts_len);
2178bdc5a62SPatrick Kelsey         else
218*ee67461eSJoseph Mingrone             ND_PRINT("%u bytes", opts_len);
2198bdc5a62SPatrick Kelsey 
220*ee67461eSJoseph Mingrone         ND_PRINT("]");
2218bdc5a62SPatrick Kelsey     }
2228bdc5a62SPatrick Kelsey 
2238bdc5a62SPatrick Kelsey     bp += opts_len;
2248bdc5a62SPatrick Kelsey     len -= opts_len;
2258bdc5a62SPatrick Kelsey 
2268bdc5a62SPatrick Kelsey     if (ndo->ndo_vflag < 1)
227*ee67461eSJoseph Mingrone         ND_PRINT(": ");
2288bdc5a62SPatrick Kelsey     else
229*ee67461eSJoseph Mingrone         ND_PRINT("\n\t");
2308bdc5a62SPatrick Kelsey 
231*ee67461eSJoseph Mingrone     if (ethertype_print(ndo, prot, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL) == 0) {
2328bdc5a62SPatrick Kelsey         if (prot == ETHERTYPE_TEB)
233*ee67461eSJoseph Mingrone             ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
2348bdc5a62SPatrick Kelsey         else
235*ee67461eSJoseph Mingrone             ND_PRINT("geneve-proto-0x%x", prot);
2368bdc5a62SPatrick Kelsey     }
2378bdc5a62SPatrick Kelsey 
2388bdc5a62SPatrick Kelsey     return;
2398bdc5a62SPatrick Kelsey 
2408bdc5a62SPatrick Kelsey trunc:
241*ee67461eSJoseph Mingrone     nd_print_trunc(ndo);
2428bdc5a62SPatrick Kelsey }
243