xref: /netbsd-src/external/bsd/tcpdump/dist/print-openflow.c (revision 3d25ea14d97c822076445296bcc6a85582fb622e)
1026d7285Schristos /*
2026d7285Schristos  * This module implements printing of the very basic (version-independent)
3026d7285Schristos  * OpenFlow header and iteration over OpenFlow messages. It is intended for
4026d7285Schristos  * dispatching of version-specific OpenFlow message decoding.
5026d7285Schristos  *
6026d7285Schristos  *
7026d7285Schristos  * Copyright (c) 2013 The TCPDUMP project
8026d7285Schristos  * All rights reserved.
9026d7285Schristos  *
10026d7285Schristos  * Redistribution and use in source and binary forms, with or without
11026d7285Schristos  * modification, are permitted provided that the following conditions
12026d7285Schristos  * are met:
13026d7285Schristos  * 1. Redistributions of source code must retain the above copyright
14026d7285Schristos  *    notice, this list of conditions and the following disclaimer.
15026d7285Schristos  * 2. Redistributions in binary form must reproduce the above copyright
16026d7285Schristos  *    notice, this list of conditions and the following disclaimer in the
17026d7285Schristos  *    documentation and/or other materials provided with the distribution.
18026d7285Schristos  *
19026d7285Schristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20026d7285Schristos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21026d7285Schristos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22026d7285Schristos  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23026d7285Schristos  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24026d7285Schristos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25026d7285Schristos  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26026d7285Schristos  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27026d7285Schristos  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28026d7285Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29026d7285Schristos  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30026d7285Schristos  * POSSIBILITY OF SUCH DAMAGE.
31026d7285Schristos  */
32026d7285Schristos 
33c47fd378Schristos #define NETDISSECT_REWORKED
34026d7285Schristos #ifdef HAVE_CONFIG_H
35026d7285Schristos #include "config.h"
36026d7285Schristos #endif
37026d7285Schristos 
38026d7285Schristos #include <tcpdump-stdinc.h>
39026d7285Schristos 
40026d7285Schristos #include "interface.h"
41026d7285Schristos #include "extract.h"
42026d7285Schristos #include "openflow.h"
43*3d25ea14Schristos #include "oui.h"
44026d7285Schristos 
45c47fd378Schristos static const char tstr[] = " [|openflow]";
46c47fd378Schristos static const char cstr[] = " (corrupt)";
47c47fd378Schristos 
48026d7285Schristos #define OF_VER_1_0    0x01
49026d7285Schristos 
50*3d25ea14Schristos const struct tok onf_exp_str[] = {
51*3d25ea14Schristos 	{ ONF_EXP_ONF,               "ONF Extensions"                                  },
52*3d25ea14Schristos 	{ ONF_EXP_BUTE,              "Budapest University of Technology and Economics" },
53*3d25ea14Schristos 	{ ONF_EXP_NOVIFLOW,          "NoviFlow"                                        },
54*3d25ea14Schristos 	{ ONF_EXP_L3,                "L3+ Extensions, Vendor Neutral"                  },
55*3d25ea14Schristos 	{ ONF_EXP_L4L7,              "L4-L7 Extensions"                                },
56*3d25ea14Schristos 	{ ONF_EXP_WMOB,              "Wireless and Mobility Extensions"                },
57*3d25ea14Schristos 	{ ONF_EXP_FABS,              "Forwarding Abstractions Extensions"              },
58*3d25ea14Schristos 	{ ONF_EXP_OTRANS,            "Optical Transport Extensions"                    },
59*3d25ea14Schristos 	{ 0, NULL }
60*3d25ea14Schristos };
61*3d25ea14Schristos 
62*3d25ea14Schristos const char *
63*3d25ea14Schristos of_vendor_name(const uint32_t vendor)
64*3d25ea14Schristos {
65*3d25ea14Schristos 	const struct tok *table = (vendor & 0xff000000) == 0 ? oui_values : onf_exp_str;
66*3d25ea14Schristos 	return tok2str(table, "unknown", vendor);
67*3d25ea14Schristos }
68*3d25ea14Schristos 
69026d7285Schristos static void
70c47fd378Schristos of_header_print(netdissect_options *ndo, const uint8_t version, const uint8_t type,
71*3d25ea14Schristos                       const uint16_t length, const uint32_t xid)
72*3d25ea14Schristos {
73c47fd378Schristos 	ND_PRINT((ndo, "\n\tversion unknown (0x%02x), type 0x%02x, length %u, xid 0x%08x",
74c47fd378Schristos 	       version, type, length, xid));
75026d7285Schristos }
76026d7285Schristos 
77026d7285Schristos /* Print a single OpenFlow message. */
78026d7285Schristos static const u_char *
79*3d25ea14Schristos of_header_body_print(netdissect_options *ndo, const u_char *cp, const u_char *ep)
80*3d25ea14Schristos {
81026d7285Schristos 	uint8_t version, type;
82026d7285Schristos 	uint16_t length;
83026d7285Schristos 	uint32_t xid;
84026d7285Schristos 
85026d7285Schristos 	if (ep < cp + OF_HEADER_LEN)
86026d7285Schristos 		goto corrupt;
87026d7285Schristos 	/* version */
88c47fd378Schristos 	ND_TCHECK2(*cp, 1);
89026d7285Schristos 	version = *cp;
90026d7285Schristos 	cp += 1;
91026d7285Schristos 	/* type */
92c47fd378Schristos 	ND_TCHECK2(*cp, 1);
93026d7285Schristos 	type = *cp;
94026d7285Schristos 	cp += 1;
95026d7285Schristos 	/* length */
96c47fd378Schristos 	ND_TCHECK2(*cp, 2);
97026d7285Schristos 	length = EXTRACT_16BITS(cp);
98026d7285Schristos 	cp += 2;
99026d7285Schristos 	/* xid */
100c47fd378Schristos 	ND_TCHECK2(*cp, 4);
101026d7285Schristos 	xid = EXTRACT_32BITS(cp);
102026d7285Schristos 	cp += 4;
103026d7285Schristos 	/* Message length includes the header length and a message always includes
104026d7285Schristos 	 * the basic header. A message length underrun fails decoding of the rest of
105026d7285Schristos 	 * the current packet. At the same time, try decoding as much of the current
106026d7285Schristos 	 * message as possible even when it does not end within the current TCP
107026d7285Schristos 	 * segment. */
108026d7285Schristos 	if (length < OF_HEADER_LEN) {
109c47fd378Schristos 		of_header_print(ndo, version, type, length, xid);
110026d7285Schristos 		goto corrupt;
111026d7285Schristos 	}
112026d7285Schristos 	/* Decode known protocol versions further without printing the header (the
113026d7285Schristos 	 * type decoding is version-specific. */
114026d7285Schristos 	switch (version) {
115026d7285Schristos 	case OF_VER_1_0:
116c47fd378Schristos 		return of10_header_body_print(ndo, cp, ep, type, length, xid);
117026d7285Schristos 	default:
118c47fd378Schristos 		of_header_print(ndo, version, type, length, xid);
119c47fd378Schristos 		ND_TCHECK2(*cp, length - OF_HEADER_LEN);
120026d7285Schristos 		return cp + length - OF_HEADER_LEN; /* done with current message */
121026d7285Schristos 	}
122026d7285Schristos 
123026d7285Schristos corrupt: /* fail current packet */
124c47fd378Schristos 	ND_PRINT((ndo, "%s", cstr));
125c47fd378Schristos 	ND_TCHECK2(*cp, ep - cp);
126026d7285Schristos 	return ep;
127026d7285Schristos trunc:
128c47fd378Schristos 	ND_PRINT((ndo, "%s", tstr));
129026d7285Schristos 	return ep;
130026d7285Schristos }
131026d7285Schristos 
132026d7285Schristos /* Print a TCP segment worth of OpenFlow messages presuming the segment begins
133026d7285Schristos  * on a message boundary. */
134026d7285Schristos void
135*3d25ea14Schristos openflow_print(netdissect_options *ndo, const u_char *cp, const u_int len)
136*3d25ea14Schristos {
137026d7285Schristos 	const u_char *ep = cp + len;
138026d7285Schristos 
139c47fd378Schristos 	ND_PRINT((ndo, ": OpenFlow"));
140026d7285Schristos 	while (cp < ep)
141c47fd378Schristos 		cp = of_header_body_print(ndo, cp, ep);
142026d7285Schristos }
143