]> git.proxmox.com Git - ovs.git/blame - lib/ofp-print.c
ofproto: Change account_cb to use uint64_t.
[ovs.git] / lib / ofp-print.c
CommitLineData
064af421 1/*
c4617b3c 2 * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
064af421 3 *
a14bc59f
BP
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
064af421 7 *
a14bc59f
BP
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
064af421
BP
15 */
16
17#include <config.h>
18#include "ofp-print.h"
064af421
BP
19
20#include <errno.h>
21#include <inttypes.h>
7f3adc00 22#include <sys/types.h>
064af421
BP
23#include <netinet/in.h>
24#include <sys/wait.h>
25#include <stdarg.h>
26#include <stdlib.h>
27#include <ctype.h>
28
10a24935 29#include "byte-order.h"
064af421
BP
30#include "compiler.h"
31#include "dynamic-string.h"
32#include "flow.h"
53ddd40a 33#include "multipath.h"
7fa91113 34#include "nx-match.h"
69b6be19 35#include "ofp-util.h"
064af421
BP
36#include "ofpbuf.h"
37#include "openflow/openflow.h"
38#include "openflow/nicira-ext.h"
39#include "packets.h"
40#include "pcap.h"
e41a9130 41#include "type-props.h"
c4617b3c 42#include "unaligned.h"
064af421
BP
43#include "util.h"
44
45static void ofp_print_port_name(struct ds *string, uint16_t port);
d2805da2 46static void ofp_print_queue_name(struct ds *string, uint32_t port);
7fa91113
BP
47static void ofp_print_error(struct ds *, int error);
48
064af421
BP
49
50/* Returns a string that represents the contents of the Ethernet frame in the
51 * 'len' bytes starting at 'data' to 'stream' as output by tcpdump.
52 * 'total_len' specifies the full length of the Ethernet frame (of which 'len'
53 * bytes were captured).
54 *
55 * The caller must free the returned string.
56 *
57 * This starts and kills a tcpdump subprocess so it's quite expensive. */
58char *
67a4917b 59ofp_packet_to_string(const void *data, size_t len, size_t total_len OVS_UNUSED)
064af421
BP
60{
61 struct ds ds = DS_EMPTY_INITIALIZER;
62 struct ofpbuf buf;
63
64 char command[128];
65 FILE *pcap;
66 FILE *tcpdump;
67 int status;
68 int c;
69
0bc9407d 70 ofpbuf_use_const(&buf, data, len);
064af421
BP
71
72 pcap = tmpfile();
73 if (!pcap) {
74 ovs_error(errno, "tmpfile");
75 return xstrdup("<error>");
76 }
77 pcap_write_header(pcap);
78 pcap_write(pcap, &buf);
79 fflush(pcap);
80 if (ferror(pcap)) {
81 ovs_error(errno, "error writing temporary file");
82 }
83 rewind(pcap);
84
85 snprintf(command, sizeof command, "/usr/sbin/tcpdump -e -n -r /dev/fd/%d 2>/dev/null",
86 fileno(pcap));
87 tcpdump = popen(command, "r");
88 fclose(pcap);
89 if (!tcpdump) {
90 ovs_error(errno, "exec(\"%s\")", command);
91 return xstrdup("<error>");
92 }
93
94 while ((c = getc(tcpdump)) != EOF) {
95 ds_put_char(&ds, c);
96 }
97
98 status = pclose(tcpdump);
99 if (WIFEXITED(status)) {
100 if (WEXITSTATUS(status))
101 ovs_error(0, "tcpdump exited with status %d", WEXITSTATUS(status));
102 } else if (WIFSIGNALED(status)) {
d295e8e9 103 ovs_error(0, "tcpdump exited with signal %d", WTERMSIG(status));
064af421
BP
104 }
105 return ds_cstr(&ds);
106}
107
064af421 108static void
d1e2cf21
BP
109ofp_print_packet_in(struct ds *string, const struct ofp_packet_in *op,
110 int verbosity)
064af421 111{
d1e2cf21 112 size_t len = ntohs(op->header.length);
064af421
BP
113 size_t data_len;
114
115 ds_put_format(string, " total_len=%"PRIu16" in_port=",
116 ntohs(op->total_len));
117 ofp_print_port_name(string, ntohs(op->in_port));
118
119 if (op->reason == OFPR_ACTION)
120 ds_put_cstr(string, " (via action)");
121 else if (op->reason != OFPR_NO_MATCH)
122 ds_put_format(string, " (***reason %"PRIu8"***)", op->reason);
123
124 data_len = len - offsetof(struct ofp_packet_in, data);
125 ds_put_format(string, " data_len=%zu", data_len);
126 if (htonl(op->buffer_id) == UINT32_MAX) {
127 ds_put_format(string, " (unbuffered)");
128 if (ntohs(op->total_len) != data_len)
129 ds_put_format(string, " (***total_len != data_len***)");
130 } else {
131 ds_put_format(string, " buffer=0x%08"PRIx32, ntohl(op->buffer_id));
132 if (ntohs(op->total_len) < data_len)
133 ds_put_format(string, " (***total_len < data_len***)");
134 }
135 ds_put_char(string, '\n');
136
137 if (verbosity > 0) {
ae412e7d 138 struct flow flow;
064af421 139 struct ofpbuf packet;
8321fb9c 140
0bc9407d 141 ofpbuf_use_const(&packet, op->data, data_len);
659586ef 142 flow_extract(&packet, 0, ntohs(op->in_port), &flow);
8321fb9c 143 flow_format(string, &flow);
064af421
BP
144 ds_put_char(string, '\n');
145 }
146 if (verbosity > 1) {
147 char *packet = ofp_packet_to_string(op->data, data_len,
d295e8e9 148 ntohs(op->total_len));
064af421
BP
149 ds_put_cstr(string, packet);
150 free(packet);
151 }
152}
153
d295e8e9 154static void ofp_print_port_name(struct ds *string, uint16_t port)
064af421
BP
155{
156 const char *name;
157 switch (port) {
158 case OFPP_IN_PORT:
159 name = "IN_PORT";
160 break;
161 case OFPP_TABLE:
162 name = "TABLE";
163 break;
164 case OFPP_NORMAL:
165 name = "NORMAL";
166 break;
167 case OFPP_FLOOD:
168 name = "FLOOD";
169 break;
170 case OFPP_ALL:
171 name = "ALL";
172 break;
173 case OFPP_CONTROLLER:
174 name = "CONTROLLER";
175 break;
176 case OFPP_LOCAL:
177 name = "LOCAL";
178 break;
179 case OFPP_NONE:
180 name = "NONE";
181 break;
182 default:
183 ds_put_format(string, "%"PRIu16, port);
184 return;
185 }
186 ds_put_cstr(string, name);
187}
188
f393f81e 189
96fc46e8
BP
190static void
191print_note(struct ds *string, const struct nx_action_note *nan)
192{
193 size_t len;
194 size_t i;
195
196 ds_put_cstr(string, "note:");
197 len = ntohs(nan->len) - offsetof(struct nx_action_note, note);
198 for (i = 0; i < len; i++) {
199 if (i) {
200 ds_put_char(string, '.');
201 }
202 ds_put_format(string, "%02"PRIx8, nan->note[i]);
203 }
204}
205
f393f81e
BP
206static int
207nx_action_len(enum nx_action_subtype subtype)
208{
209 switch (subtype) {
210 case NXAST_SNAT__OBSOLETE: return -1;
211 case NXAST_RESUBMIT: return sizeof(struct nx_action_resubmit);
212 case NXAST_SET_TUNNEL: return sizeof(struct nx_action_set_tunnel);
213 case NXAST_DROP_SPOOFED_ARP:
214 return sizeof(struct nx_action_drop_spoofed_arp);
215 case NXAST_SET_QUEUE: return sizeof(struct nx_action_set_queue);
216 case NXAST_POP_QUEUE: return sizeof(struct nx_action_pop_queue);
217 case NXAST_REG_MOVE: return sizeof(struct nx_action_reg_move);
218 case NXAST_REG_LOAD: return sizeof(struct nx_action_reg_load);
219 case NXAST_NOTE: return -1;
b9298d3f 220 case NXAST_SET_TUNNEL64: return sizeof(struct nx_action_set_tunnel64);
53ddd40a 221 case NXAST_MULTIPATH: return sizeof(struct nx_action_multipath);
f393f81e
BP
222 default: return -1;
223 }
224}
225
064af421
BP
226static void
227ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
228{
e41a9130 229 uint16_t subtype = ntohs(nah->subtype);
f393f81e
BP
230 int required_len = nx_action_len(subtype);
231 int len = ntohs(nah->len);
232
233 if (required_len != -1 && required_len != len) {
234 ds_put_format(string, "***Nicira action %"PRIu16" wrong length: %d***",
235 subtype, len);
236 return;
237 }
e41a9130
BP
238
239 if (subtype <= TYPE_MAXIMUM(enum nx_action_subtype)) {
b9298d3f 240 const struct nx_action_set_tunnel64 *nast64;
e41a9130
BP
241 const struct nx_action_set_tunnel *nast;
242 const struct nx_action_set_queue *nasq;
243 const struct nx_action_resubmit *nar;
f393f81e
BP
244 const struct nx_action_reg_move *move;
245 const struct nx_action_reg_load *load;
53ddd40a 246 const struct nx_action_multipath *nam;
e41a9130
BP
247
248 switch ((enum nx_action_subtype) subtype) {
249 case NXAST_RESUBMIT:
250 nar = (struct nx_action_resubmit *)nah;
251 ds_put_format(string, "resubmit:");
252 ofp_print_port_name(string, ntohs(nar->in_port));
253 return;
254
255 case NXAST_SET_TUNNEL:
256 nast = (struct nx_action_set_tunnel *)nah;
257 ds_put_format(string, "set_tunnel:%#"PRIx32, ntohl(nast->tun_id));
258 return;
259
260 case NXAST_DROP_SPOOFED_ARP:
261 ds_put_cstr(string, "drop_spoofed_arp");
262 return;
263
264 case NXAST_SET_QUEUE:
265 nasq = (struct nx_action_set_queue *)nah;
266 ds_put_format(string, "set_queue:%u", ntohl(nasq->queue_id));
267 return;
268
269 case NXAST_POP_QUEUE:
270 ds_put_cstr(string, "pop_queue");
271 return;
272
273 case NXAST_NOTE:
274 print_note(string, (const struct nx_action_note *) nah);
275 return;
276
277 case NXAST_REG_MOVE:
f393f81e
BP
278 move = (const struct nx_action_reg_move *) nah;
279 nxm_format_reg_move(move, string);
280 return;
281
e41a9130 282 case NXAST_REG_LOAD:
f393f81e
BP
283 load = (const struct nx_action_reg_load *) nah;
284 nxm_format_reg_load(load, string);
e41a9130
BP
285 return;
286
b9298d3f 287 case NXAST_SET_TUNNEL64:
53ddd40a 288 nast64 = (const struct nx_action_set_tunnel64 *) nah;
b9298d3f
BP
289 ds_put_format(string, "set_tunnel64:%#"PRIx64,
290 ntohll(nast64->tun_id));
291 return;
292
53ddd40a
BP
293 case NXAST_MULTIPATH:
294 nam = (const struct nx_action_multipath *) nah;
295 multipath_format(nam, string);
296 return;
297
e41a9130
BP
298 case NXAST_SNAT__OBSOLETE:
299 default:
300 break;
301 }
eedc0097
JP
302 }
303
e41a9130
BP
304 ds_put_format(string, "***unknown Nicira action:%"PRIu16"***", subtype);
305}
96fc46e8 306
e41a9130
BP
307static int
308ofp_action_len(enum ofp_action_type type)
309{
310 switch (type) {
311 case OFPAT_OUTPUT: return sizeof(struct ofp_action_output);
312 case OFPAT_SET_VLAN_VID: return sizeof(struct ofp_action_vlan_vid);
313 case OFPAT_SET_VLAN_PCP: return sizeof(struct ofp_action_vlan_pcp);
314 case OFPAT_STRIP_VLAN: return sizeof(struct ofp_action_header);
315 case OFPAT_SET_DL_SRC: return sizeof(struct ofp_action_dl_addr);
316 case OFPAT_SET_DL_DST: return sizeof(struct ofp_action_dl_addr);
317 case OFPAT_SET_NW_SRC: return sizeof(struct ofp_action_nw_addr);
318 case OFPAT_SET_NW_DST: return sizeof(struct ofp_action_nw_addr);
319 case OFPAT_SET_NW_TOS: return sizeof(struct ofp_action_nw_tos);
320 case OFPAT_SET_TP_SRC: return sizeof(struct ofp_action_tp_port);
321 case OFPAT_SET_TP_DST: return sizeof(struct ofp_action_tp_port);
322 case OFPAT_ENQUEUE: return sizeof(struct ofp_action_enqueue);
323 case OFPAT_VENDOR: return -1;
324 default: return -1;
064af421
BP
325 }
326}
327
328static int
d295e8e9
JP
329ofp_print_action(struct ds *string, const struct ofp_action_header *ah,
330 size_t actions_len)
064af421 331{
e41a9130
BP
332 enum ofp_action_type type;
333 int required_len;
064af421
BP
334 size_t len;
335
064af421
BP
336 if (actions_len < sizeof *ah) {
337 ds_put_format(string, "***action array too short for next action***\n");
338 return -1;
339 }
340
341 type = ntohs(ah->type);
342 len = ntohs(ah->len);
343 if (actions_len < len) {
e41a9130 344 ds_put_format(string, "***truncated action %d***\n", (int) type);
064af421
BP
345 return -1;
346 }
347
1d87ef5c
BP
348 if (!len) {
349 ds_put_format(string, "***zero-length action***\n");
350 return 8;
351 }
352
69b6be19 353 if ((len % OFP_ACTION_ALIGN) != 0) {
d295e8e9 354 ds_put_format(string,
e41a9130
BP
355 "***action %d length not a multiple of %d***\n",
356 (int) type, OFP_ACTION_ALIGN);
064af421
BP
357 return -1;
358 }
359
e41a9130
BP
360 required_len = ofp_action_len(type);
361 if (required_len >= 0 && len != required_len) {
362 ds_put_format(string,
363 "***action %d wrong length: %zu***\n", (int) type, len);
364 return -1;
064af421 365 }
d295e8e9 366
064af421
BP
367 switch (type) {
368 case OFPAT_OUTPUT: {
369 struct ofp_action_output *oa = (struct ofp_action_output *)ah;
d295e8e9 370 uint16_t port = ntohs(oa->port);
064af421
BP
371 if (port < OFPP_MAX) {
372 ds_put_format(string, "output:%"PRIu16, port);
373 } else {
374 ofp_print_port_name(string, port);
375 if (port == OFPP_CONTROLLER) {
376 if (oa->max_len) {
377 ds_put_format(string, ":%"PRIu16, ntohs(oa->max_len));
378 } else {
379 ds_put_cstr(string, ":all");
380 }
381 }
382 }
383 break;
384 }
385
c4d279ab
BP
386 case OFPAT_ENQUEUE: {
387 struct ofp_action_enqueue *ea = (struct ofp_action_enqueue *)ah;
388 unsigned int port = ntohs(ea->port);
389 unsigned int queue_id = ntohl(ea->queue_id);
390 ds_put_format(string, "enqueue:");
391 if (port != OFPP_IN_PORT) {
392 ds_put_format(string, "%u", port);
393 } else {
394 ds_put_cstr(string, "IN_PORT");
395 }
396 ds_put_format(string, "q%u", queue_id);
397 break;
398 }
399
064af421
BP
400 case OFPAT_SET_VLAN_VID: {
401 struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah;
402 ds_put_format(string, "mod_vlan_vid:%"PRIu16, ntohs(va->vlan_vid));
403 break;
404 }
405
406 case OFPAT_SET_VLAN_PCP: {
407 struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah;
408 ds_put_format(string, "mod_vlan_pcp:%"PRIu8, va->vlan_pcp);
409 break;
410 }
411
412 case OFPAT_STRIP_VLAN:
413 ds_put_cstr(string, "strip_vlan");
414 break;
415
416 case OFPAT_SET_DL_SRC: {
417 struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah;
d295e8e9 418 ds_put_format(string, "mod_dl_src:"ETH_ADDR_FMT,
064af421
BP
419 ETH_ADDR_ARGS(da->dl_addr));
420 break;
421 }
422
423 case OFPAT_SET_DL_DST: {
424 struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah;
d295e8e9 425 ds_put_format(string, "mod_dl_dst:"ETH_ADDR_FMT,
064af421
BP
426 ETH_ADDR_ARGS(da->dl_addr));
427 break;
428 }
429
430 case OFPAT_SET_NW_SRC: {
431 struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah;
432 ds_put_format(string, "mod_nw_src:"IP_FMT, IP_ARGS(&na->nw_addr));
433 break;
434 }
435
436 case OFPAT_SET_NW_DST: {
437 struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah;
438 ds_put_format(string, "mod_nw_dst:"IP_FMT, IP_ARGS(&na->nw_addr));
439 break;
440 }
441
959a2ecd
JP
442 case OFPAT_SET_NW_TOS: {
443 struct ofp_action_nw_tos *nt = (struct ofp_action_nw_tos *)ah;
444 ds_put_format(string, "mod_nw_tos:%d", nt->nw_tos);
445 break;
446 }
447
064af421
BP
448 case OFPAT_SET_TP_SRC: {
449 struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah;
450 ds_put_format(string, "mod_tp_src:%d", ntohs(ta->tp_port));
451 break;
452 }
453
454 case OFPAT_SET_TP_DST: {
455 struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah;
456 ds_put_format(string, "mod_tp_dst:%d", ntohs(ta->tp_port));
457 break;
458 }
459
460 case OFPAT_VENDOR: {
d295e8e9 461 struct ofp_action_vendor_header *avh
064af421
BP
462 = (struct ofp_action_vendor_header *)ah;
463 if (len < sizeof *avh) {
464 ds_put_format(string, "***ofpat_vendor truncated***\n");
465 return -1;
466 }
467 if (avh->vendor == htonl(NX_VENDOR_ID)) {
468 ofp_print_nx_action(string, (struct nx_action_header *)avh);
469 } else {
470 ds_put_format(string, "vendor action:0x%x", ntohl(avh->vendor));
471 }
472 break;
473 }
474
475 default:
e41a9130 476 ds_put_format(string, "(decoder %d not implemented)", (int) type);
064af421
BP
477 break;
478 }
479
480 return len;
481}
482
d295e8e9 483void
064af421 484ofp_print_actions(struct ds *string, const struct ofp_action_header *action,
d295e8e9 485 size_t actions_len)
064af421
BP
486{
487 uint8_t *p = (uint8_t *)action;
488 int len = 0;
489
490 ds_put_cstr(string, "actions=");
491 if (!actions_len) {
492 ds_put_cstr(string, "drop");
493 }
494 while (actions_len > 0) {
495 if (len) {
496 ds_put_cstr(string, ",");
497 }
d295e8e9 498 len = ofp_print_action(string, (struct ofp_action_header *)p,
064af421
BP
499 actions_len);
500 if (len < 0) {
501 return;
502 }
503 p += len;
504 actions_len -= len;
505 }
506}
507
d1e2cf21
BP
508static void
509ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
510 int verbosity)
064af421 511{
d1e2cf21 512 size_t len = ntohs(opo->header.length);
064af421
BP
513 size_t actions_len = ntohs(opo->actions_len);
514
515 ds_put_cstr(string, " in_port=");
516 ofp_print_port_name(string, ntohs(opo->in_port));
517
518 ds_put_format(string, " actions_len=%zu ", actions_len);
519 if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) {
520 ds_put_format(string, "***packet too short for action length***\n");
521 return;
522 }
523 ofp_print_actions(string, opo->actions, actions_len);
524
525 if (ntohl(opo->buffer_id) == UINT32_MAX) {
526 int data_len = len - sizeof *opo - actions_len;
527 ds_put_format(string, " data_len=%d", data_len);
528 if (verbosity > 0 && len > sizeof *opo) {
529 char *packet = ofp_packet_to_string(
530 (uint8_t *)opo->actions + actions_len, data_len, data_len);
531 ds_put_char(string, '\n');
532 ds_put_cstr(string, packet);
533 free(packet);
534 }
535 } else {
536 ds_put_format(string, " buffer=0x%08"PRIx32, ntohl(opo->buffer_id));
537 }
538 ds_put_char(string, '\n');
539}
540
541/* qsort comparison function. */
542static int
543compare_ports(const void *a_, const void *b_)
544{
545 const struct ofp_phy_port *a = a_;
546 const struct ofp_phy_port *b = b_;
547 uint16_t ap = ntohs(a->port_no);
548 uint16_t bp = ntohs(b->port_no);
549
550 return ap < bp ? -1 : ap > bp;
551}
552
553static void ofp_print_port_features(struct ds *string, uint32_t features)
554{
555 if (features == 0) {
556 ds_put_cstr(string, "Unsupported\n");
557 return;
558 }
559 if (features & OFPPF_10MB_HD) {
560 ds_put_cstr(string, "10MB-HD ");
561 }
562 if (features & OFPPF_10MB_FD) {
563 ds_put_cstr(string, "10MB-FD ");
564 }
565 if (features & OFPPF_100MB_HD) {
566 ds_put_cstr(string, "100MB-HD ");
567 }
568 if (features & OFPPF_100MB_FD) {
569 ds_put_cstr(string, "100MB-FD ");
570 }
571 if (features & OFPPF_1GB_HD) {
572 ds_put_cstr(string, "1GB-HD ");
573 }
574 if (features & OFPPF_1GB_FD) {
575 ds_put_cstr(string, "1GB-FD ");
576 }
577 if (features & OFPPF_10GB_FD) {
578 ds_put_cstr(string, "10GB-FD ");
579 }
580 if (features & OFPPF_COPPER) {
581 ds_put_cstr(string, "COPPER ");
582 }
583 if (features & OFPPF_FIBER) {
584 ds_put_cstr(string, "FIBER ");
585 }
586 if (features & OFPPF_AUTONEG) {
587 ds_put_cstr(string, "AUTO_NEG ");
588 }
589 if (features & OFPPF_PAUSE) {
590 ds_put_cstr(string, "AUTO_PAUSE ");
591 }
592 if (features & OFPPF_PAUSE_ASYM) {
593 ds_put_cstr(string, "AUTO_PAUSE_ASYM ");
594 }
595 ds_put_char(string, '\n');
596}
597
598static void
599ofp_print_phy_port(struct ds *string, const struct ofp_phy_port *port)
600{
0b61210e 601 char name[OFP_MAX_PORT_NAME_LEN];
064af421
BP
602 int j;
603
604 memcpy(name, port->name, sizeof name);
605 for (j = 0; j < sizeof name - 1; j++) {
606 if (!isprint(name[j])) {
607 break;
608 }
609 }
610 name[j] = '\0';
611
612 ds_put_char(string, ' ');
613 ofp_print_port_name(string, ntohs(port->port_no));
614 ds_put_format(string, "(%s): addr:"ETH_ADDR_FMT", config: %#x, state:%#x\n",
615 name, ETH_ADDR_ARGS(port->hw_addr), ntohl(port->config),
616 ntohl(port->state));
617 if (port->curr) {
618 ds_put_format(string, " current: ");
619 ofp_print_port_features(string, ntohl(port->curr));
620 }
621 if (port->advertised) {
622 ds_put_format(string, " advertised: ");
623 ofp_print_port_features(string, ntohl(port->advertised));
624 }
625 if (port->supported) {
626 ds_put_format(string, " supported: ");
627 ofp_print_port_features(string, ntohl(port->supported));
628 }
629 if (port->peer) {
630 ds_put_format(string, " peer: ");
631 ofp_print_port_features(string, ntohl(port->peer));
632 }
633}
634
064af421 635static void
d1e2cf21
BP
636ofp_print_switch_features(struct ds *string,
637 const struct ofp_switch_features *osf)
064af421 638{
d1e2cf21 639 size_t len = ntohs(osf->header.length);
064af421
BP
640 struct ofp_phy_port *port_list;
641 int n_ports;
642 int i;
643
d295e8e9 644 ds_put_format(string, " ver:0x%x, dpid:%016"PRIx64"\n",
064af421
BP
645 osf->header.version, ntohll(osf->datapath_id));
646 ds_put_format(string, "n_tables:%d, n_buffers:%d\n", osf->n_tables,
647 ntohl(osf->n_buffers));
648 ds_put_format(string, "features: capabilities:%#x, actions:%#x\n",
649 ntohl(osf->capabilities), ntohl(osf->actions));
650
064af421
BP
651 n_ports = (len - sizeof *osf) / sizeof *osf->ports;
652
d295e8e9 653 port_list = xmemdup(osf->ports, len - sizeof *osf);
064af421
BP
654 qsort(port_list, n_ports, sizeof *port_list, compare_ports);
655 for (i = 0; i < n_ports; i++) {
656 ofp_print_phy_port(string, &port_list[i]);
657 }
658 free(port_list);
659}
660
064af421 661static void
d1e2cf21 662ofp_print_switch_config(struct ds *string, const struct ofp_switch_config *osc)
064af421 663{
064af421
BP
664 uint16_t flags;
665
666 flags = ntohs(osc->flags);
3b62feba
BP
667
668 ds_put_cstr(string, " frags=");
669 switch (flags & OFPC_FRAG_MASK) {
670 case OFPC_FRAG_NORMAL:
671 ds_put_cstr(string, "normal");
672 flags &= ~OFPC_FRAG_MASK;
673 break;
674 case OFPC_FRAG_DROP:
675 ds_put_cstr(string, "drop");
676 flags &= ~OFPC_FRAG_MASK;
677 break;
678 case OFPC_FRAG_REASM:
679 ds_put_cstr(string, "reassemble");
680 flags &= ~OFPC_FRAG_MASK;
681 break;
682 }
064af421
BP
683 if (flags) {
684 ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
685 }
686
687 ds_put_format(string, " miss_send_len=%"PRIu16"\n", ntohs(osc->miss_send_len));
688}
689
690static void print_wild(struct ds *string, const char *leader, int is_wild,
d295e8e9 691 int verbosity, const char *format, ...)
064af421
BP
692 __attribute__((format(printf, 5, 6)));
693
694static void print_wild(struct ds *string, const char *leader, int is_wild,
d295e8e9 695 int verbosity, const char *format, ...)
064af421
BP
696{
697 if (is_wild && verbosity < 2) {
698 return;
699 }
700 ds_put_cstr(string, leader);
701 if (!is_wild) {
702 va_list args;
703
704 va_start(args, format);
705 ds_put_format_valist(string, format, args);
706 va_end(args);
707 } else {
708 ds_put_char(string, '*');
709 }
710 ds_put_char(string, ',');
711}
712
713static void
714print_ip_netmask(struct ds *string, const char *leader, uint32_t ip,
715 uint32_t wild_bits, int verbosity)
716{
717 if (wild_bits >= 32 && verbosity < 2) {
718 return;
719 }
720 ds_put_cstr(string, leader);
721 if (wild_bits < 32) {
722 ds_put_format(string, IP_FMT, IP_ARGS(&ip));
723 if (wild_bits) {
724 ds_put_format(string, "/%d", 32 - wild_bits);
725 }
726 } else {
727 ds_put_char(string, '*');
728 }
729 ds_put_char(string, ',');
730}
731
4f2cad2c 732void
064af421
BP
733ofp_print_match(struct ds *f, const struct ofp_match *om, int verbosity)
734{
735 char *s = ofp_match_to_string(om, verbosity);
736 ds_put_cstr(f, s);
737 free(s);
738}
739
740char *
741ofp_match_to_string(const struct ofp_match *om, int verbosity)
742{
743 struct ds f = DS_EMPTY_INITIALIZER;
744 uint32_t w = ntohl(om->wildcards);
745 bool skip_type = false;
746 bool skip_proto = false;
747
748 if (!(w & OFPFW_DL_TYPE)) {
749 skip_type = true;
750 if (om->dl_type == htons(ETH_TYPE_IP)) {
751 if (!(w & OFPFW_NW_PROTO)) {
752 skip_proto = true;
6767a2cc 753 if (om->nw_proto == IPPROTO_ICMP) {
064af421 754 ds_put_cstr(&f, "icmp,");
6767a2cc 755 } else if (om->nw_proto == IPPROTO_TCP) {
064af421 756 ds_put_cstr(&f, "tcp,");
6767a2cc 757 } else if (om->nw_proto == IPPROTO_UDP) {
064af421
BP
758 ds_put_cstr(&f, "udp,");
759 } else {
760 ds_put_cstr(&f, "ip,");
761 skip_proto = false;
762 }
763 } else {
764 ds_put_cstr(&f, "ip,");
765 }
766 } else if (om->dl_type == htons(ETH_TYPE_ARP)) {
767 ds_put_cstr(&f, "arp,");
768 } else {
769 skip_type = false;
770 }
771 }
659586ef
JG
772 if (w & NXFW_TUN_ID) {
773 ds_put_cstr(&f, "tun_id_wild,");
774 }
064af421
BP
775 print_wild(&f, "in_port=", w & OFPFW_IN_PORT, verbosity,
776 "%d", ntohs(om->in_port));
777 print_wild(&f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity,
6a1f89c8 778 "%d", ntohs(om->dl_vlan));
959a2ecd
JP
779 print_wild(&f, "dl_vlan_pcp=", w & OFPFW_DL_VLAN_PCP, verbosity,
780 "%d", om->dl_vlan_pcp);
064af421
BP
781 print_wild(&f, "dl_src=", w & OFPFW_DL_SRC, verbosity,
782 ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
783 print_wild(&f, "dl_dst=", w & OFPFW_DL_DST, verbosity,
784 ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_dst));
785 if (!skip_type) {
786 print_wild(&f, "dl_type=", w & OFPFW_DL_TYPE, verbosity,
787 "0x%04x", ntohs(om->dl_type));
788 }
789 print_ip_netmask(&f, "nw_src=", om->nw_src,
790 (w & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT, verbosity);
791 print_ip_netmask(&f, "nw_dst=", om->nw_dst,
792 (w & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT, verbosity);
793 if (!skip_proto) {
fb892732
JP
794 if (om->dl_type == htons(ETH_TYPE_ARP)) {
795 print_wild(&f, "opcode=", w & OFPFW_NW_PROTO, verbosity,
796 "%u", om->nw_proto);
797 } else {
798 print_wild(&f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity,
799 "%u", om->nw_proto);
800 }
064af421 801 }
1a960c80
RL
802 print_wild(&f, "nw_tos=", w & OFPFW_NW_TOS, verbosity,
803 "%u", om->nw_tos);
6767a2cc 804 if (om->nw_proto == IPPROTO_ICMP) {
064af421
BP
805 print_wild(&f, "icmp_type=", w & OFPFW_ICMP_TYPE, verbosity,
806 "%d", ntohs(om->icmp_type));
807 print_wild(&f, "icmp_code=", w & OFPFW_ICMP_CODE, verbosity,
808 "%d", ntohs(om->icmp_code));
809 } else {
810 print_wild(&f, "tp_src=", w & OFPFW_TP_SRC, verbosity,
811 "%d", ntohs(om->tp_src));
812 print_wild(&f, "tp_dst=", w & OFPFW_TP_DST, verbosity,
813 "%d", ntohs(om->tp_dst));
814 }
7fa91113
BP
815 if (ds_last(&f) == ',') {
816 f.length--;
817 }
064af421
BP
818 return ds_cstr(&f);
819}
820
064af421 821static void
7fa91113
BP
822ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
823 enum ofputil_msg_code code, int verbosity)
064af421 824{
7fa91113 825 struct flow_mod fm;
f904747b 826 bool need_priority;
7fa91113 827 int error;
064af421 828
7fa91113
BP
829 error = ofputil_decode_flow_mod(&fm, oh, NXFF_OPENFLOW10);
830 if (error) {
831 ofp_print_error(s, error);
832 return;
3ff4f871
BP
833 }
834
7fa91113
BP
835 ds_put_char(s, ' ');
836 switch (fm.command) {
064af421 837 case OFPFC_ADD:
7fa91113 838 ds_put_cstr(s, "ADD");
064af421
BP
839 break;
840 case OFPFC_MODIFY:
7fa91113 841 ds_put_cstr(s, "MOD");
064af421
BP
842 break;
843 case OFPFC_MODIFY_STRICT:
7fa91113 844 ds_put_cstr(s, "MOD_STRICT");
064af421
BP
845 break;
846 case OFPFC_DELETE:
7fa91113 847 ds_put_cstr(s, "DEL");
064af421
BP
848 break;
849 case OFPFC_DELETE_STRICT:
7fa91113 850 ds_put_cstr(s, "DEL_STRICT");
064af421
BP
851 break;
852 default:
7fa91113
BP
853 ds_put_format(s, "cmd:%d", fm.command);
854 }
855
856 ds_put_char(s, ' ');
857 if (verbosity >= 3 && code == OFPUTIL_OFPT_FLOW_MOD) {
858 const struct ofp_flow_mod *ofm = (const struct ofp_flow_mod *) oh;
7fa91113 859 ofp_print_match(s, &ofm->match, verbosity);
f904747b
BP
860
861 /* ofp_print_match() doesn't print priority. */
862 need_priority = true;
7fa91113
BP
863 } else if (verbosity >= 3 && code == OFPUTIL_NXT_FLOW_MOD) {
864 const struct nx_flow_mod *nfm = (const struct nx_flow_mod *) oh;
865 const void *nxm = nfm + 1;
f904747b
BP
866 char *nxm_s;
867
868 nxm_s = nx_match_to_string(nxm, ntohs(nfm->match_len));
7fa91113
BP
869 ds_put_cstr(s, nxm_s);
870 free(nxm_s);
f904747b
BP
871
872 /* nx_match_to_string() doesn't print priority. */
873 need_priority = true;
7fa91113
BP
874 } else {
875 cls_rule_format(&fm.cr, s);
f904747b
BP
876
877 /* cls_rule_format() does print priority. */
878 need_priority = false;
3ff4f871 879 }
7fa91113
BP
880
881 if (ds_last(s) != ' ') {
882 ds_put_char(s, ' ');
3ff4f871 883 }
7fa91113
BP
884 if (fm.cookie != htonll(0)) {
885 ds_put_format(s, "cookie:0x%"PRIx64" ", ntohll(fm.cookie));
3ff4f871 886 }
7fa91113
BP
887 if (fm.idle_timeout != OFP_FLOW_PERMANENT) {
888 ds_put_format(s, "idle:%"PRIu16" ", fm.idle_timeout);
064af421 889 }
7fa91113
BP
890 if (fm.hard_timeout != OFP_FLOW_PERMANENT) {
891 ds_put_format(s, "hard:%"PRIu16" ", fm.hard_timeout);
3ff4f871 892 }
f904747b 893 if (fm.cr.priority != OFP_DEFAULT_PRIORITY && need_priority) {
7fa91113 894 ds_put_format(s, "pri:%"PRIu16" ", fm.cr.priority);
3ff4f871 895 }
7fa91113
BP
896 if (fm.buffer_id != UINT32_MAX) {
897 ds_put_format(s, "buf:0x%"PRIx32" ", fm.buffer_id);
3ff4f871 898 }
7fa91113
BP
899 if (fm.flags != 0) {
900 ds_put_format(s, "flags:0x%"PRIx16" ", fm.flags);
901 }
902
903 ofp_print_actions(s, (const struct ofp_action_header *) fm.actions,
904 fm.n_actions * sizeof *fm.actions);
064af421
BP
905}
906
09862ec6
BP
907static void
908ofp_print_duration(struct ds *string, unsigned int sec, unsigned int nsec)
909{
910 ds_put_format(string, "%u", sec);
911 if (nsec > 0) {
912 ds_put_format(string, ".%09u", nsec);
913 while (string->string[string->length - 1] == '0') {
914 string->length--;
915 }
916 }
917 ds_put_char(string, 's');
918}
919
064af421 920static void
9b045a0c 921ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
064af421 922{
9b045a0c
BP
923 struct ofputil_flow_removed fr;
924 int error;
925
926 error = ofputil_decode_flow_removed(&fr, oh, NXFF_OPENFLOW10);
927 if (error) {
928 ofp_print_error(string, error);
929 return;
930 }
931
fbd76b2e 932 ds_put_char(string, ' ');
9b045a0c
BP
933 cls_rule_format(&fr.rule, string);
934
064af421 935 ds_put_cstr(string, " reason=");
9b045a0c 936 switch (fr.reason) {
ca069229 937 case OFPRR_IDLE_TIMEOUT:
064af421
BP
938 ds_put_cstr(string, "idle");
939 break;
ca069229 940 case OFPRR_HARD_TIMEOUT:
064af421
BP
941 ds_put_cstr(string, "hard");
942 break;
ca069229
JP
943 case OFPRR_DELETE:
944 ds_put_cstr(string, "delete");
945 break;
064af421 946 default:
9b045a0c 947 ds_put_format(string, "**%"PRIu8"**", fr.reason);
064af421
BP
948 break;
949 }
3ff4f871 950
9b045a0c
BP
951 if (fr.cookie != htonll(0)) {
952 ds_put_format(string, " cookie:0x%"PRIx64, ntohll(fr.cookie));
3ff4f871 953 }
09862ec6 954 ds_put_cstr(string, " duration");
9b045a0c 955 ofp_print_duration(string, fr.duration_sec, fr.duration_nsec);
09862ec6 956 ds_put_format(string, " idle%"PRIu16" pkts%"PRIu64" bytes%"PRIu64"\n",
9b045a0c 957 fr.idle_timeout, fr.packet_count, fr.byte_count);
064af421
BP
958}
959
960static void
d1e2cf21 961ofp_print_port_mod(struct ds *string, const struct ofp_port_mod *opm)
064af421 962{
064af421 963 ds_put_format(string, "port: %d: addr:"ETH_ADDR_FMT", config: %#x, mask:%#x\n",
d295e8e9 964 ntohs(opm->port_no), ETH_ADDR_ARGS(opm->hw_addr),
064af421
BP
965 ntohl(opm->config), ntohl(opm->mask));
966 ds_put_format(string, " advertise: ");
967 if (opm->advertise) {
968 ofp_print_port_features(string, ntohl(opm->advertise));
969 } else {
970 ds_put_format(string, "UNCHANGED\n");
971 }
972}
973
7fa91113
BP
974static void
975ofp_print_error(struct ds *string, int error)
976{
7fa91113
BP
977 if (string->length) {
978 ds_put_char(string, ' ');
979 }
dc4762ed
BP
980 ds_put_cstr(string, "***decode error: ");
981 ofputil_format_error(string, error);
982 ds_put_cstr(string, "***\n");
f74be05a
JP
983}
984
064af421 985static void
d1e2cf21 986ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
064af421 987{
d1e2cf21 988 size_t len = ntohs(oem->header.length);
dc4762ed
BP
989 size_t payload_ofs, payload_len;
990 const void *payload;
991 int error;
064af421
BP
992 char *s;
993
dc4762ed
BP
994 error = ofputil_decode_error_msg(&oem->header, &payload_ofs);
995 if (!is_ofp_error(error)) {
996 ofp_print_error(string, error);
997 ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true);
998 return;
f74be05a
JP
999 }
1000
dc4762ed
BP
1001 ds_put_char(string, ' ');
1002 ofputil_format_error(string, error);
1003 ds_put_char(string, '\n');
064af421 1004
dc4762ed
BP
1005 payload = (const uint8_t *) oem + payload_ofs;
1006 payload_len = len - payload_ofs;
1007 switch (get_ofp_err_type(error)) {
064af421 1008 case OFPET_HELLO_FAILED:
dc4762ed 1009 ds_put_printable(string, payload, payload_len);
064af421
BP
1010 break;
1011
1012 case OFPET_BAD_REQUEST:
dc4762ed 1013 s = ofp_to_string(payload, payload_len, 1);
064af421
BP
1014 ds_put_cstr(string, s);
1015 free(s);
1016 break;
1017
1018 default:
dc4762ed 1019 ds_put_hex_dump(string, payload, payload_len, 0, true);
064af421
BP
1020 break;
1021 }
1022}
1023
064af421 1024static void
d1e2cf21 1025ofp_print_port_status(struct ds *string, const struct ofp_port_status *ops)
064af421 1026{
064af421
BP
1027 if (ops->reason == OFPPR_ADD) {
1028 ds_put_format(string, " ADD:");
1029 } else if (ops->reason == OFPPR_DELETE) {
1030 ds_put_format(string, " DEL:");
1031 } else if (ops->reason == OFPPR_MODIFY) {
1032 ds_put_format(string, " MOD:");
1033 }
1034
1035 ofp_print_phy_port(string, &ops->desc);
1036}
1037
1038static void
d1e2cf21 1039ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_header *oh)
064af421 1040{
d1e2cf21 1041 const struct ofp_desc_stats *ods = ofputil_stats_body(oh);
064af421 1042
fbd76b2e 1043 ds_put_char(string, '\n');
d295e8e9 1044 ds_put_format(string, "Manufacturer: %.*s\n",
dd70b475
JP
1045 (int) sizeof ods->mfr_desc, ods->mfr_desc);
1046 ds_put_format(string, "Hardware: %.*s\n",
1047 (int) sizeof ods->hw_desc, ods->hw_desc);
1048 ds_put_format(string, "Software: %.*s\n",
1049 (int) sizeof ods->sw_desc, ods->sw_desc);
1050 ds_put_format(string, "Serial Num: %.*s\n",
1051 (int) sizeof ods->serial_num, ods->serial_num);
1052 ds_put_format(string, "DP Description: %.*s\n",
1053 (int) sizeof ods->dp_desc, ods->dp_desc);
064af421
BP
1054}
1055
1056static void
2af0c0ef 1057ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh)
064af421 1058{
2af0c0ef
BP
1059 struct flow_stats_request fsr;
1060 int error;
064af421 1061
2af0c0ef
BP
1062 error = ofputil_decode_flow_stats_request(&fsr, oh, NXFF_OPENFLOW10);
1063 if (error) {
1064 ofp_print_error(string, error);
1065 return;
1066 }
1067
1068 if (fsr.table_id != 0xff) {
1069 ds_put_format(string, " table_id=%"PRIu8, fsr.table_id);
064af421
BP
1070 }
1071
2af0c0ef
BP
1072 if (fsr.out_port != OFPP_NONE) {
1073 ds_put_cstr(string, " out_port=");
1074 ofp_print_port_name(string, fsr.out_port);
1075 }
1076
1077 ds_put_char(string, ' ');
1078 cls_rule_format(&fsr.match, string);
064af421
BP
1079}
1080
1081static void
d1e2cf21
BP
1082ofp_print_ofpst_flow_reply(struct ds *string, const struct ofp_header *oh,
1083 int verbosity)
064af421 1084{
d1e2cf21
BP
1085 size_t len = ofputil_stats_body_len(oh);
1086 const char *body = ofputil_stats_body(oh);
064af421
BP
1087 const char *pos = body;
1088 for (;;) {
1089 const struct ofp_flow_stats *fs;
1090 ptrdiff_t bytes_left = body + len - pos;
1091 size_t length;
1092
fab8fadb
BP
1093 ds_put_char(string, '\n');
1094
064af421
BP
1095 if (bytes_left < sizeof *fs) {
1096 if (bytes_left != 0) {
1097 ds_put_format(string, " ***%td leftover bytes at end***",
1098 bytes_left);
1099 }
1100 break;
1101 }
1102
1103 fs = (const void *) pos;
1104 length = ntohs(fs->length);
1105 if (length < sizeof *fs) {
1106 ds_put_format(string, " ***length=%zu shorter than minimum %zu***",
1107 length, sizeof *fs);
1108 break;
1109 } else if (length > bytes_left) {
1110 ds_put_format(string,
1111 " ***length=%zu but only %td bytes left***",
1112 length, bytes_left);
1113 break;
1114 } else if ((length - sizeof *fs) % sizeof fs->actions[0]) {
1115 ds_put_format(string,
1116 " ***length=%zu has %zu bytes leftover in "
1117 "final action***",
1118 length,
1119 (length - sizeof *fs) % sizeof fs->actions[0]);
1120 break;
1121 }
1122
09862ec6 1123 ds_put_format(string, " cookie=0x%"PRIx64", duration=",
c4617b3c 1124 ntohll(get_32aligned_be64(&fs->cookie)));
09862ec6
BP
1125 ofp_print_duration(string, ntohl(fs->duration_sec),
1126 ntohl(fs->duration_nsec));
1127 ds_put_format(string, ", table_id=%"PRIu8", ", fs->table_id);
05abb769 1128 ds_put_format(string, "priority=%"PRIu16", ", ntohs(fs->priority));
064af421 1129 ds_put_format(string, "n_packets=%"PRIu64", ",
c4617b3c
BP
1130 ntohll(get_32aligned_be64(&fs->packet_count)));
1131 ds_put_format(string, "n_bytes=%"PRIu64", ",
1132 ntohll(get_32aligned_be64(&fs->byte_count)));
064af421
BP
1133 if (fs->idle_timeout != htons(OFP_FLOW_PERMANENT)) {
1134 ds_put_format(string, "idle_timeout=%"PRIu16",",
1135 ntohs(fs->idle_timeout));
1136 }
1137 if (fs->hard_timeout != htons(OFP_FLOW_PERMANENT)) {
1138 ds_put_format(string, "hard_timeout=%"PRIu16",",
1139 ntohs(fs->hard_timeout));
1140 }
1141 ofp_print_match(string, &fs->match, verbosity);
05abb769 1142 ds_put_char(string, ' ');
064af421 1143 ofp_print_actions(string, fs->actions, length - sizeof *fs);
064af421
BP
1144
1145 pos += length;
1146 }
1147}
1148
c6430da5
BP
1149static void
1150ofp_print_nxst_flow_reply(struct ds *string, const struct ofp_header *oh)
1151{
1152 struct ofpbuf b;
1153
1154 ofpbuf_use_const(&b, ofputil_nxstats_body(oh),
1155 ofputil_nxstats_body_len(oh));
1156 while (b.size > 0) {
1157 const struct nx_flow_stats *fs;
1158 union ofp_action *actions;
1159 struct cls_rule rule;
1160 size_t actions_len, n_actions;
1161 size_t length;
1162 int match_len;
1163 int error;
1164
8961de6a
BP
1165 ds_put_char(string, '\n');
1166
c6430da5
BP
1167 fs = ofpbuf_try_pull(&b, sizeof *fs);
1168 if (!fs) {
1169 ds_put_format(string, " ***%td leftover bytes at end***", b.size);
1170 break;
1171 }
1172
1173 length = ntohs(fs->length);
1174 if (length < sizeof *fs) {
1175 ds_put_format(string, " ***nx_flow_stats claims length %zu***",
1176 length);
1177 break;
1178 }
1179
1180 match_len = ntohs(fs->match_len);
1181 if (match_len > length - sizeof *fs) {
1182 ds_put_format(string, " ***length=%zu match_len=%d***",
1183 length, match_len);
1184 break;
1185 }
1186
09862ec6
BP
1187 ds_put_format(string, " cookie=0x%"PRIx64", duration=",
1188 ntohll(fs->cookie));
1189 ofp_print_duration(string, ntohl(fs->duration_sec),
1190 ntohl(fs->duration_nsec));
1191 ds_put_format(string, ", table_id=%"PRIu8", ", fs->table_id);
c6430da5
BP
1192 ds_put_format(string, "n_packets=%"PRIu64", ",
1193 ntohll(fs->packet_count));
1194 ds_put_format(string, "n_bytes=%"PRIu64", ", ntohll(fs->byte_count));
1195 if (fs->idle_timeout != htons(OFP_FLOW_PERMANENT)) {
1196 ds_put_format(string, "idle_timeout=%"PRIu16",",
1197 ntohs(fs->idle_timeout));
1198 }
1199 if (fs->hard_timeout != htons(OFP_FLOW_PERMANENT)) {
1200 ds_put_format(string, "hard_timeout=%"PRIu16",",
1201 ntohs(fs->hard_timeout));
1202 }
1203
1204 error = nx_pull_match(&b, match_len, ntohs(fs->priority), &rule);
1205 if (error) {
1206 ofp_print_error(string, error);
1207 break;
1208 }
1209
1210 actions_len = length - sizeof *fs - ROUND_UP(match_len, 8);
1211 error = ofputil_pull_actions(&b, actions_len, &actions, &n_actions);
1212 if (error) {
1213 ofp_print_error(string, error);
1214 break;
1215 }
1216
1217 cls_rule_format(&rule, string);
1218 ds_put_char(string, ' ');
1219 ofp_print_actions(string, (const struct ofp_action_header *) actions,
1220 n_actions * sizeof *actions);
c6430da5
BP
1221 }
1222}
1223
064af421 1224static void
a2ad9ecd
BP
1225ofp_print_ofp_aggregate_stats_reply (
1226 struct ds *string, const struct ofp_aggregate_stats_reply *asr)
064af421 1227{
c4617b3c
BP
1228 ds_put_format(string, " packet_count=%"PRIu64,
1229 ntohll(get_32aligned_be64(&asr->packet_count)));
1230 ds_put_format(string, " byte_count=%"PRIu64,
1231 ntohll(get_32aligned_be64(&asr->byte_count)));
064af421
BP
1232 ds_put_format(string, " flow_count=%"PRIu32, ntohl(asr->flow_count));
1233}
1234
a2ad9ecd
BP
1235static void
1236ofp_print_ofpst_aggregate_reply(struct ds *string, const struct ofp_header *oh)
1237{
1238 ofp_print_ofp_aggregate_stats_reply(string, ofputil_stats_body(oh));
1239}
1240
1241static void
1242ofp_print_nxst_aggregate_reply(struct ds *string,
1243 const struct nx_aggregate_stats_reply *nasr)
1244{
1245 ofp_print_ofp_aggregate_stats_reply(string, &nasr->asr);
1246}
1247
d295e8e9 1248static void print_port_stat(struct ds *string, const char *leader,
c4617b3c 1249 const ovs_32aligned_be64 *statp, int more)
064af421 1250{
c4617b3c
BP
1251 uint64_t stat = ntohll(get_32aligned_be64(statp));
1252
064af421 1253 ds_put_cstr(string, leader);
c4617b3c 1254 if (stat != UINT64_MAX) {
064af421
BP
1255 ds_put_format(string, "%"PRIu64, stat);
1256 } else {
1257 ds_put_char(string, '?');
1258 }
1259 if (more) {
1260 ds_put_cstr(string, ", ");
1261 } else {
1262 ds_put_cstr(string, "\n");
1263 }
1264}
1265
abaad8cf 1266static void
d1e2cf21 1267ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh)
abaad8cf 1268{
d1e2cf21 1269 const struct ofp_port_stats_request *psr = ofputil_stats_body(oh);
fbd76b2e 1270 ds_put_format(string, " port_no=%"PRIu16, ntohs(psr->port_no));
abaad8cf
JP
1271}
1272
064af421 1273static void
d1e2cf21
BP
1274ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
1275 int verbosity)
064af421 1276{
d1e2cf21
BP
1277 const struct ofp_port_stats *ps = ofputil_stats_body(oh);
1278 size_t n = ofputil_stats_body_len(oh) / sizeof *ps;
064af421
BP
1279 ds_put_format(string, " %zu ports\n", n);
1280 if (verbosity < 1) {
1281 return;
1282 }
1283
1284 for (; n--; ps++) {
1285 ds_put_format(string, " port %2"PRIu16": ", ntohs(ps->port_no));
1286
1287 ds_put_cstr(string, "rx ");
c4617b3c
BP
1288 print_port_stat(string, "pkts=", &ps->rx_packets, 1);
1289 print_port_stat(string, "bytes=", &ps->rx_bytes, 1);
1290 print_port_stat(string, "drop=", &ps->rx_dropped, 1);
1291 print_port_stat(string, "errs=", &ps->rx_errors, 1);
1292 print_port_stat(string, "frame=", &ps->rx_frame_err, 1);
1293 print_port_stat(string, "over=", &ps->rx_over_err, 1);
1294 print_port_stat(string, "crc=", &ps->rx_crc_err, 0);
064af421
BP
1295
1296 ds_put_cstr(string, " tx ");
c4617b3c
BP
1297 print_port_stat(string, "pkts=", &ps->tx_packets, 1);
1298 print_port_stat(string, "bytes=", &ps->tx_bytes, 1);
1299 print_port_stat(string, "drop=", &ps->tx_dropped, 1);
1300 print_port_stat(string, "errs=", &ps->tx_errors, 1);
1301 print_port_stat(string, "coll=", &ps->collisions, 0);
064af421
BP
1302 }
1303}
1304
1305static void
d1e2cf21
BP
1306ofp_print_ofpst_table_reply(struct ds *string, const struct ofp_header *oh,
1307 int verbosity)
064af421 1308{
d1e2cf21
BP
1309 const struct ofp_table_stats *ts = ofputil_stats_body(oh);
1310 size_t n = ofputil_stats_body_len(oh) / sizeof *ts;
064af421
BP
1311 ds_put_format(string, " %zu tables\n", n);
1312 if (verbosity < 1) {
1313 return;
1314 }
1315
1316 for (; n--; ts++) {
1317 char name[OFP_MAX_TABLE_NAME_LEN + 1];
e868fb3d 1318 ovs_strlcpy(name, ts->name, sizeof name);
064af421
BP
1319
1320 ds_put_format(string, " %d: %-8s: ", ts->table_id, name);
1321 ds_put_format(string, "wild=0x%05"PRIx32", ", ntohl(ts->wildcards));
1322 ds_put_format(string, "max=%6"PRIu32", ", ntohl(ts->max_entries));
1323 ds_put_format(string, "active=%"PRIu32"\n", ntohl(ts->active_count));
1324 ds_put_cstr(string, " ");
d295e8e9 1325 ds_put_format(string, "lookup=%"PRIu64", ",
c4617b3c 1326 ntohll(get_32aligned_be64(&ts->lookup_count)));
064af421 1327 ds_put_format(string, "matched=%"PRIu64"\n",
c4617b3c 1328 ntohll(get_32aligned_be64(&ts->matched_count)));
064af421
BP
1329 }
1330}
1331
d2805da2
BP
1332static void
1333ofp_print_queue_name(struct ds *string, uint32_t queue_id)
1334{
1335 if (queue_id == OFPQ_ALL) {
1336 ds_put_cstr(string, "ALL");
1337 } else {
1338 ds_put_format(string, "%"PRIu32, queue_id);
1339 }
1340}
1341
1342static void
d1e2cf21 1343ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_header *oh)
d2805da2 1344{
d1e2cf21 1345 const struct ofp_queue_stats_request *qsr = ofputil_stats_body(oh);
d2805da2
BP
1346
1347 ds_put_cstr(string, "port=");
1348 ofp_print_port_name(string, ntohs(qsr->port_no));
1349
1350 ds_put_cstr(string, " queue=");
1351 ofp_print_queue_name(string, ntohl(qsr->queue_id));
1352}
1353
1354static void
d1e2cf21
BP
1355ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
1356 int verbosity)
d2805da2 1357{
d1e2cf21
BP
1358 const struct ofp_queue_stats *qs = ofputil_stats_body(oh);
1359 size_t n = ofputil_stats_body_len(oh) / sizeof *qs;
d2805da2
BP
1360 ds_put_format(string, " %zu queues\n", n);
1361 if (verbosity < 1) {
1362 return;
1363 }
1364
1365 for (; n--; qs++) {
1366 ds_put_cstr(string, " port ");
1367 ofp_print_port_name(string, ntohs(qs->port_no));
1368 ds_put_cstr(string, " queue ");
1369 ofp_print_queue_name(string, ntohl(qs->queue_id));
1370 ds_put_cstr(string, ": ");
1371
c4617b3c
BP
1372 print_port_stat(string, "bytes=", &qs->tx_bytes, 1);
1373 print_port_stat(string, "pkts=", &qs->tx_packets, 1);
1374 print_port_stat(string, "errors=", &qs->tx_errors, 0);
d2805da2
BP
1375 }
1376}
1377
064af421 1378static void
d1e2cf21 1379ofp_print_stats_request(struct ds *string, const struct ofp_header *oh)
064af421 1380{
d1e2cf21
BP
1381 const struct ofp_stats_request *srq
1382 = (const struct ofp_stats_request *) oh;
064af421
BP
1383
1384 if (srq->flags) {
1385 ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***",
1386 ntohs(srq->flags));
1387 }
064af421
BP
1388}
1389
1390static void
d1e2cf21 1391ofp_print_stats_reply(struct ds *string, const struct ofp_header *oh)
064af421 1392{
d1e2cf21 1393 const struct ofp_stats_reply *srp = (const struct ofp_stats_reply *) oh;
064af421 1394
d1e2cf21 1395 if (srp->flags) {
064af421 1396 uint16_t flags = ntohs(srp->flags);
d1e2cf21
BP
1397
1398 ds_put_cstr(string, " flags=");
064af421
BP
1399 if (flags & OFPSF_REPLY_MORE) {
1400 ds_put_cstr(string, "[more]");
1401 flags &= ~OFPSF_REPLY_MORE;
1402 }
1403 if (flags) {
d1e2cf21
BP
1404 ds_put_format(string, "[***unknown flags 0x%04"PRIx16"***]",
1405 flags);
064af421
BP
1406 }
1407 }
064af421
BP
1408}
1409
1410static void
d1e2cf21 1411ofp_print_echo(struct ds *string, const struct ofp_header *oh, int verbosity)
064af421 1412{
d1e2cf21 1413 size_t len = ntohs(oh->length);
064af421 1414
d1e2cf21 1415 ds_put_format(string, " %zu bytes of payload\n", len - sizeof *oh);
064af421 1416 if (verbosity > 1) {
d1e2cf21 1417 ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true);
064af421
BP
1418 }
1419}
1420
3731490f
BP
1421static void
1422ofp_print_nxt_status_message(struct ds *string, const struct ofp_header *oh)
1423{
1424 struct ofpbuf b;
1425
1426 ofpbuf_use_const(&b, oh, ntohs(oh->length));
fbd76b2e
BP
1427 ofpbuf_pull(&b, sizeof(struct nicira_header));
1428 ds_put_cstr(string, " \"");
3731490f
BP
1429 ds_put_printable(string, b.data, b.size);
1430 ds_put_char(string, '"');
1431}
1432
7fa91113
BP
1433static void
1434ofp_print_nxt_tun_id_from_cookie(struct ds *string,
1435 const struct nxt_tun_id_cookie *ntic)
1436{
1437 ds_put_format(string, " set=%"PRIu8, ntic->set);
1438}
1439
61fe3a7b
BP
1440static void
1441ofp_print_nxt_role_message(struct ds *string,
1442 const struct nx_role_request *nrr)
1443{
1444 unsigned int role = ntohl(nrr->role);
1445
1446 ds_put_cstr(string, " role=");
1447 if (role == NX_ROLE_OTHER) {
1448 ds_put_cstr(string, "other");
1449 } else if (role == NX_ROLE_MASTER) {
1450 ds_put_cstr(string, "master");
1451 } else if (role == NX_ROLE_SLAVE) {
1452 ds_put_cstr(string, "slave");
1453 } else {
1454 ds_put_format(string, "%u", role);
1455 }
1456}
1457
7fa91113
BP
1458static void
1459ofp_print_nxt_set_flow_format(struct ds *string,
1460 const struct nxt_set_flow_format *nsff)
1461{
1462 uint32_t format = ntohl(nsff->format);
1463
1464 ds_put_cstr(string, " format=");
1465 if (ofputil_flow_format_is_valid(format)) {
1466 ds_put_cstr(string, ofputil_flow_format_to_string(format));
1467 } else {
1468 ds_put_format(string, "%"PRIu32, format);
1469 }
1470}
1471
d1e2cf21
BP
1472static void
1473ofp_to_string__(const struct ofp_header *oh,
1474 const struct ofputil_msg_type *type, struct ds *string,
1475 int verbosity)
1476{
7fa91113 1477 enum ofputil_msg_code code;
d1e2cf21
BP
1478 const void *msg = oh;
1479
1480 ds_put_format(string, "%s (xid=0x%"PRIx32"):",
1481 ofputil_msg_type_name(type), ntohl(oh->xid));
1482
7fa91113
BP
1483 code = ofputil_msg_type_code(type);
1484 switch (code) {
d1e2cf21
BP
1485 case OFPUTIL_INVALID:
1486 break;
1487
1488 case OFPUTIL_OFPT_HELLO:
dc4762ed
BP
1489 ds_put_char(string, '\n');
1490 ds_put_hex_dump(string, oh + 1, ntohs(oh->length) - sizeof *oh,
1491 0, true);
d1e2cf21
BP
1492 break;
1493
1494 case OFPUTIL_OFPT_ERROR:
1495 ofp_print_error_msg(string, msg);
1496 break;
1497
1498 case OFPUTIL_OFPT_ECHO_REQUEST:
1499 case OFPUTIL_OFPT_ECHO_REPLY:
1500 ofp_print_echo(string, oh, verbosity);
1501 break;
1502
1503 case OFPUTIL_OFPT_FEATURES_REQUEST:
1504 break;
1505
1506 case OFPUTIL_OFPT_FEATURES_REPLY:
1507 ofp_print_switch_features(string, msg);
1508 break;
1509
1510 case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
1511 break;
1512
1513 case OFPUTIL_OFPT_GET_CONFIG_REPLY:
1514 case OFPUTIL_OFPT_SET_CONFIG:
1515 ofp_print_switch_config(string, msg);
1516 break;
1517
1518 case OFPUTIL_OFPT_PACKET_IN:
1519 ofp_print_packet_in(string, msg, verbosity);
1520 break;
1521
1522 case OFPUTIL_OFPT_FLOW_REMOVED:
9b045a0c
BP
1523 case OFPUTIL_NXT_FLOW_REMOVED:
1524 ofp_print_flow_removed(string, msg);
d1e2cf21
BP
1525 break;
1526
1527 case OFPUTIL_OFPT_PORT_STATUS:
1528 ofp_print_port_status(string, msg);
1529 break;
1530
1531 case OFPUTIL_OFPT_PACKET_OUT:
1532 ofp_print_packet_out(string, msg, verbosity);
1533 break;
1534
1535 case OFPUTIL_OFPT_FLOW_MOD:
7fa91113 1536 ofp_print_flow_mod(string, msg, code, verbosity);
d1e2cf21
BP
1537 break;
1538
1539 case OFPUTIL_OFPT_PORT_MOD:
1540 ofp_print_port_mod(string, msg);
1541 break;
1542
1543 case OFPUTIL_OFPT_BARRIER_REQUEST:
1544 case OFPUTIL_OFPT_BARRIER_REPLY:
1545 break;
1546
1547 case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
1548 case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
1549 /* XXX */
1550 break;
1551
1552 case OFPUTIL_OFPST_DESC_REQUEST:
1553 ofp_print_stats_request(string, oh);
1554 break;
1555
1556 case OFPUTIL_OFPST_FLOW_REQUEST:
2af0c0ef 1557 case OFPUTIL_NXST_FLOW_REQUEST:
d1e2cf21 1558 case OFPUTIL_OFPST_AGGREGATE_REQUEST:
2af0c0ef 1559 case OFPUTIL_NXST_AGGREGATE_REQUEST:
d1e2cf21 1560 ofp_print_stats_request(string, oh);
2af0c0ef 1561 ofp_print_flow_stats_request(string, oh);
d1e2cf21
BP
1562 break;
1563
1564 case OFPUTIL_OFPST_TABLE_REQUEST:
1565 ofp_print_stats_request(string, oh);
1566 break;
1567
1568 case OFPUTIL_OFPST_PORT_REQUEST:
1569 ofp_print_stats_request(string, oh);
1570 ofp_print_ofpst_port_request(string, oh);
1571 break;
1572
1573 case OFPUTIL_OFPST_QUEUE_REQUEST:
1574 ofp_print_stats_request(string, oh);
1575 ofp_print_ofpst_queue_request(string, oh);
1576 break;
1577
1578 case OFPUTIL_OFPST_DESC_REPLY:
1579 ofp_print_stats_reply(string, oh);
1580 ofp_print_ofpst_desc_reply(string, oh);
1581 break;
1582
1583 case OFPUTIL_OFPST_FLOW_REPLY:
1584 ofp_print_stats_reply(string, oh);
1585 ofp_print_ofpst_flow_reply(string, oh, verbosity);
1586 break;
1587
1588 case OFPUTIL_OFPST_QUEUE_REPLY:
1589 ofp_print_stats_reply(string, oh);
1590 ofp_print_ofpst_queue_reply(string, oh, verbosity);
1591 break;
1592
1593 case OFPUTIL_OFPST_PORT_REPLY:
1594 ofp_print_stats_reply(string, oh);
1595 ofp_print_ofpst_port_reply(string, oh, verbosity);
1596 break;
1597
1598 case OFPUTIL_OFPST_TABLE_REPLY:
1599 ofp_print_stats_reply(string, oh);
1600 ofp_print_ofpst_table_reply(string, oh, verbosity);
1601 break;
1602
1603 case OFPUTIL_OFPST_AGGREGATE_REPLY:
1604 ofp_print_stats_reply(string, oh);
1605 ofp_print_ofpst_aggregate_reply(string, oh);
1606 break;
064af421 1607
d1e2cf21
BP
1608 case OFPUTIL_NXT_STATUS_REQUEST:
1609 case OFPUTIL_NXT_STATUS_REPLY:
3731490f 1610 ofp_print_nxt_status_message(string, oh);
7fa91113
BP
1611 break;
1612
d1e2cf21 1613 case OFPUTIL_NXT_TUN_ID_FROM_COOKIE:
7fa91113
BP
1614 ofp_print_nxt_tun_id_from_cookie(string, msg);
1615 break;
1616
d1e2cf21
BP
1617 case OFPUTIL_NXT_ROLE_REQUEST:
1618 case OFPUTIL_NXT_ROLE_REPLY:
61fe3a7b 1619 ofp_print_nxt_role_message(string, msg);
7fa91113
BP
1620 break;
1621
d1e2cf21 1622 case OFPUTIL_NXT_SET_FLOW_FORMAT:
7fa91113
BP
1623 ofp_print_nxt_set_flow_format(string, msg);
1624 break;
1625
d1e2cf21 1626 case OFPUTIL_NXT_FLOW_MOD:
7fa91113
BP
1627 ofp_print_flow_mod(string, msg, code, verbosity);
1628 break;
1629
d1e2cf21 1630 case OFPUTIL_NXST_FLOW_REPLY:
c6430da5
BP
1631 ofp_print_nxst_flow_reply(string, oh);
1632 break;
1633
d1e2cf21 1634 case OFPUTIL_NXST_AGGREGATE_REPLY:
a2ad9ecd 1635 ofp_print_stats_reply(string, oh);
9b045a0c 1636 ofp_print_nxst_aggregate_reply(string, msg);
d1e2cf21 1637 break;
246e61ea 1638 }
d1e2cf21 1639}
064af421
BP
1640
1641/* Composes and returns a string representing the OpenFlow packet of 'len'
1642 * bytes at 'oh' at the given 'verbosity' level. 0 is a minimal amount of
1643 * verbosity and higher numbers increase verbosity. The caller is responsible
1644 * for freeing the string. */
1645char *
1646ofp_to_string(const void *oh_, size_t len, int verbosity)
1647{
1648 struct ds string = DS_EMPTY_INITIALIZER;
1649 const struct ofp_header *oh = oh_;
064af421 1650
49ad0403
BP
1651 if (!len) {
1652 ds_put_cstr(&string, "OpenFlow message is empty\n");
1653 } else if (len < sizeof(struct ofp_header)) {
1654 ds_put_format(&string, "OpenFlow packet too short (only %zu bytes):\n",
1655 len);
064af421 1656 } else if (oh->version != OFP_VERSION) {
d1e2cf21
BP
1657 ds_put_format(&string, "Bad OpenFlow version %"PRIu8":\n",
1658 oh->version);
1659 } else if (ntohs(oh->length) > len) {
1660 ds_put_format(&string,
49ad0403 1661 "(***truncated to %zu bytes from %"PRIu16"***)\n",
d1e2cf21
BP
1662 len, ntohs(oh->length));
1663 } else if (ntohs(oh->length) < len) {
1664 ds_put_format(&string,
1665 "(***only uses %"PRIu16" bytes out of %zu***)\n",
1666 ntohs(oh->length), len);
1667 } else {
1668 const struct ofputil_msg_type *type;
d1e2cf21
BP
1669 int error;
1670
1671 error = ofputil_decode_msg_type(oh, &type);
1672 if (!error) {
1673 ofp_to_string__(oh, type, &string, verbosity);
7fa91113
BP
1674 if (verbosity >= 5) {
1675 if (ds_last(&string) != '\n') {
1676 ds_put_char(&string, '\n');
1677 }
d1e2cf21
BP
1678 ds_put_hex_dump(&string, oh, len, 0, true);
1679 }
7fa91113 1680 if (ds_last(&string) != '\n') {
d1e2cf21
BP
1681 ds_put_char(&string, '\n');
1682 }
1683 return ds_steal_cstr(&string);
064af421 1684 }
064af421 1685
7fa91113 1686 ofp_print_error(&string, error);
064af421 1687 }
d1e2cf21
BP
1688 ds_put_hex_dump(&string, oh, len, 0, true);
1689 return ds_steal_cstr(&string);
064af421
BP
1690}
1691
1692/* Returns the name for the specified OpenFlow message type as a string,
1693 * e.g. "OFPT_FEATURES_REPLY". If no name is known, the string returned is a
1694 * hex number, e.g. "0x55".
1695 *
1696 * The caller must free the returned string when it is no longer needed. */
1697char *
1698ofp_message_type_to_string(uint8_t type)
1699{
d1e2cf21 1700 const char *name;
064af421 1701
d1e2cf21
BP
1702 switch (type) {
1703 case OFPT_HELLO:
1704 name = "HELLO";
1705 break;
1706 case OFPT_ERROR:
1707 name = "ERROR";
1708 break;
1709 case OFPT_ECHO_REQUEST:
1710 name = "ECHO_REQUEST";
1711 break;
1712 case OFPT_ECHO_REPLY:
1713 name = "ECHO_REPLY";
1714 break;
1715 case OFPT_VENDOR:
1716 name = "VENDOR";
1717 break;
1718 case OFPT_FEATURES_REQUEST:
1719 name = "FEATURES_REQUEST";
1720 break;
1721 case OFPT_FEATURES_REPLY:
1722 name = "FEATURES_REPLY";
1723 break;
1724 case OFPT_GET_CONFIG_REQUEST:
1725 name = "GET_CONFIG_REQUEST";
1726 break;
1727 case OFPT_GET_CONFIG_REPLY:
1728 name = "GET_CONFIG_REPLY";
1729 break;
1730 case OFPT_SET_CONFIG:
1731 name = "SET_CONFIG";
1732 break;
1733 case OFPT_PACKET_IN:
1734 name = "PACKET_IN";
1735 break;
1736 case OFPT_FLOW_REMOVED:
1737 name = "FLOW_REMOVED";
1738 break;
1739 case OFPT_PORT_STATUS:
1740 name = "PORT_STATUS";
1741 break;
1742 case OFPT_PACKET_OUT:
1743 name = "PACKET_OUT";
1744 break;
1745 case OFPT_FLOW_MOD:
1746 name = "FLOW_MOD";
1747 break;
1748 case OFPT_PORT_MOD:
1749 name = "PORT_MOD";
1750 break;
1751 case OFPT_STATS_REQUEST:
1752 name = "STATS_REQUEST";
1753 break;
1754 case OFPT_STATS_REPLY:
1755 name = "STATS_REPLY";
1756 break;
1757 case OFPT_BARRIER_REQUEST:
1758 name = "BARRIER_REQUEST";
1759 break;
1760 case OFPT_BARRIER_REPLY:
1761 name = "BARRIER_REPLY";
1762 break;
1763 case OFPT_QUEUE_GET_CONFIG_REQUEST:
1764 name = "QUEUE_GET_CONFIG_REQUEST";
1765 break;
1766 case OFPT_QUEUE_GET_CONFIG_REPLY:
1767 name = "QUEUE_GET_CONFIG_REPLY";
1768 break;
1769 default:
1770 name = NULL;
1771 break;
064af421 1772 }
d1e2cf21
BP
1773
1774 return name ? xasprintf("OFPT_%s", name) : xasprintf("0x%02"PRIx8, type);
064af421
BP
1775}
1776\f
1777static void
d295e8e9 1778print_and_free(FILE *stream, char *string)
064af421
BP
1779{
1780 fputs(string, stream);
1781 free(string);
1782}
1783
1784/* Pretty-print the OpenFlow packet of 'len' bytes at 'oh' to 'stream' at the
1785 * given 'verbosity' level. 0 is a minimal amount of verbosity and higher
1786 * numbers increase verbosity. */
1787void
1788ofp_print(FILE *stream, const void *oh, size_t len, int verbosity)
1789{
1790 print_and_free(stream, ofp_to_string(oh, len, verbosity));
1791}
1792
1793/* Dumps the contents of the Ethernet frame in the 'len' bytes starting at
1794 * 'data' to 'stream' using tcpdump. 'total_len' specifies the full length of
1795 * the Ethernet frame (of which 'len' bytes were captured).
1796 *
1797 * This starts and kills a tcpdump subprocess so it's quite expensive. */
1798void
1799ofp_print_packet(FILE *stream, const void *data, size_t len, size_t total_len)
1800{
1801 print_and_free(stream, ofp_packet_to_string(data, len, total_len));
1802}