Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 2014 VMware, Inc. All Rights Reserved.
      3  *
      4  * Jesse Gross <jesse (at) nicira.com>
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that: (1) source code
      8  * distributions retain the above copyright notice and this paragraph
      9  * in its entirety, and (2) distributions including binary code include
     10  * the above copyright notice and this paragraph in its entirety in
     11  * the documentation or other materials provided with the distribution.
     12  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
     13  * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
     14  * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     15  * FOR A PARTICULAR PURPOSE.
     16  */
     17 
     18 #define NETDISSECT_REWORKED
     19 #ifdef HAVE_CONFIG_H
     20 #include "config.h"
     21 #endif
     22 
     23 #include <tcpdump-stdinc.h>
     24 
     25 #include "interface.h"
     26 #include "extract.h"
     27 #include "ethertype.h"
     28 
     29 /*
     30  * Geneve header, draft-gross-geneve-02
     31  *
     32  *    0                   1                   2                   3
     33  *    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
     34  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     35  *    |Ver|  Opt Len  |O|C|    Rsvd.  |          Protocol Type        |
     36  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     37  *    |        Virtual Network Identifier (VNI)       |    Reserved   |
     38  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     39  *    |                    Variable Length Options                    |
     40  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     41  *
     42  * Options:
     43  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     44  *    |          Option Class         |      Type     |R|R|R| Length  |
     45  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     46  *    |                      Variable Option Data                     |
     47  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     48  */
     49 
     50 #define VER_SHIFT 6
     51 #define HDR_OPTS_LEN_MASK 0x3F
     52 
     53 #define FLAG_OAM      (1 << 7)
     54 #define FLAG_CRITICAL (1 << 6)
     55 #define FLAG_R1       (1 << 5)
     56 #define FLAG_R2       (1 << 4)
     57 #define FLAG_R3       (1 << 3)
     58 #define FLAG_R4       (1 << 2)
     59 #define FLAG_R5       (1 << 1)
     60 #define FLAG_R6       (1 << 0)
     61 
     62 #define OPT_TYPE_CRITICAL (1 << 7)
     63 #define OPT_LEN_MASK 0x1F
     64 
     65 static const struct tok geneve_flag_values[] = {
     66         { FLAG_OAM, "O" },
     67         { FLAG_CRITICAL, "C" },
     68         { FLAG_R1, "R1" },
     69         { FLAG_R2, "R2" },
     70         { FLAG_R3, "R3" },
     71         { FLAG_R4, "R4" },
     72         { FLAG_R5, "R5" },
     73         { FLAG_R6, "R6" },
     74         { 0, NULL }
     75 };
     76 
     77 static const char *
     78 format_opt_class(uint16_t opt_class)
     79 {
     80     if (opt_class <= 0xff)
     81         return "Standard";
     82     else if (opt_class == 0xffff)
     83         return "Experimental";
     84     else
     85         return "Unknown";
     86 }
     87 
     88 static void
     89 geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len)
     90 {
     91     const char *sep = "";
     92 
     93     while (len > 0) {
     94         uint16_t opt_class;
     95         uint8_t opt_type;
     96         uint8_t opt_len;
     97 
     98         ND_PRINT((ndo, "%s", sep));
     99         sep = ", ";
    100 
    101         opt_class = EXTRACT_16BITS(bp);
    102         opt_type = *(bp + 2);
    103         opt_len = 4 + ((*(bp + 3) & OPT_LEN_MASK) * 4);
    104 
    105         ND_PRINT((ndo, "class %s (0x%x) type 0x%x%s len %u",
    106                   format_opt_class(opt_class), opt_class, opt_type,
    107                   opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len));
    108 
    109         if (opt_len > len) {
    110             ND_PRINT((ndo, " [bad length]"));
    111             return;
    112         }
    113 
    114         if (ndo->ndo_vflag > 1 && opt_len > 4) {
    115             uint32_t *print_data = (uint32_t *)(bp + 4);
    116             int i;
    117 
    118             ND_PRINT((ndo, " data"));
    119 
    120             for (i = 4; i < opt_len; i += 4) {
    121                 ND_PRINT((ndo, " %08x", EXTRACT_32BITS(print_data)));
    122                 print_data++;
    123             }
    124         }
    125 
    126         bp += opt_len;
    127         len -= opt_len;
    128     }
    129 }
    130 
    131 void
    132 geneve_print(netdissect_options *ndo, const u_char *bp, u_int len)
    133 {
    134     uint8_t ver_opt;
    135     uint version;
    136     uint8_t flags;
    137     uint16_t prot;
    138     uint32_t vni;
    139     uint8_t reserved;
    140     u_int opts_len;
    141 
    142     ND_PRINT((ndo, "Geneve"));
    143 
    144     ND_TCHECK2(*bp, 8);
    145 
    146     ver_opt = *bp;
    147     bp += 1;
    148     len -= 1;
    149 
    150     version = ver_opt >> VER_SHIFT;
    151     if (version != 0) {
    152         ND_PRINT((ndo, " ERROR: unknown-version %u", version));
    153         return;
    154     }
    155 
    156     flags = *bp;
    157     bp += 1;
    158     len -= 1;
    159 
    160     prot = EXTRACT_16BITS(bp);
    161     bp += 2;
    162     len -= 2;
    163 
    164     vni = EXTRACT_24BITS(bp);
    165     bp += 3;
    166     len -= 3;
    167 
    168     reserved = *bp;
    169     bp += 1;
    170     len -= 1;
    171 
    172     ND_PRINT((ndo, ", Flags [%s]",
    173               bittok2str_nosep(geneve_flag_values, "none", flags)));
    174     ND_PRINT((ndo, ", vni 0x%x", vni));
    175 
    176     if (reserved)
    177         ND_PRINT((ndo, ", rsvd 0x%x", reserved));
    178 
    179     if (ndo->ndo_eflag)
    180         ND_PRINT((ndo, ", proto %s (0x%04x)",
    181                   tok2str(ethertype_values, "unknown", prot), prot));
    182 
    183     opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4;
    184 
    185     if (len < opts_len) {
    186         ND_PRINT((ndo, " truncated-geneve - %u bytes missing",
    187                   len - opts_len));
    188         return;
    189     }
    190 
    191     ND_TCHECK2(*bp, opts_len);
    192 
    193     if (opts_len > 0) {
    194         ND_PRINT((ndo, ", options ["));
    195 
    196         if (ndo->ndo_vflag)
    197             geneve_opts_print(ndo, bp, opts_len);
    198         else
    199             ND_PRINT((ndo, "%u bytes", opts_len));
    200 
    201         ND_PRINT((ndo, "]"));
    202     }
    203 
    204     bp += opts_len;
    205     len -= opts_len;
    206 
    207     if (ndo->ndo_vflag < 1)
    208         ND_PRINT((ndo, ": "));
    209     else
    210         ND_PRINT((ndo, "\n\t"));
    211 
    212     if (ethertype_print(ndo, prot, bp, len, len) == 0) {
    213         if (prot == ETHERTYPE_TEB)
    214             ether_print(ndo, bp, len, len, NULL, NULL);
    215         else
    216             ND_PRINT((ndo, "geneve-proto-0x%x", prot));
    217     }
    218 
    219     return;
    220 
    221 trunc:
    222     ND_PRINT((ndo, " [|geneve]"));
    223 }
    224