print-geneve.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * Copyright (c) 2014 VMware, Inc. All Rights Reserved.
  3. *
  4. * Jesse Gross <jesse@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. /* \summary: Generic Network Virtualization Encapsulation (Geneve) printer */
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include <netdissect-stdinc.h>
  22. #include "netdissect.h"
  23. #include "extract.h"
  24. #include "ethertype.h"
  25. /*
  26. * Geneve header, draft-ietf-nvo3-geneve
  27. *
  28. * 0 1 2 3
  29. * 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
  30. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  31. * |Ver| Opt Len |O|C| Rsvd. | Protocol Type |
  32. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  33. * | Virtual Network Identifier (VNI) | Reserved |
  34. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  35. * | Variable Length Options |
  36. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  37. *
  38. * Options:
  39. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  40. * | Option Class | Type |R|R|R| Length |
  41. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  42. * | Variable Option Data |
  43. * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  44. */
  45. #define VER_SHIFT 6
  46. #define HDR_OPTS_LEN_MASK 0x3F
  47. #define FLAG_OAM (1 << 7)
  48. #define FLAG_CRITICAL (1 << 6)
  49. #define FLAG_R1 (1 << 5)
  50. #define FLAG_R2 (1 << 4)
  51. #define FLAG_R3 (1 << 3)
  52. #define FLAG_R4 (1 << 2)
  53. #define FLAG_R5 (1 << 1)
  54. #define FLAG_R6 (1 << 0)
  55. #define OPT_TYPE_CRITICAL (1 << 7)
  56. #define OPT_LEN_MASK 0x1F
  57. static const struct tok geneve_flag_values[] = {
  58. { FLAG_OAM, "O" },
  59. { FLAG_CRITICAL, "C" },
  60. { FLAG_R1, "R1" },
  61. { FLAG_R2, "R2" },
  62. { FLAG_R3, "R3" },
  63. { FLAG_R4, "R4" },
  64. { FLAG_R5, "R5" },
  65. { FLAG_R6, "R6" },
  66. { 0, NULL }
  67. };
  68. static const char *
  69. format_opt_class(uint16_t opt_class)
  70. {
  71. switch (opt_class) {
  72. case 0x0100:
  73. return "Linux";
  74. case 0x0101:
  75. return "Open vSwitch";
  76. case 0x0102:
  77. return "Open Virtual Networking (OVN)";
  78. case 0x0103:
  79. return "In-band Network Telemetry (INT)";
  80. case 0x0104:
  81. return "VMware";
  82. default:
  83. if (opt_class <= 0x00ff)
  84. return "Standard";
  85. else if (opt_class >= 0xfff0)
  86. return "Experimental";
  87. }
  88. return "Unknown";
  89. }
  90. static void
  91. geneve_opts_print(netdissect_options *ndo, const u_char *bp, u_int len)
  92. {
  93. const char *sep = "";
  94. while (len > 0) {
  95. uint16_t opt_class;
  96. uint8_t opt_type;
  97. uint8_t opt_len;
  98. ND_PRINT((ndo, "%s", sep));
  99. sep = ", ";
  100. opt_class = EXTRACT_16BITS(bp);
  101. opt_type = *(bp + 2);
  102. opt_len = 4 + ((*(bp + 3) & OPT_LEN_MASK) * 4);
  103. ND_PRINT((ndo, "class %s (0x%x) type 0x%x%s len %u",
  104. format_opt_class(opt_class), opt_class, opt_type,
  105. opt_type & OPT_TYPE_CRITICAL ? "(C)" : "", opt_len));
  106. if (opt_len > len) {
  107. ND_PRINT((ndo, " [bad length]"));
  108. return;
  109. }
  110. if (ndo->ndo_vflag > 1 && opt_len > 4) {
  111. const uint32_t *data = (const uint32_t *)(bp + 4);
  112. int i;
  113. ND_PRINT((ndo, " data"));
  114. for (i = 4; i < opt_len; i += 4) {
  115. ND_PRINT((ndo, " %08x", EXTRACT_32BITS(data)));
  116. data++;
  117. }
  118. }
  119. bp += opt_len;
  120. len -= opt_len;
  121. }
  122. }
  123. void
  124. geneve_print(netdissect_options *ndo, const u_char *bp, u_int len)
  125. {
  126. uint8_t ver_opt;
  127. u_int version;
  128. uint8_t flags;
  129. uint16_t prot;
  130. uint32_t vni;
  131. uint8_t reserved;
  132. u_int opts_len;
  133. ND_PRINT((ndo, "Geneve"));
  134. ND_TCHECK2(*bp, 8);
  135. ver_opt = *bp;
  136. bp += 1;
  137. len -= 1;
  138. version = ver_opt >> VER_SHIFT;
  139. if (version != 0) {
  140. ND_PRINT((ndo, " ERROR: unknown-version %u", version));
  141. return;
  142. }
  143. flags = *bp;
  144. bp += 1;
  145. len -= 1;
  146. prot = EXTRACT_16BITS(bp);
  147. bp += 2;
  148. len -= 2;
  149. vni = EXTRACT_24BITS(bp);
  150. bp += 3;
  151. len -= 3;
  152. reserved = *bp;
  153. bp += 1;
  154. len -= 1;
  155. ND_PRINT((ndo, ", Flags [%s]",
  156. bittok2str_nosep(geneve_flag_values, "none", flags)));
  157. ND_PRINT((ndo, ", vni 0x%x", vni));
  158. if (reserved)
  159. ND_PRINT((ndo, ", rsvd 0x%x", reserved));
  160. if (ndo->ndo_eflag)
  161. ND_PRINT((ndo, ", proto %s (0x%04x)",
  162. tok2str(ethertype_values, "unknown", prot), prot));
  163. opts_len = (ver_opt & HDR_OPTS_LEN_MASK) * 4;
  164. if (len < opts_len) {
  165. ND_PRINT((ndo, " truncated-geneve - %u bytes missing",
  166. opts_len - len));
  167. return;
  168. }
  169. ND_TCHECK2(*bp, opts_len);
  170. if (opts_len > 0) {
  171. ND_PRINT((ndo, ", options ["));
  172. if (ndo->ndo_vflag)
  173. geneve_opts_print(ndo, bp, opts_len);
  174. else
  175. ND_PRINT((ndo, "%u bytes", opts_len));
  176. ND_PRINT((ndo, "]"));
  177. }
  178. bp += opts_len;
  179. len -= opts_len;
  180. if (ndo->ndo_vflag < 1)
  181. ND_PRINT((ndo, ": "));
  182. else
  183. ND_PRINT((ndo, "\n\t"));
  184. if (ethertype_print(ndo, prot, bp, len, ndo->ndo_snapend - bp, NULL, NULL) == 0) {
  185. if (prot == ETHERTYPE_TEB)
  186. ether_print(ndo, bp, len, ndo->ndo_snapend - bp, NULL, NULL);
  187. else
  188. ND_PRINT((ndo, "geneve-proto-0x%x", prot));
  189. }
  190. return;
  191. trunc:
  192. ND_PRINT((ndo, " [|geneve]"));
  193. }