]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ofp-print.c
Add OpenFlow extensions for group support in OpenFlow 1.0.
[mirror_ovs.git] / lib / ofp-print.c
CommitLineData
064af421 1/*
04f48a68 2 * Copyright (c) 2008-2017 Nicira, Inc.
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>
064af421 18
0c24b0ba
BP
19#include "openvswitch/ofp-print.h"
20
064af421
BP
21#include <errno.h>
22#include <inttypes.h>
7f3adc00 23#include <sys/types.h>
064af421
BP
24#include <netinet/in.h>
25#include <sys/wait.h>
26#include <stdarg.h>
27#include <stdlib.h>
28#include <ctype.h>
29
daff3353 30#include "bundle.h"
10a24935 31#include "byte-order.h"
ab8e7f7d 32#include "colors.h"
064af421 33#include "compiler.h"
25d436fb 34#include "dp-packet.h"
064af421 35#include "flow.h"
75a75043 36#include "learn.h"
53ddd40a 37#include "multipath.h"
9e1fd49b 38#include "netdev.h"
7fa91113 39#include "nx-match.h"
25d436fb 40#include "odp-util.h"
064af421 41#include "openflow/nicira-ext.h"
b598f214 42#include "openflow/openflow.h"
d271907f
BW
43#include "openvswitch/dynamic-string.h"
44#include "openvswitch/meta-flow.h"
b598f214 45#include "openvswitch/ofp-actions.h"
0d71302e
BP
46#include "openvswitch/ofp-bundle.h"
47#include "openvswitch/ofp-connection.h"
e03c096d 48#include "openvswitch/ofp-errors.h"
0d71302e
BP
49#include "openvswitch/ofp-group.h"
50#include "openvswitch/ofp-ipfix.h"
51#include "openvswitch/ofp-match.h"
52#include "openvswitch/ofp-meter.h"
53#include "openvswitch/ofp-monitor.h"
d271907f 54#include "openvswitch/ofp-msgs.h"
0d71302e
BP
55#include "openvswitch/ofp-port.h"
56#include "openvswitch/ofp-queue.h"
57#include "openvswitch/ofp-switch.h"
58#include "openvswitch/ofp-table.h"
d271907f
BW
59#include "openvswitch/ofp-util.h"
60#include "openvswitch/ofpbuf.h"
61#include "openvswitch/type-props.h"
064af421 62#include "packets.h"
c4617b3c 63#include "unaligned.h"
064af421 64#include "util.h"
d5dc60f0 65#include "uuid.h"
064af421 66
d2805da2 67static void ofp_print_queue_name(struct ds *string, uint32_t port);
90bf1e07 68static void ofp_print_error(struct ds *, enum ofperr);
064af421
BP
69
70/* Returns a string that represents the contents of the Ethernet frame in the
897a8e07 71 * 'len' bytes starting at 'data'. The caller must free the returned string.*/
064af421 72char *
2482b0b0 73ofp_packet_to_string(const void *data, size_t len, ovs_be32 packet_type)
064af421
BP
74{
75 struct ds ds = DS_EMPTY_INITIALIZER;
cf62fa4c 76 struct dp_packet buf;
897a8e07 77 struct flow flow;
5a51b2cd 78 size_t l4_size;
064af421 79
cf62fa4c 80 dp_packet_use_const(&buf, data, len);
2482b0b0 81 buf.packet_type = packet_type;
cf62fa4c 82 flow_extract(&buf, &flow);
50f96b10 83 flow_format(&ds, &flow, NULL);
e50abca5 84
cf62fa4c 85 l4_size = dp_packet_l4_size(&buf);
5a51b2cd
JR
86
87 if (flow.nw_proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) {
cf62fa4c 88 struct tcp_header *th = dp_packet_l4(&buf);
5a51b2cd
JR
89 ds_put_format(&ds, " tcp_csum:%"PRIx16, ntohs(th->tcp_csum));
90 } else if (flow.nw_proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN) {
cf62fa4c 91 struct udp_header *uh = dp_packet_l4(&buf);
5a51b2cd
JR
92 ds_put_format(&ds, " udp_csum:%"PRIx16, ntohs(uh->udp_csum));
93 } else if (flow.nw_proto == IPPROTO_SCTP && l4_size >= SCTP_HEADER_LEN) {
cf62fa4c 94 struct sctp_header *sh = dp_packet_l4(&buf);
5fa008d4
BP
95 ds_put_format(&ds, " sctp_csum:%"PRIx32,
96 ntohl(get_16aligned_be32(&sh->sctp_csum)));
e60e935b 97 } else if (flow.nw_proto == IPPROTO_ICMP && l4_size >= ICMP_HEADER_LEN) {
cf62fa4c 98 struct icmp_header *icmph = dp_packet_l4(&buf);
e60e935b
SRCSA
99 ds_put_format(&ds, " icmp_csum:%"PRIx16,
100 ntohs(icmph->icmp_csum));
101 } else if (flow.nw_proto == IPPROTO_ICMPV6 && l4_size >= ICMP6_HEADER_LEN) {
cf62fa4c 102 struct icmp6_header *icmp6h = dp_packet_l4(&buf);
e60e935b
SRCSA
103 ds_put_format(&ds, " icmp6_csum:%"PRIx16,
104 ntohs(icmp6h->icmp6_cksum));
e50abca5
EJ
105 }
106
897a8e07 107 ds_put_char(&ds, '\n');
064af421 108
064af421
BP
109 return ds_cstr(&ds);
110}
111
2482b0b0
JS
112char *
113ofp_dp_packet_to_string(const struct dp_packet *packet)
114{
115 return ofp_packet_to_string(dp_packet_data(packet),
116 dp_packet_size(packet),
117 packet->packet_type);
118}
119
2d071a32 120static enum ofperr
65120a8a 121ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
4bc938cc
BP
122 const struct ofputil_port_map *port_map,
123 const struct ofputil_table_map *table_map, int verbosity)
064af421 124{
77ab5fd2 125 struct ofputil_packet_in_private pin;
9bfe9334
BP
126 uint32_t buffer_id;
127 size_t total_len;
dfc77282
BP
128 enum ofperr error = ofputil_decode_packet_in_private(oh, true, NULL, NULL,
129 &pin, &total_len,
130 &buffer_id);
131 if (!error) {
132 ofputil_packet_in_private_format(string, &pin, total_len, buffer_id,
133 port_map, table_map, verbosity);
134 ofputil_packet_in_private_destroy(&pin);
b4ccee75 135 }
dfc77282 136 return error;
064af421
BP
137}
138
2d071a32 139static enum ofperr
982697a4 140ofp_print_packet_out(struct ds *string, const struct ofp_header *oh,
4bc938cc
BP
141 const struct ofputil_port_map *port_map,
142 const struct ofputil_table_map *table_map, int verbosity)
064af421 143{
c6a93eb7 144 struct ofputil_packet_out po;
f25d0cf3 145 struct ofpbuf ofpacts;
c6a93eb7 146 enum ofperr error;
064af421 147
f25d0cf3 148 ofpbuf_init(&ofpacts, 64);
89d7927b 149 error = ofputil_decode_packet_out(&po, oh, NULL, &ofpacts);
dfc77282
BP
150 if (!error) {
151 ofputil_packet_out_format(string, &po, port_map, table_map, verbosity);
064af421 152 }
f25d0cf3 153 ofpbuf_uninit(&ofpacts);
dfc77282 154 return error;
064af421
BP
155}
156
dfc77282 157void
0ab14c8e 158ofp_print_bit_names(struct ds *string, uint32_t bits,
e8fa940e
BP
159 const char *(*bit_to_name)(uint32_t bit),
160 char separator)
064af421 161{
0ab14c8e 162 int n = 0;
9e1fd49b 163 int i;
0ab14c8e
BP
164
165 if (!bits) {
166 ds_put_cstr(string, "0");
064af421
BP
167 return;
168 }
0ab14c8e 169
9e1fd49b
BP
170 for (i = 0; i < 32; i++) {
171 uint32_t bit = UINT32_C(1) << i;
172
173 if (bits & bit) {
174 const char *name = bit_to_name(bit);
175 if (name) {
176 if (n++) {
e8fa940e 177 ds_put_char(string, separator);
9e1fd49b
BP
178 }
179 ds_put_cstr(string, name);
180 bits &= ~bit;
0ab14c8e 181 }
0ab14c8e 182 }
064af421 183 }
0ab14c8e
BP
184
185 if (bits) {
f5cd6874 186 if (n) {
e8fa940e 187 ds_put_char(string, separator);
0ab14c8e
BP
188 }
189 ds_put_format(string, "0x%"PRIx32, bits);
064af421 190 }
0ab14c8e
BP
191}
192
2d071a32 193static enum ofperr
982697a4 194ofp_print_switch_features(struct ds *string, const struct ofp_header *oh)
064af421 195{
9e1fd49b 196 struct ofputil_switch_features features;
0a2869d5
BP
197 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
198 enum ofperr error = ofputil_pull_switch_features(&b, &features);
dfc77282
BP
199 if (!error) {
200 ofputil_switch_features_format(string, &features);
201 error = ofputil_phy_ports_format(string, oh->version, &b);
f0fd1a17 202 }
dfc77282 203 return error;
ad99e2ed
BP
204}
205
2d071a32 206static enum ofperr
ad99e2ed
BP
207ofp_print_set_config(struct ds *string, const struct ofp_header *oh)
208{
209 struct ofputil_switch_config config;
210 enum ofperr error;
211
212 error = ofputil_decode_set_config(oh, &config);
213 if (error) {
2d071a32 214 return error;
064af421 215 }
dfc77282 216 ofputil_switch_config_format(string, &config);
2d071a32 217 return 0;
ad99e2ed 218}
064af421 219
2d071a32 220static enum ofperr
ad99e2ed
BP
221ofp_print_get_config_reply(struct ds *string, const struct ofp_header *oh)
222{
223 struct ofputil_switch_config config;
224 ofputil_decode_get_config_reply(oh, &config);
dfc77282 225 ofputil_switch_config_format(string, &config);
2d071a32 226 return 0;
064af421
BP
227}
228
2d071a32 229static enum ofperr
dfc77282
BP
230ofp_print_table_features_reply(struct ds *s, const struct ofp_header *oh,
231 const struct ofputil_table_map *table_map)
064af421 232{
dfc77282 233 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
f904747b 234
dfc77282
BP
235 struct ofputil_table_features prev;
236 for (int i = 0; ; i++) {
237 struct ofputil_table_features tf;
238 int retval;
7fa91113 239
dfc77282
BP
240 retval = ofputil_decode_table_features(&b, &tf, true);
241 if (retval) {
242 return retval != EOF ? retval : 0;
243 }
0fb88c18 244
dfc77282
BP
245 ds_put_char(s, '\n');
246 ofputil_table_features_format(s, &tf, i ? &prev : NULL, NULL, NULL,
247 table_map);
248 prev = tf;
7fa91113 249 }
064af421
BP
250}
251
dfc77282 252void
09862ec6
BP
253ofp_print_duration(struct ds *string, unsigned int sec, unsigned int nsec)
254{
255 ds_put_format(string, "%u", sec);
b1634591
BP
256
257 /* If there are no fractional seconds, don't print any decimals.
258 *
259 * If the fractional seconds can be expressed exactly as milliseconds,
260 * print 3 decimals. Open vSwitch provides millisecond precision for most
261 * time measurements, so printing 3 decimals every time makes it easier to
dfc77282
BP
262 * spot real changes in flow dumps that refresh themselves quickly.
263 *
264 * If the fractional seconds are more precise than milliseconds, print the
265 * number of decimals needed to express them exactly.
266 */
267 if (nsec > 0) {
268 unsigned int msec = nsec / 1000000;
269 if (msec * 1000000 == nsec) {
270 ds_put_format(string, ".%03u", msec);
271 } else {
272 ds_put_format(string, ".%09u", nsec);
273 while (string->string[string->length - 1] == '0') {
274 string->length--;
275 }
276 }
82c22d34 277 }
dfc77282 278 ds_put_char(string, 's');
82c22d34
BP
279}
280
dfc77282
BP
281static enum ofperr
282ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh,
283 const struct ofputil_port_map *port_map,
284 const struct ofputil_table_map *table_map)
82c22d34 285{
dfc77282
BP
286 struct ofputil_flow_removed fr;
287 enum ofperr error = ofputil_decode_flow_removed(&fr, oh);
288 if (!error) {
289 ofputil_flow_removed_format(string, &fr, port_map, table_map);
918f2b82 290 }
dfc77282 291 return error;
918f2b82
AZ
292}
293
dfc77282
BP
294static enum ofperr
295ofp_print_port_mod(struct ds *string, const struct ofp_header *oh,
296 const struct ofputil_port_map *port_map)
de7d3c07 297{
dfc77282
BP
298 struct ofputil_port_mod pm;
299 enum ofperr error = ofputil_decode_port_mod(oh, &pm, true);
300 if (!error) {
301 ofputil_port_mod_format(string, &pm, port_map);
de7d3c07 302 }
dfc77282 303 return error;
de7d3c07
SJ
304}
305
2d071a32 306static enum ofperr
4bc938cc
BP
307ofp_print_table_mod(struct ds *string, const struct ofp_header *oh,
308 const struct ofputil_table_map *table_map)
918f2b82 309{
dfc77282
BP
310 struct ofputil_table_mod tm;
311 enum ofperr error = ofputil_decode_table_mod(oh, &tm);
312 if (!error) {
313 ofputil_table_mod_format(string, &tm, table_map);
bab86012 314 }
dfc77282 315 return error;
03c72922
BP
316}
317
2d071a32 318static enum ofperr
4bc938cc
BP
319ofp_print_table_status_message(struct ds *string, const struct ofp_header *oh,
320 const struct ofputil_table_map *table_map)
6c6eedc5
SJ
321{
322 struct ofputil_table_status ts;
323 enum ofperr error;
324
325 error = ofputil_decode_table_status(oh, &ts);
326 if (error) {
2d071a32 327 return error;
6c6eedc5
SJ
328 }
329
330 if (ts.reason == OFPTR_VACANCY_DOWN) {
331 ds_put_format(string, " reason=VACANCY_DOWN");
332 } else if (ts.reason == OFPTR_VACANCY_UP) {
333 ds_put_format(string, " reason=VACANCY_UP");
334 }
335
336 ds_put_format(string, "\ntable_desc:-");
dfc77282 337 ofputil_table_desc_format(string, &ts.desc, table_map);
2d071a32
BP
338
339 return 0;
6c6eedc5
SJ
340}
341
2d071a32 342static enum ofperr
e8f9a7bb 343ofp_print_queue_get_config_request(struct ds *string,
50f96b10
BP
344 const struct ofp_header *oh,
345 const struct ofputil_port_map *port_map)
e8f9a7bb
VG
346{
347 enum ofperr error;
348 ofp_port_t port;
e016fb63 349 uint32_t queue;
e8f9a7bb 350
e016fb63 351 error = ofputil_decode_queue_get_config_request(oh, &port, &queue);
e8f9a7bb 352 if (error) {
2d071a32 353 return error;
e8f9a7bb
VG
354 }
355
356 ds_put_cstr(string, " port=");
50f96b10 357 ofputil_format_port(port, port_map, string);
e016fb63
BP
358
359 if (queue != OFPQ_ALL) {
360 ds_put_cstr(string, " queue=");
361 ofp_print_queue_name(string, queue);
362 }
2d071a32
BP
363
364 return 0;
e8f9a7bb
VG
365}
366
367static void
368print_queue_rate(struct ds *string, const char *name, unsigned int rate)
369{
370 if (rate <= 1000) {
371 ds_put_format(string, " %s:%u.%u%%", name, rate / 10, rate % 10);
372 } else if (rate < UINT16_MAX) {
373 ds_put_format(string, " %s:(disabled)", name);
374 }
375}
376
a28239c0
BP
377/* qsort comparison function. */
378static int
379compare_queues(const void *a_, const void *b_)
380{
381 const struct ofputil_queue_config *a = a_;
382 const struct ofputil_queue_config *b = b_;
383
384 uint16_t ap = ofp_to_u16(a->port);
385 uint16_t bp = ofp_to_u16(b->port);
386 if (ap != bp) {
387 return ap < bp ? -1 : 1;
388 }
389
390 uint32_t aq = a->queue;
391 uint32_t bq = b->queue;
392 return aq < bq ? -1 : aq > bq;
393}
394
2d071a32 395static enum ofperr
e8f9a7bb 396ofp_print_queue_get_config_reply(struct ds *string,
50f96b10
BP
397 const struct ofp_header *oh,
398 const struct ofputil_port_map *port_map)
e8f9a7bb 399{
0a2869d5 400 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
e8f9a7bb 401
a28239c0
BP
402 struct ofputil_queue_config *queues = NULL;
403 size_t allocated_queues = 0;
404 size_t n = 0;
e8f9a7bb 405
a28239c0
BP
406 int retval = 0;
407 for (;;) {
408 if (n >= allocated_queues) {
409 queues = x2nrealloc(queues, &allocated_queues, sizeof *queues);
410 }
411 retval = ofputil_pull_queue_get_config_reply(&b, &queues[n]);
e8f9a7bb 412 if (retval) {
e8f9a7bb
VG
413 break;
414 }
a28239c0
BP
415 n++;
416 }
e8f9a7bb 417
a28239c0
BP
418 qsort(queues, n, sizeof *queues, compare_queues);
419
420 ds_put_char(string, ' ');
421
422 ofp_port_t port = 0;
423 for (const struct ofputil_queue_config *q = queues; q < &queues[n]; q++) {
424 if (q->port != port) {
425 port = q->port;
e016fb63
BP
426
427 ds_put_cstr(string, "port=");
50f96b10 428 ofputil_format_port(port, port_map, string);
e016fb63
BP
429 ds_put_char(string, '\n');
430 }
431
a28239c0
BP
432 ds_put_format(string, "queue %"PRIu32":", q->queue);
433 print_queue_rate(string, "min_rate", q->min_rate);
434 print_queue_rate(string, "max_rate", q->max_rate);
e8f9a7bb
VG
435 ds_put_char(string, '\n');
436 }
a28239c0 437
a28239c0 438 ds_chomp(string, ' ');
18dc96b0 439 free(queues);
2d071a32
BP
440
441 return retval != EOF ? retval : 0;
e8f9a7bb
VG
442}
443
638a19b0
JR
444static void
445ofp_print_meter_flags(struct ds *s, uint16_t flags)
446{
447 if (flags & OFPMF13_KBPS) {
448 ds_put_cstr(s, "kbps ");
449 }
450 if (flags & OFPMF13_PKTPS) {
451 ds_put_cstr(s, "pktps ");
452 }
453 if (flags & OFPMF13_BURST) {
454 ds_put_cstr(s, "burst ");
455 }
456 if (flags & OFPMF13_STATS) {
457 ds_put_cstr(s, "stats ");
458 }
459
460 flags &= ~(OFPMF13_KBPS | OFPMF13_PKTPS | OFPMF13_BURST | OFPMF13_STATS);
461 if (flags) {
462 ds_put_format(s, "flags:0x%"PRIx16" ", flags);
463 }
464}
465
466static void
467ofp_print_meter_band(struct ds *s, uint16_t flags,
468 const struct ofputil_meter_band *mb)
469{
470 ds_put_cstr(s, "\ntype=");
471 switch (mb->type) {
472 case OFPMBT13_DROP:
473 ds_put_cstr(s, "drop");
474 break;
475 case OFPMBT13_DSCP_REMARK:
476 ds_put_cstr(s, "dscp_remark");
477 break;
478 default:
479 ds_put_format(s, "%u", mb->type);
480 }
481
482 ds_put_format(s, " rate=%"PRIu32, mb->rate);
483
484 if (flags & OFPMF13_BURST) {
485 ds_put_format(s, " burst_size=%"PRIu32, mb->burst_size);
486 }
487 if (mb->type == OFPMBT13_DSCP_REMARK) {
488 ds_put_format(s, " prec_level=%"PRIu8, mb->prec_level);
489 }
490}
491
9e638f22
AZ
492static void
493ofp_print_meter_id(struct ds *s, uint32_t meter_id, char seperator)
494{
495 if (meter_id <= OFPM13_MAX) {
496 ds_put_format(s, "meter%c%"PRIu32, seperator, meter_id);
497 } else {
498 const char *name;
499 switch (meter_id) {
500 case OFPM13_SLOWPATH:
501 name = "slowpath";
502 break;
503 case OFPM13_CONTROLLER:
504 name = "controller";
505 break;
506 case OFPM13_ALL:
507 name = "all";
508 break;
509 default:
510 name = "unknown";
511 }
512 ds_put_format(s, "meter%c%s", seperator, name);
513 }
514}
515
638a19b0
JR
516static void
517ofp_print_meter_stats(struct ds *s, const struct ofputil_meter_stats *ms)
518{
519 uint16_t i;
520
9e638f22
AZ
521 ofp_print_meter_id(s, ms->meter_id, ':');
522 ds_put_char(s, ' ');
638a19b0
JR
523 ds_put_format(s, "flow_count:%"PRIu32" ", ms->flow_count);
524 ds_put_format(s, "packet_in_count:%"PRIu64" ", ms->packet_in_count);
525 ds_put_format(s, "byte_in_count:%"PRIu64" ", ms->byte_in_count);
526 ds_put_cstr(s, "duration:");
527 ofp_print_duration(s, ms->duration_sec, ms->duration_nsec);
528 ds_put_char(s, ' ');
529
530 ds_put_cstr(s, "bands:\n");
531 for (i = 0; i < ms->n_bands; ++i) {
532 ds_put_format(s, "%d: ", i);
533 ds_put_format(s, "packet_count:%"PRIu64" ", ms->bands[i].packet_count);
534 ds_put_format(s, "byte_count:%"PRIu64"\n", ms->bands[i].byte_count);
535 }
536}
537
538static void
539ofp_print_meter_config(struct ds *s, const struct ofputil_meter_config *mc)
540{
541 uint16_t i;
542
9e638f22
AZ
543 ofp_print_meter_id(s, mc->meter_id, '=');
544 ds_put_char(s, ' ');
638a19b0
JR
545
546 ofp_print_meter_flags(s, mc->flags);
547
548 ds_put_cstr(s, "bands=");
549 for (i = 0; i < mc->n_bands; ++i) {
550 ofp_print_meter_band(s, mc->flags, &mc->bands[i]);
551 }
552 ds_put_char(s, '\n');
553}
554
555static void
3c35db62 556ofp_print_meter_mod__(struct ds *s, const struct ofputil_meter_mod *mm)
638a19b0 557{
3c35db62 558 switch (mm->command) {
638a19b0
JR
559 case OFPMC13_ADD:
560 ds_put_cstr(s, " ADD ");
561 break;
562 case OFPMC13_MODIFY:
563 ds_put_cstr(s, " MOD ");
564 break;
565 case OFPMC13_DELETE:
566 ds_put_cstr(s, " DEL ");
567 break;
568 default:
3c35db62 569 ds_put_format(s, " cmd:%d ", mm->command);
638a19b0
JR
570 }
571
3c35db62
NR
572 ofp_print_meter_config(s, &mm->meter);
573}
574
2d071a32 575static enum ofperr
3c35db62
NR
576ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh)
577{
578 struct ofputil_meter_mod mm;
579 struct ofpbuf bands;
580 enum ofperr error;
581
582 ofpbuf_init(&bands, 64);
583 error = ofputil_decode_meter_mod(oh, &mm, &bands);
2d071a32 584 if (!error) {
3c35db62
NR
585 ofp_print_meter_mod__(s, &mm);
586 }
638a19b0 587 ofpbuf_uninit(&bands);
2d071a32
BP
588
589 return error;
638a19b0
JR
590}
591
2d071a32 592static enum ofperr
638a19b0
JR
593ofp_print_meter_stats_request(struct ds *s, const struct ofp_header *oh)
594{
595 uint32_t meter_id;
596
597 ofputil_decode_meter_request(oh, &meter_id);
9e638f22 598 ds_put_char(s, ' ');
638a19b0 599
9e638f22 600 ofp_print_meter_id(s, meter_id, '=');
2d071a32
BP
601
602 return 0;
638a19b0
JR
603}
604
605static const char *
606ofputil_meter_capabilities_to_name(uint32_t bit)
607{
608 enum ofp13_meter_flags flag = bit;
609
610 switch (flag) {
611 case OFPMF13_KBPS: return "kbps";
612 case OFPMF13_PKTPS: return "pktps";
613 case OFPMF13_BURST: return "burst";
614 case OFPMF13_STATS: return "stats";
615 }
616
617 return NULL;
618}
619
620static const char *
621ofputil_meter_band_types_to_name(uint32_t bit)
622{
638a19b0 623 switch (bit) {
6e055a6c
BP
624 case 1 << OFPMBT13_DROP: return "drop";
625 case 1 << OFPMBT13_DSCP_REMARK: return "dscp_remark";
638a19b0
JR
626 }
627
628 return NULL;
629}
630
2d071a32 631static enum ofperr
638a19b0
JR
632ofp_print_meter_features_reply(struct ds *s, const struct ofp_header *oh)
633{
634 struct ofputil_meter_features mf;
635
636 ofputil_decode_meter_features(oh, &mf);
637
638 ds_put_format(s, "\nmax_meter:%"PRIu32, mf.max_meters);
639 ds_put_format(s, " max_bands:%"PRIu8, mf.max_bands);
640 ds_put_format(s, " max_color:%"PRIu8"\n", mf.max_color);
641
642 ds_put_cstr(s, "band_types: ");
643 ofp_print_bit_names(s, mf.band_types,
644 ofputil_meter_band_types_to_name, ' ');
645 ds_put_char(s, '\n');
646
647 ds_put_cstr(s, "capabilities: ");
648 ofp_print_bit_names(s, mf.capabilities,
649 ofputil_meter_capabilities_to_name, ' ');
650 ds_put_char(s, '\n');
2d071a32
BP
651
652 return 0;
638a19b0
JR
653}
654
2d071a32 655static enum ofperr
638a19b0
JR
656ofp_print_meter_config_reply(struct ds *s, const struct ofp_header *oh)
657{
0a2869d5 658 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
638a19b0 659 struct ofpbuf bands;
2d071a32 660 int retval;
638a19b0 661
638a19b0
JR
662 ofpbuf_init(&bands, 64);
663 for (;;) {
664 struct ofputil_meter_config mc;
638a19b0
JR
665
666 retval = ofputil_decode_meter_config(&b, &mc, &bands);
667 if (retval) {
638a19b0
JR
668 break;
669 }
670 ds_put_char(s, '\n');
671 ofp_print_meter_config(s, &mc);
672 }
673 ofpbuf_uninit(&bands);
2d071a32
BP
674
675 return retval != EOF ? retval : 0;
638a19b0
JR
676}
677
2d071a32 678static enum ofperr
638a19b0
JR
679ofp_print_meter_stats_reply(struct ds *s, const struct ofp_header *oh)
680{
0a2869d5 681 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
638a19b0 682 struct ofpbuf bands;
2d071a32 683 int retval;
638a19b0 684
638a19b0
JR
685 ofpbuf_init(&bands, 64);
686 for (;;) {
687 struct ofputil_meter_stats ms;
638a19b0
JR
688
689 retval = ofputil_decode_meter_stats(&b, &ms, &bands);
690 if (retval) {
638a19b0
JR
691 break;
692 }
693 ds_put_char(s, '\n');
694 ofp_print_meter_stats(s, &ms);
695 }
696 ofpbuf_uninit(&bands);
2d071a32
BP
697
698 return retval != EOF ? retval : 0;
638a19b0
JR
699}
700
7fa91113 701static void
90bf1e07 702ofp_print_error(struct ds *string, enum ofperr error)
7fa91113 703{
90bf1e07 704 ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error));
f74be05a
JP
705}
706
2d071a32 707static enum ofperr
de6c85b0
SH
708ofp_print_hello(struct ds *string, const struct ofp_header *oh)
709{
dfc77282 710 ofputil_hello_format(string, oh);
2d071a32 711 return 0;
de6c85b0
SH
712}
713
2d071a32 714static enum ofperr
50f96b10 715ofp_print_error_msg(struct ds *string, const struct ofp_header *oh,
4bc938cc
BP
716 const struct ofputil_port_map *port_map,
717 const struct ofputil_table_map *table_map)
064af421 718{
982697a4 719 struct ofpbuf payload;
dfc77282 720 enum ofperr error = ofperr_decode_msg(oh, &payload);
90bf1e07 721 if (!error) {
2d071a32 722 return OFPERR_OFPBRC_BAD_LEN;
f74be05a 723 }
dfc77282 724 ofperr_msg_format(string, error, &payload, port_map, table_map);
dea241f1 725 ofpbuf_uninit(&payload);
2d071a32
BP
726
727 return 0;
064af421
BP
728}
729
2d071a32 730static enum ofperr
982697a4 731ofp_print_port_status(struct ds *string, const struct ofp_header *oh)
064af421 732{
9e1fd49b 733 struct ofputil_port_status ps;
dfc77282
BP
734 enum ofperr error = ofputil_decode_port_status(oh, &ps);
735 if (!error) {
736 ofputil_port_status_format(string, &ps);
064af421 737 }
dfc77282 738 return error;
064af421
BP
739}
740
2d071a32 741static enum ofperr
982697a4 742ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_header *oh)
064af421 743{
982697a4
BP
744 const struct ofp_desc_stats *ods = ofpmsg_body(oh);
745
fbd76b2e 746 ds_put_char(string, '\n');
d295e8e9 747 ds_put_format(string, "Manufacturer: %.*s\n",
dd70b475
JP
748 (int) sizeof ods->mfr_desc, ods->mfr_desc);
749 ds_put_format(string, "Hardware: %.*s\n",
750 (int) sizeof ods->hw_desc, ods->hw_desc);
751 ds_put_format(string, "Software: %.*s\n",
752 (int) sizeof ods->sw_desc, ods->sw_desc);
753 ds_put_format(string, "Serial Num: %.*s\n",
754 (int) sizeof ods->serial_num, ods->serial_num);
755 ds_put_format(string, "DP Description: %.*s\n",
756 (int) sizeof ods->dp_desc, ods->dp_desc);
2d071a32
BP
757
758 return 0;
064af421
BP
759}
760
2d071a32 761static enum ofperr
50f96b10 762ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh,
4bc938cc
BP
763 const struct ofputil_port_map *port_map,
764 const struct ofputil_table_map *table_map)
064af421 765{
81d1ea94 766 struct ofputil_flow_stats_request fsr;
dfc77282
BP
767 enum ofperr error = ofputil_decode_flow_stats_request(&fsr, oh, NULL,
768 NULL);
769 if (!error) {
770 ofputil_flow_stats_request_format(string, &fsr, port_map, table_map);
bdcc5925 771 }
dfc77282 772 return error;
bdcc5925
BP
773}
774
2d071a32 775static enum ofperr
50f96b10 776ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh,
4bc938cc
BP
777 const struct ofputil_port_map *port_map,
778 const struct ofputil_table_map *table_map)
064af421 779{
0a2869d5 780 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
f25d0cf3 781 struct ofpbuf ofpacts;
2d071a32 782 int retval;
064af421 783
f25d0cf3 784 ofpbuf_init(&ofpacts, 64);
4ffd1b43
BP
785 for (;;) {
786 struct ofputil_flow_stats fs;
fab8fadb 787
f25d0cf3 788 retval = ofputil_decode_flow_stats_reply(&fs, &b, true, &ofpacts);
4ffd1b43 789 if (retval) {
064af421
BP
790 break;
791 }
1b3758c3 792 ds_put_cstr(string, "\n ");
dfc77282 793 ofputil_flow_stats_format(string, &fs, port_map, table_map, true);
bdcc5925 794 }
cb80d803 795 ofpbuf_uninit(&ofpacts);
2d071a32
BP
796
797 return retval != EOF ? retval : 0;
c6430da5
BP
798}
799
2d071a32 800static enum ofperr
982697a4 801ofp_print_aggregate_stats_reply(struct ds *string, const struct ofp_header *oh)
064af421 802{
982697a4
BP
803 struct ofputil_aggregate_stats as;
804 enum ofperr error;
064af421 805
982697a4 806 error = ofputil_decode_aggregate_stats_reply(&as, oh);
dfc77282
BP
807 if (!error) {
808 ofputil_aggregate_stats_format(string, &as);
982697a4 809 }
dfc77282 810 return error;
a2ad9ecd
BP
811}
812
f8e4867e
SH
813static void
814print_port_stat(struct ds *string, const char *leader, uint64_t stat, int more)
064af421
BP
815{
816 ds_put_cstr(string, leader);
c4617b3c 817 if (stat != UINT64_MAX) {
064af421
BP
818 ds_put_format(string, "%"PRIu64, stat);
819 } else {
820 ds_put_char(string, '?');
821 }
822 if (more) {
823 ds_put_cstr(string, ", ");
824 } else {
825 ds_put_cstr(string, "\n");
826 }
827}
828
d6e3feb5 829static void
830print_port_stat_cond(struct ds *string, const char *leader, uint64_t stat)
831{
832 if (stat != UINT64_MAX) {
833 ds_put_format(string, "%s%"PRIu64", ", leader, stat);
834 }
835}
836
2d071a32 837static enum ofperr
50f96b10
BP
838ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh,
839 const struct ofputil_port_map *port_map)
abaad8cf 840{
4e022ec0 841 ofp_port_t ofp10_port;
f8e4867e
SH
842 enum ofperr error;
843
844 error = ofputil_decode_port_stats_request(oh, &ofp10_port);
845 if (error) {
2d071a32 846 return error;
f8e4867e
SH
847 }
848
e1db42d6 849 ds_put_cstr(string, " port_no=");
50f96b10 850 ofputil_format_port(ofp10_port, port_map, string);
2d071a32
BP
851
852 return 0;
abaad8cf
JP
853}
854
2d071a32 855static enum ofperr
d1e2cf21 856ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
50f96b10 857 const struct ofputil_port_map *port_map,
d1e2cf21 858 int verbosity)
064af421 859{
971f4b39 860 uint32_t i;
34582733 861 ds_put_format(string, " %"PRIuSIZE" ports\n", ofputil_count_port_stats(oh));
064af421 862 if (verbosity < 1) {
2d071a32 863 return 0;
064af421
BP
864 }
865
0a2869d5 866 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
982697a4 867 for (;;) {
f8e4867e
SH
868 struct ofputil_port_stats ps;
869 int retval;
870
871 retval = ofputil_decode_port_stats(&ps, &b);
872 if (retval) {
2d071a32 873 return retval != EOF ? retval : 0;
982697a4
BP
874 }
875
e1db42d6 876 ds_put_cstr(string, " port ");
4e022ec0 877 if (ofp_to_u16(ps.port_no) < 10) {
e1db42d6
JR
878 ds_put_char(string, ' ');
879 }
50f96b10 880 ofputil_format_port(ps.port_no, port_map, string);
064af421 881
f8e4867e
SH
882 ds_put_cstr(string, ": rx ");
883 print_port_stat(string, "pkts=", ps.stats.rx_packets, 1);
884 print_port_stat(string, "bytes=", ps.stats.rx_bytes, 1);
885 print_port_stat(string, "drop=", ps.stats.rx_dropped, 1);
886 print_port_stat(string, "errs=", ps.stats.rx_errors, 1);
887 print_port_stat(string, "frame=", ps.stats.rx_frame_errors, 1);
888 print_port_stat(string, "over=", ps.stats.rx_over_errors, 1);
889 print_port_stat(string, "crc=", ps.stats.rx_crc_errors, 0);
064af421
BP
890
891 ds_put_cstr(string, " tx ");
f8e4867e
SH
892 print_port_stat(string, "pkts=", ps.stats.tx_packets, 1);
893 print_port_stat(string, "bytes=", ps.stats.tx_bytes, 1);
894 print_port_stat(string, "drop=", ps.stats.tx_dropped, 1);
895 print_port_stat(string, "errs=", ps.stats.tx_errors, 1);
896 print_port_stat(string, "coll=", ps.stats.collisions, 0);
65e0be10
BP
897
898 if (ps.duration_sec != UINT32_MAX) {
899 ds_put_cstr(string, " duration=");
900 ofp_print_duration(string, ps.duration_sec, ps.duration_nsec);
901 ds_put_char(string, '\n');
902 }
d6e3feb5 903 struct ds string_ext_stats = DS_EMPTY_INITIALIZER;
904
905 ds_init(&string_ext_stats);
906
907 print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
908 ps.stats.rx_1_to_64_packets);
909 print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
910 ps.stats.rx_65_to_127_packets);
911 print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
912 ps.stats.rx_128_to_255_packets);
913 print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
914 ps.stats.rx_256_to_511_packets);
915 print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
916 ps.stats.rx_512_to_1023_packets);
917 print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
918 ps.stats.rx_1024_to_1522_packets);
919 print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
920 ps.stats.rx_1523_to_max_packets);
921 print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
922 ps.stats.rx_broadcast_packets);
923 print_port_stat_cond(&string_ext_stats, "undersized_errors=",
924 ps.stats.rx_undersized_errors);
925 print_port_stat_cond(&string_ext_stats, "oversize_errors=",
926 ps.stats.rx_oversize_errors);
927 print_port_stat_cond(&string_ext_stats, "rx_fragmented_errors=",
928 ps.stats.rx_fragmented_errors);
929 print_port_stat_cond(&string_ext_stats, "rx_jabber_errors=",
930 ps.stats.rx_jabber_errors);
931
932 if (string_ext_stats.length != 0) {
933 /* If at least one statistics counter is reported: */
934 ds_put_cstr(string, " rx rfc2819 ");
935 ds_put_buffer(string, string_ext_stats.string,
936 string_ext_stats.length);
937 ds_put_cstr(string, "\n");
938 ds_destroy(&string_ext_stats);
939 }
940
941 ds_init(&string_ext_stats);
942
943 print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
944 ps.stats.tx_1_to_64_packets);
945 print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
946 ps.stats.tx_65_to_127_packets);
947 print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
948 ps.stats.tx_128_to_255_packets);
949 print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
950 ps.stats.tx_256_to_511_packets);
951 print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
952 ps.stats.tx_512_to_1023_packets);
953 print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
954 ps.stats.tx_1024_to_1522_packets);
955 print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
956 ps.stats.tx_1523_to_max_packets);
957 print_port_stat_cond(&string_ext_stats, "multicast_packets=",
958 ps.stats.tx_multicast_packets);
959 print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
960 ps.stats.tx_broadcast_packets);
961
962 if (string_ext_stats.length != 0) {
963 /* If at least one statistics counter is reported: */
964 ds_put_cstr(string, " tx rfc2819 ");
965 ds_put_buffer(string, string_ext_stats.string,
966 string_ext_stats.length);
967 ds_put_cstr(string, "\n");
968 ds_destroy(&string_ext_stats);
969 }
971f4b39
MW
970
971 if (ps.custom_stats.size) {
972 ds_put_cstr(string, " CUSTOM Statistics");
973 for (i = 0; i < ps.custom_stats.size; i++) {
974 /* 3 counters in the row */
975 if (ps.custom_stats.counters[i].name[0]) {
976 if (i % 3 == 0) {
977 ds_put_cstr(string, "\n");
978 ds_put_cstr(string, " ");
979 } else {
980 ds_put_char(string, ' ');
981 }
982 ds_put_format(string, "%s=%"PRIu64",",
983 ps.custom_stats.counters[i].name,
984 ps.custom_stats.counters[i].value);
985 }
986 }
987 ds_put_cstr(string, "\n");
988 }
064af421
BP
989 }
990}
991
2d071a32 992static enum ofperr
4bc938cc
BP
993ofp_print_table_stats_reply(struct ds *string, const struct ofp_header *oh,
994 const struct ofputil_table_map *table_map)
26df8b3e 995{
0a2869d5 996 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
26df8b3e
SH
997 ofpraw_pull_assert(&b);
998
8811fc0a
BP
999 struct ofputil_table_features prev_features;
1000 struct ofputil_table_stats prev_stats;
1001 for (int i = 0;; i++) {
3c1bb396
BP
1002 struct ofputil_table_features features;
1003 struct ofputil_table_stats stats;
1004 int retval;
982697a4 1005
3c1bb396
BP
1006 retval = ofputil_decode_table_stats_reply(&b, &stats, &features);
1007 if (retval) {
2d071a32 1008 return retval != EOF ? retval : 0;
982697a4
BP
1009 }
1010
8811fc0a 1011 ds_put_char(string, '\n');
dfc77282
BP
1012 ofputil_table_features_format(string,
1013 &features, i ? &prev_features : NULL,
1014 &stats, i ? &prev_stats : NULL,
1015 table_map);
8811fc0a
BP
1016 prev_features = features;
1017 prev_stats = stats;
26df8b3e
SH
1018 }
1019}
1020
d2805da2
BP
1021static void
1022ofp_print_queue_name(struct ds *string, uint32_t queue_id)
1023{
1024 if (queue_id == OFPQ_ALL) {
1025 ds_put_cstr(string, "ALL");
1026 } else {
1027 ds_put_format(string, "%"PRIu32, queue_id);
1028 }
1029}
1030
2d071a32 1031static enum ofperr
50f96b10
BP
1032ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_header *oh,
1033 const struct ofputil_port_map *port_map)
d2805da2 1034{
64626975
SH
1035 struct ofputil_queue_stats_request oqsr;
1036 enum ofperr error;
1037
1038 error = ofputil_decode_queue_stats_request(oh, &oqsr);
1039 if (error) {
2d071a32 1040 return error;
64626975 1041 }
982697a4 1042
3e461c2c 1043 ds_put_cstr(string, " port=");
50f96b10 1044 ofputil_format_port(oqsr.port_no, port_map, string);
d2805da2
BP
1045
1046 ds_put_cstr(string, " queue=");
64626975 1047 ofp_print_queue_name(string, oqsr.queue_id);
2d071a32
BP
1048
1049 return 0;
f8e4867e
SH
1050}
1051
2d071a32 1052static enum ofperr
d1e2cf21 1053ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
50f96b10 1054 const struct ofputil_port_map *port_map,
d1e2cf21 1055 int verbosity)
d2805da2 1056{
34582733 1057 ds_put_format(string, " %"PRIuSIZE" queues\n", ofputil_count_queue_stats(oh));
d2805da2 1058 if (verbosity < 1) {
2d071a32 1059 return 0;
d2805da2
BP
1060 }
1061
0a2869d5 1062 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
982697a4 1063 for (;;) {
64626975
SH
1064 struct ofputil_queue_stats qs;
1065 int retval;
1066
1067 retval = ofputil_decode_queue_stats(&qs, &b);
1068 if (retval) {
2d071a32 1069 return retval != EOF ? retval : 0;
982697a4
BP
1070 }
1071
d2805da2 1072 ds_put_cstr(string, " port ");
50f96b10 1073 ofputil_format_port(qs.port_no, port_map, string);
d2805da2 1074 ds_put_cstr(string, " queue ");
64626975 1075 ofp_print_queue_name(string, qs.queue_id);
d2805da2
BP
1076 ds_put_cstr(string, ": ");
1077
6dc34a0d
BP
1078 print_port_stat(string, "bytes=", qs.tx_bytes, 1);
1079 print_port_stat(string, "pkts=", qs.tx_packets, 1);
1080 print_port_stat(string, "errors=", qs.tx_errors, 1);
1081
1082 ds_put_cstr(string, "duration=");
1083 if (qs.duration_sec != UINT32_MAX) {
1084 ofp_print_duration(string, qs.duration_sec, qs.duration_nsec);
1085 } else {
1086 ds_put_char(string, '?');
1087 }
1088 ds_put_char(string, '\n');
d2805da2
BP
1089 }
1090}
1091
2d071a32 1092static enum ofperr
70ae4f93 1093ofp_print_ofpst_port_desc_request(struct ds *string,
50f96b10
BP
1094 const struct ofp_header *oh,
1095 const struct ofputil_port_map *port_map)
70ae4f93
BP
1096{
1097 enum ofperr error;
1098 ofp_port_t port;
1099
1100 error = ofputil_decode_port_desc_stats_request(oh, &port);
1101 if (error) {
2d071a32 1102 return error;
70ae4f93
BP
1103 }
1104
1105 ds_put_cstr(string, " port=");
50f96b10 1106 ofputil_format_port(port, port_map, string);
2d071a32
BP
1107
1108 return 0;
70ae4f93
BP
1109}
1110
2d071a32 1111static enum ofperr
2be393ed
JP
1112ofp_print_ofpst_port_desc_reply(struct ds *string,
1113 const struct ofp_header *oh)
1114{
0a2869d5 1115 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
982697a4 1116 ofpraw_pull_assert(&b);
2be393ed 1117 ds_put_char(string, '\n');
dfc77282 1118 return ofputil_phy_ports_format(string, oh->version, &b);
2be393ed
JP
1119}
1120
064af421 1121static void
5d40fc57 1122ofp_print_stats(struct ds *string, const struct ofp_header *oh)
064af421 1123{
982697a4 1124 uint16_t flags = ofpmp_flags(oh);
d1e2cf21 1125
982697a4 1126 if (flags) {
d1e2cf21 1127 ds_put_cstr(string, " flags=");
5d40fc57
SH
1128 if ((!ofpmsg_is_stat_request(oh) || oh->version >= OFP13_VERSION)
1129 && (flags & OFPSF_REPLY_MORE)) {
064af421
BP
1130 ds_put_cstr(string, "[more]");
1131 flags &= ~OFPSF_REPLY_MORE;
1132 }
1133 if (flags) {
d1e2cf21
BP
1134 ds_put_format(string, "[***unknown flags 0x%04"PRIx16"***]",
1135 flags);
064af421
BP
1136 }
1137 }
064af421
BP
1138}
1139
2d071a32 1140static enum ofperr
d1e2cf21 1141ofp_print_echo(struct ds *string, const struct ofp_header *oh, int verbosity)
064af421 1142{
d1e2cf21 1143 size_t len = ntohs(oh->length);
064af421 1144
34582733 1145 ds_put_format(string, " %"PRIuSIZE" bytes of payload\n", len - sizeof *oh);
064af421 1146 if (verbosity > 1) {
d1e2cf21 1147 ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true);
064af421 1148 }
2d071a32
BP
1149
1150 return 0;
064af421
BP
1151}
1152
61fe3a7b 1153static void
00467f73
AC
1154ofp_print_role_generic(struct ds *string, enum ofp12_controller_role role,
1155 uint64_t generation_id)
61fe3a7b 1156{
61fe3a7b 1157 ds_put_cstr(string, " role=");
6ea4776b 1158
00467f73 1159 switch (role) {
f4f1ea7e
BP
1160 case OFPCR12_ROLE_NOCHANGE:
1161 ds_put_cstr(string, "nochange");
1162 break;
1163 case OFPCR12_ROLE_EQUAL:
6ea4776b
JR
1164 ds_put_cstr(string, "equal"); /* OF 1.2 wording */
1165 break;
f4f1ea7e 1166 case OFPCR12_ROLE_MASTER:
61fe3a7b 1167 ds_put_cstr(string, "master");
6ea4776b 1168 break;
f4f1ea7e 1169 case OFPCR12_ROLE_SLAVE:
61fe3a7b 1170 ds_put_cstr(string, "slave");
6ea4776b
JR
1171 break;
1172 default:
428b2edd 1173 OVS_NOT_REACHED();
6ea4776b
JR
1174 }
1175
00467f73
AC
1176 if (generation_id != UINT64_MAX) {
1177 ds_put_format(string, " generation_id=%"PRIu64, generation_id);
1178 }
1179}
1180
2d071a32 1181static enum ofperr
00467f73
AC
1182ofp_print_role_message(struct ds *string, const struct ofp_header *oh)
1183{
1184 struct ofputil_role_request rr;
1185 enum ofperr error;
1186
1187 error = ofputil_decode_role_message(oh, &rr);
1188 if (error) {
2d071a32 1189 return error;
00467f73
AC
1190 }
1191
1192 ofp_print_role_generic(string, rr.role, rr.have_generation_id ? rr.generation_id : UINT64_MAX);
2d071a32
BP
1193
1194 return 0;
00467f73
AC
1195}
1196
2d071a32 1197static enum ofperr
00467f73
AC
1198ofp_print_role_status_message(struct ds *string, const struct ofp_header *oh)
1199{
1200 struct ofputil_role_status rs;
1201 enum ofperr error;
1202
1203 error = ofputil_decode_role_status(oh, &rs);
1204 if (error) {
2d071a32 1205 return error;
00467f73
AC
1206 }
1207
1208 ofp_print_role_generic(string, rs.role, rs.generation_id);
1209
1210 ds_put_cstr(string, " reason=");
1211
1212 switch (rs.reason) {
1213 case OFPCRR_MASTER_REQUEST:
1214 ds_put_cstr(string, "master_request");
1215 break;
1216 case OFPCRR_CONFIG:
1217 ds_put_cstr(string, "configuration_changed");
1218 break;
1219 case OFPCRR_EXPERIMENTER:
1220 ds_put_cstr(string, "experimenter_data_changed");
1221 break;
d18cc1ee 1222 case OFPCRR_N_REASONS:
00467f73 1223 default:
b76d4a81
BP
1224 ds_put_cstr(string, "(unknown)");
1225 break;
61fe3a7b 1226 }
2d071a32
BP
1227
1228 return 0;
61fe3a7b
BP
1229}
1230
2d071a32 1231static enum ofperr
225c33ba 1232ofp_print_nxt_flow_mod_table_id(struct ds *string, const struct ofp_header *oh)
6c1491fb 1233{
225c33ba
BP
1234 bool enable = ofputil_decode_nx_flow_mod_table_id(oh);
1235 ds_put_format(string, " %s", enable ? "enable" : "disable");
2d071a32 1236 return 0;
6c1491fb
BP
1237}
1238
2d071a32 1239static enum ofperr
225c33ba 1240ofp_print_nxt_set_flow_format(struct ds *string, const struct ofp_header *oh)
7fa91113 1241{
225c33ba
BP
1242 enum ofputil_protocol p = ofputil_decode_nx_set_flow_format(oh);
1243 ds_put_format(string, " format=%s",
1244 p == OFPUTIL_P_OF10_STD ? "openflow10"
1245 : p == OFPUTIL_P_OF10_NXM ? "nxm"
1246 : "(unknown)");
2d071a32 1247 return 0;
7fa91113
BP
1248}
1249
2d071a32 1250static enum ofperr
54834960 1251ofp_print_nxt_set_packet_in_format(struct ds *string,
d8790c08 1252 const struct ofp_header *oh)
54834960 1253{
d8790c08
BP
1254 enum ofputil_packet_in_format format;
1255 enum ofperr error = ofputil_decode_set_packet_in_format(oh, &format);
1256 if (!error) {
1257 ds_put_format(string, " format=%s",
1258 ofputil_packet_in_format_to_string(format));
54834960 1259 }
d8790c08 1260 return error;
54834960
EJ
1261}
1262
8961699e
BP
1263/* Returns a string form of 'reason'. The return value is either a statically
1264 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
1265 * 'bufsize' should be at least OFP_PORT_REASON_BUFSIZE. */
1266#define OFP_PORT_REASON_BUFSIZE (INT_STRLEN(int) + 1)
80d5aefd 1267static const char *
8961699e
BP
1268ofp_port_reason_to_string(enum ofp_port_reason reason,
1269 char *reasonbuf, size_t bufsize)
80d5aefd 1270{
80d5aefd
BP
1271 switch (reason) {
1272 case OFPPR_ADD:
1273 return "add";
1274
1275 case OFPPR_DELETE:
1276 return "delete";
1277
1278 case OFPPR_MODIFY:
1279 return "modify";
1280
d18cc1ee 1281 case OFPPR_N_REASONS:
80d5aefd 1282 default:
8961699e
BP
1283 snprintf(reasonbuf, bufsize, "%d", (int) reason);
1284 return reasonbuf;
80d5aefd
BP
1285 }
1286}
1287
98090482
NR
1288/* Returns a string form of 'reason'. The return value is either a statically
1289 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
1290 * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
1291static const char*
1292ofp_role_reason_to_string(enum ofp14_controller_role_reason reason,
1293 char *reasonbuf, size_t bufsize)
1294{
1295 switch (reason) {
1296 case OFPCRR_MASTER_REQUEST:
1297 return "master_request";
1298
1299 case OFPCRR_CONFIG:
1300 return "configuration_changed";
1301
1302 case OFPCRR_EXPERIMENTER:
1303 return "experimenter_data_changed";
1304
d18cc1ee 1305 case OFPCRR_N_REASONS:
98090482
NR
1306 default:
1307 snprintf(reasonbuf, bufsize, "%d", (int) reason);
1308 return reasonbuf;
1309 }
1310}
1311
1312/* Returns a string form of 'reason'. The return value is either a statically
1313 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
1314 * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
1315static const char*
1316ofp_table_reason_to_string(enum ofp14_table_reason reason,
1317 char *reasonbuf, size_t bufsize)
1318{
1319 switch (reason) {
1320 case OFPTR_VACANCY_DOWN:
1321 return "vacancy_down";
1322
1323 case OFPTR_VACANCY_UP:
1324 return "vacancy_up";
1325
1326 default:
1327 snprintf(reasonbuf, bufsize, "%d", (int) reason);
1328 return reasonbuf;
1329 }
1330}
1331
1332/* Returns a string form of 'reason'. The return value is either a statically
1333 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
1334 * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
1335static const char*
1336ofp_requestforward_reason_to_string(enum ofp14_requestforward_reason reason,
1337 char *reasonbuf, size_t bufsize)
1338{
1339 switch (reason) {
1340 case OFPRFR_GROUP_MOD:
1341 return "group_mod_request";
1342
1343 case OFPRFR_METER_MOD:
1344 return "meter_mod_request";
1345
d18cc1ee 1346 case OFPRFR_N_REASONS:
98090482
NR
1347 default:
1348 snprintf(reasonbuf, bufsize, "%d", (int) reason);
1349 return reasonbuf;
1350 }
1351}
1352
1353static const char *
1354ofp_async_config_reason_to_string(uint32_t reason,
1355 enum ofputil_async_msg_type type,
1356 char *reasonbuf, size_t bufsize)
1357{
1358 switch (type) {
1359 case OAM_PACKET_IN:
1360 return ofputil_packet_in_reason_to_string(reason, reasonbuf, bufsize);
1361
1362 case OAM_PORT_STATUS:
1363 return ofp_port_reason_to_string(reason, reasonbuf, bufsize);
1364
1365 case OAM_FLOW_REMOVED:
1366 return ofp_flow_removed_reason_to_string(reason, reasonbuf, bufsize);
1367
1368 case OAM_ROLE_STATUS:
1369 return ofp_role_reason_to_string(reason, reasonbuf, bufsize);
1370
1371 case OAM_TABLE_STATUS:
1372 return ofp_table_reason_to_string(reason, reasonbuf, bufsize);
1373
1374 case OAM_REQUESTFORWARD:
1375 return ofp_requestforward_reason_to_string(reason, reasonbuf, bufsize);
1376
1377 case OAM_N_TYPES:
1378 default:
1379 return "Unknown asynchronous configuration message type";
1380 }
1381}
1382
1383
1384#define OFP_ASYNC_CONFIG_REASON_BUFSIZE (INT_STRLEN(int) + 1)
2d071a32 1385static enum ofperr
904e5202 1386ofp_print_set_async_config(struct ds *string, const struct ofp_header *oh,
71f21279 1387 enum ofptype ofptype)
80d5aefd 1388{
904e5202
BP
1389 struct ofputil_async_cfg basis = OFPUTIL_ASYNC_CFG_INIT;
1390 struct ofputil_async_cfg ac;
80d5aefd 1391
71f21279 1392 bool is_reply = ofptype == OFPTYPE_GET_ASYNC_REPLY;
904e5202
BP
1393 enum ofperr error = ofputil_decode_set_async_config(oh, is_reply,
1394 &basis, &ac);
1395 if (error) {
2d071a32 1396 return error;
904e5202 1397 }
8961699e 1398
904e5202
BP
1399 for (int i = 0; i < 2; i++) {
1400 ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave");
1401 for (uint32_t type = 0; type < OAM_N_TYPES; type++) {
1402 ds_put_format(string, "%16s:",
1403 ofputil_async_msg_type_to_string(type));
80d5aefd 1404
904e5202
BP
1405 uint32_t role = i == 0 ? ac.master[type] : ac.slave[type];
1406 for (int j = 0; j < 32; j++) {
1407 if (role & (1u << j)) {
1408 char reasonbuf[OFP_ASYNC_CONFIG_REASON_BUFSIZE];
98090482 1409 const char *reason;
8961699e 1410
904e5202
BP
1411 reason = ofp_async_config_reason_to_string(
1412 j, type, reasonbuf, sizeof reasonbuf);
9bfe9334
BP
1413 if (reason[0]) {
1414 ds_put_format(string, " %s", reason);
1415 }
98090482 1416 }
80d5aefd 1417 }
904e5202 1418 if (!role) {
98090482
NR
1419 ds_put_cstr(string, " (off)");
1420 }
1421 ds_put_char(string, '\n');
80d5aefd 1422 }
80d5aefd 1423 }
2d071a32
BP
1424
1425 return 0;
80d5aefd
BP
1426}
1427
2d071a32 1428static enum ofperr
a7349929
BP
1429ofp_print_nxt_set_controller_id(struct ds *string,
1430 const struct nx_controller_id *nci)
1431{
1432 ds_put_format(string, " id=%"PRIu16, ntohs(nci->controller_id));
2d071a32 1433 return 0;
a7349929
BP
1434}
1435
2d071a32 1436static enum ofperr
2b07c8b1
BP
1437ofp_print_nxt_flow_monitor_cancel(struct ds *string,
1438 const struct ofp_header *oh)
1439{
1440 ds_put_format(string, " id=%"PRIu32,
1441 ofputil_decode_flow_monitor_cancel(oh));
2d071a32 1442 return 0;
2b07c8b1
BP
1443}
1444
2d071a32 1445static enum ofperr
2b07c8b1 1446ofp_print_nxst_flow_monitor_request(struct ds *string,
50f96b10 1447 const struct ofp_header *oh,
4bc938cc
BP
1448 const struct ofputil_port_map *port_map,
1449 const struct ofputil_table_map *table_map)
2b07c8b1 1450{
0a2869d5 1451 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
2b07c8b1
BP
1452 for (;;) {
1453 struct ofputil_flow_monitor_request request;
1454 int retval;
1455
1456 retval = ofputil_decode_flow_monitor_request(&request, &b);
1457 if (retval) {
2d071a32 1458 return retval != EOF ? retval : 0;
2b07c8b1
BP
1459 }
1460
dfc77282
BP
1461 ofputil_flow_monitor_request_format(string, &request,
1462 port_map, table_map);
2b07c8b1
BP
1463 }
1464}
1465
2d071a32 1466static enum ofperr
2b07c8b1 1467ofp_print_nxst_flow_monitor_reply(struct ds *string,
50f96b10 1468 const struct ofp_header *oh,
4bc938cc
BP
1469 const struct ofputil_port_map *port_map,
1470 const struct ofputil_table_map *table_map)
2b07c8b1
BP
1471{
1472 uint64_t ofpacts_stub[1024 / 8];
0a2869d5
BP
1473 struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
1474 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
2b07c8b1 1475
2b07c8b1
BP
1476 for (;;) {
1477 struct ofputil_flow_update update;
dfc77282 1478 int retval = ofputil_decode_flow_update(&update, &b, &ofpacts);
2b07c8b1 1479 if (retval) {
2b07c8b1 1480 ofpbuf_uninit(&ofpacts);
2d071a32 1481 return retval != EOF ? retval : 0;
2b07c8b1 1482 }
dfc77282 1483 ofputil_flow_update_format(string, &update, port_map, table_map);
2b07c8b1
BP
1484 }
1485}
1486
bdcc5925
BP
1487void
1488ofp_print_version(const struct ofp_header *oh,
1489 struct ds *string)
d1e2cf21 1490{
3811e66b
BP
1491 switch (oh->version) {
1492 case OFP10_VERSION:
1493 break;
1494 case OFP11_VERSION:
1495 ds_put_cstr(string, " (OF1.1)");
4232ef77
SH
1496 break;
1497 case OFP12_VERSION:
1498 ds_put_cstr(string, " (OF1.2)");
3811e66b 1499 break;
2e1ae200
JR
1500 case OFP13_VERSION:
1501 ds_put_cstr(string, " (OF1.3)");
1502 break;
9620f50c
AC
1503 case OFP14_VERSION:
1504 ds_put_cstr(string, " (OF1.4)");
1505 break;
42dccab5
BP
1506 case OFP15_VERSION:
1507 ds_put_cstr(string, " (OF1.5)");
1508 break;
b79d45a1
BP
1509 case OFP16_VERSION:
1510 ds_put_cstr(string, " (OF1.6)");
1511 break;
3811e66b
BP
1512 default:
1513 ds_put_format(string, " (OF 0x%02"PRIx8")", oh->version);
1514 break;
1515 }
1516 ds_put_format(string, " (xid=0x%"PRIx32"):", ntohl(oh->xid));
bdcc5925 1517}
d1e2cf21 1518
f25b4a81 1519static void
982697a4
BP
1520ofp_header_to_string__(const struct ofp_header *oh, enum ofpraw raw,
1521 struct ds *string)
f25b4a81 1522{
982697a4 1523 ds_put_cstr(string, ofpraw_get_name(raw));
f25b4a81
BP
1524 ofp_print_version(oh, string);
1525}
1526
1c4c05af 1527static void
76c41209 1528ofp_print_bucket_id(struct ds *s, const char *label, uint32_t bucket_id,
1c4c05af
SH
1529 enum ofp_version ofp_version)
1530{
7b809df9 1531 if (ofp_version > OFP10_VERSION && ofp_version < OFP15_VERSION) {
1c4c05af
SH
1532 return;
1533 }
1534
76c41209 1535 ds_put_cstr(s, label);
1c4c05af
SH
1536
1537 switch (bucket_id) {
1538 case OFPG15_BUCKET_FIRST:
1539 ds_put_cstr(s, "first");
1540 break;
1541 case OFPG15_BUCKET_LAST:
1542 ds_put_cstr(s, "last");
1543 break;
1544 case OFPG15_BUCKET_ALL:
1545 ds_put_cstr(s, "all");
1546 break;
1547 default:
1548 ds_put_format(s, "%"PRIu32, bucket_id);
1549 break;
1550 }
1551
1552 ds_put_char(s, ',');
1553}
1554
7395c052
NZ
1555static void
1556ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type,
3c35db62
NR
1557 const struct ovs_list *p_buckets,
1558 const struct ofputil_group_props *props,
50f96b10 1559 enum ofp_version ofp_version, bool suppress_type,
4bc938cc
BP
1560 const struct ofputil_port_map *port_map,
1561 const struct ofputil_table_map *table_map)
7395c052 1562{
7395c052
NZ
1563 struct ofputil_bucket *bucket;
1564
76c41209
SH
1565 ds_put_format(s, "group_id=%"PRIu32, group_id);
1566
1567 if (!suppress_type) {
1568 static const char *type_str[] = { "all", "select", "indirect",
1569 "ff", "unknown" };
1570 ds_put_format(s, ",type=%s", type_str[type > 4 ? 4 : type]);
1571 }
1572
53eb84a5 1573 if (props->selection_method[0]) {
68dfc25b 1574 ds_put_format(s, ",selection_method=%s", props->selection_method);
53eb84a5 1575 if (props->selection_method_param) {
68dfc25b 1576 ds_put_format(s, ",selection_method_param=%"PRIu64,
53eb84a5
SH
1577 props->selection_method_param);
1578 }
1579
68dfc25b
BP
1580 size_t n = bitmap_count1(props->fields.used.bm, MFF_N_IDS);
1581 if (n == 1) {
1582 ds_put_cstr(s, ",fields=");
1583 oxm_format_field_array(s, &props->fields);
1584 } else if (n > 1) {
1585 ds_put_cstr(s, ",fields(");
1586 oxm_format_field_array(s, &props->fields);
1587 ds_put_char(s, ')');
53eb84a5
SH
1588 }
1589 }
1590
7395c052
NZ
1591 if (!p_buckets) {
1592 return;
1593 }
1594
76c41209
SH
1595 ds_put_char(s, ',');
1596
7395c052 1597 LIST_FOR_EACH (bucket, list_node, p_buckets) {
76c41209 1598 ds_put_cstr(s, "bucket=");
7395c052 1599
76c41209 1600 ofp_print_bucket_id(s, "bucket_id:", bucket->bucket_id, ofp_version);
64e8c446 1601 if (bucket->weight != (type == OFPGT11_SELECT ? 1 : 0)) {
7395c052
NZ
1602 ds_put_format(s, "weight:%"PRIu16",", bucket->weight);
1603 }
1604 if (bucket->watch_port != OFPP_NONE) {
50f96b10
BP
1605 ds_put_cstr(s, "watch_port:");
1606 ofputil_format_port(bucket->watch_port, port_map, s);
1607 ds_put_char(s, ',');
7395c052 1608 }
30ef36c6 1609 if (bucket->watch_group != OFPG_ANY) {
7395c052
NZ
1610 ds_put_format(s, "watch_group:%"PRIu32",", bucket->watch_group);
1611 }
1612
455ecd77 1613 ds_put_cstr(s, "actions=");
efefbcae
BP
1614 struct ofpact_format_params fp = {
1615 .port_map = port_map,
4bc938cc 1616 .table_map = table_map,
efefbcae
BP
1617 .s = s,
1618 };
1619 ofpacts_format(bucket->ofpacts, bucket->ofpacts_len, &fp);
76c41209 1620 ds_put_char(s, ',');
7395c052 1621 }
76c41209
SH
1622
1623 ds_chomp(s, ',');
7395c052
NZ
1624}
1625
2d071a32 1626static enum ofperr
19187a71
BP
1627ofp_print_ofpst_group_desc_request(struct ds *string,
1628 const struct ofp_header *oh)
1629{
1630 uint32_t group_id = ofputil_decode_group_desc_request(oh);
1631 ds_put_cstr(string, " group_id=");
1632 ofputil_format_group(group_id, string);
2d071a32
BP
1633
1634 return 0;
19187a71
BP
1635}
1636
2d071a32 1637static enum ofperr
50f96b10 1638ofp_print_group_desc(struct ds *s, const struct ofp_header *oh,
4bc938cc
BP
1639 const struct ofputil_port_map *port_map,
1640 const struct ofputil_table_map *table_map)
7395c052 1641{
0a2869d5 1642 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
7395c052
NZ
1643 for (;;) {
1644 struct ofputil_group_desc gd;
1645 int retval;
1646
a7a2d006 1647 retval = ofputil_decode_group_desc_reply(&gd, &b, oh->version);
7395c052 1648 if (retval) {
2d071a32 1649 return retval != EOF ? retval : 0;
7395c052
NZ
1650 }
1651
1652 ds_put_char(s, '\n');
1653 ds_put_char(s, ' ');
53eb84a5 1654 ofp_print_group(s, gd.group_id, gd.type, &gd.buckets, &gd.props,
4bc938cc 1655 oh->version, false, port_map, table_map);
75868d0e 1656 ofputil_uninit_group_desc(&gd);
7395c052
NZ
1657 }
1658}
1659
2d071a32 1660static enum ofperr
7395c052
NZ
1661ofp_print_ofpst_group_request(struct ds *string, const struct ofp_header *oh)
1662{
1663 enum ofperr error;
1664 uint32_t group_id;
1665
1666 error = ofputil_decode_group_stats_request(oh, &group_id);
1667 if (error) {
2d071a32 1668 return error;
7395c052
NZ
1669 }
1670
1671 ds_put_cstr(string, " group_id=");
1672 ofputil_format_group(group_id, string);
2d071a32 1673 return 0;
7395c052
NZ
1674}
1675
2d071a32 1676static enum ofperr
7395c052
NZ
1677ofp_print_group_stats(struct ds *s, const struct ofp_header *oh)
1678{
0a2869d5 1679 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
7395c052
NZ
1680 for (;;) {
1681 struct ofputil_group_stats gs;
1682 int retval;
1683
1684 retval = ofputil_decode_group_stats_reply(&b, &gs);
1685 if (retval) {
1686 if (retval != EOF) {
1687 ds_put_cstr(s, " ***parse error***");
2d071a32 1688 return retval;
7395c052
NZ
1689 }
1690 break;
1691 }
1692
1693 ds_put_char(s, '\n');
1694
1695 ds_put_char(s, ' ');
1696 ds_put_format(s, "group_id=%"PRIu32",", gs.group_id);
1697
1698 if (gs.duration_sec != UINT32_MAX) {
1699 ds_put_cstr(s, "duration=");
1700 ofp_print_duration(s, gs.duration_sec, gs.duration_nsec);
1701 ds_put_char(s, ',');
1702 }
1703 ds_put_format(s, "ref_count=%"PRIu32",", gs.ref_count);
1704 ds_put_format(s, "packet_count=%"PRIu64",", gs.packet_count);
1705 ds_put_format(s, "byte_count=%"PRIu64"", gs.byte_count);
1706
0a2869d5 1707 for (uint32_t bucket_i = 0; bucket_i < gs.n_buckets; bucket_i++) {
7395c052
NZ
1708 if (gs.bucket_stats[bucket_i].packet_count != UINT64_MAX) {
1709 ds_put_format(s, ",bucket%"PRIu32":", bucket_i);
1710 ds_put_format(s, "packet_count=%"PRIu64",", gs.bucket_stats[bucket_i].packet_count);
1711 ds_put_format(s, "byte_count=%"PRIu64"", gs.bucket_stats[bucket_i].byte_count);
1712 }
1713 }
646b2a9c
SH
1714
1715 free(gs.bucket_stats);
2d071a32
BP
1716 }
1717 return 0;
7395c052
NZ
1718}
1719
08d1e234
BP
1720static const char *
1721group_type_to_string(enum ofp11_group_type type)
1722{
1723 switch (type) {
1724 case OFPGT11_ALL: return "all";
1725 case OFPGT11_SELECT: return "select";
1726 case OFPGT11_INDIRECT: return "indirect";
1727 case OFPGT11_FF: return "fast failover";
1728 default: OVS_NOT_REACHED();
1729 }
1730}
1731
2d071a32 1732static enum ofperr
7395c052
NZ
1733ofp_print_group_features(struct ds *string, const struct ofp_header *oh)
1734{
1735 struct ofputil_group_features features;
08d1e234 1736 int i;
7395c052
NZ
1737
1738 ofputil_decode_group_features_reply(oh, &features);
1739
1740 ds_put_format(string, "\n Group table:\n");
1741 ds_put_format(string, " Types: 0x%"PRIx32"\n", features.types);
1742 ds_put_format(string, " Capabilities: 0x%"PRIx32"\n",
1743 features.capabilities);
1744
08d1e234
BP
1745 for (i = 0; i < OFPGT12_N_TYPES; i++) {
1746 if (features.types & (1u << i)) {
1747 ds_put_format(string, " %s group:\n", group_type_to_string(i));
1748 ds_put_format(string, " max_groups=%#"PRIx32"\n",
1749 features.max_groups[i]);
1750 ds_put_format(string, " actions: ");
1751 ofpact_bitmap_format(features.ofpacts[i], string);
1752 ds_put_char(string, '\n');
1753 }
7395c052 1754 }
2d071a32
BP
1755
1756 return 0;
7395c052
NZ
1757}
1758
1759static void
3c35db62 1760ofp_print_group_mod__(struct ds *s, enum ofp_version ofp_version,
50f96b10 1761 const struct ofputil_group_mod *gm,
4bc938cc
BP
1762 const struct ofputil_port_map *port_map,
1763 const struct ofputil_table_map *table_map)
7395c052 1764{
76c41209 1765 bool bucket_command = false;
7395c052 1766
7395c052
NZ
1767 ds_put_char(s, '\n');
1768
1769 ds_put_char(s, ' ');
3c35db62 1770 switch (gm->command) {
7395c052
NZ
1771 case OFPGC11_ADD:
1772 ds_put_cstr(s, "ADD");
1773 break;
1774
1775 case OFPGC11_MODIFY:
1776 ds_put_cstr(s, "MOD");
1777 break;
1778
88b87a36
JS
1779 case OFPGC11_ADD_OR_MOD:
1780 ds_put_cstr(s, "ADD_OR_MOD");
1781 break;
1782
7395c052
NZ
1783 case OFPGC11_DELETE:
1784 ds_put_cstr(s, "DEL");
1785 break;
1786
76c41209
SH
1787 case OFPGC15_INSERT_BUCKET:
1788 ds_put_cstr(s, "INSERT_BUCKET");
1789 bucket_command = true;
1790 break;
1791
1792 case OFPGC15_REMOVE_BUCKET:
1793 ds_put_cstr(s, "REMOVE_BUCKET");
1794 bucket_command = true;
1795 break;
1796
7395c052 1797 default:
3c35db62 1798 ds_put_format(s, "cmd:%"PRIu16"", gm->command);
7395c052
NZ
1799 }
1800 ds_put_char(s, ' ');
1801
76c41209
SH
1802 if (bucket_command) {
1803 ofp_print_bucket_id(s, "command_bucket_id:",
3c35db62 1804 gm->command_bucket_id, ofp_version);
76c41209
SH
1805 }
1806
3c35db62 1807 ofp_print_group(s, gm->group_id, gm->type, &gm->buckets, &gm->props,
4bc938cc 1808 ofp_version, bucket_command, port_map, table_map);
3c35db62
NR
1809}
1810
2d071a32 1811static enum ofperr
50f96b10 1812ofp_print_group_mod(struct ds *s, const struct ofp_header *oh,
4bc938cc
BP
1813 const struct ofputil_port_map *port_map,
1814 const struct ofputil_table_map *table_map)
3c35db62
NR
1815{
1816 struct ofputil_group_mod gm;
1817 int error;
1818
1819 error = ofputil_decode_group_mod(oh, &gm);
1820 if (error) {
2d071a32 1821 return error;
3c35db62 1822 }
4bc938cc 1823 ofp_print_group_mod__(s, oh->version, &gm, port_map, table_map);
75868d0e 1824 ofputil_uninit_group_mod(&gm);
2d071a32 1825 return 0;
7395c052
NZ
1826}
1827
2d071a32 1828static enum ofperr
4bc938cc
BP
1829ofp_print_table_desc_reply(struct ds *s, const struct ofp_header *oh,
1830 const struct ofputil_table_map *table_map)
03c72922 1831{
0a2869d5 1832 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
03c72922
BP
1833 for (;;) {
1834 struct ofputil_table_desc td;
1835 int retval;
1836
1837 retval = ofputil_decode_table_desc(&b, &td, oh->version);
1838 if (retval) {
2d071a32 1839 return retval != EOF ? retval : 0;
03c72922 1840 }
dfc77282 1841 ofputil_table_desc_format(s, &td, table_map);
03c72922
BP
1842 }
1843}
1844
777af88d
AC
1845static const char *
1846bundle_flags_to_name(uint32_t bit)
1847{
1848 switch (bit) {
1849 case OFPBF_ATOMIC:
1850 return "atomic";
1851 case OFPBF_ORDERED:
1852 return "ordered";
1853 default:
1854 return NULL;
1855 }
1856}
1857
2d071a32 1858static enum ofperr
777af88d
AC
1859ofp_print_bundle_ctrl(struct ds *s, const struct ofp_header *oh)
1860{
1861 int error;
1862 struct ofputil_bundle_ctrl_msg bctrl;
1863
1864 error = ofputil_decode_bundle_ctrl(oh, &bctrl);
1865 if (error) {
2d071a32 1866 return error;
777af88d
AC
1867 }
1868
1869 ds_put_char(s, '\n');
1870
1871 ds_put_format(s, " bundle_id=%#"PRIx32" type=", bctrl.bundle_id);
1872 switch (bctrl.type) {
1873 case OFPBCT_OPEN_REQUEST:
1874 ds_put_cstr(s, "OPEN_REQUEST");
1875 break;
1876 case OFPBCT_OPEN_REPLY:
1877 ds_put_cstr(s, "OPEN_REPLY");
1878 break;
1879 case OFPBCT_CLOSE_REQUEST:
1880 ds_put_cstr(s, "CLOSE_REQUEST");
1881 break;
1882 case OFPBCT_CLOSE_REPLY:
1883 ds_put_cstr(s, "CLOSE_REPLY");
1884 break;
1885 case OFPBCT_COMMIT_REQUEST:
1886 ds_put_cstr(s, "COMMIT_REQUEST");
1887 break;
1888 case OFPBCT_COMMIT_REPLY:
1889 ds_put_cstr(s, "COMMIT_REPLY");
1890 break;
1891 case OFPBCT_DISCARD_REQUEST:
1892 ds_put_cstr(s, "DISCARD_REQUEST");
1893 break;
1894 case OFPBCT_DISCARD_REPLY:
1895 ds_put_cstr(s, "DISCARD_REPLY");
1896 break;
1897 }
1898
1899 ds_put_cstr(s, " flags=");
1900 ofp_print_bit_names(s, bctrl.flags, bundle_flags_to_name, ' ');
2d071a32
BP
1901
1902 return 0;
777af88d
AC
1903}
1904
2d071a32 1905static enum ofperr
50f96b10 1906ofp_print_bundle_add(struct ds *s, const struct ofp_header *oh,
4bc938cc
BP
1907 const struct ofputil_port_map *port_map,
1908 const struct ofputil_table_map *table_map,
1909 int verbosity)
777af88d
AC
1910{
1911 int error;
1912 struct ofputil_bundle_add_msg badd;
777af88d 1913
7ac27a04 1914 error = ofputil_decode_bundle_add(oh, &badd, NULL);
777af88d 1915 if (error) {
2d071a32 1916 return error;
777af88d
AC
1917 }
1918
1919 ds_put_char(s, '\n');
1920 ds_put_format(s, " bundle_id=%#"PRIx32, badd.bundle_id);
1921 ds_put_cstr(s, " flags=");
1922 ofp_print_bit_names(s, badd.flags, bundle_flags_to_name, ' ');
1923
1924 ds_put_char(s, '\n');
50f96b10 1925 char *msg = ofp_to_string(badd.msg, ntohs(badd.msg->length), port_map,
4bc938cc 1926 table_map, verbosity);
cf8fbeaa 1927 ds_put_and_free_cstr(s, msg);
2d071a32
BP
1928
1929 return 0;
777af88d
AC
1930}
1931
6159c531 1932static void
4e548ad9 1933print_tlv_table(struct ds *s, struct ovs_list *mappings)
6159c531 1934{
4e548ad9 1935 struct ofputil_tlv_map *map;
6159c531
JG
1936
1937 ds_put_cstr(s, " mapping table:\n");
1938 ds_put_cstr(s, " class\ttype\tlength\tmatch field\n");
1939 ds_put_cstr(s, " -----\t----\t------\t-----------");
1940
1941 LIST_FOR_EACH (map, list_node, mappings) {
1942 ds_put_char(s, '\n');
1943 ds_put_format(s, " 0x%"PRIx16"\t0x%"PRIx8"\t%"PRIu8"\ttun_metadata%"PRIu16,
1944 map->option_class, map->option_type, map->option_len,
1945 map->index);
1946 }
1947}
1948
2d071a32 1949static enum ofperr
4e548ad9 1950ofp_print_tlv_table_mod(struct ds *s, const struct ofp_header *oh)
6159c531
JG
1951{
1952 int error;
4e548ad9 1953 struct ofputil_tlv_table_mod ttm;
6159c531 1954
4e548ad9 1955 error = ofputil_decode_tlv_table_mod(oh, &ttm);
6159c531 1956 if (error) {
2d071a32 1957 return error;
6159c531
JG
1958 }
1959
1960 ds_put_cstr(s, "\n ");
1961
4e548ad9
ML
1962 switch (ttm.command) {
1963 case NXTTMC_ADD:
6159c531
JG
1964 ds_put_cstr(s, "ADD");
1965 break;
4e548ad9 1966 case NXTTMC_DELETE:
6159c531
JG
1967 ds_put_cstr(s, "DEL");
1968 break;
4e548ad9 1969 case NXTTMC_CLEAR:
6159c531
JG
1970 ds_put_cstr(s, "CLEAR");
1971 break;
1972 }
1973
4e548ad9
ML
1974 if (ttm.command != NXTTMC_CLEAR) {
1975 print_tlv_table(s, &ttm.mappings);
6159c531
JG
1976 }
1977
4e548ad9 1978 ofputil_uninit_tlv_table(&ttm.mappings);
2d071a32
BP
1979
1980 return 0;
6159c531
JG
1981}
1982
2d071a32 1983static enum ofperr
4e548ad9 1984ofp_print_tlv_table_reply(struct ds *s, const struct ofp_header *oh)
6159c531
JG
1985{
1986 int error;
4e548ad9
ML
1987 struct ofputil_tlv_table_reply ttr;
1988 struct ofputil_tlv_map *map;
6159c531
JG
1989 int allocated_space = 0;
1990
4e548ad9 1991 error = ofputil_decode_tlv_table_reply(oh, &ttr);
6159c531 1992 if (error) {
2d071a32 1993 return error;
6159c531
JG
1994 }
1995
1996 ds_put_char(s, '\n');
1997
4e548ad9 1998 LIST_FOR_EACH (map, list_node, &ttr.mappings) {
6159c531
JG
1999 allocated_space += map->option_len;
2000 }
2001
2002 ds_put_format(s, " max option space=%"PRIu32" max fields=%"PRIu16"\n",
4e548ad9 2003 ttr.max_option_space, ttr.max_fields);
6159c531
JG
2004 ds_put_format(s, " allocated option space=%d\n", allocated_space);
2005 ds_put_char(s, '\n');
4e548ad9 2006 print_tlv_table(s, &ttr.mappings);
6159c531 2007
4e548ad9 2008 ofputil_uninit_tlv_table(&ttr.mappings);
2d071a32
BP
2009
2010 return 0;
6159c531
JG
2011}
2012
3c35db62
NR
2013/* This function will print the request forward message. The reason for
2014 * request forward is taken from rf.request.type */
2d071a32 2015static enum ofperr
50f96b10 2016ofp_print_requestforward(struct ds *string, const struct ofp_header *oh,
4bc938cc
BP
2017 const struct ofputil_port_map *port_map,
2018 const struct ofputil_table_map *table_map)
3c35db62
NR
2019{
2020 struct ofputil_requestforward rf;
2021 enum ofperr error;
2022
2023 error = ofputil_decode_requestforward(oh, &rf);
2024 if (error) {
2d071a32 2025 return error;
3c35db62
NR
2026 }
2027
2028 ds_put_cstr(string, " reason=");
2029
2030 switch (rf.reason) {
2031 case OFPRFR_GROUP_MOD:
2032 ds_put_cstr(string, "group_mod");
4bc938cc
BP
2033 ofp_print_group_mod__(string, oh->version, rf.group_mod, port_map,
2034 table_map);
3c35db62
NR
2035 break;
2036
2037 case OFPRFR_METER_MOD:
2038 ds_put_cstr(string, "meter_mod");
2039 ofp_print_meter_mod__(string, rf.meter_mod);
2040 break;
d18cc1ee
AA
2041
2042 case OFPRFR_N_REASONS:
2043 OVS_NOT_REACHED();
3c35db62
NR
2044 }
2045 ofputil_destroy_requestforward(&rf);
2d071a32
BP
2046
2047 return 0;
3c35db62
NR
2048}
2049
fb8f22c1
BY
2050static void
2051print_ipfix_stat(struct ds *string, const char *leader, uint64_t stat, int more)
2052{
2053 ds_put_cstr(string, leader);
2054 if (stat != UINT64_MAX) {
2055 ds_put_format(string, "%"PRIu64, stat);
2056 } else {
2057 ds_put_char(string, '?');
2058 }
2059 if (more) {
2060 ds_put_cstr(string, ", ");
2061 } else {
2062 ds_put_cstr(string, "\n");
2063 }
2064}
2065
2d071a32 2066static enum ofperr
fb8f22c1
BY
2067ofp_print_nxst_ipfix_bridge_reply(struct ds *string, const struct ofp_header *oh)
2068{
2069 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
2070 for (;;) {
2071 struct ofputil_ipfix_stats is;
2072 int retval;
2073
2074 retval = ofputil_pull_ipfix_stats(&is, &b);
2075 if (retval) {
2d071a32 2076 return retval != EOF ? retval : 0;
fb8f22c1
BY
2077 }
2078
2079 ds_put_cstr(string, "\n bridge ipfix: ");
2080 print_ipfix_stat(string, "flows=", is.total_flows, 1);
2081 print_ipfix_stat(string, "current flows=", is.current_flows, 1);
2082 print_ipfix_stat(string, "sampled pkts=", is.pkts, 1);
2083 print_ipfix_stat(string, "ipv4 ok=", is.ipv4_pkts, 1);
2084 print_ipfix_stat(string, "ipv6 ok=", is.ipv6_pkts, 1);
2085 print_ipfix_stat(string, "tx pkts=", is.tx_pkts, 0);
2086 ds_put_cstr(string, " ");
2087 print_ipfix_stat(string, "pkts errs=", is.error_pkts, 1);
2088 print_ipfix_stat(string, "ipv4 errs=", is.ipv4_error_pkts, 1);
2089 print_ipfix_stat(string, "ipv6 errs=", is.ipv6_error_pkts, 1);
2090 print_ipfix_stat(string, "tx errs=", is.tx_errors, 0);
2091 }
2092}
2093
2d071a32 2094static enum ofperr
fb8f22c1
BY
2095ofp_print_nxst_ipfix_flow_reply(struct ds *string, const struct ofp_header *oh)
2096{
2097 ds_put_format(string, " %"PRIuSIZE" ids\n", ofputil_count_ipfix_stats(oh));
2098
2099 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
2100 for (;;) {
2101 struct ofputil_ipfix_stats is;
2102 int retval;
2103
2104 retval = ofputil_pull_ipfix_stats(&is, &b);
2105 if (retval) {
2d071a32 2106 return retval != EOF ? retval : 0;
fb8f22c1
BY
2107 }
2108
2109 ds_put_cstr(string, " id");
2110 ds_put_format(string, " %3"PRIuSIZE": ", (size_t) is.collector_set_id);
2111 print_ipfix_stat(string, "flows=", is.total_flows, 1);
2112 print_ipfix_stat(string, "current flows=", is.current_flows, 1);
2113 print_ipfix_stat(string, "sampled pkts=", is.pkts, 1);
2114 print_ipfix_stat(string, "ipv4 ok=", is.ipv4_pkts, 1);
2115 print_ipfix_stat(string, "ipv6 ok=", is.ipv6_pkts, 1);
2116 print_ipfix_stat(string, "tx pkts=", is.tx_pkts, 0);
2117 ds_put_cstr(string, " ");
2118 print_ipfix_stat(string, "pkts errs=", is.error_pkts, 1);
2119 print_ipfix_stat(string, "ipv4 errs=", is.ipv4_error_pkts, 1);
2120 print_ipfix_stat(string, "ipv6 errs=", is.ipv6_error_pkts, 1);
2121 print_ipfix_stat(string, "tx errs=", is.tx_errors, 0);
2122 }
2123}
2124
2d071a32 2125static enum ofperr
2a7c4805
JP
2126ofp_print_nxt_ct_flush_zone(struct ds *string, const struct nx_zone_id *nzi)
2127{
2128 ds_put_format(string, " zone_id=%"PRIu16, ntohs(nzi->zone_id));
2d071a32 2129 return 0;
2a7c4805
JP
2130}
2131
2d071a32 2132static enum ofperr
50f96b10 2133ofp_to_string__(const struct ofp_header *oh,
4bc938cc
BP
2134 const struct ofputil_port_map *port_map,
2135 const struct ofputil_table_map *table_map, enum ofpraw raw,
982697a4 2136 struct ds *string, int verbosity)
bdcc5925 2137{
bdcc5925 2138 const void *msg = oh;
904e5202
BP
2139 enum ofptype type = ofptype_from_ofpraw(raw);
2140 switch (type) {
261bd854 2141 case OFPTYPE_GROUP_STATS_REQUEST:
5d40fc57 2142 ofp_print_stats(string, oh);
2d071a32 2143 return ofp_print_ofpst_group_request(string, oh);
7395c052 2144
261bd854 2145 case OFPTYPE_GROUP_STATS_REPLY:
2d071a32 2146 return ofp_print_group_stats(string, oh);
7395c052 2147
261bd854 2148 case OFPTYPE_GROUP_DESC_STATS_REQUEST:
5d40fc57 2149 ofp_print_stats(string, oh);
2d071a32 2150 return ofp_print_ofpst_group_desc_request(string, oh);
7395c052 2151
261bd854 2152 case OFPTYPE_GROUP_DESC_STATS_REPLY:
4bc938cc 2153 return ofp_print_group_desc(string, oh, port_map, table_map);
7395c052 2154
261bd854 2155 case OFPTYPE_GROUP_FEATURES_STATS_REQUEST:
5d40fc57 2156 ofp_print_stats(string, oh);
7395c052
NZ
2157 break;
2158
261bd854 2159 case OFPTYPE_GROUP_FEATURES_STATS_REPLY:
2d071a32 2160 return ofp_print_group_features(string, oh);
7395c052
NZ
2161
2162 case OFPTYPE_GROUP_MOD:
4bc938cc 2163 return ofp_print_group_mod(string, oh, port_map, table_map);
7395c052 2164
261bd854
BP
2165 case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
2166 case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
4bc938cc 2167 return ofp_print_table_features_reply(string, oh, table_map);
2e1ae200 2168
03c72922
BP
2169 case OFPTYPE_TABLE_DESC_REQUEST:
2170 case OFPTYPE_TABLE_DESC_REPLY:
4bc938cc 2171 return ofp_print_table_desc_reply(string, oh, table_map);
03c72922 2172
982697a4 2173 case OFPTYPE_HELLO:
2d071a32 2174 return ofp_print_hello(string, oh);
d1e2cf21 2175
982697a4 2176 case OFPTYPE_ERROR:
4bc938cc 2177 return ofp_print_error_msg(string, oh, port_map, table_map);
d1e2cf21 2178
982697a4
BP
2179 case OFPTYPE_ECHO_REQUEST:
2180 case OFPTYPE_ECHO_REPLY:
2d071a32 2181 return ofp_print_echo(string, oh, verbosity);
d1e2cf21 2182
982697a4 2183 case OFPTYPE_FEATURES_REQUEST:
d1e2cf21
BP
2184 break;
2185
982697a4 2186 case OFPTYPE_FEATURES_REPLY:
2d071a32 2187 return ofp_print_switch_features(string, oh);
d1e2cf21 2188
982697a4 2189 case OFPTYPE_GET_CONFIG_REQUEST:
d1e2cf21
BP
2190 break;
2191
982697a4 2192 case OFPTYPE_GET_CONFIG_REPLY:
2d071a32 2193 return ofp_print_get_config_reply(string, oh);
ad99e2ed 2194
982697a4 2195 case OFPTYPE_SET_CONFIG:
2d071a32 2196 return ofp_print_set_config(string, oh);
d1e2cf21 2197
982697a4 2198 case OFPTYPE_PACKET_IN:
4bc938cc 2199 return ofp_print_packet_in(string, oh, port_map, table_map, verbosity);
d1e2cf21 2200
982697a4 2201 case OFPTYPE_FLOW_REMOVED:
4bc938cc 2202 return ofp_print_flow_removed(string, oh, port_map, table_map);
d1e2cf21 2203
982697a4 2204 case OFPTYPE_PORT_STATUS:
2d071a32 2205 return ofp_print_port_status(string, oh);
d1e2cf21 2206
982697a4 2207 case OFPTYPE_PACKET_OUT:
4bc938cc
BP
2208 return ofp_print_packet_out(string, oh, port_map, table_map,
2209 verbosity);
d1e2cf21 2210
982697a4 2211 case OFPTYPE_FLOW_MOD:
dfc77282
BP
2212 return ofputil_flow_mod_format(string, oh, port_map, table_map,
2213 verbosity);
d1e2cf21 2214
982697a4 2215 case OFPTYPE_PORT_MOD:
2d071a32 2216 return ofp_print_port_mod(string, oh, port_map);
d1e2cf21 2217
918f2b82 2218 case OFPTYPE_TABLE_MOD:
4bc938cc 2219 return ofp_print_table_mod(string, oh, table_map);
918f2b82 2220
638a19b0 2221 case OFPTYPE_METER_MOD:
2d071a32 2222 return ofp_print_meter_mod(string, oh);
638a19b0 2223
982697a4
BP
2224 case OFPTYPE_BARRIER_REQUEST:
2225 case OFPTYPE_BARRIER_REPLY:
d1e2cf21
BP
2226 break;
2227
e8f9a7bb 2228 case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
2d071a32 2229 return ofp_print_queue_get_config_request(string, oh, port_map);
e8f9a7bb
VG
2230
2231 case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
2d071a32 2232 return ofp_print_queue_get_config_reply(string, oh, port_map);
e8f9a7bb 2233
6ea4776b
JR
2234 case OFPTYPE_ROLE_REQUEST:
2235 case OFPTYPE_ROLE_REPLY:
2d071a32 2236 return ofp_print_role_message(string, oh);
252f3411 2237 case OFPTYPE_ROLE_STATUS:
2d071a32 2238 return ofp_print_role_status_message(string, oh);
6ea4776b 2239
3c35db62 2240 case OFPTYPE_REQUESTFORWARD:
4bc938cc 2241 return ofp_print_requestforward(string, oh, port_map, table_map);
3c35db62 2242
6c6eedc5 2243 case OFPTYPE_TABLE_STATUS:
4bc938cc 2244 return ofp_print_table_status_message(string, oh, table_map);
6c6eedc5 2245
261bd854
BP
2246 case OFPTYPE_METER_STATS_REQUEST:
2247 case OFPTYPE_METER_CONFIG_STATS_REQUEST:
5d40fc57 2248 ofp_print_stats(string, oh);
2d071a32 2249 return ofp_print_meter_stats_request(string, oh);
638a19b0 2250
261bd854 2251 case OFPTYPE_METER_STATS_REPLY:
5d40fc57 2252 ofp_print_stats(string, oh);
2d071a32 2253 return ofp_print_meter_stats_reply(string, oh);
638a19b0 2254
261bd854 2255 case OFPTYPE_METER_CONFIG_STATS_REPLY:
5d40fc57 2256 ofp_print_stats(string, oh);
2d071a32 2257 return ofp_print_meter_config_reply(string, oh);
638a19b0 2258
261bd854 2259 case OFPTYPE_METER_FEATURES_STATS_REPLY:
5d40fc57 2260 ofp_print_stats(string, oh);
2d071a32 2261 return ofp_print_meter_features_reply(string, oh);
638a19b0 2262
982697a4 2263 case OFPTYPE_DESC_STATS_REQUEST:
261bd854 2264 case OFPTYPE_METER_FEATURES_STATS_REQUEST:
5d40fc57 2265 ofp_print_stats(string, oh);
d1e2cf21
BP
2266 break;
2267
982697a4
BP
2268 case OFPTYPE_FLOW_STATS_REQUEST:
2269 case OFPTYPE_AGGREGATE_STATS_REQUEST:
5d40fc57 2270 ofp_print_stats(string, oh);
4bc938cc 2271 return ofp_print_flow_stats_request(string, oh, port_map, table_map);
d1e2cf21 2272
982697a4 2273 case OFPTYPE_TABLE_STATS_REQUEST:
5d40fc57 2274 ofp_print_stats(string, oh);
d1e2cf21
BP
2275 break;
2276
982697a4 2277 case OFPTYPE_PORT_STATS_REQUEST:
5d40fc57 2278 ofp_print_stats(string, oh);
2d071a32 2279 return ofp_print_ofpst_port_request(string, oh, port_map);
d1e2cf21 2280
982697a4 2281 case OFPTYPE_QUEUE_STATS_REQUEST:
5d40fc57 2282 ofp_print_stats(string, oh);
2d071a32 2283 return ofp_print_ofpst_queue_request(string, oh, port_map);
d1e2cf21 2284
982697a4 2285 case OFPTYPE_DESC_STATS_REPLY:
5d40fc57 2286 ofp_print_stats(string, oh);
2d071a32 2287 return ofp_print_ofpst_desc_reply(string, oh);
d1e2cf21 2288
982697a4 2289 case OFPTYPE_FLOW_STATS_REPLY:
5d40fc57 2290 ofp_print_stats(string, oh);
4bc938cc 2291 return ofp_print_flow_stats_reply(string, oh, port_map, table_map);
d1e2cf21 2292
982697a4 2293 case OFPTYPE_QUEUE_STATS_REPLY:
5d40fc57 2294 ofp_print_stats(string, oh);
2d071a32 2295 return ofp_print_ofpst_queue_reply(string, oh, port_map, verbosity);
d1e2cf21 2296
982697a4 2297 case OFPTYPE_PORT_STATS_REPLY:
5d40fc57 2298 ofp_print_stats(string, oh);
2d071a32 2299 return ofp_print_ofpst_port_reply(string, oh, port_map, verbosity);
d1e2cf21 2300
982697a4 2301 case OFPTYPE_TABLE_STATS_REPLY:
5d40fc57 2302 ofp_print_stats(string, oh);
4bc938cc 2303 return ofp_print_table_stats_reply(string, oh, table_map);
d1e2cf21 2304
982697a4 2305 case OFPTYPE_AGGREGATE_STATS_REPLY:
5d40fc57 2306 ofp_print_stats(string, oh);
2d071a32 2307 return ofp_print_aggregate_stats_reply(string, oh);
064af421 2308
70ae4f93 2309 case OFPTYPE_PORT_DESC_STATS_REQUEST:
5d40fc57 2310 ofp_print_stats(string, oh);
2d071a32 2311 return ofp_print_ofpst_port_desc_request(string, oh, port_map);
70ae4f93 2312
982697a4 2313 case OFPTYPE_PORT_DESC_STATS_REPLY:
5d40fc57 2314 ofp_print_stats(string, oh);
2d071a32 2315 return ofp_print_ofpst_port_desc_reply(string, oh);
2be393ed 2316
982697a4 2317 case OFPTYPE_FLOW_MOD_TABLE_ID:
225c33ba 2318 return ofp_print_nxt_flow_mod_table_id(string, oh);
6c1491fb 2319
982697a4 2320 case OFPTYPE_SET_FLOW_FORMAT:
225c33ba 2321 return ofp_print_nxt_set_flow_format(string, oh);
7fa91113 2322
982697a4 2323 case OFPTYPE_SET_PACKET_IN_FORMAT:
d8790c08 2324 return ofp_print_nxt_set_packet_in_format(string, oh);
54834960 2325
982697a4 2326 case OFPTYPE_FLOW_AGE:
f27f2134
BP
2327 break;
2328
982697a4 2329 case OFPTYPE_SET_CONTROLLER_ID:
2d071a32 2330 return ofp_print_nxt_set_controller_id(string, ofpmsg_body(oh));
a7349929 2331
db09e430 2332 case OFPTYPE_GET_ASYNC_REPLY:
982697a4 2333 case OFPTYPE_SET_ASYNC_CONFIG:
2d071a32 2334 return ofp_print_set_async_config(string, oh, type);
db09e430
AC
2335 case OFPTYPE_GET_ASYNC_REQUEST:
2336 break;
982697a4 2337 case OFPTYPE_FLOW_MONITOR_CANCEL:
2d071a32 2338 return ofp_print_nxt_flow_monitor_cancel(string, msg);
2b07c8b1 2339
982697a4
BP
2340 case OFPTYPE_FLOW_MONITOR_PAUSED:
2341 case OFPTYPE_FLOW_MONITOR_RESUMED:
2b07c8b1
BP
2342 break;
2343
982697a4 2344 case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
4bc938cc
BP
2345 return ofp_print_nxst_flow_monitor_request(string, msg, port_map,
2346 table_map);
2b07c8b1 2347
982697a4 2348 case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
4bc938cc
BP
2349 return ofp_print_nxst_flow_monitor_reply(string, msg, port_map,
2350 table_map);
777af88d
AC
2351
2352 case OFPTYPE_BUNDLE_CONTROL:
2d071a32 2353 return ofp_print_bundle_ctrl(string, msg);
777af88d
AC
2354
2355 case OFPTYPE_BUNDLE_ADD_MESSAGE:
4bc938cc
BP
2356 return ofp_print_bundle_add(string, msg, port_map, table_map,
2357 verbosity);
6159c531 2358
4e548ad9 2359 case OFPTYPE_NXT_TLV_TABLE_MOD:
2d071a32 2360 return ofp_print_tlv_table_mod(string, msg);
6159c531 2361
4e548ad9 2362 case OFPTYPE_NXT_TLV_TABLE_REQUEST:
6159c531
JG
2363 break;
2364
4e548ad9 2365 case OFPTYPE_NXT_TLV_TABLE_REPLY:
2d071a32 2366 return ofp_print_tlv_table_reply(string, msg);
6159c531 2367
77ab5fd2 2368 case OFPTYPE_NXT_RESUME:
4bc938cc
BP
2369 return ofp_print_packet_in(string, msg, port_map, table_map,
2370 verbosity);
fb8f22c1
BY
2371 case OFPTYPE_IPFIX_BRIDGE_STATS_REQUEST:
2372 break;
2373 case OFPTYPE_IPFIX_BRIDGE_STATS_REPLY:
2d071a32 2374 return ofp_print_nxst_ipfix_bridge_reply(string, oh);
fb8f22c1
BY
2375 case OFPTYPE_IPFIX_FLOW_STATS_REQUEST:
2376 break;
2377 case OFPTYPE_IPFIX_FLOW_STATS_REPLY:
2d071a32 2378 return ofp_print_nxst_ipfix_flow_reply(string, oh);
2a7c4805
JP
2379
2380 case OFPTYPE_CT_FLUSH_ZONE:
2d071a32
BP
2381 return ofp_print_nxt_ct_flush_zone(string, ofpmsg_body(oh));
2382 }
2383
2384 return 0;
2385}
2386
2387static void
2388add_newline(struct ds *s)
2389{
2390 if (s->length && s->string[s->length - 1] != '\n') {
2391 ds_put_char(s, '\n');
246e61ea 2392 }
d1e2cf21 2393}
064af421
BP
2394
2395/* Composes and returns a string representing the OpenFlow packet of 'len'
2396 * bytes at 'oh' at the given 'verbosity' level. 0 is a minimal amount of
2397 * verbosity and higher numbers increase verbosity. The caller is responsible
2398 * for freeing the string. */
2399char *
50f96b10 2400ofp_to_string(const void *oh_, size_t len,
4bc938cc
BP
2401 const struct ofputil_port_map *port_map,
2402 const struct ofputil_table_map *table_map,
2403 int verbosity)
064af421
BP
2404{
2405 struct ds string = DS_EMPTY_INITIALIZER;
2406 const struct ofp_header *oh = oh_;
064af421 2407
49ad0403
BP
2408 if (!len) {
2409 ds_put_cstr(&string, "OpenFlow message is empty\n");
2410 } else if (len < sizeof(struct ofp_header)) {
34582733 2411 ds_put_format(&string, "OpenFlow packet too short (only %"PRIuSIZE" bytes):\n",
49ad0403 2412 len);
d1e2cf21 2413 } else if (ntohs(oh->length) > len) {
f25b4a81 2414 enum ofperr error;
982697a4 2415 enum ofpraw raw;
f25b4a81 2416
982697a4 2417 error = ofpraw_decode_partial(&raw, oh, len);
f25b4a81 2418 if (!error) {
982697a4 2419 ofp_header_to_string__(oh, raw, &string);
f25b4a81
BP
2420 ds_put_char(&string, '\n');
2421 }
2422
d1e2cf21 2423 ds_put_format(&string,
34582733 2424 "(***truncated to %"PRIuSIZE" bytes from %"PRIu16"***)\n",
d1e2cf21
BP
2425 len, ntohs(oh->length));
2426 } else if (ntohs(oh->length) < len) {
2427 ds_put_format(&string,
34582733 2428 "(***only uses %"PRIu16" bytes out of %"PRIuSIZE"***)\n",
d1e2cf21
BP
2429 ntohs(oh->length), len);
2430 } else {
90bf1e07 2431 enum ofperr error;
982697a4 2432 enum ofpraw raw;
d1e2cf21 2433
982697a4 2434 error = ofpraw_decode(&raw, oh);
d1e2cf21 2435 if (!error) {
2d071a32
BP
2436 ofp_header_to_string__(oh, raw, &string);
2437 size_t header_len = string.length;
2438
4bc938cc
BP
2439 error = ofp_to_string__(oh, port_map, table_map,
2440 raw, &string, verbosity);
2d071a32
BP
2441 if (error) {
2442 if (string.length > header_len) {
2443 ds_chomp(&string, ' ');
2444 add_newline(&string);
2445 } else {
2446 ds_put_char(&string, ' ');
7fa91113 2447 }
2d071a32
BP
2448 ofp_print_error(&string, error);
2449 } else {
2450 ds_chomp(&string, ' ');
d1e2cf21 2451 }
2d071a32
BP
2452 } else {
2453 ofp_print_error(&string, error);
2454 }
2455
2456 if (verbosity >= 5 || error) {
2457 add_newline(&string);
2458 ds_put_hex_dump(&string, oh, len, 0, true);
064af421 2459 }
064af421 2460
2d071a32
BP
2461 add_newline(&string);
2462 return ds_steal_cstr(&string);
064af421 2463 }
d1e2cf21
BP
2464 ds_put_hex_dump(&string, oh, len, 0, true);
2465 return ds_steal_cstr(&string);
064af421 2466}
064af421
BP
2467\f
2468static void
d295e8e9 2469print_and_free(FILE *stream, char *string)
064af421
BP
2470{
2471 fputs(string, stream);
2472 free(string);
2473}
2474
2475/* Pretty-print the OpenFlow packet of 'len' bytes at 'oh' to 'stream' at the
2476 * given 'verbosity' level. 0 is a minimal amount of verbosity and higher
2477 * numbers increase verbosity. */
2478void
50f96b10 2479ofp_print(FILE *stream, const void *oh, size_t len,
4bc938cc
BP
2480 const struct ofputil_port_map *port_map,
2481 const struct ofputil_table_map *table_map, int verbosity)
064af421 2482{
4bc938cc
BP
2483 print_and_free(stream, ofp_to_string(oh, len, port_map, table_map,
2484 verbosity));
064af421
BP
2485}
2486
2487/* Dumps the contents of the Ethernet frame in the 'len' bytes starting at
897a8e07 2488 * 'data' to 'stream'. */
064af421 2489void
2482b0b0
JS
2490ofp_print_packet(FILE *stream, const void *data, size_t len,
2491 ovs_be32 packet_type)
2492{
2493 print_and_free(stream, ofp_packet_to_string(data, len, packet_type));
2494}
2495
2496void
2497ofp_print_dp_packet(FILE *stream, const struct dp_packet *packet)
064af421 2498{
2482b0b0 2499 print_and_free(stream, ofp_dp_packet_to_string(packet));
064af421 2500}