diff options
-rw-r--r-- | CREDITS | 1 | ||||
-rw-r--r-- | Makefile.in | 1 | ||||
-rw-r--r-- | netdissect.h | 1 | ||||
-rw-r--r-- | print-geneve.c | 223 | ||||
-rw-r--r-- | print-udp.c | 2 | ||||
-rw-r--r-- | tests/TESTLIST | 3 | ||||
-rw-r--r-- | tests/geneve-vv.out | 40 | ||||
-rw-r--r-- | tests/geneve.pcap | bin | 0 -> 1704 bytes | |||
-rw-r--r-- | udp.h | 1 |
9 files changed, 272 insertions, 0 deletions
@@ -96,6 +96,7 @@ Additional people who have contributed patches: Jefferson Ogata <jogata at nodc dot noaa dot gov> Jeffrey Hutzelman <jhutz at cmu dot edu> Jesper Peterson <jesper at endace dot com> + Jesse Gross <jesse at nicira dot com> Jim Hutchins <jim at ca dot sandia dot gov> João Medeiros <ignotus21 at sourceforge dot net> Joerg Mayer <jmayer at loplof dot de> diff --git a/Makefile.in b/Makefile.in index d6836f69..1296d1d0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -125,6 +125,7 @@ LIBNETDISSECT_SRC=\ print-forces.c \ print-fr.c \ print-ftp.c \ + print-geneve.c \ print-geonet.c \ print-gre.c \ print-hsrp.c \ diff --git a/netdissect.h b/netdissect.h index a554eae2..e0a0205d 100644 --- a/netdissect.h +++ b/netdissect.h @@ -556,6 +556,7 @@ extern void ftp_print(netdissect_options *, const u_char *, u_int); extern void http_print(netdissect_options *, const u_char *, u_int); extern void rtsp_print(netdissect_options *, const u_char *, u_int); extern void smtp_print(netdissect_options *, const u_char *, u_int); +extern void geneve_print(netdissect_options *, const u_char *, u_int); /* stuff that has not yet been rototiled */ diff --git a/print-geneve.c b/print-geneve.c new file mode 100644 index 00000000..2187ab8e --- /dev/null +++ b/print-geneve.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2014 VMware, Inc. All Rights Reserved. + * + * Jesse Gross <jesse@nicira.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code + * distributions retain the above copyright notice and this paragraph + * in its entirety, and (2) distributions including binary code include + * the above copyright notice and this paragraph in its entirety in + * the documentation or other materials provided with the distribution. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND + * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT + * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + */ + +#define NETDISSECT_REWORKED +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <tcpdump-stdinc.h> + +#include "interface.h" +#include "extract.h" +#include "ethertype.h" + +/* + * Geneve header, draft-gross-geneve-02 + * + * 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Ver| Opt Len |O|C| Rsvd. | Protocol Type | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Virtual Network Identifier (VNI) | Reserved | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Variable Length Options | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Options: + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Option Class | Type |R|R|R| Length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Variable Option Data | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +#define VER_SHIFT 6 +#define HDR_OPTS_LEN_MASK 0x3F + +#define FLAG_OAM (1 << 7) +#define FLAG_CRITICAL (1 << 6) +#define FLAG_R1 (1 << 5) +#define FLAG_R2 (1 << 4) +#define FLAG_R3 (1 << 3) +#define FLAG_R4 (1 << 2) +#define FLAG_R5 (1 << 1) +#define FLAG_R6 (1 << 0) + +#define OPT_TYPE_CRITICAL (1 << 7) +#define OPT_LEN_MASK 0x1F + +static const struct tok geneve_flag_values[] = { + { FLAG_OAM, "O" }, + { FLAG_CRITICAL, "C" }, + { FLAG_R1, "R1" }, + { FLAG_R2, "R2" }, + { FLAG_R3, "R3" }, + { FLAG_R4, "R4" }, + { FLAG_R5, "R5" }, + { FLAG_R6, "R6" }, + { 0, NULL } +}; + +static const char * +format_opt_class(uint16_t opt_class) +{ + if (opt_class <= 0xff) + return "Standard"; + else if (opt_class == 0xffff) + return "Experimental"; + else + return "Unknown"; +} + +static void +geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len) +{ + const char *sep = ""; + + while (len > 0) { + uint16_t opt_class; + uint8_t opt_type; + uint8_t opt_len; + + ND_PRINT((ndo, "%s", sep)); + sep = ", "; + + opt_class = EXTRACT_16BITS(bp); + opt_type = *(bp + 2); + opt_len = 4 + ((*(bp + 3) & OPT_LEN_MASK) * 4); + + ND_PRINT((ndo, "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)); + + if (opt_len > len) { + ND_PRINT((ndo, " [bad length]")); + return; + } + + if (ndo->ndo_vflag > 1 && opt_len > 4) { + uint32_t *print_data = (uint32_t *)(bp + 4); + int i; + + ND_PRINT((ndo, " data")); + + for (i = 4; i < opt_len; i += 4) { + ND_PRINT((ndo, " %08x", EXTRACT_32BITS(print_data))); + print_data++; + } + } + + bp += opt_len; + len -= opt_len; + } +} + +void +geneve_print(netdissect_options *ndo, const u_char *bp, u_int len) +{ + uint8_t ver_opt; + uint version; + uint8_t flags; + uint16_t prot; + uint32_t vni; + uint8_t reserved; + u_int opts_len; + + ND_PRINT((ndo, "Geneve")); + + ND_TCHECK2(*bp, 8); + + ver_opt = *bp; + bp += 1; + len -= 1; + + version = ver_opt >> VER_SHIFT; + if (version != 0) { + ND_PRINT((ndo, " ERROR: unknown-version %u", version)); + return; + } + + flags = *bp; + bp += 1; + len -= 1; + + prot = EXTRACT_16BITS(bp); + bp += 2; + len -= 2; + + vni = EXTRACT_24BITS(bp); + bp += 3; + len -= 3; + + reserved = *bp; + bp += 1; + len -= 1; + + ND_PRINT((ndo, ", Flags [%s]", + bittok2str_nosep(geneve_flag_values, "none", flags))); + ND_PRINT((ndo, ", vni 0x%x", vni)); + + if (reserved) + ND_PRINT((ndo, ", rsvd 0x%x", reserved)); + + if (ndo->ndo_eflag) + ND_PRINT((ndo, ", 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", + len - opts_len)); + return; + } + + ND_TCHECK2(*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((ndo, "]")); + } + + bp += opts_len; + len -= opts_len; + + if (ndo->ndo_vflag < 1) + ND_PRINT((ndo, ": ")); + else + ND_PRINT((ndo, "\n\t")); + + if (ethertype_print(ndo, prot, bp, len, len) == 0) { + if (prot == ETHERTYPE_TEB) + ether_print(ndo, bp, len, len, NULL, NULL); + else + ND_PRINT((ndo, "geneve-proto-0x%x", prot)); + } + + return; + +trunc: + ND_PRINT((ndo, " [|geneve]")); +} diff --git a/print-udp.c b/print-udp.c index eafdaf88..49097daa 100644 --- a/print-udp.c +++ b/print-udp.c @@ -679,6 +679,8 @@ udp_print(netdissect_options *ndo, register const u_char *bp, u_int length, otv_print(ndo, (const u_char *)(up + 1), length); else if (ISPORT(VXLAN_PORT)) vxlan_print(ndo, (const u_char *)(up + 1), length); + else if (ISPORT(GENEVE_PORT)) + geneve_print(ndo, (const u_char *)(up + 1), length); else { if (ulen > length) ND_PRINT((ndo, "UDP, bad length %u > %u", diff --git a/tests/TESTLIST b/tests/TESTLIST index 55841851..094f0f2f 100644 --- a/tests/TESTLIST +++ b/tests/TESTLIST @@ -257,3 +257,6 @@ isis_4-v ISIS_p2p_adjacency.pcap isis_4-v.out -t -v # ATA-over-Ethernet tests aoe_1 AoE_Linux.pcap aoe_1.out -t aoe_1-v AoE_Linux.pcap aoe_1-v.out -t -v + +# Geneve tests +geneve-v geneve.pcap geneve-vv.out -t -vv diff --git a/tests/geneve-vv.out b/tests/geneve-vv.out new file mode 100644 index 00000000..4412017e --- /dev/null +++ b/tests/geneve-vv.out @@ -0,0 +1,40 @@ +IP (tos 0x0, ttl 64, id 7071, offset 0, flags [DF], proto UDP (17), length 142) + 20.0.0.1.587 > 20.0.0.2.6081: [no cksum] Geneve, Flags [C], vni 0xb, options [class Experimental (0xffff) type 0x8a(C) len 8 data 0000000a] + IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84) + 30.0.0.1 > 30.0.0.2: ICMP echo request, id 4349, seq 40, length 64 +IP (tos 0x0, ttl 64, id 49690, offset 0, flags [DF], proto UDP (17), length 134) + 20.0.0.2.1 > 20.0.0.1.6081: [no cksum] Geneve, Flags [none], vni 0xb + IP (tos 0x0, ttl 64, id 4796, offset 0, flags [none], proto ICMP (1), length 84) + 30.0.0.2 > 30.0.0.1: ICMP echo reply, id 4349, seq 40, length 64 +IP (tos 0x0, ttl 64, id 7072, offset 0, flags [DF], proto UDP (17), length 142) + 20.0.0.1.587 > 20.0.0.2.6081: [no cksum] Geneve, Flags [C], vni 0xb, options [class Experimental (0xffff) type 0x8a(C) len 8 data 0000000a] + IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84) + 30.0.0.1 > 30.0.0.2: ICMP echo request, id 4349, seq 41, length 64 +IP (tos 0x0, ttl 64, id 49691, offset 0, flags [DF], proto UDP (17), length 134) + 20.0.0.2.1 > 20.0.0.1.6081: [no cksum] Geneve, Flags [none], vni 0xb + IP (tos 0x0, ttl 64, id 4797, offset 0, flags [none], proto ICMP (1), length 84) + 30.0.0.2 > 30.0.0.1: ICMP echo reply, id 4349, seq 41, length 64 +IP (tos 0x0, ttl 64, id 7073, offset 0, flags [DF], proto UDP (17), length 142) + 20.0.0.1.587 > 20.0.0.2.6081: [no cksum] Geneve, Flags [C], vni 0xb, options [class Experimental (0xffff) type 0x8a(C) len 8 data 0000000a] + IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84) + 30.0.0.1 > 30.0.0.2: ICMP echo request, id 4349, seq 42, length 64 +IP (tos 0x0, ttl 64, id 49692, offset 0, flags [DF], proto UDP (17), length 134) + 20.0.0.2.1 > 20.0.0.1.6081: [no cksum] Geneve, Flags [none], vni 0xb + IP (tos 0x0, ttl 64, id 4798, offset 0, flags [none], proto ICMP (1), length 84) + 30.0.0.2 > 30.0.0.1: ICMP echo reply, id 4349, seq 42, length 64 +IP (tos 0x0, ttl 64, id 7074, offset 0, flags [DF], proto UDP (17), length 142) + 20.0.0.1.587 > 20.0.0.2.6081: [no cksum] Geneve, Flags [C], vni 0xb, options [class Experimental (0xffff) type 0x8a(C) len 8 data 0000000a] + IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84) + 30.0.0.1 > 30.0.0.2: ICMP echo request, id 4349, seq 43, length 64 +IP (tos 0x0, ttl 64, id 49693, offset 0, flags [DF], proto UDP (17), length 134) + 20.0.0.2.1 > 20.0.0.1.6081: [no cksum] Geneve, Flags [none], vni 0xb + IP (tos 0x0, ttl 64, id 4799, offset 0, flags [none], proto ICMP (1), length 84) + 30.0.0.2 > 30.0.0.1: ICMP echo reply, id 4349, seq 43, length 64 +IP (tos 0x0, ttl 64, id 7075, offset 0, flags [DF], proto UDP (17), length 142) + 20.0.0.1.587 > 20.0.0.2.6081: [no cksum] Geneve, Flags [C], vni 0xb, options [class Experimental (0xffff) type 0x8a(C) len 8 data 0000000a] + IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto ICMP (1), length 84) + 30.0.0.1 > 30.0.0.2: ICMP echo request, id 4349, seq 44, length 64 +IP (tos 0x0, ttl 64, id 49694, offset 0, flags [DF], proto UDP (17), length 134) + 20.0.0.2.1 > 20.0.0.1.6081: [no cksum] Geneve, Flags [none], vni 0xb + IP (tos 0x0, ttl 64, id 4800, offset 0, flags [none], proto ICMP (1), length 84) + 30.0.0.2 > 30.0.0.1: ICMP echo reply, id 4349, seq 44, length 64 diff --git a/tests/geneve.pcap b/tests/geneve.pcap Binary files differnew file mode 100644 index 00000000..9844c56b --- /dev/null +++ b/tests/geneve.pcap @@ -91,6 +91,7 @@ struct udphdr { #define LWAPP_CONTROL_PORT 12223 /* draft-ohara-capwap-lwapp-04.txt */ #define OTV_PORT 8472 /* draft-hasmit-otv-04 */ #define VXLAN_PORT 4789 /* draft-mahalingam-dutt-dcops-vxlan-04 */ +#define GENEVE_PORT 6081 /* draft-gross-geneve-02 */ #ifdef INET6 #define RIPNG_PORT 521 /*XXX*/ |