xref: /dflybsd-src/contrib/tcpdump/print-geneve.c (revision 59c07fbdf8168fa08c76c515186d561b5a92690c)
1411677aeSAaron LI /*
2411677aeSAaron LI  * Copyright (c) 2014 VMware, Inc. All Rights Reserved.
3411677aeSAaron LI  *
4411677aeSAaron LI  * Jesse Gross <jesse@nicira.com>
5411677aeSAaron LI  *
6411677aeSAaron LI  * Redistribution and use in source and binary forms, with or without
7411677aeSAaron LI  * modification, are permitted provided that: (1) source code
8411677aeSAaron LI  * distributions retain the above copyright notice and this paragraph
9411677aeSAaron LI  * in its entirety, and (2) distributions including binary code include
10411677aeSAaron LI  * the above copyright notice and this paragraph in its entirety in
11411677aeSAaron LI  * the documentation or other materials provided with the distribution.
12411677aeSAaron LI  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
13411677aeSAaron LI  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
14411677aeSAaron LI  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
15411677aeSAaron LI  * FOR A PARTICULAR PURPOSE.
16411677aeSAaron LI  */
17411677aeSAaron LI 
18411677aeSAaron LI /* \summary: Generic Network Virtualization Encapsulation (Geneve) printer */
19411677aeSAaron LI 
20411677aeSAaron LI #ifdef HAVE_CONFIG_H
21*ed775ee7SAntonio Huete Jimenez #include <config.h>
22411677aeSAaron LI #endif
23411677aeSAaron LI 
24*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
25411677aeSAaron LI 
26411677aeSAaron LI #include "netdissect.h"
27411677aeSAaron LI #include "extract.h"
28411677aeSAaron LI #include "ethertype.h"
29411677aeSAaron LI 
30411677aeSAaron LI /*
31411677aeSAaron LI  * Geneve header, draft-ietf-nvo3-geneve
32411677aeSAaron LI  *
33411677aeSAaron LI  *    0                   1                   2                   3
34411677aeSAaron LI  *    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
35411677aeSAaron LI  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36411677aeSAaron LI  *    |Ver|  Opt Len  |O|C|    Rsvd.  |          Protocol Type        |
37411677aeSAaron LI  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38411677aeSAaron LI  *    |        Virtual Network Identifier (VNI)       |    Reserved   |
39411677aeSAaron LI  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40411677aeSAaron LI  *    |                    Variable Length Options                    |
41411677aeSAaron LI  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42411677aeSAaron LI  *
43411677aeSAaron LI  * Options:
44411677aeSAaron LI  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45411677aeSAaron LI  *    |          Option Class         |      Type     |R|R|R| Length  |
46411677aeSAaron LI  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47411677aeSAaron LI  *    |                      Variable Option Data                     |
48411677aeSAaron LI  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49411677aeSAaron LI  */
50411677aeSAaron LI 
51411677aeSAaron LI #define VER_SHIFT 6
52411677aeSAaron LI #define HDR_OPTS_LEN_MASK 0x3F
53411677aeSAaron LI 
54411677aeSAaron LI #define FLAG_OAM      (1 << 7)
55411677aeSAaron LI #define FLAG_CRITICAL (1 << 6)
56411677aeSAaron LI #define FLAG_R1       (1 << 5)
57411677aeSAaron LI #define FLAG_R2       (1 << 4)
58411677aeSAaron LI #define FLAG_R3       (1 << 3)
59411677aeSAaron LI #define FLAG_R4       (1 << 2)
60411677aeSAaron LI #define FLAG_R5       (1 << 1)
61411677aeSAaron LI #define FLAG_R6       (1 << 0)
62411677aeSAaron LI 
63411677aeSAaron LI #define OPT_TYPE_CRITICAL (1 << 7)
64411677aeSAaron LI #define OPT_LEN_MASK 0x1F
65411677aeSAaron LI 
66411677aeSAaron LI static const struct tok geneve_flag_values[] = {
67411677aeSAaron LI         { FLAG_OAM, "O" },
68411677aeSAaron LI         { FLAG_CRITICAL, "C" },
69411677aeSAaron LI         { FLAG_R1, "R1" },
70411677aeSAaron LI         { FLAG_R2, "R2" },
71411677aeSAaron LI         { FLAG_R3, "R3" },
72411677aeSAaron LI         { FLAG_R4, "R4" },
73411677aeSAaron LI         { FLAG_R5, "R5" },
74411677aeSAaron LI         { FLAG_R6, "R6" },
75411677aeSAaron LI         { 0, NULL }
76411677aeSAaron LI };
77411677aeSAaron LI 
78411677aeSAaron LI static const char *
format_opt_class(uint16_t opt_class)79411677aeSAaron LI format_opt_class(uint16_t opt_class)
80411677aeSAaron LI {
81411677aeSAaron LI     switch (opt_class) {
82411677aeSAaron LI     case 0x0100:
83411677aeSAaron LI         return "Linux";
84411677aeSAaron LI     case 0x0101:
85411677aeSAaron LI         return "Open vSwitch";
86411677aeSAaron LI     case 0x0102:
87411677aeSAaron LI         return "Open Virtual Networking (OVN)";
88411677aeSAaron LI     case 0x0103:
89411677aeSAaron LI         return "In-band Network Telemetry (INT)";
90411677aeSAaron LI     case 0x0104:
91411677aeSAaron LI         return "VMware";
92411677aeSAaron LI     default:
93411677aeSAaron LI         if (opt_class <= 0x00ff)
94411677aeSAaron LI             return "Standard";
95411677aeSAaron LI         else if (opt_class >= 0xfff0)
96411677aeSAaron LI             return "Experimental";
97411677aeSAaron LI     }
98411677aeSAaron LI 
99411677aeSAaron LI     return "Unknown";
100411677aeSAaron LI }
101411677aeSAaron LI 
102411677aeSAaron LI static void
geneve_opts_print(netdissect_options * ndo,const u_char * bp,u_int len)103411677aeSAaron LI geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len)
104411677aeSAaron LI {
105411677aeSAaron LI     const char *sep = "";
106411677aeSAaron LI 
107411677aeSAaron LI     while (len > 0) {
108411677aeSAaron LI         uint16_t opt_class;
109411677aeSAaron LI         uint8_t opt_type;
110411677aeSAaron LI         uint8_t opt_len;
111411677aeSAaron LI 
112*ed775ee7SAntonio Huete Jimenez         ND_PRINT("%s", sep);
113411677aeSAaron LI         sep = ", ";
114411677aeSAaron LI 
115*ed775ee7SAntonio Huete Jimenez         opt_class = GET_BE_U_2(bp);
116*ed775ee7SAntonio Huete Jimenez         opt_type = GET_U_1(bp + 2);
117*ed775ee7SAntonio Huete Jimenez         opt_len = 4 + ((GET_U_1(bp + 3) & OPT_LEN_MASK) * 4);
118411677aeSAaron LI 
119*ed775ee7SAntonio Huete Jimenez         ND_PRINT("class %s (0x%x) type 0x%x%s len %u",
120411677aeSAaron LI                   format_opt_class(opt_class), opt_class, opt_type,
121*ed775ee7SAntonio Huete Jimenez                   opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len);
122411677aeSAaron LI 
123411677aeSAaron LI         if (opt_len > len) {
124*ed775ee7SAntonio Huete Jimenez             ND_PRINT(" [bad length]");
125411677aeSAaron LI             return;
126411677aeSAaron LI         }
127411677aeSAaron LI 
128411677aeSAaron LI         if (ndo->ndo_vflag > 1 && opt_len > 4) {
129411677aeSAaron LI             const uint32_t *data = (const uint32_t *)(bp + 4);
130411677aeSAaron LI             int i;
131411677aeSAaron LI 
132*ed775ee7SAntonio Huete Jimenez             ND_PRINT(" data");
133411677aeSAaron LI 
134411677aeSAaron LI             for (i = 4; i < opt_len; i += 4) {
135*ed775ee7SAntonio Huete Jimenez                 ND_PRINT(" %08x", GET_BE_U_4(data));
136411677aeSAaron LI                 data++;
137411677aeSAaron LI             }
138411677aeSAaron LI         }
139411677aeSAaron LI 
140411677aeSAaron LI         bp += opt_len;
141411677aeSAaron LI         len -= opt_len;
142411677aeSAaron LI     }
143411677aeSAaron LI }
144411677aeSAaron LI 
145411677aeSAaron LI void
geneve_print(netdissect_options * ndo,const u_char * bp,u_int len)146411677aeSAaron LI geneve_print(netdissect_options *ndo, const u_char *bp, u_int len)
147411677aeSAaron LI {
148411677aeSAaron LI     uint8_t ver_opt;
149411677aeSAaron LI     u_int version;
150411677aeSAaron LI     uint8_t flags;
151411677aeSAaron LI     uint16_t prot;
152411677aeSAaron LI     uint32_t vni;
153411677aeSAaron LI     uint8_t reserved;
154411677aeSAaron LI     u_int opts_len;
155411677aeSAaron LI 
156*ed775ee7SAntonio Huete Jimenez     ndo->ndo_protocol = "geneve";
157*ed775ee7SAntonio Huete Jimenez     ND_PRINT("Geneve");
158411677aeSAaron LI 
159*ed775ee7SAntonio Huete Jimenez     if (len < 8) {
160*ed775ee7SAntonio Huete Jimenez         ND_PRINT(" [length %u < 8]", len);
161*ed775ee7SAntonio Huete Jimenez         nd_print_invalid(ndo);
162*ed775ee7SAntonio Huete Jimenez         return;
163*ed775ee7SAntonio Huete Jimenez     }
164411677aeSAaron LI 
165*ed775ee7SAntonio Huete Jimenez     ND_TCHECK_8(bp);
166*ed775ee7SAntonio Huete Jimenez 
167*ed775ee7SAntonio Huete Jimenez     ver_opt = GET_U_1(bp);
168411677aeSAaron LI     bp += 1;
169411677aeSAaron LI     len -= 1;
170411677aeSAaron LI 
171411677aeSAaron LI     version = ver_opt >> VER_SHIFT;
172411677aeSAaron LI     if (version != 0) {
173*ed775ee7SAntonio Huete Jimenez         ND_PRINT(" ERROR: unknown-version %u", version);
174411677aeSAaron LI         return;
175411677aeSAaron LI     }
176411677aeSAaron LI 
177*ed775ee7SAntonio Huete Jimenez     flags = GET_U_1(bp);
178411677aeSAaron LI     bp += 1;
179411677aeSAaron LI     len -= 1;
180411677aeSAaron LI 
181*ed775ee7SAntonio Huete Jimenez     prot = GET_BE_U_2(bp);
182411677aeSAaron LI     bp += 2;
183411677aeSAaron LI     len -= 2;
184411677aeSAaron LI 
185*ed775ee7SAntonio Huete Jimenez     vni = GET_BE_U_3(bp);
186411677aeSAaron LI     bp += 3;
187411677aeSAaron LI     len -= 3;
188411677aeSAaron LI 
189*ed775ee7SAntonio Huete Jimenez     reserved = GET_U_1(bp);
190411677aeSAaron LI     bp += 1;
191411677aeSAaron LI     len -= 1;
192411677aeSAaron LI 
193*ed775ee7SAntonio Huete Jimenez     ND_PRINT(", Flags [%s]",
194*ed775ee7SAntonio Huete Jimenez               bittok2str_nosep(geneve_flag_values, "none", flags));
195*ed775ee7SAntonio Huete Jimenez     ND_PRINT(", vni 0x%x", vni);
196411677aeSAaron LI 
197411677aeSAaron LI     if (reserved)
198*ed775ee7SAntonio Huete Jimenez         ND_PRINT(", rsvd 0x%x", reserved);
199411677aeSAaron LI 
200411677aeSAaron LI     if (ndo->ndo_eflag)
201*ed775ee7SAntonio Huete Jimenez         ND_PRINT(", proto %s (0x%04x)",
202*ed775ee7SAntonio Huete Jimenez                   tok2str(ethertype_values, "unknown", prot), prot);
203411677aeSAaron LI 
204411677aeSAaron LI     opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4;
205411677aeSAaron LI 
206411677aeSAaron LI     if (len < opts_len) {
207*ed775ee7SAntonio Huete Jimenez         ND_PRINT(" truncated-geneve - %u bytes missing",
208*ed775ee7SAntonio Huete Jimenez                   opts_len - len);
209411677aeSAaron LI         return;
210411677aeSAaron LI     }
211411677aeSAaron LI 
212*ed775ee7SAntonio Huete Jimenez     ND_TCHECK_LEN(bp, opts_len);
213411677aeSAaron LI 
214411677aeSAaron LI     if (opts_len > 0) {
215*ed775ee7SAntonio Huete Jimenez         ND_PRINT(", options [");
216411677aeSAaron LI 
217411677aeSAaron LI         if (ndo->ndo_vflag)
218411677aeSAaron LI             geneve_opts_print(ndo, bp, opts_len);
219411677aeSAaron LI         else
220*ed775ee7SAntonio Huete Jimenez             ND_PRINT("%u bytes", opts_len);
221411677aeSAaron LI 
222*ed775ee7SAntonio Huete Jimenez         ND_PRINT("]");
223411677aeSAaron LI     }
224411677aeSAaron LI 
225411677aeSAaron LI     bp += opts_len;
226411677aeSAaron LI     len -= opts_len;
227411677aeSAaron LI 
228411677aeSAaron LI     if (ndo->ndo_vflag < 1)
229*ed775ee7SAntonio Huete Jimenez         ND_PRINT(": ");
230411677aeSAaron LI     else
231*ed775ee7SAntonio Huete Jimenez         ND_PRINT("\n\t");
232411677aeSAaron LI 
233*ed775ee7SAntonio Huete Jimenez     if (ethertype_print(ndo, prot, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL) == 0) {
234411677aeSAaron LI         if (prot == ETHERTYPE_TEB)
235*ed775ee7SAntonio Huete Jimenez             ether_print(ndo, bp, len, ND_BYTES_AVAILABLE_AFTER(bp), NULL, NULL);
236411677aeSAaron LI         else
237*ed775ee7SAntonio Huete Jimenez             ND_PRINT("geneve-proto-0x%x", prot);
238411677aeSAaron LI     }
239411677aeSAaron LI 
240411677aeSAaron LI     return;
241411677aeSAaron LI 
242411677aeSAaron LI trunc:
243*ed775ee7SAntonio Huete Jimenez     nd_print_trunc(ndo);
244411677aeSAaron LI }
245