]> The Tcpdump Group git mirrors - tcpdump/blob - print-openflow-1.0.c
Print truncations with nd_print_trunc() instead of tstr[] strings
[tcpdump] / print-openflow-1.0.c
1 /*
2 * This module implements decoding of OpenFlow protocol version 1.0 (wire
3 * protocol 0x01). The decoder implements terse (default), detailed (-v) and
4 * full (-vv) output formats and, as much as each format implies, detects and
5 * tries to work around sizing anomalies inside the messages. The decoder marks
6 * up bogus values of selected message fields and decodes partially captured
7 * messages up to the snapshot end. It is based on the specification below:
8 *
9 * [OF10] http://www.openflow.org/documents/openflow-spec-v1.0.0.pdf
10 *
11 * Most functions in this file take 3 arguments into account:
12 * * cp -- the pointer to the first octet to decode
13 * * len -- the length of the current structure as declared on the wire
14 * * ep -- the pointer to the end of the captured frame
15 * They return either the pointer to the next not-yet-decoded part of the frame
16 * or the value of ep, which means the current frame processing is over as it
17 * has been fully decoded or is invalid or truncated. This way it is possible
18 * to chain and nest such functions uniformly to decode an OF1.0 message, which
19 * consists of several layers of nested structures.
20 *
21 * Decoding of Ethernet frames nested in OFPT_PACKET_IN and OFPT_PACKET_OUT
22 * messages is done only when the verbosity level set by command-line argument
23 * is "-vvv" or higher. In that case the verbosity level is temporarily
24 * decremented by 3 during the nested frame decoding. For example, running
25 * tcpdump with "-vvvv" will do full decoding of OpenFlow and "-v" decoding of
26 * the nested frames.
27 *
28 * Partial decoding of Big Switch Networks vendor extensions is done after the
29 * oftest (OpenFlow Testing Framework) and Loxigen (library generator) source
30 * code.
31 *
32 *
33 * Copyright (c) 2013 The TCPDUMP project
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
46 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
47 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
48 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
49 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
50 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
51 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
52 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
53 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
55 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
56 * POSSIBILITY OF SUCH DAMAGE.
57 */
58
59 /* \summary: OpenFlow protocol version 1.0 printer */
60
61 #ifdef HAVE_CONFIG_H
62 #include <config.h>
63 #endif
64
65 #include "netdissect-stdinc.h"
66
67 #include "netdissect.h"
68 #include "extract.h"
69 #include "addrtoname.h"
70 #include "ethertype.h"
71 #include "ipproto.h"
72 #include "oui.h"
73 #include "openflow.h"
74
75
76 #define OFPT_HELLO 0x00
77 #define OFPT_ERROR 0x01
78 #define OFPT_ECHO_REQUEST 0x02
79 #define OFPT_ECHO_REPLY 0x03
80 #define OFPT_VENDOR 0x04
81 #define OFPT_FEATURES_REQUEST 0x05
82 #define OFPT_FEATURES_REPLY 0x06
83 #define OFPT_GET_CONFIG_REQUEST 0x07
84 #define OFPT_GET_CONFIG_REPLY 0x08
85 #define OFPT_SET_CONFIG 0x09
86 #define OFPT_PACKET_IN 0x0a
87 #define OFPT_FLOW_REMOVED 0x0b
88 #define OFPT_PORT_STATUS 0x0c
89 #define OFPT_PACKET_OUT 0x0d
90 #define OFPT_FLOW_MOD 0x0e
91 #define OFPT_PORT_MOD 0x0f
92 #define OFPT_STATS_REQUEST 0x10
93 #define OFPT_STATS_REPLY 0x11
94 #define OFPT_BARRIER_REQUEST 0x12
95 #define OFPT_BARRIER_REPLY 0x13
96 #define OFPT_QUEUE_GET_CONFIG_REQUEST 0x14
97 #define OFPT_QUEUE_GET_CONFIG_REPLY 0x15
98 static const struct tok ofpt_str[] = {
99 { OFPT_HELLO, "HELLO" },
100 { OFPT_ERROR, "ERROR" },
101 { OFPT_ECHO_REQUEST, "ECHO_REQUEST" },
102 { OFPT_ECHO_REPLY, "ECHO_REPLY" },
103 { OFPT_VENDOR, "VENDOR" },
104 { OFPT_FEATURES_REQUEST, "FEATURES_REQUEST" },
105 { OFPT_FEATURES_REPLY, "FEATURES_REPLY" },
106 { OFPT_GET_CONFIG_REQUEST, "GET_CONFIG_REQUEST" },
107 { OFPT_GET_CONFIG_REPLY, "GET_CONFIG_REPLY" },
108 { OFPT_SET_CONFIG, "SET_CONFIG" },
109 { OFPT_PACKET_IN, "PACKET_IN" },
110 { OFPT_FLOW_REMOVED, "FLOW_REMOVED" },
111 { OFPT_PORT_STATUS, "PORT_STATUS" },
112 { OFPT_PACKET_OUT, "PACKET_OUT" },
113 { OFPT_FLOW_MOD, "FLOW_MOD" },
114 { OFPT_PORT_MOD, "PORT_MOD" },
115 { OFPT_STATS_REQUEST, "STATS_REQUEST" },
116 { OFPT_STATS_REPLY, "STATS_REPLY" },
117 { OFPT_BARRIER_REQUEST, "BARRIER_REQUEST" },
118 { OFPT_BARRIER_REPLY, "BARRIER_REPLY" },
119 { OFPT_QUEUE_GET_CONFIG_REQUEST, "QUEUE_GET_CONFIG_REQUEST" },
120 { OFPT_QUEUE_GET_CONFIG_REPLY, "QUEUE_GET_CONFIG_REPLY" },
121 { 0, NULL }
122 };
123
124 #define OFPPC_PORT_DOWN (1U <<0)
125 #define OFPPC_NO_STP (1U <<1)
126 #define OFPPC_NO_RECV (1U <<2)
127 #define OFPPC_NO_RECV_STP (1U <<3)
128 #define OFPPC_NO_FLOOD (1U <<4)
129 #define OFPPC_NO_FWD (1U <<5)
130 #define OFPPC_NO_PACKET_IN (1U <<6)
131 static const struct tok ofppc_bm[] = {
132 { OFPPC_PORT_DOWN, "PORT_DOWN" },
133 { OFPPC_NO_STP, "NO_STP" },
134 { OFPPC_NO_RECV, "NO_RECV" },
135 { OFPPC_NO_RECV_STP, "NO_RECV_STP" },
136 { OFPPC_NO_FLOOD, "NO_FLOOD" },
137 { OFPPC_NO_FWD, "NO_FWD" },
138 { OFPPC_NO_PACKET_IN, "NO_PACKET_IN" },
139 { 0, NULL }
140 };
141 #define OFPPC_U (~(OFPPC_PORT_DOWN | OFPPC_NO_STP | OFPPC_NO_RECV | \
142 OFPPC_NO_RECV_STP | OFPPC_NO_FLOOD | OFPPC_NO_FWD | \
143 OFPPC_NO_PACKET_IN))
144
145 #define OFPPS_LINK_DOWN (1U << 0)
146 #define OFPPS_STP_LISTEN (0U << 8)
147 #define OFPPS_STP_LEARN (1U << 8)
148 #define OFPPS_STP_FORWARD (2U << 8)
149 #define OFPPS_STP_BLOCK (3U << 8)
150 #define OFPPS_STP_MASK (3U << 8)
151 static const struct tok ofpps_bm[] = {
152 { OFPPS_LINK_DOWN, "LINK_DOWN" },
153 { OFPPS_STP_LISTEN, "STP_LISTEN" },
154 { OFPPS_STP_LEARN, "STP_LEARN" },
155 { OFPPS_STP_FORWARD, "STP_FORWARD" },
156 { OFPPS_STP_BLOCK, "STP_BLOCK" },
157 { 0, NULL }
158 };
159 #define OFPPS_U (~(OFPPS_LINK_DOWN | OFPPS_STP_LISTEN | OFPPS_STP_LEARN | \
160 OFPPS_STP_FORWARD | OFPPS_STP_BLOCK))
161
162 #define OFPP_MAX 0xff00U
163 #define OFPP_IN_PORT 0xfff8U
164 #define OFPP_TABLE 0xfff9U
165 #define OFPP_NORMAL 0xfffaU
166 #define OFPP_FLOOD 0xfffbU
167 #define OFPP_ALL 0xfffcU
168 #define OFPP_CONTROLLER 0xfffdU
169 #define OFPP_LOCAL 0xfffeU
170 #define OFPP_NONE 0xffffU
171 static const struct tok ofpp_str[] = {
172 { OFPP_MAX, "MAX" },
173 { OFPP_IN_PORT, "IN_PORT" },
174 { OFPP_TABLE, "TABLE" },
175 { OFPP_NORMAL, "NORMAL" },
176 { OFPP_FLOOD, "FLOOD" },
177 { OFPP_ALL, "ALL" },
178 { OFPP_CONTROLLER, "CONTROLLER" },
179 { OFPP_LOCAL, "LOCAL" },
180 { OFPP_NONE, "NONE" },
181 { 0, NULL }
182 };
183
184 #define OFPPF_10MB_HD (1U << 0)
185 #define OFPPF_10MB_FD (1U << 1)
186 #define OFPPF_100MB_HD (1U << 2)
187 #define OFPPF_100MB_FD (1U << 3)
188 #define OFPPF_1GB_HD (1U << 4)
189 #define OFPPF_1GB_FD (1U << 5)
190 #define OFPPF_10GB_FD (1U << 6)
191 #define OFPPF_COPPER (1U << 7)
192 #define OFPPF_FIBER (1U << 8)
193 #define OFPPF_AUTONEG (1U << 9)
194 #define OFPPF_PAUSE (1U <<10)
195 #define OFPPF_PAUSE_ASYM (1U <<11)
196 static const struct tok ofppf_bm[] = {
197 { OFPPF_10MB_HD, "10MB_HD" },
198 { OFPPF_10MB_FD, "10MB_FD" },
199 { OFPPF_100MB_HD, "100MB_HD" },
200 { OFPPF_100MB_FD, "100MB_FD" },
201 { OFPPF_1GB_HD, "1GB_HD" },
202 { OFPPF_1GB_FD, "1GB_FD" },
203 { OFPPF_10GB_FD, "10GB_FD" },
204 { OFPPF_COPPER, "COPPER" },
205 { OFPPF_FIBER, "FIBER" },
206 { OFPPF_AUTONEG, "AUTONEG" },
207 { OFPPF_PAUSE, "PAUSE" },
208 { OFPPF_PAUSE_ASYM, "PAUSE_ASYM" },
209 { 0, NULL }
210 };
211 #define OFPPF_U (~(OFPPF_10MB_HD | OFPPF_10MB_FD | OFPPF_100MB_HD | \
212 OFPPF_100MB_FD | OFPPF_1GB_HD | OFPPF_1GB_FD | \
213 OFPPF_10GB_FD | OFPPF_COPPER | OFPPF_FIBER | \
214 OFPPF_AUTONEG | OFPPF_PAUSE | OFPPF_PAUSE_ASYM))
215
216 #define OFPQT_NONE 0x0000
217 #define OFPQT_MIN_RATE 0x0001
218 static const struct tok ofpqt_str[] = {
219 { OFPQT_NONE, "NONE" },
220 { OFPQT_MIN_RATE, "MIN_RATE" },
221 { 0, NULL }
222 };
223
224 #define OFPFW_IN_PORT (1U <<0)
225 #define OFPFW_DL_VLAN (1U <<1)
226 #define OFPFW_DL_SRC (1U <<2)
227 #define OFPFW_DL_DST (1U <<3)
228 #define OFPFW_DL_TYPE (1U <<4)
229 #define OFPFW_NW_PROTO (1U <<5)
230 #define OFPFW_TP_SRC (1U <<6)
231 #define OFPFW_TP_DST (1U <<7)
232 #define OFPFW_NW_SRC_SHIFT 8
233 #define OFPFW_NW_SRC_BITS 6
234 #define OFPFW_NW_SRC_MASK (((1U <<OFPFW_NW_SRC_BITS) - 1) << OFPFW_NW_SRC_SHIFT)
235 #define OFPFW_NW_DST_SHIFT 14
236 #define OFPFW_NW_DST_BITS 6
237 #define OFPFW_NW_DST_MASK (((1U <<OFPFW_NW_DST_BITS) - 1) << OFPFW_NW_DST_SHIFT)
238 #define OFPFW_DL_VLAN_PCP (1U <<20)
239 #define OFPFW_NW_TOS (1U <<21)
240 #define OFPFW_ALL ((1U <<22) - 1)
241 static const struct tok ofpfw_bm[] = {
242 { OFPFW_IN_PORT, "IN_PORT" },
243 { OFPFW_DL_VLAN, "DL_VLAN" },
244 { OFPFW_DL_SRC, "DL_SRC" },
245 { OFPFW_DL_DST, "DL_DST" },
246 { OFPFW_DL_TYPE, "DL_TYPE" },
247 { OFPFW_NW_PROTO, "NW_PROTO" },
248 { OFPFW_TP_SRC, "TP_SRC" },
249 { OFPFW_TP_DST, "TP_DST" },
250 { OFPFW_DL_VLAN_PCP, "DL_VLAN_PCP" },
251 { OFPFW_NW_TOS, "NW_TOS" },
252 { 0, NULL }
253 };
254 /* The above array does not include bits 8~13 (OFPFW_NW_SRC_*) and 14~19
255 * (OFPFW_NW_DST_*), which are not a part of the bitmap and require decoding
256 * other than that of tok2str(). The macro below includes these bits such that
257 * they are not reported as bogus in the decoding. */
258 #define OFPFW_U (~(OFPFW_ALL))
259
260 #define OFPAT_OUTPUT 0x0000U
261 #define OFPAT_SET_VLAN_VID 0x0001U
262 #define OFPAT_SET_VLAN_PCP 0x0002U
263 #define OFPAT_STRIP_VLAN 0x0003U
264 #define OFPAT_SET_DL_SRC 0x0004U
265 #define OFPAT_SET_DL_DST 0x0005U
266 #define OFPAT_SET_NW_SRC 0x0006U
267 #define OFPAT_SET_NW_DST 0x0007U
268 #define OFPAT_SET_NW_TOS 0x0008U
269 #define OFPAT_SET_TP_SRC 0x0009U
270 #define OFPAT_SET_TP_DST 0x000aU
271 #define OFPAT_ENQUEUE 0x000bU
272 #define OFPAT_VENDOR 0xffffU
273 static const struct tok ofpat_str[] = {
274 { OFPAT_OUTPUT, "OUTPUT" },
275 { OFPAT_SET_VLAN_VID, "SET_VLAN_VID" },
276 { OFPAT_SET_VLAN_PCP, "SET_VLAN_PCP" },
277 { OFPAT_STRIP_VLAN, "STRIP_VLAN" },
278 { OFPAT_SET_DL_SRC, "SET_DL_SRC" },
279 { OFPAT_SET_DL_DST, "SET_DL_DST" },
280 { OFPAT_SET_NW_SRC, "SET_NW_SRC" },
281 { OFPAT_SET_NW_DST, "SET_NW_DST" },
282 { OFPAT_SET_NW_TOS, "SET_NW_TOS" },
283 { OFPAT_SET_TP_SRC, "SET_TP_SRC" },
284 { OFPAT_SET_TP_DST, "SET_TP_DST" },
285 { OFPAT_ENQUEUE, "ENQUEUE" },
286 { OFPAT_VENDOR, "VENDOR" },
287 { 0, NULL }
288 };
289
290 /* bit-shifted, w/o vendor action */
291 static const struct tok ofpat_bm[] = {
292 { 1U <<OFPAT_OUTPUT, "OUTPUT" },
293 { 1U <<OFPAT_SET_VLAN_VID, "SET_VLAN_VID" },
294 { 1U <<OFPAT_SET_VLAN_PCP, "SET_VLAN_PCP" },
295 { 1U <<OFPAT_STRIP_VLAN, "STRIP_VLAN" },
296 { 1U <<OFPAT_SET_DL_SRC, "SET_DL_SRC" },
297 { 1U <<OFPAT_SET_DL_DST, "SET_DL_DST" },
298 { 1U <<OFPAT_SET_NW_SRC, "SET_NW_SRC" },
299 { 1U <<OFPAT_SET_NW_DST, "SET_NW_DST" },
300 { 1U <<OFPAT_SET_NW_TOS, "SET_NW_TOS" },
301 { 1U <<OFPAT_SET_TP_SRC, "SET_TP_SRC" },
302 { 1U <<OFPAT_SET_TP_DST, "SET_TP_DST" },
303 { 1U <<OFPAT_ENQUEUE, "ENQUEUE" },
304 { 0, NULL }
305 };
306 #define OFPAT_U (~(1U <<OFPAT_OUTPUT | 1U <<OFPAT_SET_VLAN_VID | \
307 1U <<OFPAT_SET_VLAN_PCP | 1U <<OFPAT_STRIP_VLAN | \
308 1U <<OFPAT_SET_DL_SRC | 1U <<OFPAT_SET_DL_DST | \
309 1U <<OFPAT_SET_NW_SRC | 1U <<OFPAT_SET_NW_DST | \
310 1U <<OFPAT_SET_NW_TOS | 1U <<OFPAT_SET_TP_SRC | \
311 1U <<OFPAT_SET_TP_DST | 1U <<OFPAT_ENQUEUE))
312
313 #define OFPC_FLOW_STATS (1U <<0)
314 #define OFPC_TABLE_STATS (1U <<1)
315 #define OFPC_PORT_STATS (1U <<2)
316 #define OFPC_STP (1U <<3)
317 #define OFPC_RESERVED (1U <<4)
318 #define OFPC_IP_REASM (1U <<5)
319 #define OFPC_QUEUE_STATS (1U <<6)
320 #define OFPC_ARP_MATCH_IP (1U <<7)
321 static const struct tok ofp_capabilities_bm[] = {
322 { OFPC_FLOW_STATS, "FLOW_STATS" },
323 { OFPC_TABLE_STATS, "TABLE_STATS" },
324 { OFPC_PORT_STATS, "PORT_STATS" },
325 { OFPC_STP, "STP" },
326 { OFPC_RESERVED, "RESERVED" }, /* not in the mask below */
327 { OFPC_IP_REASM, "IP_REASM" },
328 { OFPC_QUEUE_STATS, "QUEUE_STATS" },
329 { OFPC_ARP_MATCH_IP, "ARP_MATCH_IP" },
330 { 0, NULL }
331 };
332 #define OFPCAP_U (~(OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | \
333 OFPC_STP | OFPC_IP_REASM | OFPC_QUEUE_STATS | \
334 OFPC_ARP_MATCH_IP))
335
336 #define OFPC_FRAG_NORMAL 0x0000U
337 #define OFPC_FRAG_DROP 0x0001U
338 #define OFPC_FRAG_REASM 0x0002U
339 #define OFPC_FRAG_MASK 0x0003U
340 static const struct tok ofp_config_str[] = {
341 { OFPC_FRAG_NORMAL, "FRAG_NORMAL" },
342 { OFPC_FRAG_DROP, "FRAG_DROP" },
343 { OFPC_FRAG_REASM, "FRAG_REASM" },
344 { 0, NULL }
345 };
346
347 #define OFPFC_ADD 0x0000U
348 #define OFPFC_MODIFY 0x0001U
349 #define OFPFC_MODIFY_STRICT 0x0002U
350 #define OFPFC_DELETE 0x0003U
351 #define OFPFC_DELETE_STRICT 0x0004U
352 static const struct tok ofpfc_str[] = {
353 { OFPFC_ADD, "ADD" },
354 { OFPFC_MODIFY, "MODIFY" },
355 { OFPFC_MODIFY_STRICT, "MODIFY_STRICT" },
356 { OFPFC_DELETE, "DELETE" },
357 { OFPFC_DELETE_STRICT, "DELETE_STRICT" },
358 { 0, NULL }
359 };
360
361 static const struct tok bufferid_str[] = {
362 { 0xffffffff, "NONE" },
363 { 0, NULL }
364 };
365
366 #define OFPFF_SEND_FLOW_REM (1U <<0)
367 #define OFPFF_CHECK_OVERLAP (1U <<1)
368 #define OFPFF_EMERG (1U <<2)
369 static const struct tok ofpff_bm[] = {
370 { OFPFF_SEND_FLOW_REM, "SEND_FLOW_REM" },
371 { OFPFF_CHECK_OVERLAP, "CHECK_OVERLAP" },
372 { OFPFF_EMERG, "EMERG" },
373 { 0, NULL }
374 };
375 #define OFPFF_U (~(OFPFF_SEND_FLOW_REM | OFPFF_CHECK_OVERLAP | OFPFF_EMERG))
376
377 #define OFPST_DESC 0x0000U
378 #define OFPST_FLOW 0x0001U
379 #define OFPST_AGGREGATE 0x0002U
380 #define OFPST_TABLE 0x0003U
381 #define OFPST_PORT 0x0004U
382 #define OFPST_QUEUE 0x0005U
383 #define OFPST_VENDOR 0xffffU
384 static const struct tok ofpst_str[] = {
385 { OFPST_DESC, "DESC" },
386 { OFPST_FLOW, "FLOW" },
387 { OFPST_AGGREGATE, "AGGREGATE" },
388 { OFPST_TABLE, "TABLE" },
389 { OFPST_PORT, "PORT" },
390 { OFPST_QUEUE, "QUEUE" },
391 { OFPST_VENDOR, "VENDOR" },
392 { 0, NULL }
393 };
394
395 static const struct tok tableid_str[] = {
396 { 0xfeU, "EMERG" },
397 { 0xffU, "ALL" },
398 { 0, NULL }
399 };
400
401 #define OFPQ_ALL 0xffffffffU
402 static const struct tok ofpq_str[] = {
403 { OFPQ_ALL, "ALL" },
404 { 0, NULL }
405 };
406
407 #define OFPSF_REPLY_MORE 0x0001U
408 static const struct tok ofpsf_reply_bm[] = {
409 { OFPSF_REPLY_MORE, "MORE" },
410 { 0, NULL }
411 };
412 #define OFPSF_REPLY_U (~(OFPSF_REPLY_MORE))
413
414 #define OFPR_NO_MATCH 0x00U
415 #define OFPR_ACTION 0x01U
416 static const struct tok ofpr_str[] = {
417 { OFPR_NO_MATCH, "NO_MATCH" },
418 { OFPR_ACTION, "ACTION" },
419 { 0, NULL }
420 };
421
422 #define OFPRR_IDLE_TIMEOUT 0x00U
423 #define OFPRR_HARD_TIMEOUT 0x01U
424 #define OFPRR_DELETE 0x02U
425 static const struct tok ofprr_str[] = {
426 { OFPRR_IDLE_TIMEOUT, "IDLE_TIMEOUT" },
427 { OFPRR_HARD_TIMEOUT, "HARD_TIMEOUT" },
428 { OFPRR_DELETE, "DELETE" },
429 { 0, NULL }
430 };
431
432 #define OFPPR_ADD 0x00U
433 #define OFPPR_DELETE 0x01U
434 #define OFPPR_MODIFY 0x02U
435 static const struct tok ofppr_str[] = {
436 { OFPPR_ADD, "ADD" },
437 { OFPPR_DELETE, "DELETE" },
438 { OFPPR_MODIFY, "MODIFY" },
439 { 0, NULL }
440 };
441
442 #define OFPET_HELLO_FAILED 0x0000U
443 #define OFPET_BAD_REQUEST 0x0001U
444 #define OFPET_BAD_ACTION 0x0002U
445 #define OFPET_FLOW_MOD_FAILED 0x0003U
446 #define OFPET_PORT_MOD_FAILED 0x0004U
447 #define OFPET_QUEUE_OP_FAILED 0x0005U
448 static const struct tok ofpet_str[] = {
449 { OFPET_HELLO_FAILED, "HELLO_FAILED" },
450 { OFPET_BAD_REQUEST, "BAD_REQUEST" },
451 { OFPET_BAD_ACTION, "BAD_ACTION" },
452 { OFPET_FLOW_MOD_FAILED, "FLOW_MOD_FAILED" },
453 { OFPET_PORT_MOD_FAILED, "PORT_MOD_FAILED" },
454 { OFPET_QUEUE_OP_FAILED, "QUEUE_OP_FAILED" },
455 { 0, NULL }
456 };
457
458 #define OFPHFC_INCOMPATIBLE 0x0000U
459 #define OFPHFC_EPERM 0x0001U
460 static const struct tok ofphfc_str[] = {
461 { OFPHFC_INCOMPATIBLE, "INCOMPATIBLE" },
462 { OFPHFC_EPERM, "EPERM" },
463 { 0, NULL }
464 };
465
466 #define OFPBRC_BAD_VERSION 0x0000U
467 #define OFPBRC_BAD_TYPE 0x0001U
468 #define OFPBRC_BAD_STAT 0x0002U
469 #define OFPBRC_BAD_VENDOR 0x0003U
470 #define OFPBRC_BAD_SUBTYPE 0x0004U
471 #define OFPBRC_EPERM 0x0005U
472 #define OFPBRC_BAD_LEN 0x0006U
473 #define OFPBRC_BUFFER_EMPTY 0x0007U
474 #define OFPBRC_BUFFER_UNKNOWN 0x0008U
475 static const struct tok ofpbrc_str[] = {
476 { OFPBRC_BAD_VERSION, "BAD_VERSION" },
477 { OFPBRC_BAD_TYPE, "BAD_TYPE" },
478 { OFPBRC_BAD_STAT, "BAD_STAT" },
479 { OFPBRC_BAD_VENDOR, "BAD_VENDOR" },
480 { OFPBRC_BAD_SUBTYPE, "BAD_SUBTYPE" },
481 { OFPBRC_EPERM, "EPERM" },
482 { OFPBRC_BAD_LEN, "BAD_LEN" },
483 { OFPBRC_BUFFER_EMPTY, "BUFFER_EMPTY" },
484 { OFPBRC_BUFFER_UNKNOWN, "BUFFER_UNKNOWN" },
485 { 0, NULL }
486 };
487
488 #define OFPBAC_BAD_TYPE 0x0000U
489 #define OFPBAC_BAD_LEN 0x0001U
490 #define OFPBAC_BAD_VENDOR 0x0002U
491 #define OFPBAC_BAD_VENDOR_TYPE 0x0003U
492 #define OFPBAC_BAD_OUT_PORT 0x0004U
493 #define OFPBAC_BAD_ARGUMENT 0x0005U
494 #define OFPBAC_EPERM 0x0006U
495 #define OFPBAC_TOO_MANY 0x0007U
496 #define OFPBAC_BAD_QUEUE 0x0008U
497 static const struct tok ofpbac_str[] = {
498 { OFPBAC_BAD_TYPE, "BAD_TYPE" },
499 { OFPBAC_BAD_LEN, "BAD_LEN" },
500 { OFPBAC_BAD_VENDOR, "BAD_VENDOR" },
501 { OFPBAC_BAD_VENDOR_TYPE, "BAD_VENDOR_TYPE" },
502 { OFPBAC_BAD_OUT_PORT, "BAD_OUT_PORT" },
503 { OFPBAC_BAD_ARGUMENT, "BAD_ARGUMENT" },
504 { OFPBAC_EPERM, "EPERM" },
505 { OFPBAC_TOO_MANY, "TOO_MANY" },
506 { OFPBAC_BAD_QUEUE, "BAD_QUEUE" },
507 { 0, NULL }
508 };
509
510 #define OFPFMFC_ALL_TABLES_FULL 0x0000U
511 #define OFPFMFC_OVERLAP 0x0001U
512 #define OFPFMFC_EPERM 0x0002U
513 #define OFPFMFC_BAD_EMERG_TIMEOUT 0x0003U
514 #define OFPFMFC_BAD_COMMAND 0x0004U
515 #define OFPFMFC_UNSUPPORTED 0x0005U
516 static const struct tok ofpfmfc_str[] = {
517 { OFPFMFC_ALL_TABLES_FULL, "ALL_TABLES_FULL" },
518 { OFPFMFC_OVERLAP, "OVERLAP" },
519 { OFPFMFC_EPERM, "EPERM" },
520 { OFPFMFC_BAD_EMERG_TIMEOUT, "BAD_EMERG_TIMEOUT" },
521 { OFPFMFC_BAD_COMMAND, "BAD_COMMAND" },
522 { OFPFMFC_UNSUPPORTED, "UNSUPPORTED" },
523 { 0, NULL }
524 };
525
526 #define OFPPMFC_BAD_PORT 0x0000U
527 #define OFPPMFC_BAD_HW_ADDR 0x0001U
528 static const struct tok ofppmfc_str[] = {
529 { OFPPMFC_BAD_PORT, "BAD_PORT" },
530 { OFPPMFC_BAD_HW_ADDR, "BAD_HW_ADDR" },
531 { 0, NULL }
532 };
533
534 #define OFPQOFC_BAD_PORT 0x0000U
535 #define OFPQOFC_BAD_QUEUE 0x0001U
536 #define OFPQOFC_EPERM 0x0002U
537 static const struct tok ofpqofc_str[] = {
538 { OFPQOFC_BAD_PORT, "BAD_PORT" },
539 { OFPQOFC_BAD_QUEUE, "BAD_QUEUE" },
540 { OFPQOFC_EPERM, "EPERM" },
541 { 0, NULL }
542 };
543
544 static const struct tok empty_str[] = {
545 { 0, NULL }
546 };
547
548 /* lengths (fixed or minimal) of particular protocol structures */
549 #define OF_SWITCH_CONFIG_LEN 12
550 #define OF_PHY_PORT_LEN 48
551 #define OF_SWITCH_FEATURES_LEN 32
552 #define OF_PORT_STATUS_LEN 64
553 #define OF_PORT_MOD_LEN 32
554 #define OF_PACKET_IN_LEN 20
555 #define OF_ACTION_OUTPUT_LEN 8
556 #define OF_ACTION_VLAN_VID_LEN 8
557 #define OF_ACTION_VLAN_PCP_LEN 8
558 #define OF_ACTION_DL_ADDR_LEN 16
559 #define OF_ACTION_NW_ADDR_LEN 8
560 #define OF_ACTION_TP_PORT_LEN 8
561 #define OF_ACTION_NW_TOS_LEN 8
562 #define OF_ACTION_VENDOR_HEADER_LEN 8
563 #define OF_ACTION_HEADER_LEN 8
564 #define OF_PACKET_OUT_LEN 16
565 #define OF_MATCH_LEN 40
566 #define OF_FLOW_MOD_LEN 72
567 #define OF_FLOW_REMOVED_LEN 88
568 #define OF_ERROR_MSG_LEN 12
569 #define OF_STATS_REQUEST_LEN 12
570 #define OF_STATS_REPLY_LEN 12
571 #define OF_DESC_STATS_LEN 1056
572 #define OF_FLOW_STATS_REQUEST_LEN 44
573 #define OF_FLOW_STATS_LEN 88
574 #define OF_AGGREGATE_STATS_REQUEST_LEN 44
575 #define OF_AGGREGATE_STATS_REPLY_LEN 24
576 #define OF_TABLE_STATS_LEN 64
577 #define OF_PORT_STATS_REQUEST_LEN 8
578 #define OF_PORT_STATS_LEN 104
579 #define OF_VENDOR_HEADER_LEN 12
580 #define OF_QUEUE_PROP_HEADER_LEN 8
581 #define OF_QUEUE_PROP_MIN_RATE_LEN 16
582 #define OF_PACKET_QUEUE_LEN 8
583 #define OF_QUEUE_GET_CONFIG_REQUEST_LEN 12
584 #define OF_QUEUE_GET_CONFIG_REPLY_LEN 16
585 #define OF_ACTION_ENQUEUE_LEN 16
586 #define OF_QUEUE_STATS_REQUEST_LEN 8
587 #define OF_QUEUE_STATS_LEN 32
588
589 /* miscellaneous constants from [OF10] */
590 #define OFP_MAX_TABLE_NAME_LEN 32
591 #define OFP_MAX_PORT_NAME_LEN 16
592 #define DESC_STR_LEN 256
593 #define SERIAL_NUM_LEN 32
594 #define OFP_VLAN_NONE 0xffffU
595
596 /* vendor extensions */
597 #define BSN_SET_IP_MASK 0
598 #define BSN_GET_IP_MASK_REQUEST 1
599 #define BSN_GET_IP_MASK_REPLY 2
600 #define BSN_SET_MIRRORING 3
601 #define BSN_GET_MIRRORING_REQUEST 4
602 #define BSN_GET_MIRRORING_REPLY 5
603 #define BSN_SHELL_COMMAND 6
604 #define BSN_SHELL_OUTPUT 7
605 #define BSN_SHELL_STATUS 8
606 #define BSN_GET_INTERFACES_REQUEST 9
607 #define BSN_GET_INTERFACES_REPLY 10
608 #define BSN_SET_PKTIN_SUPPRESSION_REQUEST 11
609 #define BSN_SET_L2_TABLE_REQUEST 12
610 #define BSN_GET_L2_TABLE_REQUEST 13
611 #define BSN_GET_L2_TABLE_REPLY 14
612 #define BSN_VIRTUAL_PORT_CREATE_REQUEST 15
613 #define BSN_VIRTUAL_PORT_CREATE_REPLY 16
614 #define BSN_VIRTUAL_PORT_REMOVE_REQUEST 17
615 #define BSN_BW_ENABLE_SET_REQUEST 18
616 #define BSN_BW_ENABLE_GET_REQUEST 19
617 #define BSN_BW_ENABLE_GET_REPLY 20
618 #define BSN_BW_CLEAR_DATA_REQUEST 21
619 #define BSN_BW_CLEAR_DATA_REPLY 22
620 #define BSN_BW_ENABLE_SET_REPLY 23
621 #define BSN_SET_L2_TABLE_REPLY 24
622 #define BSN_SET_PKTIN_SUPPRESSION_REPLY 25
623 #define BSN_VIRTUAL_PORT_REMOVE_REPLY 26
624 #define BSN_HYBRID_GET_REQUEST 27
625 #define BSN_HYBRID_GET_REPLY 28
626 /* 29 */
627 /* 30 */
628 #define BSN_PDU_TX_REQUEST 31
629 #define BSN_PDU_TX_REPLY 32
630 #define BSN_PDU_RX_REQUEST 33
631 #define BSN_PDU_RX_REPLY 34
632 #define BSN_PDU_RX_TIMEOUT 35
633
634 static const struct tok bsn_subtype_str[] = {
635 { BSN_SET_IP_MASK, "SET_IP_MASK" },
636 { BSN_GET_IP_MASK_REQUEST, "GET_IP_MASK_REQUEST" },
637 { BSN_GET_IP_MASK_REPLY, "GET_IP_MASK_REPLY" },
638 { BSN_SET_MIRRORING, "SET_MIRRORING" },
639 { BSN_GET_MIRRORING_REQUEST, "GET_MIRRORING_REQUEST" },
640 { BSN_GET_MIRRORING_REPLY, "GET_MIRRORING_REPLY" },
641 { BSN_SHELL_COMMAND, "SHELL_COMMAND" },
642 { BSN_SHELL_OUTPUT, "SHELL_OUTPUT" },
643 { BSN_SHELL_STATUS, "SHELL_STATUS" },
644 { BSN_GET_INTERFACES_REQUEST, "GET_INTERFACES_REQUEST" },
645 { BSN_GET_INTERFACES_REPLY, "GET_INTERFACES_REPLY" },
646 { BSN_SET_PKTIN_SUPPRESSION_REQUEST, "SET_PKTIN_SUPPRESSION_REQUEST" },
647 { BSN_SET_L2_TABLE_REQUEST, "SET_L2_TABLE_REQUEST" },
648 { BSN_GET_L2_TABLE_REQUEST, "GET_L2_TABLE_REQUEST" },
649 { BSN_GET_L2_TABLE_REPLY, "GET_L2_TABLE_REPLY" },
650 { BSN_VIRTUAL_PORT_CREATE_REQUEST, "VIRTUAL_PORT_CREATE_REQUEST" },
651 { BSN_VIRTUAL_PORT_CREATE_REPLY, "VIRTUAL_PORT_CREATE_REPLY" },
652 { BSN_VIRTUAL_PORT_REMOVE_REQUEST, "VIRTUAL_PORT_REMOVE_REQUEST" },
653 { BSN_BW_ENABLE_SET_REQUEST, "BW_ENABLE_SET_REQUEST" },
654 { BSN_BW_ENABLE_GET_REQUEST, "BW_ENABLE_GET_REQUEST" },
655 { BSN_BW_ENABLE_GET_REPLY, "BW_ENABLE_GET_REPLY" },
656 { BSN_BW_CLEAR_DATA_REQUEST, "BW_CLEAR_DATA_REQUEST" },
657 { BSN_BW_CLEAR_DATA_REPLY, "BW_CLEAR_DATA_REPLY" },
658 { BSN_BW_ENABLE_SET_REPLY, "BW_ENABLE_SET_REPLY" },
659 { BSN_SET_L2_TABLE_REPLY, "SET_L2_TABLE_REPLY" },
660 { BSN_SET_PKTIN_SUPPRESSION_REPLY, "SET_PKTIN_SUPPRESSION_REPLY" },
661 { BSN_VIRTUAL_PORT_REMOVE_REPLY, "VIRTUAL_PORT_REMOVE_REPLY" },
662 { BSN_HYBRID_GET_REQUEST, "HYBRID_GET_REQUEST" },
663 { BSN_HYBRID_GET_REPLY, "HYBRID_GET_REPLY" },
664 { BSN_PDU_TX_REQUEST, "PDU_TX_REQUEST" },
665 { BSN_PDU_TX_REPLY, "PDU_TX_REPLY" },
666 { BSN_PDU_RX_REQUEST, "PDU_RX_REQUEST" },
667 { BSN_PDU_RX_REPLY, "PDU_RX_REPLY" },
668 { BSN_PDU_RX_TIMEOUT, "PDU_RX_TIMEOUT" },
669 { 0, NULL }
670 };
671
672 #define BSN_ACTION_MIRROR 1
673 #define BSN_ACTION_SET_TUNNEL_DST 2
674 /* 3 */
675 #define BSN_ACTION_CHECKSUM 4
676
677 static const struct tok bsn_action_subtype_str[] = {
678 { BSN_ACTION_MIRROR, "MIRROR" },
679 { BSN_ACTION_SET_TUNNEL_DST, "SET_TUNNEL_DST" },
680 { BSN_ACTION_CHECKSUM, "CHECKSUM" },
681 { 0, NULL }
682 };
683
684 static const struct tok bsn_mirror_copy_stage_str[] = {
685 { 0, "INGRESS" },
686 { 1, "EGRESS" },
687 { 0, NULL },
688 };
689
690 static const struct tok bsn_onoff_str[] = {
691 { 0, "OFF" },
692 { 1, "ON" },
693 { 0, NULL },
694 };
695
696 static const char *
697 vlan_str(const uint16_t vid)
698 {
699 static char buf[sizeof("65535 (bogus)")];
700 const char *fmt;
701
702 if (vid == OFP_VLAN_NONE)
703 return "NONE";
704 fmt = (vid > 0 && vid < 0x0fff) ? "%u" : "%u (bogus)";
705 nd_snprintf(buf, sizeof(buf), fmt, vid);
706 return buf;
707 }
708
709 static const char *
710 pcp_str(const uint8_t pcp)
711 {
712 static char buf[sizeof("255 (bogus)")];
713 nd_snprintf(buf, sizeof(buf), pcp <= 7 ? "%u" : "%u (bogus)", pcp);
714 return buf;
715 }
716
717 static void
718 of10_bitmap_print(netdissect_options *ndo,
719 const struct tok *t, const uint32_t v, const uint32_t u)
720 {
721 const char *sep = " (";
722
723 if (v == 0)
724 return;
725 /* assigned bits */
726 for (; t->s != NULL; t++)
727 if (v & t->v) {
728 ND_PRINT("%s%s", sep, t->s);
729 sep = ", ";
730 }
731 /* unassigned bits? */
732 ND_PRINT(v & u ? ") (bogus)" : ")");
733 }
734
735 static const u_char *
736 of10_data_print(netdissect_options *ndo,
737 const u_char *cp, const u_char *ep, const u_int len)
738 {
739 if (len == 0)
740 return cp;
741 /* data */
742 ND_PRINT("\n\t data (%u octets)", len);
743 ND_TCHECK_LEN(cp, len);
744 if (ndo->ndo_vflag >= 2)
745 hex_and_ascii_print(ndo, "\n\t ", cp, len);
746 return cp + len;
747
748 trunc:
749 nd_print_trunc(ndo);
750 return ep;
751 }
752
753 static const u_char *
754 of10_bsn_message_print(netdissect_options *ndo,
755 const u_char *cp, const u_char *ep, const u_int len)
756 {
757 const u_char *cp0 = cp;
758 uint32_t subtype;
759
760 if (len < 4)
761 goto invalid;
762 /* subtype */
763 ND_TCHECK_4(cp);
764 subtype = EXTRACT_BE_U_4(cp);
765 cp += 4;
766 ND_PRINT("\n\t subtype %s", tok2str(bsn_subtype_str, "unknown (0x%08x)", subtype));
767 switch (subtype) {
768 case BSN_GET_IP_MASK_REQUEST:
769 /*
770 * 0 1 2 3
771 * 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
772 * +---------------+---------------+---------------+---------------+
773 * | subtype |
774 * +---------------+---------------+---------------+---------------+
775 * | index | pad |
776 * +---------------+---------------+---------------+---------------+
777 * | pad |
778 * +---------------+---------------+---------------+---------------+
779 *
780 */
781 if (len != 12)
782 goto invalid;
783 /* index */
784 ND_TCHECK_1(cp);
785 ND_PRINT(", index %u", EXTRACT_U_1(cp));
786 cp += 1;
787 /* pad */
788 ND_TCHECK_7(cp);
789 cp += 7;
790 break;
791 case BSN_SET_IP_MASK:
792 case BSN_GET_IP_MASK_REPLY:
793 /*
794 * 0 1 2 3
795 * 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
796 * +---------------+---------------+---------------+---------------+
797 * | subtype |
798 * +---------------+---------------+---------------+---------------+
799 * | index | pad |
800 * +---------------+---------------+---------------+---------------+
801 * | mask |
802 * +---------------+---------------+---------------+---------------+
803 *
804 */
805 if (len != 12)
806 goto invalid;
807 /* index */
808 ND_TCHECK_1(cp);
809 ND_PRINT(", index %u", EXTRACT_U_1(cp));
810 cp += 1;
811 /* pad */
812 ND_TCHECK_3(cp);
813 cp += 3;
814 /* mask */
815 ND_TCHECK_4(cp);
816 ND_PRINT(", mask %s", ipaddr_string(ndo, cp));
817 cp += 4;
818 break;
819 case BSN_SET_MIRRORING:
820 case BSN_GET_MIRRORING_REQUEST:
821 case BSN_GET_MIRRORING_REPLY:
822 /*
823 * 0 1 2 3
824 * 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
825 * +---------------+---------------+---------------+---------------+
826 * | subtype |
827 * +---------------+---------------+---------------+---------------+
828 * | report m. p. | pad |
829 * +---------------+---------------+---------------+---------------+
830 *
831 */
832 if (len != 8)
833 goto invalid;
834 /* report_mirror_ports */
835 ND_TCHECK_1(cp);
836 ND_PRINT(", report_mirror_ports %s", tok2str(bsn_onoff_str, "bogus (%u)", EXTRACT_U_1(cp)));
837 cp += 1;
838 /* pad */
839 ND_TCHECK_3(cp);
840 cp += 3;
841 break;
842 case BSN_GET_INTERFACES_REQUEST:
843 case BSN_GET_L2_TABLE_REQUEST:
844 case BSN_BW_ENABLE_GET_REQUEST:
845 case BSN_BW_CLEAR_DATA_REQUEST:
846 case BSN_HYBRID_GET_REQUEST:
847 /*
848 * 0 1 2 3
849 * 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
850 * +---------------+---------------+---------------+---------------+
851 * | subtype |
852 * +---------------+---------------+---------------+---------------+
853 *
854 */
855 if (len != 4)
856 goto invalid;
857 break;
858 case BSN_VIRTUAL_PORT_REMOVE_REQUEST:
859 /*
860 * 0 1 2 3
861 * 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
862 * +---------------+---------------+---------------+---------------+
863 * | subtype |
864 * +---------------+---------------+---------------+---------------+
865 * | vport_no |
866 * +---------------+---------------+---------------+---------------+
867 *
868 */
869 if (len != 8)
870 goto invalid;
871 /* vport_no */
872 ND_TCHECK_4(cp);
873 ND_PRINT(", vport_no %u", EXTRACT_BE_U_4(cp));
874 cp += 4;
875 break;
876 case BSN_SHELL_COMMAND:
877 /*
878 * 0 1 2 3
879 * 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
880 * +---------------+---------------+---------------+---------------+
881 * | subtype |
882 * +---------------+---------------+---------------+---------------+
883 * | service |
884 * +---------------+---------------+---------------+---------------+
885 * | data ...
886 * +---------------+---------------+--------
887 *
888 */
889 if (len < 8)
890 goto invalid;
891 /* service */
892 ND_TCHECK_4(cp);
893 ND_PRINT(", service %u", EXTRACT_BE_U_4(cp));
894 cp += 4;
895 /* data */
896 ND_PRINT(", data '");
897 if (nd_printn(ndo, cp, len - 8, ep)) {
898 ND_PRINT("'");
899 goto trunc;
900 }
901 ND_PRINT("'");
902 cp += len - 8;
903 break;
904 case BSN_SHELL_OUTPUT:
905 /*
906 * 0 1 2 3
907 * 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
908 * +---------------+---------------+---------------+---------------+
909 * | subtype |
910 * +---------------+---------------+---------------+---------------+
911 * | data ...
912 * +---------------+---------------+--------
913 *
914 */
915 /* already checked that len >= 4 */
916 /* data */
917 ND_PRINT(", data '");
918 if (nd_printn(ndo, cp, len - 4, ep)) {
919 ND_PRINT("'");
920 goto trunc;
921 }
922 ND_PRINT("'");
923 cp += len - 4;
924 break;
925 case BSN_SHELL_STATUS:
926 /*
927 * 0 1 2 3
928 * 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
929 * +---------------+---------------+---------------+---------------+
930 * | subtype |
931 * +---------------+---------------+---------------+---------------+
932 * | status |
933 * +---------------+---------------+---------------+---------------+
934 *
935 */
936 if (len != 8)
937 goto invalid;
938 /* status */
939 ND_TCHECK_4(cp);
940 ND_PRINT(", status 0x%08x", EXTRACT_BE_U_4(cp));
941 cp += 4;
942 break;
943 default:
944 ND_TCHECK_LEN(cp, len - 4);
945 cp += len - 4;
946 }
947 return cp;
948
949 invalid: /* skip the undersized data */
950 ND_PRINT("%s", istr);
951 ND_TCHECK_LEN(cp0, len);
952 return cp0 + len;
953 trunc:
954 nd_print_trunc(ndo);
955 return ep;
956 }
957
958 static const u_char *
959 of10_bsn_actions_print(netdissect_options *ndo,
960 const u_char *cp, const u_char *ep, const u_int len)
961 {
962 const u_char *cp0 = cp;
963 uint32_t subtype, vlan_tag;
964
965 if (len < 4)
966 goto invalid;
967 /* subtype */
968 ND_TCHECK_4(cp);
969 subtype = EXTRACT_BE_U_4(cp);
970 cp += 4;
971 ND_PRINT("\n\t subtype %s", tok2str(bsn_action_subtype_str, "unknown (0x%08x)", subtype));
972 switch (subtype) {
973 case BSN_ACTION_MIRROR:
974 /*
975 * 0 1 2 3
976 * 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
977 * +---------------+---------------+---------------+---------------+
978 * | subtype |
979 * +---------------+---------------+---------------+---------------+
980 * | dest_port |
981 * +---------------+---------------+---------------+---------------+
982 * | vlan_tag |
983 * +---------------+---------------+---------------+---------------+
984 * | copy_stage | pad |
985 * +---------------+---------------+---------------+---------------+
986 *
987 */
988 if (len != 16)
989 goto invalid;
990 /* dest_port */
991 ND_TCHECK_4(cp);
992 ND_PRINT(", dest_port %u", EXTRACT_BE_U_4(cp));
993 cp += 4;
994 /* vlan_tag */
995 ND_TCHECK_4(cp);
996 vlan_tag = EXTRACT_BE_U_4(cp);
997 cp += 4;
998 switch (vlan_tag >> 16) {
999 case 0:
1000 ND_PRINT(", vlan_tag none");
1001 break;
1002 case ETHERTYPE_8021Q:
1003 ND_PRINT(", vlan_tag 802.1Q (%s)", ieee8021q_tci_string(vlan_tag & 0xffff));
1004 break;
1005 default:
1006 ND_PRINT(", vlan_tag unknown (0x%04x)", vlan_tag >> 16);
1007 }
1008 /* copy_stage */
1009 ND_TCHECK_1(cp);
1010 ND_PRINT(", copy_stage %s", tok2str(bsn_mirror_copy_stage_str, "unknown (%u)", EXTRACT_U_1(cp)));
1011 cp += 1;
1012 /* pad */
1013 ND_TCHECK_3(cp);
1014 cp += 3;
1015 break;
1016 default:
1017 ND_TCHECK_LEN(cp, len - 4);
1018 cp += len - 4;
1019 }
1020
1021 return cp;
1022
1023 invalid:
1024 ND_PRINT("%s", istr);
1025 ND_TCHECK_LEN(cp0, len);
1026 return cp0 + len;
1027 trunc:
1028 nd_print_trunc(ndo);
1029 return ep;
1030 }
1031
1032 static const u_char *
1033 of10_vendor_action_print(netdissect_options *ndo,
1034 const u_char *cp, const u_char *ep, const u_int len)
1035 {
1036 uint32_t vendor;
1037 const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, const u_int);
1038
1039 if (len < 4)
1040 goto invalid;
1041 /* vendor */
1042 ND_TCHECK_4(cp);
1043 vendor = EXTRACT_BE_U_4(cp);
1044 cp += 4;
1045 ND_PRINT(", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor));
1046 /* data */
1047 decoder =
1048 vendor == OUI_BSN ? of10_bsn_actions_print :
1049 of10_data_print;
1050 return decoder(ndo, cp, ep, len - 4);
1051
1052 invalid: /* skip the undersized data */
1053 ND_PRINT("%s", istr);
1054 ND_TCHECK_LEN(cp, len);
1055 return cp + len;
1056 trunc:
1057 nd_print_trunc(ndo);
1058 return ep;
1059 }
1060
1061 static const u_char *
1062 of10_vendor_message_print(netdissect_options *ndo,
1063 const u_char *cp, const u_char *ep, const u_int len)
1064 {
1065 uint32_t vendor;
1066 const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, u_int);
1067
1068 if (len < 4)
1069 goto invalid;
1070 /* vendor */
1071 ND_TCHECK_4(cp);
1072 vendor = EXTRACT_BE_U_4(cp);
1073 cp += 4;
1074 ND_PRINT(", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor));
1075 /* data */
1076 decoder =
1077 vendor == OUI_BSN ? of10_bsn_message_print :
1078 of10_data_print;
1079 return decoder(ndo, cp, ep, len - 4);
1080
1081 invalid: /* skip the undersized data */
1082 ND_PRINT("%s", istr);
1083 ND_TCHECK_LEN(cp, len);
1084 return cp + len;
1085 trunc:
1086 nd_print_trunc(ndo);
1087 return ep;
1088 }
1089
1090 /* Vendor ID is mandatory, data is optional. */
1091 static const u_char *
1092 of10_vendor_data_print(netdissect_options *ndo,
1093 const u_char *cp, const u_char *ep, const u_int len)
1094 {
1095 uint32_t vendor;
1096
1097 if (len < 4)
1098 goto invalid;
1099 /* vendor */
1100 ND_TCHECK_4(cp);
1101 vendor = EXTRACT_BE_U_4(cp);
1102 cp += 4;
1103 ND_PRINT(", vendor 0x%08x (%s)", vendor, of_vendor_name(vendor));
1104 /* data */
1105 return of10_data_print(ndo, cp, ep, len - 4);
1106
1107 invalid: /* skip the undersized data */
1108 ND_PRINT("%s", istr);
1109 ND_TCHECK_LEN(cp, len);
1110 return cp + len;
1111 trunc:
1112 nd_print_trunc(ndo);
1113 return ep;
1114 }
1115
1116 static const u_char *
1117 of10_packet_data_print(netdissect_options *ndo,
1118 const u_char *cp, const u_char *ep, const u_int len)
1119 {
1120 if (len == 0)
1121 return cp;
1122 /* data */
1123 ND_PRINT("\n\t data (%u octets)", len);
1124 if (ndo->ndo_vflag < 3)
1125 return cp + len;
1126 ND_TCHECK_LEN(cp, len);
1127 ndo->ndo_vflag -= 3;
1128 ND_PRINT(", frame decoding below\n");
1129 ether_print(ndo, cp, len, ndo->ndo_snapend - cp, NULL, NULL);
1130 ndo->ndo_vflag += 3;
1131 return cp + len;
1132
1133 trunc:
1134 nd_print_trunc(ndo);
1135 return ep;
1136 }
1137
1138 /* [OF10] Section 5.2.1 */
1139 static const u_char *
1140 of10_phy_ports_print(netdissect_options *ndo,
1141 const u_char *cp, const u_char *ep, u_int len)
1142 {
1143 const u_char *cp0 = cp;
1144 const u_int len0 = len;
1145
1146 while (len) {
1147 if (len < OF_PHY_PORT_LEN)
1148 goto invalid;
1149 /* port_no */
1150 ND_TCHECK_2(cp);
1151 ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
1152 cp += 2;
1153 /* hw_addr */
1154 ND_TCHECK_LEN(cp, MAC_ADDR_LEN);
1155 ND_PRINT(", hw_addr %s", etheraddr_string(ndo, cp));
1156 cp += MAC_ADDR_LEN;
1157 /* name */
1158 ND_TCHECK_LEN(cp, OFP_MAX_PORT_NAME_LEN);
1159 ND_PRINT(", name '");
1160 nd_print(ndo, cp, cp + OFP_MAX_PORT_NAME_LEN);
1161 ND_PRINT("'");
1162 cp += OFP_MAX_PORT_NAME_LEN;
1163
1164 if (ndo->ndo_vflag < 2) {
1165 ND_TCHECK_LEN(cp, 24);
1166 cp += 24;
1167 goto next_port;
1168 }
1169 /* config */
1170 ND_TCHECK_4(cp);
1171 ND_PRINT("\n\t config 0x%08x", EXTRACT_BE_U_4(cp));
1172 of10_bitmap_print(ndo, ofppc_bm, EXTRACT_BE_U_4(cp),
1173 OFPPC_U);
1174 cp += 4;
1175 /* state */
1176 ND_TCHECK_4(cp);
1177 ND_PRINT("\n\t state 0x%08x", EXTRACT_BE_U_4(cp));
1178 of10_bitmap_print(ndo, ofpps_bm, EXTRACT_BE_U_4(cp),
1179 OFPPS_U);
1180 cp += 4;
1181 /* curr */
1182 ND_TCHECK_4(cp);
1183 ND_PRINT("\n\t curr 0x%08x", EXTRACT_BE_U_4(cp));
1184 of10_bitmap_print(ndo, ofppf_bm, EXTRACT_BE_U_4(cp),
1185 OFPPF_U);
1186 cp += 4;
1187 /* advertised */
1188 ND_TCHECK_4(cp);
1189 ND_PRINT("\n\t advertised 0x%08x", EXTRACT_BE_U_4(cp));
1190 of10_bitmap_print(ndo, ofppf_bm, EXTRACT_BE_U_4(cp),
1191 OFPPF_U);
1192 cp += 4;
1193 /* supported */
1194 ND_TCHECK_4(cp);
1195 ND_PRINT("\n\t supported 0x%08x", EXTRACT_BE_U_4(cp));
1196 of10_bitmap_print(ndo, ofppf_bm, EXTRACT_BE_U_4(cp),
1197 OFPPF_U);
1198 cp += 4;
1199 /* peer */
1200 ND_TCHECK_4(cp);
1201 ND_PRINT("\n\t peer 0x%08x", EXTRACT_BE_U_4(cp));
1202 of10_bitmap_print(ndo, ofppf_bm, EXTRACT_BE_U_4(cp),
1203 OFPPF_U);
1204 cp += 4;
1205 next_port:
1206 len -= OF_PHY_PORT_LEN;
1207 } /* while */
1208 return cp;
1209
1210 invalid: /* skip the undersized trailing data */
1211 ND_PRINT("%s", istr);
1212 ND_TCHECK_LEN(cp0, len0);
1213 return cp0 + len0;
1214 trunc:
1215 nd_print_trunc(ndo);
1216 return ep;
1217 }
1218
1219 /* [OF10] Section 5.2.2 */
1220 static const u_char *
1221 of10_queue_props_print(netdissect_options *ndo,
1222 const u_char *cp, const u_char *ep, u_int len)
1223 {
1224 const u_char *cp0 = cp;
1225 const u_int len0 = len;
1226 uint16_t property, plen, rate;
1227
1228 while (len) {
1229 u_char plen_bogus = 0, skip = 0;
1230
1231 if (len < OF_QUEUE_PROP_HEADER_LEN)
1232 goto invalid;
1233 /* property */
1234 ND_TCHECK_2(cp);
1235 property = EXTRACT_BE_U_2(cp);
1236 cp += 2;
1237 ND_PRINT("\n\t property %s", tok2str(ofpqt_str, "invalid (0x%04x)", property));
1238 /* len */
1239 ND_TCHECK_2(cp);
1240 plen = EXTRACT_BE_U_2(cp);
1241 cp += 2;
1242 ND_PRINT(", len %u", plen);
1243 if (plen < OF_QUEUE_PROP_HEADER_LEN || plen > len)
1244 goto invalid;
1245 /* pad */
1246 ND_TCHECK_4(cp);
1247 cp += 4;
1248 /* property-specific constraints and decoding */
1249 switch (property) {
1250 case OFPQT_NONE:
1251 plen_bogus = plen != OF_QUEUE_PROP_HEADER_LEN;
1252 break;
1253 case OFPQT_MIN_RATE:
1254 plen_bogus = plen != OF_QUEUE_PROP_MIN_RATE_LEN;
1255 break;
1256 default:
1257 skip = 1;
1258 }
1259 if (plen_bogus) {
1260 ND_PRINT(" (bogus)");
1261 skip = 1;
1262 }
1263 if (skip) {
1264 ND_TCHECK_LEN(cp, plen - 4);
1265 cp += plen - 4;
1266 goto next_property;
1267 }
1268 if (property == OFPQT_MIN_RATE) { /* the only case of property decoding */
1269 /* rate */
1270 ND_TCHECK_2(cp);
1271 rate = EXTRACT_BE_U_2(cp);
1272 cp += 2;
1273 if (rate > 1000)
1274 ND_PRINT(", rate disabled");
1275 else
1276 ND_PRINT(", rate %u.%u%%", rate / 10, rate % 10);
1277 /* pad */
1278 ND_TCHECK_6(cp);
1279 cp += 6;
1280 }
1281 next_property:
1282 len -= plen;
1283 } /* while */
1284 return cp;
1285
1286 invalid: /* skip the rest of queue properties */
1287 ND_PRINT("%s", istr);
1288 ND_TCHECK_LEN(cp0, len0);
1289 return cp0 + len0;
1290 trunc:
1291 nd_print_trunc(ndo);
1292 return ep;
1293 }
1294
1295 /* ibid */
1296 static const u_char *
1297 of10_queues_print(netdissect_options *ndo,
1298 const u_char *cp, const u_char *ep, u_int len)
1299 {
1300 const u_char *cp0 = cp;
1301 const u_int len0 = len;
1302 uint16_t desclen;
1303
1304 while (len) {
1305 if (len < OF_PACKET_QUEUE_LEN)
1306 goto invalid;
1307 /* queue_id */
1308 ND_TCHECK_4(cp);
1309 ND_PRINT("\n\t queue_id %u", EXTRACT_BE_U_4(cp));
1310 cp += 4;
1311 /* len */
1312 ND_TCHECK_2(cp);
1313 desclen = EXTRACT_BE_U_2(cp);
1314 cp += 2;
1315 ND_PRINT(", len %u", desclen);
1316 if (desclen < OF_PACKET_QUEUE_LEN || desclen > len)
1317 goto invalid;
1318 /* pad */
1319 ND_TCHECK_2(cp);
1320 cp += 2;
1321 /* properties */
1322 if (ndo->ndo_vflag < 2) {
1323 ND_TCHECK_LEN(cp, desclen - OF_PACKET_QUEUE_LEN);
1324 cp += desclen - OF_PACKET_QUEUE_LEN;
1325 goto next_queue;
1326 }
1327 if (ep == (cp = of10_queue_props_print(ndo, cp, ep, desclen - OF_PACKET_QUEUE_LEN)))
1328 return ep; /* end of snapshot */
1329 next_queue:
1330 len -= desclen;
1331 } /* while */
1332 return cp;
1333
1334 invalid: /* skip the rest of queues */
1335 ND_PRINT("%s", istr);
1336 ND_TCHECK_LEN(cp0, len0);
1337 return cp0 + len0;
1338 trunc:
1339 nd_print_trunc(ndo);
1340 return ep;
1341 }
1342
1343 /* [OF10] Section 5.2.3 */
1344 static const u_char *
1345 of10_match_print(netdissect_options *ndo,
1346 const char *pfx, const u_char *cp, const u_char *ep)
1347 {
1348 uint32_t wildcards;
1349 uint16_t dl_type;
1350 uint8_t nw_proto;
1351 u_char nw_bits;
1352 const char *field_name;
1353
1354 /* wildcards */
1355 ND_TCHECK_4(cp);
1356 wildcards = EXTRACT_BE_U_4(cp);
1357 if (wildcards & OFPFW_U)
1358 ND_PRINT("%swildcards 0x%08x (bogus)", pfx, wildcards);
1359 cp += 4;
1360 /* in_port */
1361 ND_TCHECK_2(cp);
1362 if (! (wildcards & OFPFW_IN_PORT))
1363 ND_PRINT("%smatch in_port %s", pfx, tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
1364 cp += 2;
1365 /* dl_src */
1366 ND_TCHECK_LEN(cp, MAC_ADDR_LEN);
1367 if (! (wildcards & OFPFW_DL_SRC))
1368 ND_PRINT("%smatch dl_src %s", pfx, etheraddr_string(ndo, cp));
1369 cp += MAC_ADDR_LEN;
1370 /* dl_dst */
1371 ND_TCHECK_LEN(cp, MAC_ADDR_LEN);
1372 if (! (wildcards & OFPFW_DL_DST))
1373 ND_PRINT("%smatch dl_dst %s", pfx, etheraddr_string(ndo, cp));
1374 cp += MAC_ADDR_LEN;
1375 /* dl_vlan */
1376 ND_TCHECK_2(cp);
1377 if (! (wildcards & OFPFW_DL_VLAN))
1378 ND_PRINT("%smatch dl_vlan %s", pfx, vlan_str(EXTRACT_BE_U_2(cp)));
1379 cp += 2;
1380 /* dl_vlan_pcp */
1381 ND_TCHECK_1(cp);
1382 if (! (wildcards & OFPFW_DL_VLAN_PCP))
1383 ND_PRINT("%smatch dl_vlan_pcp %s", pfx, pcp_str(EXTRACT_U_1(cp)));
1384 cp += 1;
1385 /* pad1 */
1386 ND_TCHECK_1(cp);
1387 cp += 1;
1388 /* dl_type */
1389 ND_TCHECK_2(cp);
1390 dl_type = EXTRACT_BE_U_2(cp);
1391 cp += 2;
1392 if (! (wildcards & OFPFW_DL_TYPE))
1393 ND_PRINT("%smatch dl_type 0x%04x", pfx, dl_type);
1394 /* nw_tos */
1395 ND_TCHECK_1(cp);
1396 if (! (wildcards & OFPFW_NW_TOS))
1397 ND_PRINT("%smatch nw_tos 0x%02x", pfx, EXTRACT_U_1(cp));
1398 cp += 1;
1399 /* nw_proto */
1400 ND_TCHECK_1(cp);
1401 nw_proto = EXTRACT_U_1(cp);
1402 cp += 1;
1403 if (! (wildcards & OFPFW_NW_PROTO)) {
1404 field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_ARP
1405 ? "arp_opcode" : "nw_proto";
1406 ND_PRINT("%smatch %s %u", pfx, field_name, nw_proto);
1407 }
1408 /* pad2 */
1409 ND_TCHECK_2(cp);
1410 cp += 2;
1411 /* nw_src */
1412 ND_TCHECK_4(cp);
1413 nw_bits = (wildcards & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT;
1414 if (nw_bits < 32)
1415 ND_PRINT("%smatch nw_src %s/%u", pfx, ipaddr_string(ndo, cp), 32 - nw_bits);
1416 cp += 4;
1417 /* nw_dst */
1418 ND_TCHECK_4(cp);
1419 nw_bits = (wildcards & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT;
1420 if (nw_bits < 32)
1421 ND_PRINT("%smatch nw_dst %s/%u", pfx, ipaddr_string(ndo, cp), 32 - nw_bits);
1422 cp += 4;
1423 /* tp_src */
1424 ND_TCHECK_2(cp);
1425 if (! (wildcards & OFPFW_TP_SRC)) {
1426 field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_IP
1427 && ! (wildcards & OFPFW_NW_PROTO) && nw_proto == IPPROTO_ICMP
1428 ? "icmp_type" : "tp_src";
1429 ND_PRINT("%smatch %s %u", pfx, field_name, EXTRACT_BE_U_2(cp));
1430 }
1431 cp += 2;
1432 /* tp_dst */
1433 ND_TCHECK_2(cp);
1434 if (! (wildcards & OFPFW_TP_DST)) {
1435 field_name = ! (wildcards & OFPFW_DL_TYPE) && dl_type == ETHERTYPE_IP
1436 && ! (wildcards & OFPFW_NW_PROTO) && nw_proto == IPPROTO_ICMP
1437 ? "icmp_code" : "tp_dst";
1438 ND_PRINT("%smatch %s %u", pfx, field_name, EXTRACT_BE_U_2(cp));
1439 }
1440 return cp + 2;
1441
1442 trunc:
1443 nd_print_trunc(ndo);
1444 return ep;
1445 }
1446
1447 /* [OF10] Section 5.2.4 */
1448 static const u_char *
1449 of10_actions_print(netdissect_options *ndo,
1450 const char *pfx, const u_char *cp, const u_char *ep,
1451 u_int len)
1452 {
1453 const u_char *cp0 = cp;
1454 const u_int len0 = len;
1455 uint16_t type, alen, output_port;
1456
1457 while (len) {
1458 u_char alen_bogus = 0, skip = 0;
1459
1460 if (len < OF_ACTION_HEADER_LEN)
1461 goto invalid;
1462 /* type */
1463 ND_TCHECK_2(cp);
1464 type = EXTRACT_BE_U_2(cp);
1465 cp += 2;
1466 ND_PRINT("%saction type %s", pfx, tok2str(ofpat_str, "invalid (0x%04x)", type));
1467 /* length */
1468 ND_TCHECK_2(cp);
1469 alen = EXTRACT_BE_U_2(cp);
1470 cp += 2;
1471 ND_PRINT(", len %u", alen);
1472 /* On action size underrun/overrun skip the rest of the action list. */
1473 if (alen < OF_ACTION_HEADER_LEN || alen > len)
1474 goto invalid;
1475 /* On action size inappropriate for the given type or invalid type just skip
1476 * the current action, as the basic length constraint has been met. */
1477 switch (type) {
1478 case OFPAT_OUTPUT:
1479 case OFPAT_SET_VLAN_VID:
1480 case OFPAT_SET_VLAN_PCP:
1481 case OFPAT_STRIP_VLAN:
1482 case OFPAT_SET_NW_SRC:
1483 case OFPAT_SET_NW_DST:
1484 case OFPAT_SET_NW_TOS:
1485 case OFPAT_SET_TP_SRC:
1486 case OFPAT_SET_TP_DST:
1487 alen_bogus = alen != 8;
1488 break;
1489 case OFPAT_SET_DL_SRC:
1490 case OFPAT_SET_DL_DST:
1491 case OFPAT_ENQUEUE:
1492 alen_bogus = alen != 16;
1493 break;
1494 case OFPAT_VENDOR:
1495 alen_bogus = alen % 8 != 0; /* already >= 8 so far */
1496 break;
1497 default:
1498 skip = 1;
1499 }
1500 if (alen_bogus) {
1501 ND_PRINT(" (bogus)");
1502 skip = 1;
1503 }
1504 if (skip) {
1505 ND_TCHECK_LEN(cp, alen - 4);
1506 cp += alen - 4;
1507 goto next_action;
1508 }
1509 /* OK to decode the rest of the action structure */
1510 switch (type) {
1511 case OFPAT_OUTPUT:
1512 /* port */
1513 ND_TCHECK_2(cp);
1514 output_port = EXTRACT_BE_U_2(cp);
1515 cp += 2;
1516 ND_PRINT(", port %s", tok2str(ofpp_str, "%u", output_port));
1517 /* max_len */
1518 ND_TCHECK_2(cp);
1519 if (output_port == OFPP_CONTROLLER)
1520 ND_PRINT(", max_len %u", EXTRACT_BE_U_2(cp));
1521 cp += 2;
1522 break;
1523 case OFPAT_SET_VLAN_VID:
1524 /* vlan_vid */
1525 ND_TCHECK_2(cp);
1526 ND_PRINT(", vlan_vid %s", vlan_str(EXTRACT_BE_U_2(cp)));
1527 cp += 2;
1528 /* pad */
1529 ND_TCHECK_2(cp);
1530 cp += 2;
1531 break;
1532 case OFPAT_SET_VLAN_PCP:
1533 /* vlan_pcp */
1534 ND_TCHECK_1(cp);
1535 ND_PRINT(", vlan_pcp %s", pcp_str(EXTRACT_U_1(cp)));
1536 cp += 1;
1537 /* pad */
1538 ND_TCHECK_3(cp);
1539 cp += 3;
1540 break;
1541 case OFPAT_SET_DL_SRC:
1542 case OFPAT_SET_DL_DST:
1543 /* dl_addr */
1544 ND_TCHECK_LEN(cp, MAC_ADDR_LEN);
1545 ND_PRINT(", dl_addr %s", etheraddr_string(ndo, cp));
1546 cp += MAC_ADDR_LEN;
1547 /* pad */
1548 ND_TCHECK_6(cp);
1549 cp += 6;
1550 break;
1551 case OFPAT_SET_NW_SRC:
1552 case OFPAT_SET_NW_DST:
1553 /* nw_addr */
1554 ND_TCHECK_4(cp);
1555 ND_PRINT(", nw_addr %s", ipaddr_string(ndo, cp));
1556 cp += 4;
1557 break;
1558 case OFPAT_SET_NW_TOS:
1559 /* nw_tos */
1560 ND_TCHECK_1(cp);
1561 ND_PRINT(", nw_tos 0x%02x", EXTRACT_U_1(cp));
1562 cp += 1;
1563 /* pad */
1564 ND_TCHECK_3(cp);
1565 cp += 3;
1566 break;
1567 case OFPAT_SET_TP_SRC:
1568 case OFPAT_SET_TP_DST:
1569 /* nw_tos */
1570 ND_TCHECK_2(cp);
1571 ND_PRINT(", tp_port %u", EXTRACT_BE_U_2(cp));
1572 cp += 2;
1573 /* pad */
1574 ND_TCHECK_2(cp);
1575 cp += 2;
1576 break;
1577 case OFPAT_ENQUEUE:
1578 /* port */
1579 ND_TCHECK_2(cp);
1580 ND_PRINT(", port %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
1581 cp += 2;
1582 /* pad */
1583 ND_TCHECK_6(cp);
1584 cp += 6;
1585 /* queue_id */
1586 ND_TCHECK_4(cp);
1587 ND_PRINT(", queue_id %s", tok2str(ofpq_str, "%u", EXTRACT_BE_U_4(cp)));
1588 cp += 4;
1589 break;
1590 case OFPAT_VENDOR:
1591 if (ep == (cp = of10_vendor_action_print(ndo, cp, ep, alen - 4)))
1592 return ep; /* end of snapshot */
1593 break;
1594 case OFPAT_STRIP_VLAN:
1595 /* pad */
1596 ND_TCHECK_4(cp);
1597 cp += 4;
1598 break;
1599 } /* switch */
1600 next_action:
1601 len -= alen;
1602 } /* while */
1603 return cp;
1604
1605 invalid: /* skip the rest of actions */
1606 ND_PRINT("%s", istr);
1607 ND_TCHECK_LEN(cp0, len0);
1608 return cp0 + len0;
1609 trunc:
1610 nd_print_trunc(ndo);
1611 return ep;
1612 }
1613
1614 /* [OF10] Section 5.3.1 */
1615 static const u_char *
1616 of10_features_reply_print(netdissect_options *ndo,
1617 const u_char *cp, const u_char *ep, const u_int len)
1618 {
1619 /* datapath_id */
1620 ND_TCHECK_8(cp);
1621 ND_PRINT("\n\t dpid 0x%016" PRIx64, EXTRACT_BE_U_8(cp));
1622 cp += 8;
1623 /* n_buffers */
1624 ND_TCHECK_4(cp);
1625 ND_PRINT(", n_buffers %u", EXTRACT_BE_U_4(cp));
1626 cp += 4;
1627 /* n_tables */
1628 ND_TCHECK_1(cp);
1629 ND_PRINT(", n_tables %u", EXTRACT_U_1(cp));
1630 cp += 1;
1631 /* pad */
1632 ND_TCHECK_3(cp);
1633 cp += 3;
1634 /* capabilities */
1635 ND_TCHECK_4(cp);
1636 ND_PRINT("\n\t capabilities 0x%08x", EXTRACT_BE_U_4(cp));
1637 of10_bitmap_print(ndo, ofp_capabilities_bm, EXTRACT_BE_U_4(cp),
1638 OFPCAP_U);
1639 cp += 4;
1640 /* actions */
1641 ND_TCHECK_4(cp);
1642 ND_PRINT("\n\t actions 0x%08x", EXTRACT_BE_U_4(cp));
1643 of10_bitmap_print(ndo, ofpat_bm, EXTRACT_BE_U_4(cp), OFPAT_U);
1644 cp += 4;
1645 /* ports */
1646 return of10_phy_ports_print(ndo, cp, ep, len - OF_SWITCH_FEATURES_LEN);
1647
1648 trunc:
1649 nd_print_trunc(ndo);
1650 return ep;
1651 }
1652
1653 /* [OF10] Section 5.3.3 */
1654 static const u_char *
1655 of10_flow_mod_print(netdissect_options *ndo,
1656 const u_char *cp, const u_char *ep, const u_int len)
1657 {
1658 uint16_t command;
1659
1660 /* match */
1661 if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep)))
1662 return ep; /* end of snapshot */
1663 /* cookie */
1664 ND_TCHECK_8(cp);
1665 ND_PRINT("\n\t cookie 0x%016" PRIx64, EXTRACT_BE_U_8(cp));
1666 cp += 8;
1667 /* command */
1668 ND_TCHECK_2(cp);
1669 command = EXTRACT_BE_U_2(cp);
1670 ND_PRINT(", command %s", tok2str(ofpfc_str, "invalid (0x%04x)", command));
1671 cp += 2;
1672 /* idle_timeout */
1673 ND_TCHECK_2(cp);
1674 if (EXTRACT_BE_U_2(cp))
1675 ND_PRINT(", idle_timeout %u", EXTRACT_BE_U_2(cp));
1676 cp += 2;
1677 /* hard_timeout */
1678 ND_TCHECK_2(cp);
1679 if (EXTRACT_BE_U_2(cp))
1680 ND_PRINT(", hard_timeout %u", EXTRACT_BE_U_2(cp));
1681 cp += 2;
1682 /* priority */
1683 ND_TCHECK_2(cp);
1684 if (EXTRACT_BE_U_2(cp))
1685 ND_PRINT(", priority %u", EXTRACT_BE_U_2(cp));
1686 cp += 2;
1687 /* buffer_id */
1688 ND_TCHECK_4(cp);
1689 if (command == OFPFC_ADD || command == OFPFC_MODIFY ||
1690 command == OFPFC_MODIFY_STRICT)
1691 ND_PRINT(", buffer_id %s", tok2str(bufferid_str, "0x%08x", EXTRACT_BE_U_4(cp)));
1692 cp += 4;
1693 /* out_port */
1694 ND_TCHECK_2(cp);
1695 if (command == OFPFC_DELETE || command == OFPFC_DELETE_STRICT)
1696 ND_PRINT(", out_port %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
1697 cp += 2;
1698 /* flags */
1699 ND_TCHECK_2(cp);
1700 ND_PRINT(", flags 0x%04x", EXTRACT_BE_U_2(cp));
1701 of10_bitmap_print(ndo, ofpff_bm, EXTRACT_BE_U_2(cp), OFPFF_U);
1702 cp += 2;
1703 /* actions */
1704 return of10_actions_print(ndo, "\n\t ", cp, ep, len - OF_FLOW_MOD_LEN);
1705
1706 trunc:
1707 nd_print_trunc(ndo);
1708 return ep;
1709 }
1710
1711 /* ibid */
1712 static const u_char *
1713 of10_port_mod_print(netdissect_options *ndo,
1714 const u_char *cp, const u_char *ep)
1715 {
1716 /* port_no */
1717 ND_TCHECK_2(cp);
1718 ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
1719 cp += 2;
1720 /* hw_addr */
1721 ND_TCHECK_LEN(cp, MAC_ADDR_LEN);
1722 ND_PRINT(", hw_addr %s", etheraddr_string(ndo, cp));
1723 cp += MAC_ADDR_LEN;
1724 /* config */
1725 ND_TCHECK_4(cp);
1726 ND_PRINT("\n\t config 0x%08x", EXTRACT_BE_U_4(cp));
1727 of10_bitmap_print(ndo, ofppc_bm, EXTRACT_BE_U_4(cp), OFPPC_U);
1728 cp += 4;
1729 /* mask */
1730 ND_TCHECK_4(cp);
1731 ND_PRINT("\n\t mask 0x%08x", EXTRACT_BE_U_4(cp));
1732 of10_bitmap_print(ndo, ofppc_bm, EXTRACT_BE_U_4(cp), OFPPC_U);
1733 cp += 4;
1734 /* advertise */
1735 ND_TCHECK_4(cp);
1736 ND_PRINT("\n\t advertise 0x%08x", EXTRACT_BE_U_4(cp));
1737 of10_bitmap_print(ndo, ofppf_bm, EXTRACT_BE_U_4(cp), OFPPF_U);
1738 cp += 4;
1739 /* pad */
1740 ND_TCHECK_4(cp);
1741 return cp + 4;
1742
1743 trunc:
1744 nd_print_trunc(ndo);
1745 return ep;
1746 }
1747
1748 /* [OF10] Section 5.3.5 */
1749 static const u_char *
1750 of10_stats_request_print(netdissect_options *ndo,
1751 const u_char *cp, const u_char *ep, u_int len)
1752 {
1753 const u_char *cp0 = cp;
1754 const u_int len0 = len;
1755 uint16_t type;
1756
1757 /* type */
1758 ND_TCHECK_2(cp);
1759 type = EXTRACT_BE_U_2(cp);
1760 cp += 2;
1761 ND_PRINT("\n\t type %s", tok2str(ofpst_str, "invalid (0x%04x)", type));
1762 /* flags */
1763 ND_TCHECK_2(cp);
1764 ND_PRINT(", flags 0x%04x", EXTRACT_BE_U_2(cp));
1765 if (EXTRACT_BE_U_2(cp))
1766 ND_PRINT(" (bogus)");
1767 cp += 2;
1768 /* type-specific body of one of fixed lengths */
1769 len -= OF_STATS_REQUEST_LEN;
1770 switch(type) {
1771 case OFPST_DESC:
1772 case OFPST_TABLE:
1773 if (len)
1774 goto invalid;
1775 return cp;
1776 case OFPST_FLOW:
1777 case OFPST_AGGREGATE:
1778 if (len != OF_FLOW_STATS_REQUEST_LEN)
1779 goto invalid;
1780 /* match */
1781 if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep)))
1782 return ep; /* end of snapshot */
1783 /* table_id */
1784 ND_TCHECK_1(cp);
1785 ND_PRINT("\n\t table_id %s", tok2str(tableid_str, "%u", EXTRACT_U_1(cp)));
1786 cp += 1;
1787 /* pad */
1788 ND_TCHECK_1(cp);
1789 cp += 1;
1790 /* out_port */
1791 ND_TCHECK_2(cp);
1792 ND_PRINT(", out_port %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
1793 return cp + 2;
1794 case OFPST_PORT:
1795 if (len != OF_PORT_STATS_REQUEST_LEN)
1796 goto invalid;
1797 /* port_no */
1798 ND_TCHECK_2(cp);
1799 ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
1800 cp += 2;
1801 /* pad */
1802 ND_TCHECK_6(cp);
1803 return cp + 6;
1804 case OFPST_QUEUE:
1805 if (len != OF_QUEUE_STATS_REQUEST_LEN)
1806 goto invalid;
1807 /* port_no */
1808 ND_TCHECK_2(cp);
1809 ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
1810 cp += 2;
1811 /* pad */
1812 ND_TCHECK_2(cp);
1813 cp += 2;
1814 /* queue_id */
1815 ND_TCHECK_4(cp);
1816 ND_PRINT(", queue_id %s", tok2str(ofpq_str, "%u", EXTRACT_BE_U_4(cp)));
1817 return cp + 4;
1818 case OFPST_VENDOR:
1819 return of10_vendor_data_print(ndo, cp, ep, len);
1820 }
1821 return cp;
1822
1823 invalid: /* skip the message body */
1824 ND_PRINT("%s", istr);
1825 ND_TCHECK_LEN(cp0, len0);
1826 return cp0 + len0;
1827 trunc:
1828 nd_print_trunc(ndo);
1829 return ep;
1830 }
1831
1832 /* ibid */
1833 static const u_char *
1834 of10_desc_stats_reply_print(netdissect_options *ndo,
1835 const u_char *cp, const u_char *ep, const u_int len)
1836 {
1837 if (len != OF_DESC_STATS_LEN)
1838 goto invalid;
1839 /* mfr_desc */
1840 ND_TCHECK_LEN(cp, DESC_STR_LEN);
1841 ND_PRINT("\n\t mfr_desc '");
1842 nd_print(ndo, cp, cp + DESC_STR_LEN);
1843 ND_PRINT("'");
1844 cp += DESC_STR_LEN;
1845 /* hw_desc */
1846 ND_TCHECK_LEN(cp, DESC_STR_LEN);
1847 ND_PRINT("\n\t hw_desc '");
1848 nd_print(ndo, cp, cp + DESC_STR_LEN);
1849 ND_PRINT("'");
1850 cp += DESC_STR_LEN;
1851 /* sw_desc */
1852 ND_TCHECK_LEN(cp, DESC_STR_LEN);
1853 ND_PRINT("\n\t sw_desc '");
1854 nd_print(ndo, cp, cp + DESC_STR_LEN);
1855 ND_PRINT("'");
1856 cp += DESC_STR_LEN;
1857 /* serial_num */
1858 ND_TCHECK_LEN(cp, SERIAL_NUM_LEN);
1859 ND_PRINT("\n\t serial_num '");
1860 nd_print(ndo, cp, cp + SERIAL_NUM_LEN);
1861 ND_PRINT("'");
1862 cp += SERIAL_NUM_LEN;
1863 /* dp_desc */
1864 ND_TCHECK_LEN(cp, DESC_STR_LEN);
1865 ND_PRINT("\n\t dp_desc '");
1866 nd_print(ndo, cp, cp + DESC_STR_LEN);
1867 ND_PRINT("'");
1868 return cp + DESC_STR_LEN;
1869
1870 invalid: /* skip the message body */
1871 ND_PRINT("%s", istr);
1872 ND_TCHECK_LEN(cp, len);
1873 return cp + len;
1874 trunc:
1875 nd_print_trunc(ndo);
1876 return ep;
1877 }
1878
1879 /* ibid */
1880 static const u_char *
1881 of10_flow_stats_reply_print(netdissect_options *ndo,
1882 const u_char *cp, const u_char *ep, u_int len)
1883 {
1884 const u_char *cp0 = cp;
1885 const u_int len0 = len;
1886 uint16_t entry_len;
1887
1888 while (len) {
1889 if (len < OF_FLOW_STATS_LEN)
1890 goto invalid;
1891 /* length */
1892 ND_TCHECK_2(cp);
1893 entry_len = EXTRACT_BE_U_2(cp);
1894 ND_PRINT("\n\t length %u", entry_len);
1895 if (entry_len < OF_FLOW_STATS_LEN || entry_len > len)
1896 goto invalid;
1897 cp += 2;
1898 /* table_id */
1899 ND_TCHECK_1(cp);
1900 ND_PRINT(", table_id %s", tok2str(tableid_str, "%u", EXTRACT_U_1(cp)));
1901 cp += 1;
1902 /* pad */
1903 ND_TCHECK_1(cp);
1904 cp += 1;
1905 /* match */
1906 if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep)))
1907 return ep; /* end of snapshot */
1908 /* duration_sec */
1909 ND_TCHECK_4(cp);
1910 ND_PRINT("\n\t duration_sec %u", EXTRACT_BE_U_4(cp));
1911 cp += 4;
1912 /* duration_nsec */
1913 ND_TCHECK_4(cp);
1914 ND_PRINT(", duration_nsec %u", EXTRACT_BE_U_4(cp));
1915 cp += 4;
1916 /* priority */
1917 ND_TCHECK_2(cp);
1918 ND_PRINT(", priority %u", EXTRACT_BE_U_2(cp));
1919 cp += 2;
1920 /* idle_timeout */
1921 ND_TCHECK_2(cp);
1922 ND_PRINT(", idle_timeout %u", EXTRACT_BE_U_2(cp));
1923 cp += 2;
1924 /* hard_timeout */
1925 ND_TCHECK_2(cp);
1926 ND_PRINT(", hard_timeout %u", EXTRACT_BE_U_2(cp));
1927 cp += 2;
1928 /* pad2 */
1929 ND_TCHECK_6(cp);
1930 cp += 6;
1931 /* cookie */
1932 ND_TCHECK_8(cp);
1933 ND_PRINT(", cookie 0x%016" PRIx64, EXTRACT_BE_U_8(cp));
1934 cp += 8;
1935 /* packet_count */
1936 ND_TCHECK_8(cp);
1937 ND_PRINT(", packet_count %" PRIu64, EXTRACT_BE_U_8(cp));
1938 cp += 8;
1939 /* byte_count */
1940 ND_TCHECK_8(cp);
1941 ND_PRINT(", byte_count %" PRIu64, EXTRACT_BE_U_8(cp));
1942 cp += 8;
1943 /* actions */
1944 if (ep == (cp = of10_actions_print(ndo, "\n\t ", cp, ep, entry_len - OF_FLOW_STATS_LEN)))
1945 return ep; /* end of snapshot */
1946
1947 len -= entry_len;
1948 } /* while */
1949 return cp;
1950
1951 invalid: /* skip the rest of flow statistics entries */
1952 ND_PRINT("%s", istr);
1953 ND_TCHECK_LEN(cp0, len0);
1954 return cp0 + len0;
1955 trunc:
1956 nd_print_trunc(ndo);
1957 return ep;
1958 }
1959
1960 /* ibid */
1961 static const u_char *
1962 of10_aggregate_stats_reply_print(netdissect_options *ndo,
1963 const u_char *cp, const u_char *ep,
1964 const u_int len)
1965 {
1966 if (len != OF_AGGREGATE_STATS_REPLY_LEN)
1967 goto invalid;
1968 /* packet_count */
1969 ND_TCHECK_8(cp);
1970 ND_PRINT("\n\t packet_count %" PRIu64, EXTRACT_BE_U_8(cp));
1971 cp += 8;
1972 /* byte_count */
1973 ND_TCHECK_8(cp);
1974 ND_PRINT(", byte_count %" PRIu64, EXTRACT_BE_U_8(cp));
1975 cp += 8;
1976 /* flow_count */
1977 ND_TCHECK_4(cp);
1978 ND_PRINT(", flow_count %u", EXTRACT_BE_U_4(cp));
1979 cp += 4;
1980 /* pad */
1981 ND_TCHECK_4(cp);
1982 return cp + 4;
1983
1984 invalid: /* skip the message body */
1985 ND_PRINT("%s", istr);
1986 ND_TCHECK_LEN(cp, len);
1987 return cp + len;
1988 trunc:
1989 nd_print_trunc(ndo);
1990 return ep;
1991 }
1992
1993 /* ibid */
1994 static const u_char *
1995 of10_table_stats_reply_print(netdissect_options *ndo,
1996 const u_char *cp, const u_char *ep, u_int len)
1997 {
1998 const u_char *cp0 = cp;
1999 const u_int len0 = len;
2000
2001 while (len) {
2002 if (len < OF_TABLE_STATS_LEN)
2003 goto invalid;
2004 /* table_id */
2005 ND_TCHECK_1(cp);
2006 ND_PRINT("\n\t table_id %s", tok2str(tableid_str, "%u", EXTRACT_U_1(cp)));
2007 cp += 1;
2008 /* pad */
2009 ND_TCHECK_3(cp);
2010 cp += 3;
2011 /* name */
2012 ND_TCHECK_LEN(cp, OFP_MAX_TABLE_NAME_LEN);
2013 ND_PRINT(", name '");
2014 nd_print(ndo, cp, cp + OFP_MAX_TABLE_NAME_LEN);
2015 ND_PRINT("'");
2016 cp += OFP_MAX_TABLE_NAME_LEN;
2017 /* wildcards */
2018 ND_TCHECK_4(cp);
2019 ND_PRINT("\n\t wildcards 0x%08x", EXTRACT_BE_U_4(cp));
2020 of10_bitmap_print(ndo, ofpfw_bm, EXTRACT_BE_U_4(cp),
2021 OFPFW_U);
2022 cp += 4;
2023 /* max_entries */
2024 ND_TCHECK_4(cp);
2025 ND_PRINT("\n\t max_entries %u", EXTRACT_BE_U_4(cp));
2026 cp += 4;
2027 /* active_count */
2028 ND_TCHECK_4(cp);
2029 ND_PRINT(", active_count %u", EXTRACT_BE_U_4(cp));
2030 cp += 4;
2031 /* lookup_count */
2032 ND_TCHECK_8(cp);
2033 ND_PRINT(", lookup_count %" PRIu64, EXTRACT_BE_U_8(cp));
2034 cp += 8;
2035 /* matched_count */
2036 ND_TCHECK_8(cp);
2037 ND_PRINT(", matched_count %" PRIu64, EXTRACT_BE_U_8(cp));
2038 cp += 8;
2039
2040 len -= OF_TABLE_STATS_LEN;
2041 } /* while */
2042 return cp;
2043
2044 invalid: /* skip the undersized trailing data */
2045 ND_PRINT("%s", istr);
2046 ND_TCHECK_LEN(cp0, len0);
2047 return cp0 + len0;
2048 trunc:
2049 nd_print_trunc(ndo);
2050 return ep;
2051 }
2052
2053 /* ibid */
2054 static const u_char *
2055 of10_port_stats_reply_print(netdissect_options *ndo,
2056 const u_char *cp, const u_char *ep, u_int len)
2057 {
2058 const u_char *cp0 = cp;
2059 const u_int len0 = len;
2060
2061 while (len) {
2062 if (len < OF_PORT_STATS_LEN)
2063 goto invalid;
2064 /* port_no */
2065 ND_TCHECK_2(cp);
2066 ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
2067 cp += 2;
2068 if (ndo->ndo_vflag < 2) {
2069 ND_TCHECK_LEN(cp, OF_PORT_STATS_LEN - 2);
2070 cp += OF_PORT_STATS_LEN - 2;
2071 goto next_port;
2072 }
2073 /* pad */
2074 ND_TCHECK_6(cp);
2075 cp += 6;
2076 /* rx_packets */
2077 ND_TCHECK_8(cp);
2078 ND_PRINT(", rx_packets %" PRIu64, EXTRACT_BE_U_8(cp));
2079 cp += 8;
2080 /* tx_packets */
2081 ND_TCHECK_8(cp);
2082 ND_PRINT(", tx_packets %" PRIu64, EXTRACT_BE_U_8(cp));
2083 cp += 8;
2084 /* rx_bytes */
2085 ND_TCHECK_8(cp);
2086 ND_PRINT(", rx_bytes %" PRIu64, EXTRACT_BE_U_8(cp));
2087 cp += 8;
2088 /* tx_bytes */
2089 ND_TCHECK_8(cp);
2090 ND_PRINT(", tx_bytes %" PRIu64, EXTRACT_BE_U_8(cp));
2091 cp += 8;
2092 /* rx_dropped */
2093 ND_TCHECK_8(cp);
2094 ND_PRINT(", rx_dropped %" PRIu64, EXTRACT_BE_U_8(cp));
2095 cp += 8;
2096 /* tx_dropped */
2097 ND_TCHECK_8(cp);
2098 ND_PRINT(", tx_dropped %" PRIu64, EXTRACT_BE_U_8(cp));
2099 cp += 8;
2100 /* rx_errors */
2101 ND_TCHECK_8(cp);
2102 ND_PRINT(", rx_errors %" PRIu64, EXTRACT_BE_U_8(cp));
2103 cp += 8;
2104 /* tx_errors */
2105 ND_TCHECK_8(cp);
2106 ND_PRINT(", tx_errors %" PRIu64, EXTRACT_BE_U_8(cp));
2107 cp += 8;
2108 /* rx_frame_err */
2109 ND_TCHECK_8(cp);
2110 ND_PRINT(", rx_frame_err %" PRIu64, EXTRACT_BE_U_8(cp));
2111 cp += 8;
2112 /* rx_over_err */
2113 ND_TCHECK_8(cp);
2114 ND_PRINT(", rx_over_err %" PRIu64, EXTRACT_BE_U_8(cp));
2115 cp += 8;
2116 /* rx_crc_err */
2117 ND_TCHECK_8(cp);
2118 ND_PRINT(", rx_crc_err %" PRIu64, EXTRACT_BE_U_8(cp));
2119 cp += 8;
2120 /* collisions */
2121 ND_TCHECK_8(cp);
2122 ND_PRINT(", collisions %" PRIu64, EXTRACT_BE_U_8(cp));
2123 cp += 8;
2124 next_port:
2125 len -= OF_PORT_STATS_LEN;
2126 } /* while */
2127 return cp;
2128
2129 invalid: /* skip the undersized trailing data */
2130 ND_PRINT("%s", istr);
2131 ND_TCHECK_LEN(cp0, len0);
2132 return cp0 + len0;
2133 trunc:
2134 nd_print_trunc(ndo);
2135 return ep;
2136 }
2137
2138 /* ibid */
2139 static const u_char *
2140 of10_queue_stats_reply_print(netdissect_options *ndo,
2141 const u_char *cp, const u_char *ep, u_int len)
2142 {
2143 const u_char *cp0 = cp;
2144 const u_int len0 = len;
2145
2146 while (len) {
2147 if (len < OF_QUEUE_STATS_LEN)
2148 goto invalid;
2149 /* port_no */
2150 ND_TCHECK_2(cp);
2151 ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
2152 cp += 2;
2153 /* pad */
2154 ND_TCHECK_2(cp);
2155 cp += 2;
2156 /* queue_id */
2157 ND_TCHECK_4(cp);
2158 ND_PRINT(", queue_id %u", EXTRACT_BE_U_4(cp));
2159 cp += 4;
2160 /* tx_bytes */
2161 ND_TCHECK_8(cp);
2162 ND_PRINT(", tx_bytes %" PRIu64, EXTRACT_BE_U_8(cp));
2163 cp += 8;
2164 /* tx_packets */
2165 ND_TCHECK_8(cp);
2166 ND_PRINT(", tx_packets %" PRIu64, EXTRACT_BE_U_8(cp));
2167 cp += 8;
2168 /* tx_errors */
2169 ND_TCHECK_8(cp);
2170 ND_PRINT(", tx_errors %" PRIu64, EXTRACT_BE_U_8(cp));
2171 cp += 8;
2172
2173 len -= OF_QUEUE_STATS_LEN;
2174 } /* while */
2175 return cp;
2176
2177 invalid: /* skip the undersized trailing data */
2178 ND_PRINT("%s", istr);
2179 ND_TCHECK_LEN(cp0, len0);
2180 return cp0 + len0;
2181 trunc:
2182 nd_print_trunc(ndo);
2183 return ep;
2184 }
2185
2186 /* ibid */
2187 static const u_char *
2188 of10_stats_reply_print(netdissect_options *ndo,
2189 const u_char *cp, const u_char *ep, const u_int len)
2190 {
2191 const u_char *cp0 = cp;
2192 uint16_t type;
2193
2194 /* type */
2195 ND_TCHECK_2(cp);
2196 type = EXTRACT_BE_U_2(cp);
2197 ND_PRINT("\n\t type %s", tok2str(ofpst_str, "invalid (0x%04x)", type));
2198 cp += 2;
2199 /* flags */
2200 ND_TCHECK_2(cp);
2201 ND_PRINT(", flags 0x%04x", EXTRACT_BE_U_2(cp));
2202 of10_bitmap_print(ndo, ofpsf_reply_bm, EXTRACT_BE_U_2(cp),
2203 OFPSF_REPLY_U);
2204 cp += 2;
2205
2206 if (ndo->ndo_vflag > 0) {
2207 const u_char *(*decoder)(netdissect_options *, const u_char *, const u_char *, u_int) =
2208 type == OFPST_DESC ? of10_desc_stats_reply_print :
2209 type == OFPST_FLOW ? of10_flow_stats_reply_print :
2210 type == OFPST_AGGREGATE ? of10_aggregate_stats_reply_print :
2211 type == OFPST_TABLE ? of10_table_stats_reply_print :
2212 type == OFPST_PORT ? of10_port_stats_reply_print :
2213 type == OFPST_QUEUE ? of10_queue_stats_reply_print :
2214 type == OFPST_VENDOR ? of10_vendor_data_print :
2215 NULL;
2216 if (decoder != NULL)
2217 return decoder(ndo, cp, ep, len - OF_STATS_REPLY_LEN);
2218 }
2219 ND_TCHECK_LEN(cp0, len);
2220 return cp0 + len;
2221
2222 trunc:
2223 nd_print_trunc(ndo);
2224 return ep;
2225 }
2226
2227 /* [OF10] Section 5.3.6 */
2228 static const u_char *
2229 of10_packet_out_print(netdissect_options *ndo,
2230 const u_char *cp, const u_char *ep, const u_int len)
2231 {
2232 const u_char *cp0 = cp;
2233 const u_int len0 = len;
2234 uint16_t actions_len;
2235
2236 /* buffer_id */
2237 ND_TCHECK_4(cp);
2238 ND_PRINT("\n\t buffer_id 0x%08x", EXTRACT_BE_U_4(cp));
2239 cp += 4;
2240 /* in_port */
2241 ND_TCHECK_2(cp);
2242 ND_PRINT(", in_port %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
2243 cp += 2;
2244 /* actions_len */
2245 ND_TCHECK_2(cp);
2246 actions_len = EXTRACT_BE_U_2(cp);
2247 cp += 2;
2248 if (actions_len > len - OF_PACKET_OUT_LEN)
2249 goto invalid;
2250 /* actions */
2251 if (ep == (cp = of10_actions_print(ndo, "\n\t ", cp, ep, actions_len)))
2252 return ep; /* end of snapshot */
2253 /* data */
2254 return of10_packet_data_print(ndo, cp, ep, len - OF_PACKET_OUT_LEN - actions_len);
2255
2256 invalid: /* skip the rest of the message body */
2257 ND_PRINT("%s", istr);
2258 ND_TCHECK_LEN(cp0, len0);
2259 return cp0 + len0;
2260 trunc:
2261 nd_print_trunc(ndo);
2262 return ep;
2263 }
2264
2265 /* [OF10] Section 5.4.1 */
2266 static const u_char *
2267 of10_packet_in_print(netdissect_options *ndo,
2268 const u_char *cp, const u_char *ep, const u_int len)
2269 {
2270 /* buffer_id */
2271 ND_TCHECK_4(cp);
2272 ND_PRINT("\n\t buffer_id %s", tok2str(bufferid_str, "0x%08x", EXTRACT_BE_U_4(cp)));
2273 cp += 4;
2274 /* total_len */
2275 ND_TCHECK_2(cp);
2276 ND_PRINT(", total_len %u", EXTRACT_BE_U_2(cp));
2277 cp += 2;
2278 /* in_port */
2279 ND_TCHECK_2(cp);
2280 ND_PRINT(", in_port %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
2281 cp += 2;
2282 /* reason */
2283 ND_TCHECK_1(cp);
2284 ND_PRINT(", reason %s", tok2str(ofpr_str, "invalid (0x%02x)", EXTRACT_U_1(cp)));
2285 cp += 1;
2286 /* pad */
2287 ND_TCHECK_1(cp);
2288 cp += 1;
2289 /* data */
2290 /* 2 mock octets count in OF_PACKET_IN_LEN but not in len */
2291 return of10_packet_data_print(ndo, cp, ep, len - (OF_PACKET_IN_LEN - 2));
2292
2293 trunc:
2294 nd_print_trunc(ndo);
2295 return ep;
2296 }
2297
2298 /* [OF10] Section 5.4.2 */
2299 static const u_char *
2300 of10_flow_removed_print(netdissect_options *ndo,
2301 const u_char *cp, const u_char *ep)
2302 {
2303 /* match */
2304 if (ep == (cp = of10_match_print(ndo, "\n\t ", cp, ep)))
2305 return ep; /* end of snapshot */
2306 /* cookie */
2307 ND_TCHECK_8(cp);
2308 ND_PRINT("\n\t cookie 0x%016" PRIx64, EXTRACT_BE_U_8(cp));
2309 cp += 8;
2310 /* priority */
2311 ND_TCHECK_2(cp);
2312 if (EXTRACT_BE_U_2(cp))
2313 ND_PRINT(", priority %u", EXTRACT_BE_U_2(cp));
2314 cp += 2;
2315 /* reason */
2316 ND_TCHECK_1(cp);
2317 ND_PRINT(", reason %s", tok2str(ofprr_str, "unknown (0x%02x)", EXTRACT_U_1(cp)));
2318 cp += 1;
2319 /* pad */
2320 ND_TCHECK_1(cp);
2321 cp += 1;
2322 /* duration_sec */
2323 ND_TCHECK_4(cp);
2324 ND_PRINT(", duration_sec %u", EXTRACT_BE_U_4(cp));
2325 cp += 4;
2326 /* duration_nsec */
2327 ND_TCHECK_4(cp);
2328 ND_PRINT(", duration_nsec %u", EXTRACT_BE_U_4(cp));
2329 cp += 4;
2330 /* idle_timeout */
2331 ND_TCHECK_2(cp);
2332 if (EXTRACT_BE_U_2(cp))
2333 ND_PRINT(", idle_timeout %u", EXTRACT_BE_U_2(cp));
2334 cp += 2;
2335 /* pad2 */
2336 ND_TCHECK_2(cp);
2337 cp += 2;
2338 /* packet_count */
2339 ND_TCHECK_8(cp);
2340 ND_PRINT(", packet_count %" PRIu64, EXTRACT_BE_U_8(cp));
2341 cp += 8;
2342 /* byte_count */
2343 ND_TCHECK_8(cp);
2344 ND_PRINT(", byte_count %" PRIu64, EXTRACT_BE_U_8(cp));
2345 return cp + 8;
2346
2347 trunc:
2348 nd_print_trunc(ndo);
2349 return ep;
2350 }
2351
2352 /* [OF10] Section 5.4.4 */
2353 static const u_char *
2354 of10_error_print(netdissect_options *ndo,
2355 const u_char *cp, const u_char *ep, const u_int len)
2356 {
2357 uint16_t type;
2358 const struct tok *code_str;
2359
2360 /* type */
2361 ND_TCHECK_2(cp);
2362 type = EXTRACT_BE_U_2(cp);
2363 cp += 2;
2364 ND_PRINT("\n\t type %s", tok2str(ofpet_str, "invalid (0x%04x)", type));
2365 /* code */
2366 ND_TCHECK_2(cp);
2367 code_str =
2368 type == OFPET_HELLO_FAILED ? ofphfc_str :
2369 type == OFPET_BAD_REQUEST ? ofpbrc_str :
2370 type == OFPET_BAD_ACTION ? ofpbac_str :
2371 type == OFPET_FLOW_MOD_FAILED ? ofpfmfc_str :
2372 type == OFPET_PORT_MOD_FAILED ? ofppmfc_str :
2373 type == OFPET_QUEUE_OP_FAILED ? ofpqofc_str :
2374 empty_str;
2375 ND_PRINT(", code %s", tok2str(code_str, "invalid (0x%04x)", EXTRACT_BE_U_2(cp)));
2376 cp += 2;
2377 /* data */
2378 return of10_data_print(ndo, cp, ep, len - OF_ERROR_MSG_LEN);
2379
2380 trunc:
2381 nd_print_trunc(ndo);
2382 return ep;
2383 }
2384
2385 const u_char *
2386 of10_header_body_print(netdissect_options *ndo,
2387 const u_char *cp, const u_char *ep, const uint8_t type,
2388 const uint16_t len, const uint32_t xid)
2389 {
2390 const u_char *cp0 = cp;
2391 const u_int len0 = len;
2392 /* Thus far message length is not less than the basic header size, but most
2393 * message types have additional assorted constraints on the length. Wherever
2394 * possible, check that message length meets the constraint, in remaining
2395 * cases check that the length is OK to begin decoding and leave any final
2396 * verification up to a lower-layer function. When the current message is
2397 * invalid, proceed to the next message. */
2398
2399 /* [OF10] Section 5.1 */
2400 ND_PRINT("\n\tversion 1.0, type %s, length %u, xid 0x%08x",
2401 tok2str(ofpt_str, "invalid (0x%02x)", type), len, xid);
2402 switch (type) {
2403 /* OpenFlow header only. */
2404 case OFPT_FEATURES_REQUEST: /* [OF10] Section 5.3.1 */
2405 case OFPT_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.2 */
2406 case OFPT_BARRIER_REQUEST: /* [OF10] Section 5.3.7 */
2407 case OFPT_BARRIER_REPLY: /* ibid */
2408 if (len != OF_HEADER_LEN)
2409 goto invalid;
2410 break;
2411
2412 /* OpenFlow header and fixed-size message body. */
2413 case OFPT_SET_CONFIG: /* [OF10] Section 5.3.2 */
2414 case OFPT_GET_CONFIG_REPLY: /* ibid */
2415 if (len != OF_SWITCH_CONFIG_LEN)
2416 goto invalid;
2417 if (ndo->ndo_vflag < 1)
2418 goto next_message;
2419 /* flags */
2420 ND_TCHECK_2(cp);
2421 ND_PRINT("\n\t flags %s", tok2str(ofp_config_str, "invalid (0x%04x)", EXTRACT_BE_U_2(cp)));
2422 cp += 2;
2423 /* miss_send_len */
2424 ND_TCHECK_2(cp);
2425 ND_PRINT(", miss_send_len %u", EXTRACT_BE_U_2(cp));
2426 return cp + 2;
2427 case OFPT_PORT_MOD:
2428 if (len != OF_PORT_MOD_LEN)
2429 goto invalid;
2430 if (ndo->ndo_vflag < 1)
2431 goto next_message;
2432 return of10_port_mod_print(ndo, cp, ep);
2433 case OFPT_QUEUE_GET_CONFIG_REQUEST: /* [OF10] Section 5.3.4 */
2434 if (len != OF_QUEUE_GET_CONFIG_REQUEST_LEN)
2435 goto invalid;
2436 if (ndo->ndo_vflag < 1)
2437 goto next_message;
2438 /* port */
2439 ND_TCHECK_2(cp);
2440 ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
2441 cp += 2;
2442 /* pad */
2443 ND_TCHECK_2(cp);
2444 return cp + 2;
2445 case OFPT_FLOW_REMOVED:
2446 if (len != OF_FLOW_REMOVED_LEN)
2447 goto invalid;
2448 if (ndo->ndo_vflag < 1)
2449 goto next_message;
2450 return of10_flow_removed_print(ndo, cp, ep);
2451 case OFPT_PORT_STATUS: /* [OF10] Section 5.4.3 */
2452 if (len != OF_PORT_STATUS_LEN)
2453 goto invalid;
2454 if (ndo->ndo_vflag < 1)
2455 goto next_message;
2456 /* reason */
2457 ND_TCHECK_1(cp);
2458 ND_PRINT("\n\t reason %s", tok2str(ofppr_str, "invalid (0x%02x)", EXTRACT_U_1(cp)));
2459 cp += 1;
2460 /* pad */
2461 ND_TCHECK_7(cp);
2462 cp += 7;
2463 /* desc */
2464 return of10_phy_ports_print(ndo, cp, ep, OF_PHY_PORT_LEN);
2465
2466 /* OpenFlow header, fixed-size message body and n * fixed-size data units. */
2467 case OFPT_FEATURES_REPLY:
2468 if (len < OF_SWITCH_FEATURES_LEN)
2469 goto invalid;
2470 if (ndo->ndo_vflag < 1)
2471 goto next_message;
2472 return of10_features_reply_print(ndo, cp, ep, len);
2473
2474 /* OpenFlow header and variable-size data. */
2475 case OFPT_HELLO: /* [OF10] Section 5.5.1 */
2476 case OFPT_ECHO_REQUEST: /* [OF10] Section 5.5.2 */
2477 case OFPT_ECHO_REPLY: /* [OF10] Section 5.5.3 */
2478 if (ndo->ndo_vflag < 1)
2479 goto next_message;
2480 return of10_data_print(ndo, cp, ep, len - OF_HEADER_LEN);
2481
2482 /* OpenFlow header, fixed-size message body and variable-size data. */
2483 case OFPT_ERROR:
2484 if (len < OF_ERROR_MSG_LEN)
2485 goto invalid;
2486 if (ndo->ndo_vflag < 1)
2487 goto next_message;
2488 return of10_error_print(ndo, cp, ep, len);
2489 case OFPT_VENDOR:
2490 /* [OF10] Section 5.5.4 */
2491 if (len < OF_VENDOR_HEADER_LEN)
2492 goto invalid;
2493 if (ndo->ndo_vflag < 1)
2494 goto next_message;
2495 return of10_vendor_message_print(ndo, cp, ep, len - OF_HEADER_LEN);
2496 case OFPT_PACKET_IN:
2497 /* 2 mock octets count in OF_PACKET_IN_LEN but not in len */
2498 if (len < OF_PACKET_IN_LEN - 2)
2499 goto invalid;
2500 if (ndo->ndo_vflag < 1)
2501 goto next_message;
2502 return of10_packet_in_print(ndo, cp, ep, len);
2503
2504 /* a. OpenFlow header. */
2505 /* b. OpenFlow header and one of the fixed-size message bodies. */
2506 /* c. OpenFlow header, fixed-size message body and variable-size data. */
2507 case OFPT_STATS_REQUEST:
2508 if (len < OF_STATS_REQUEST_LEN)
2509 goto invalid;
2510 if (ndo->ndo_vflag < 1)
2511 goto next_message;
2512 return of10_stats_request_print(ndo, cp, ep, len);
2513
2514 /* a. OpenFlow header and fixed-size message body. */
2515 /* b. OpenFlow header and n * fixed-size data units. */
2516 /* c. OpenFlow header and n * variable-size data units. */
2517 /* d. OpenFlow header, fixed-size message body and variable-size data. */
2518 case OFPT_STATS_REPLY:
2519 if (len < OF_STATS_REPLY_LEN)
2520 goto invalid;
2521 if (ndo->ndo_vflag < 1)
2522 goto next_message;
2523 return of10_stats_reply_print(ndo, cp, ep, len);
2524
2525 /* OpenFlow header and n * variable-size data units and variable-size data. */
2526 case OFPT_PACKET_OUT:
2527 if (len < OF_PACKET_OUT_LEN)
2528 goto invalid;
2529 if (ndo->ndo_vflag < 1)
2530 goto next_message;
2531 return of10_packet_out_print(ndo, cp, ep, len);
2532
2533 /* OpenFlow header, fixed-size message body and n * variable-size data units. */
2534 case OFPT_FLOW_MOD:
2535 if (len < OF_FLOW_MOD_LEN)
2536 goto invalid;
2537 if (ndo->ndo_vflag < 1)
2538 goto next_message;
2539 return of10_flow_mod_print(ndo, cp, ep, len);
2540
2541 /* OpenFlow header, fixed-size message body and n * variable-size data units. */
2542 case OFPT_QUEUE_GET_CONFIG_REPLY: /* [OF10] Section 5.3.4 */
2543 if (len < OF_QUEUE_GET_CONFIG_REPLY_LEN)
2544 goto invalid;
2545 if (ndo->ndo_vflag < 1)
2546 goto next_message;
2547 /* port */
2548 ND_TCHECK_2(cp);
2549 ND_PRINT("\n\t port_no %s", tok2str(ofpp_str, "%u", EXTRACT_BE_U_2(cp)));
2550 cp += 2;
2551 /* pad */
2552 ND_TCHECK_6(cp);
2553 cp += 6;
2554 /* queues */
2555 return of10_queues_print(ndo, cp, ep, len - OF_QUEUE_GET_CONFIG_REPLY_LEN);
2556 } /* switch (type) */
2557 goto next_message;
2558
2559 invalid: /* skip the message body */
2560 ND_PRINT("%s", istr);
2561 next_message:
2562 ND_TCHECK_LEN(cp0, len0 - OF_HEADER_LEN);
2563 return cp0 + len0 - OF_HEADER_LEN;
2564 trunc:
2565 nd_print_trunc(ndo);
2566 return ep;
2567 }