]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ofp-print.c
ofp-util: Zero out padding bytes in ofputil_ipfix_stats_to_reply().
[mirror_ovs.git] / lib / ofp-print.c
CommitLineData
064af421 1/*
cf8fbeaa 2 * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 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
BP
18
19#include <errno.h>
20#include <inttypes.h>
7f3adc00 21#include <sys/types.h>
064af421
BP
22#include <netinet/in.h>
23#include <sys/wait.h>
24#include <stdarg.h>
25#include <stdlib.h>
26#include <ctype.h>
27
daff3353 28#include "bundle.h"
10a24935 29#include "byte-order.h"
ab8e7f7d 30#include "colors.h"
064af421 31#include "compiler.h"
25d436fb 32#include "dp-packet.h"
064af421 33#include "flow.h"
75a75043 34#include "learn.h"
53ddd40a 35#include "multipath.h"
9e1fd49b 36#include "netdev.h"
7fa91113 37#include "nx-match.h"
25d436fb 38#include "odp-util.h"
064af421 39#include "openflow/nicira-ext.h"
b598f214 40#include "openflow/openflow.h"
d271907f
BW
41#include "openvswitch/dynamic-string.h"
42#include "openvswitch/meta-flow.h"
b598f214 43#include "openvswitch/ofp-actions.h"
e03c096d 44#include "openvswitch/ofp-errors.h"
d271907f 45#include "openvswitch/ofp-msgs.h"
25d436fb 46#include "openvswitch/ofp-print.h"
d271907f
BW
47#include "openvswitch/ofp-util.h"
48#include "openvswitch/ofpbuf.h"
49#include "openvswitch/type-props.h"
064af421 50#include "packets.h"
c4617b3c 51#include "unaligned.h"
064af421 52#include "util.h"
d5dc60f0 53#include "uuid.h"
064af421 54
d2805da2 55static void ofp_print_queue_name(struct ds *string, uint32_t port);
90bf1e07 56static void ofp_print_error(struct ds *, enum ofperr);
064af421
BP
57
58/* Returns a string that represents the contents of the Ethernet frame in the
897a8e07 59 * 'len' bytes starting at 'data'. The caller must free the returned string.*/
064af421 60char *
c499c75d 61ofp_packet_to_string(const void *data, size_t len)
064af421
BP
62{
63 struct ds ds = DS_EMPTY_INITIALIZER;
cf62fa4c 64 struct dp_packet buf;
897a8e07 65 struct flow flow;
5a51b2cd 66 size_t l4_size;
064af421 67
cf62fa4c
PS
68 dp_packet_use_const(&buf, data, len);
69 flow_extract(&buf, &flow);
897a8e07 70 flow_format(&ds, &flow);
e50abca5 71
cf62fa4c 72 l4_size = dp_packet_l4_size(&buf);
5a51b2cd
JR
73
74 if (flow.nw_proto == IPPROTO_TCP && l4_size >= TCP_HEADER_LEN) {
cf62fa4c 75 struct tcp_header *th = dp_packet_l4(&buf);
5a51b2cd
JR
76 ds_put_format(&ds, " tcp_csum:%"PRIx16, ntohs(th->tcp_csum));
77 } else if (flow.nw_proto == IPPROTO_UDP && l4_size >= UDP_HEADER_LEN) {
cf62fa4c 78 struct udp_header *uh = dp_packet_l4(&buf);
5a51b2cd
JR
79 ds_put_format(&ds, " udp_csum:%"PRIx16, ntohs(uh->udp_csum));
80 } else if (flow.nw_proto == IPPROTO_SCTP && l4_size >= SCTP_HEADER_LEN) {
cf62fa4c 81 struct sctp_header *sh = dp_packet_l4(&buf);
5fa008d4
BP
82 ds_put_format(&ds, " sctp_csum:%"PRIx32,
83 ntohl(get_16aligned_be32(&sh->sctp_csum)));
e60e935b 84 } else if (flow.nw_proto == IPPROTO_ICMP && l4_size >= ICMP_HEADER_LEN) {
cf62fa4c 85 struct icmp_header *icmph = dp_packet_l4(&buf);
e60e935b
SRCSA
86 ds_put_format(&ds, " icmp_csum:%"PRIx16,
87 ntohs(icmph->icmp_csum));
88 } else if (flow.nw_proto == IPPROTO_ICMPV6 && l4_size >= ICMP6_HEADER_LEN) {
cf62fa4c 89 struct icmp6_header *icmp6h = dp_packet_l4(&buf);
e60e935b
SRCSA
90 ds_put_format(&ds, " icmp6_csum:%"PRIx16,
91 ntohs(icmp6h->icmp6_cksum));
e50abca5
EJ
92 }
93
897a8e07 94 ds_put_char(&ds, '\n');
064af421 95
064af421
BP
96 return ds_cstr(&ds);
97}
98
bdcad671
BP
99static void
100format_hex_arg(struct ds *s, const uint8_t *data, size_t len)
101{
102 for (size_t i = 0; i < len; i++) {
103 if (i) {
104 ds_put_char(s, '.');
105 }
106 ds_put_format(s, "%02"PRIx8, data[i]);
107 }
108}
109
064af421 110static void
65120a8a 111ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
d1e2cf21 112 int verbosity)
064af421 113{
5014a89d 114 char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];
77ab5fd2
BP
115 struct ofputil_packet_in_private pin;
116 const struct ofputil_packet_in *public = &pin.public;
9bfe9334
BP
117 uint32_t buffer_id;
118 size_t total_len;
77ab5fd2 119 enum ofperr error;
064af421 120
77ab5fd2
BP
121 error = ofputil_decode_packet_in_private(oh, true,
122 &pin, &total_len, &buffer_id);
65120a8a
EJ
123 if (error) {
124 ofp_print_error(string, error);
125 return;
126 }
127
77ab5fd2
BP
128 if (public->table_id) {
129 ds_put_format(string, " table_id=%"PRIu8, public->table_id);
54834960
EJ
130 }
131
77ab5fd2
BP
132 if (public->cookie != OVS_BE64_MAX) {
133 ds_put_format(string, " cookie=0x%"PRIx64, ntohll(public->cookie));
54834960
EJ
134 }
135
9bfe9334 136 ds_put_format(string, " total_len=%"PRIuSIZE" ", total_len);
5d6c3af0 137
77ab5fd2 138 match_format(&public->flow_metadata, string, OFP_DEFAULT_PRIORITY);
ac923e91 139
80d5aefd 140 ds_put_format(string, " (via %s)",
77ab5fd2 141 ofputil_packet_in_reason_to_string(public->reason,
9bfe9334 142 reasonbuf,
5014a89d 143 sizeof reasonbuf));
064af421 144
77ab5fd2 145 ds_put_format(string, " data_len=%"PRIuSIZE, public->packet_len);
9bfe9334 146 if (buffer_id == UINT32_MAX) {
064af421 147 ds_put_format(string, " (unbuffered)");
77ab5fd2 148 if (total_len != public->packet_len) {
064af421 149 ds_put_format(string, " (***total_len != data_len***)");
65120a8a 150 }
064af421 151 } else {
9bfe9334 152 ds_put_format(string, " buffer=0x%08"PRIx32, buffer_id);
77ab5fd2 153 if (total_len < public->packet_len) {
064af421 154 ds_put_format(string, " (***total_len < data_len***)");
65120a8a 155 }
064af421
BP
156 }
157 ds_put_char(string, '\n');
158
77ab5fd2 159 if (public->userdata_len) {
bdcad671 160 ds_put_cstr(string, " userdata=");
77ab5fd2
BP
161 format_hex_arg(string, pin.public.userdata, pin.public.userdata_len);
162 ds_put_char(string, '\n');
163 }
164
165 if (!uuid_is_zero(&pin.bridge)) {
166 ds_put_format(string, " continuation.bridge="UUID_FMT"\n",
167 UUID_ARGS(&pin.bridge));
168 }
169
170 if (pin.n_stack) {
171 ds_put_cstr(string, " continuation.stack=");
172 for (size_t i = 0; i < pin.n_stack; i++) {
173 if (i) {
174 ds_put_char(string, ' ');
175 }
176 mf_subvalue_format(&pin.stack[i], string);
177 }
178 }
179
180 if (pin.mirrors) {
181 ds_put_format(string, " continuation.mirrors=0x%"PRIx32"\n",
182 pin.mirrors);
183 }
184
185 if (pin.conntracked) {
186 ds_put_cstr(string, " continuation.conntracked=true\n");
187 }
188
189 if (pin.actions_len) {
190 ds_put_cstr(string, " continuation.actions=");
191 ofpacts_format(pin.actions, pin.actions_len, string);
192 ds_put_char(string, '\n');
193 }
194
195 if (pin.action_set_len) {
196 ds_put_cstr(string, " continuation.action_set=");
197 ofpacts_format(pin.action_set, pin.action_set_len, string);
bdcad671
BP
198 ds_put_char(string, '\n');
199 }
200
064af421 201 if (verbosity > 0) {
77ab5fd2
BP
202 char *packet = ofp_packet_to_string(public->packet,
203 public->packet_len);
064af421
BP
204 ds_put_cstr(string, packet);
205 free(packet);
206 }
b4ccee75 207 if (verbosity > 2) {
77ab5fd2 208 ds_put_hex_dump(string, public->packet, public->packet_len, 0, false);
b4ccee75 209 }
77ab5fd2
BP
210
211 ofputil_packet_in_private_destroy(&pin);
064af421
BP
212}
213
d1e2cf21 214static void
982697a4 215ofp_print_packet_out(struct ds *string, const struct ofp_header *oh,
d1e2cf21 216 int verbosity)
064af421 217{
c6a93eb7 218 struct ofputil_packet_out po;
f25d0cf3 219 struct ofpbuf ofpacts;
c6a93eb7 220 enum ofperr error;
064af421 221
f25d0cf3 222 ofpbuf_init(&ofpacts, 64);
982697a4 223 error = ofputil_decode_packet_out(&po, oh, &ofpacts);
c6a93eb7 224 if (error) {
f25d0cf3 225 ofpbuf_uninit(&ofpacts);
c6a93eb7 226 ofp_print_error(string, error);
064af421
BP
227 return;
228 }
c6a93eb7
BP
229
230 ds_put_cstr(string, " in_port=");
231 ofputil_format_port(po.in_port, string);
232
455ecd77 233 ds_put_cstr(string, " actions=");
f25d0cf3 234 ofpacts_format(po.ofpacts, po.ofpacts_len, string);
c6a93eb7
BP
235
236 if (po.buffer_id == UINT32_MAX) {
34582733 237 ds_put_format(string, " data_len=%"PRIuSIZE, po.packet_len);
c6a93eb7
BP
238 if (verbosity > 0 && po.packet_len > 0) {
239 char *packet = ofp_packet_to_string(po.packet, po.packet_len);
064af421
BP
240 ds_put_char(string, '\n');
241 ds_put_cstr(string, packet);
242 free(packet);
243 }
b4ccee75
SH
244 if (verbosity > 2) {
245 ds_put_hex_dump(string, po.packet, po.packet_len, 0, false);
246 }
064af421 247 } else {
c6a93eb7 248 ds_put_format(string, " buffer=0x%08"PRIx32, po.buffer_id);
064af421 249 }
f25d0cf3
BP
250
251 ofpbuf_uninit(&ofpacts);
064af421
BP
252}
253
254/* qsort comparison function. */
255static int
256compare_ports(const void *a_, const void *b_)
257{
9e1fd49b
BP
258 const struct ofputil_phy_port *a = a_;
259 const struct ofputil_phy_port *b = b_;
4e022ec0
AW
260 uint16_t ap = ofp_to_u16(a->port_no);
261 uint16_t bp = ofp_to_u16(b->port_no);
064af421
BP
262
263 return ap < bp ? -1 : ap > bp;
264}
265
0ab14c8e
BP
266static void
267ofp_print_bit_names(struct ds *string, uint32_t bits,
e8fa940e
BP
268 const char *(*bit_to_name)(uint32_t bit),
269 char separator)
064af421 270{
0ab14c8e 271 int n = 0;
9e1fd49b 272 int i;
0ab14c8e
BP
273
274 if (!bits) {
275 ds_put_cstr(string, "0");
064af421
BP
276 return;
277 }
0ab14c8e 278
9e1fd49b
BP
279 for (i = 0; i < 32; i++) {
280 uint32_t bit = UINT32_C(1) << i;
281
282 if (bits & bit) {
283 const char *name = bit_to_name(bit);
284 if (name) {
285 if (n++) {
e8fa940e 286 ds_put_char(string, separator);
9e1fd49b
BP
287 }
288 ds_put_cstr(string, name);
289 bits &= ~bit;
0ab14c8e 290 }
0ab14c8e 291 }
064af421 292 }
0ab14c8e
BP
293
294 if (bits) {
f5cd6874 295 if (n) {
e8fa940e 296 ds_put_char(string, separator);
0ab14c8e
BP
297 }
298 ds_put_format(string, "0x%"PRIx32, bits);
064af421 299 }
0ab14c8e
BP
300}
301
9e1fd49b
BP
302static const char *
303netdev_feature_to_name(uint32_t bit)
304{
305 enum netdev_features f = bit;
306
307 switch (f) {
308 case NETDEV_F_10MB_HD: return "10MB-HD";
309 case NETDEV_F_10MB_FD: return "10MB-FD";
310 case NETDEV_F_100MB_HD: return "100MB-HD";
311 case NETDEV_F_100MB_FD: return "100MB-FD";
312 case NETDEV_F_1GB_HD: return "1GB-HD";
313 case NETDEV_F_1GB_FD: return "1GB-FD";
314 case NETDEV_F_10GB_FD: return "10GB-FD";
315 case NETDEV_F_40GB_FD: return "40GB-FD";
316 case NETDEV_F_100GB_FD: return "100GB-FD";
317 case NETDEV_F_1TB_FD: return "1TB-FD";
318 case NETDEV_F_OTHER: return "OTHER";
319 case NETDEV_F_COPPER: return "COPPER";
320 case NETDEV_F_FIBER: return "FIBER";
321 case NETDEV_F_AUTONEG: return "AUTO_NEG";
322 case NETDEV_F_PAUSE: return "AUTO_PAUSE";
323 case NETDEV_F_PAUSE_ASYM: return "AUTO_PAUSE_ASYM";
324 }
325
326 return NULL;
327}
328
0ab14c8e 329static void
9e1fd49b 330ofp_print_port_features(struct ds *string, enum netdev_features features)
0ab14c8e 331{
e8fa940e 332 ofp_print_bit_names(string, features, netdev_feature_to_name, ' ');
0ab14c8e
BP
333 ds_put_char(string, '\n');
334}
335
9e1fd49b
BP
336static const char *
337ofputil_port_config_to_name(uint32_t bit)
338{
339 enum ofputil_port_config pc = bit;
340
341 switch (pc) {
342 case OFPUTIL_PC_PORT_DOWN: return "PORT_DOWN";
343 case OFPUTIL_PC_NO_STP: return "NO_STP";
344 case OFPUTIL_PC_NO_RECV: return "NO_RECV";
345 case OFPUTIL_PC_NO_RECV_STP: return "NO_RECV_STP";
346 case OFPUTIL_PC_NO_FLOOD: return "NO_FLOOD";
347 case OFPUTIL_PC_NO_FWD: return "NO_FWD";
348 case OFPUTIL_PC_NO_PACKET_IN: return "NO_PACKET_IN";
349 }
350
351 return NULL;
352}
353
0ab14c8e 354static void
9e1fd49b 355ofp_print_port_config(struct ds *string, enum ofputil_port_config config)
0ab14c8e 356{
e8fa940e 357 ofp_print_bit_names(string, config, ofputil_port_config_to_name, ' ');
0ab14c8e
BP
358 ds_put_char(string, '\n');
359}
360
9e1fd49b
BP
361static const char *
362ofputil_port_state_to_name(uint32_t bit)
363{
364 enum ofputil_port_state ps = bit;
365
366 switch (ps) {
367 case OFPUTIL_PS_LINK_DOWN: return "LINK_DOWN";
368 case OFPUTIL_PS_BLOCKED: return "BLOCKED";
369 case OFPUTIL_PS_LIVE: return "LIVE";
370
371 case OFPUTIL_PS_STP_LISTEN:
372 case OFPUTIL_PS_STP_LEARN:
373 case OFPUTIL_PS_STP_FORWARD:
374 case OFPUTIL_PS_STP_BLOCK:
375 /* Handled elsewhere. */
376 return NULL;
377 }
378
379 return NULL;
380}
381
0ab14c8e 382static void
9e1fd49b 383ofp_print_port_state(struct ds *string, enum ofputil_port_state state)
0ab14c8e 384{
9e1fd49b 385 enum ofputil_port_state stp_state;
0ab14c8e
BP
386
387 /* The STP state is a 2-bit field so it doesn't fit in with the bitmask
388 * pattern. We have to special case it.
389 *
390 * OVS doesn't support STP, so this field will always be 0 if we are
391 * talking to OVS, so we'd always print STP_LISTEN in that case.
392 * Therefore, we don't print anything at all if the value is STP_LISTEN, to
393 * avoid confusing users. */
9e1fd49b 394 stp_state = state & OFPUTIL_PS_STP_MASK;
0ab14c8e 395 if (stp_state) {
9e1fd49b
BP
396 ds_put_cstr(string,
397 (stp_state == OFPUTIL_PS_STP_LEARN ? "STP_LEARN"
398 : stp_state == OFPUTIL_PS_STP_FORWARD ? "STP_FORWARD"
399 : "STP_BLOCK"));
400 state &= ~OFPUTIL_PS_STP_MASK;
0ab14c8e 401 if (state) {
e8fa940e
BP
402 ofp_print_bit_names(string, state, ofputil_port_state_to_name,
403 ' ');
0ab14c8e
BP
404 }
405 } else {
e8fa940e 406 ofp_print_bit_names(string, state, ofputil_port_state_to_name, ' ');
064af421
BP
407 }
408 ds_put_char(string, '\n');
409}
410
411static void
9e1fd49b 412ofp_print_phy_port(struct ds *string, const struct ofputil_phy_port *port)
064af421 413{
9e1fd49b 414 char name[sizeof port->name];
064af421
BP
415 int j;
416
417 memcpy(name, port->name, sizeof name);
418 for (j = 0; j < sizeof name - 1; j++) {
858f2852 419 if (!isprint((unsigned char) name[j])) {
064af421
BP
420 break;
421 }
422 }
423 name[j] = '\0';
424
425 ds_put_char(string, ' ');
9e1fd49b 426 ofputil_format_port(port->port_no, string);
0ab14c8e
BP
427 ds_put_format(string, "(%s): addr:"ETH_ADDR_FMT"\n",
428 name, ETH_ADDR_ARGS(port->hw_addr));
429
430 ds_put_cstr(string, " config: ");
9e1fd49b 431 ofp_print_port_config(string, port->config);
0ab14c8e
BP
432
433 ds_put_cstr(string, " state: ");
9e1fd49b 434 ofp_print_port_state(string, port->state);
0ab14c8e 435
064af421
BP
436 if (port->curr) {
437 ds_put_format(string, " current: ");
9e1fd49b 438 ofp_print_port_features(string, port->curr);
064af421
BP
439 }
440 if (port->advertised) {
441 ds_put_format(string, " advertised: ");
9e1fd49b 442 ofp_print_port_features(string, port->advertised);
064af421
BP
443 }
444 if (port->supported) {
445 ds_put_format(string, " supported: ");
9e1fd49b 446 ofp_print_port_features(string, port->supported);
064af421
BP
447 }
448 if (port->peer) {
449 ds_put_format(string, " peer: ");
9e1fd49b
BP
450 ofp_print_port_features(string, port->peer);
451 }
452 ds_put_format(string, " speed: %"PRIu32" Mbps now, "
453 "%"PRIu32" Mbps max\n",
454 port->curr_speed / UINT32_C(1000),
455 port->max_speed / UINT32_C(1000));
456}
457
2be393ed
JP
458/* Given a buffer 'b' that contains an array of OpenFlow ports of type
459 * 'ofp_version', writes a detailed description of each port into
460 * 'string'. */
461static void
462ofp_print_phy_ports(struct ds *string, uint8_t ofp_version,
463 struct ofpbuf *b)
464{
2be393ed 465 struct ofputil_phy_port *ports;
9b77a336
BP
466 size_t allocated_ports, n_ports;
467 int retval;
2be393ed
JP
468 size_t i;
469
9b77a336
BP
470 ports = NULL;
471 allocated_ports = 0;
472 for (n_ports = 0; ; n_ports++) {
473 if (n_ports >= allocated_ports) {
474 ports = x2nrealloc(ports, &allocated_ports, sizeof *ports);
475 }
2be393ed 476
9b77a336
BP
477 retval = ofputil_pull_phy_port(ofp_version, b, &ports[n_ports]);
478 if (retval) {
479 break;
2be393ed
JP
480 }
481 }
9b77a336 482
2be393ed
JP
483 qsort(ports, n_ports, sizeof *ports, compare_ports);
484 for (i = 0; i < n_ports; i++) {
485 ofp_print_phy_port(string, &ports[i]);
486 }
2be393ed 487 free(ports);
9b77a336
BP
488
489 if (retval != EOF) {
490 ofp_print_error(string, retval);
491 }
2be393ed
JP
492}
493
9e1fd49b
BP
494static const char *
495ofputil_capabilities_to_name(uint32_t bit)
496{
497 enum ofputil_capabilities capabilities = bit;
498
499 switch (capabilities) {
500 case OFPUTIL_C_FLOW_STATS: return "FLOW_STATS";
501 case OFPUTIL_C_TABLE_STATS: return "TABLE_STATS";
502 case OFPUTIL_C_PORT_STATS: return "PORT_STATS";
503 case OFPUTIL_C_IP_REASM: return "IP_REASM";
504 case OFPUTIL_C_QUEUE_STATS: return "QUEUE_STATS";
505 case OFPUTIL_C_ARP_MATCH_IP: return "ARP_MATCH_IP";
506 case OFPUTIL_C_STP: return "STP";
507 case OFPUTIL_C_GROUP_STATS: return "GROUP_STATS";
60202987 508 case OFPUTIL_C_PORT_BLOCKED: return "PORT_BLOCKED";
9e1fd49b
BP
509 }
510
511 return NULL;
512}
513
064af421 514static void
982697a4 515ofp_print_switch_features(struct ds *string, const struct ofp_header *oh)
064af421 516{
9e1fd49b 517 struct ofputil_switch_features features;
0a2869d5
BP
518 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
519 enum ofperr error = ofputil_pull_switch_features(&b, &features);
9e1fd49b
BP
520 if (error) {
521 ofp_print_error(string, error);
522 return;
523 }
064af421 524
9e1fd49b 525 ds_put_format(string, " dpid:%016"PRIx64"\n", features.datapath_id);
2e1ae200
JR
526
527 ds_put_format(string, "n_tables:%"PRIu8", n_buffers:%"PRIu32,
9e1fd49b 528 features.n_tables, features.n_buffers);
2e1ae200
JR
529 if (features.auxiliary_id) {
530 ds_put_format(string, ", auxiliary_id:%"PRIu8, features.auxiliary_id);
531 }
532 ds_put_char(string, '\n');
064af421 533
9e1fd49b
BP
534 ds_put_cstr(string, "capabilities: ");
535 ofp_print_bit_names(string, features.capabilities,
e8fa940e 536 ofputil_capabilities_to_name, ' ');
9e1fd49b
BP
537 ds_put_char(string, '\n');
538
210d8d9c
SH
539 switch ((enum ofp_version)oh->version) {
540 case OFP10_VERSION:
541 ds_put_cstr(string, "actions: ");
08d1e234 542 ofpact_bitmap_format(features.ofpacts, string);
210d8d9c
SH
543 ds_put_char(string, '\n');
544 break;
545 case OFP11_VERSION:
546 case OFP12_VERSION:
547 break;
2e1ae200 548 case OFP13_VERSION:
c37c0382 549 case OFP14_VERSION:
42dccab5 550 case OFP15_VERSION:
b79d45a1 551 case OFP16_VERSION:
2e1ae200 552 return; /* no ports in ofp13_switch_features */
210d8d9c 553 default:
428b2edd 554 OVS_NOT_REACHED();
210d8d9c 555 }
9e1fd49b 556
982697a4 557 ofp_print_phy_ports(string, oh->version, &b);
064af421
BP
558}
559
064af421 560static void
ad99e2ed
BP
561ofp_print_switch_config(struct ds *string,
562 const struct ofputil_switch_config *config)
064af421 563{
ad99e2ed
BP
564 ds_put_format(string, " frags=%s",
565 ofputil_frag_handling_to_string(config->frag));
064af421 566
ad99e2ed 567 if (config->invalid_ttl_to_controller > 0) {
f0fd1a17 568 ds_put_format(string, " invalid_ttl_to_controller");
f0fd1a17
PS
569 }
570
ad99e2ed
BP
571 ds_put_format(string, " miss_send_len=%"PRIu16"\n", config->miss_send_len);
572}
573
574static void
575ofp_print_set_config(struct ds *string, const struct ofp_header *oh)
576{
577 struct ofputil_switch_config config;
578 enum ofperr error;
579
580 error = ofputil_decode_set_config(oh, &config);
581 if (error) {
582 ofp_print_error(string, error);
583 return;
064af421 584 }
ad99e2ed
BP
585 ofp_print_switch_config(string, &config);
586}
064af421 587
ad99e2ed
BP
588static void
589ofp_print_get_config_reply(struct ds *string, const struct ofp_header *oh)
590{
591 struct ofputil_switch_config config;
592 ofputil_decode_get_config_reply(oh, &config);
593 ofp_print_switch_config(string, &config);
064af421
BP
594}
595
596static void print_wild(struct ds *string, const char *leader, int is_wild,
d295e8e9 597 int verbosity, const char *format, ...)
cab50449 598 OVS_PRINTF_FORMAT(5, 6);
064af421
BP
599
600static void print_wild(struct ds *string, const char *leader, int is_wild,
d295e8e9 601 int verbosity, const char *format, ...)
064af421
BP
602{
603 if (is_wild && verbosity < 2) {
604 return;
605 }
606 ds_put_cstr(string, leader);
607 if (!is_wild) {
608 va_list args;
609
610 va_start(args, format);
611 ds_put_format_valist(string, format, args);
612 va_end(args);
613 } else {
614 ds_put_char(string, '*');
615 }
616 ds_put_char(string, ',');
617}
618
e1db42d6
JR
619static void
620print_wild_port(struct ds *string, const char *leader, int is_wild,
4e022ec0 621 int verbosity, ofp_port_t port)
e1db42d6
JR
622{
623 if (is_wild && verbosity < 2) {
624 return;
625 }
626 ds_put_cstr(string, leader);
627 if (!is_wild) {
628 ofputil_format_port(port, string);
629 } else {
630 ds_put_char(string, '*');
631 }
632 ds_put_char(string, ',');
633}
634
064af421 635static void
dbba996b 636print_ip_netmask(struct ds *string, const char *leader, ovs_be32 ip,
064af421
BP
637 uint32_t wild_bits, int verbosity)
638{
639 if (wild_bits >= 32 && verbosity < 2) {
640 return;
641 }
642 ds_put_cstr(string, leader);
643 if (wild_bits < 32) {
ed36537e 644 ds_put_format(string, IP_FMT, IP_ARGS(ip));
064af421
BP
645 if (wild_bits) {
646 ds_put_format(string, "/%d", 32 - wild_bits);
647 }
648 } else {
649 ds_put_char(string, '*');
650 }
651 ds_put_char(string, ',');
652}
653
4f2cad2c 654void
eec25dc1 655ofp10_match_print(struct ds *f, const struct ofp10_match *om, int verbosity)
064af421 656{
eec25dc1 657 char *s = ofp10_match_to_string(om, verbosity);
064af421
BP
658 ds_put_cstr(f, s);
659 free(s);
660}
661
662char *
eec25dc1 663ofp10_match_to_string(const struct ofp10_match *om, int verbosity)
064af421
BP
664{
665 struct ds f = DS_EMPTY_INITIALIZER;
666 uint32_t w = ntohl(om->wildcards);
667 bool skip_type = false;
668 bool skip_proto = false;
669
eec25dc1 670 if (!(w & OFPFW10_DL_TYPE)) {
064af421
BP
671 skip_type = true;
672 if (om->dl_type == htons(ETH_TYPE_IP)) {
eec25dc1 673 if (!(w & OFPFW10_NW_PROTO)) {
064af421 674 skip_proto = true;
6767a2cc 675 if (om->nw_proto == IPPROTO_ICMP) {
064af421 676 ds_put_cstr(&f, "icmp,");
6767a2cc 677 } else if (om->nw_proto == IPPROTO_TCP) {
064af421 678 ds_put_cstr(&f, "tcp,");
6767a2cc 679 } else if (om->nw_proto == IPPROTO_UDP) {
064af421 680 ds_put_cstr(&f, "udp,");
0d56eaf2
JS
681 } else if (om->nw_proto == IPPROTO_SCTP) {
682 ds_put_cstr(&f, "sctp,");
064af421
BP
683 } else {
684 ds_put_cstr(&f, "ip,");
685 skip_proto = false;
686 }
687 } else {
688 ds_put_cstr(&f, "ip,");
689 }
690 } else if (om->dl_type == htons(ETH_TYPE_ARP)) {
691 ds_put_cstr(&f, "arp,");
8087f5ff
MM
692 } else if (om->dl_type == htons(ETH_TYPE_RARP)){
693 ds_put_cstr(&f, "rarp,");
b02475c5
SH
694 } else if (om->dl_type == htons(ETH_TYPE_MPLS)) {
695 ds_put_cstr(&f, "mpls,");
696 } else if (om->dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
697 ds_put_cstr(&f, "mplsm,");
064af421
BP
698 } else {
699 skip_type = false;
700 }
701 }
e1db42d6 702 print_wild_port(&f, "in_port=", w & OFPFW10_IN_PORT, verbosity,
4e022ec0 703 u16_to_ofp(ntohs(om->in_port)));
eec25dc1 704 print_wild(&f, "dl_vlan=", w & OFPFW10_DL_VLAN, verbosity,
6a1f89c8 705 "%d", ntohs(om->dl_vlan));
eec25dc1 706 print_wild(&f, "dl_vlan_pcp=", w & OFPFW10_DL_VLAN_PCP, verbosity,
959a2ecd 707 "%d", om->dl_vlan_pcp);
eec25dc1 708 print_wild(&f, "dl_src=", w & OFPFW10_DL_SRC, verbosity,
064af421 709 ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
eec25dc1 710 print_wild(&f, "dl_dst=", w & OFPFW10_DL_DST, verbosity,
064af421
BP
711 ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_dst));
712 if (!skip_type) {
eec25dc1 713 print_wild(&f, "dl_type=", w & OFPFW10_DL_TYPE, verbosity,
064af421
BP
714 "0x%04x", ntohs(om->dl_type));
715 }
716 print_ip_netmask(&f, "nw_src=", om->nw_src,
eec25dc1
BP
717 (w & OFPFW10_NW_SRC_MASK) >> OFPFW10_NW_SRC_SHIFT,
718 verbosity);
064af421 719 print_ip_netmask(&f, "nw_dst=", om->nw_dst,
eec25dc1
BP
720 (w & OFPFW10_NW_DST_MASK) >> OFPFW10_NW_DST_SHIFT,
721 verbosity);
064af421 722 if (!skip_proto) {
8087f5ff
MM
723 if (om->dl_type == htons(ETH_TYPE_ARP) ||
724 om->dl_type == htons(ETH_TYPE_RARP)) {
eec25dc1 725 print_wild(&f, "arp_op=", w & OFPFW10_NW_PROTO, verbosity,
fb892732
JP
726 "%u", om->nw_proto);
727 } else {
eec25dc1 728 print_wild(&f, "nw_proto=", w & OFPFW10_NW_PROTO, verbosity,
fb892732
JP
729 "%u", om->nw_proto);
730 }
064af421 731 }
eec25dc1 732 print_wild(&f, "nw_tos=", w & OFPFW10_NW_TOS, verbosity,
1a960c80 733 "%u", om->nw_tos);
6767a2cc 734 if (om->nw_proto == IPPROTO_ICMP) {
eec25dc1 735 print_wild(&f, "icmp_type=", w & OFPFW10_ICMP_TYPE, verbosity,
3ee8a9f0 736 "%d", ntohs(om->tp_src));
eec25dc1 737 print_wild(&f, "icmp_code=", w & OFPFW10_ICMP_CODE, verbosity,
3ee8a9f0 738 "%d", ntohs(om->tp_dst));
064af421 739 } else {
eec25dc1 740 print_wild(&f, "tp_src=", w & OFPFW10_TP_SRC, verbosity,
064af421 741 "%d", ntohs(om->tp_src));
eec25dc1 742 print_wild(&f, "tp_dst=", w & OFPFW10_TP_DST, verbosity,
064af421
BP
743 "%d", ntohs(om->tp_dst));
744 }
dbf9e6d9 745 ds_chomp(&f, ',');
064af421
BP
746 return ds_cstr(&f);
747}
748
2e1ae200 749static void
0fb88c18 750ofp_print_flow_flags(struct ds *s, enum ofputil_flow_mod_flags flags)
2e1ae200 751{
0fb88c18 752 if (flags & OFPUTIL_FF_SEND_FLOW_REM) {
2e1ae200
JR
753 ds_put_cstr(s, "send_flow_rem ");
754 }
0fb88c18 755 if (flags & OFPUTIL_FF_CHECK_OVERLAP) {
2e1ae200
JR
756 ds_put_cstr(s, "check_overlap ");
757 }
0fb88c18 758 if (flags & OFPUTIL_FF_RESET_COUNTS) {
2e1ae200
JR
759 ds_put_cstr(s, "reset_counts ");
760 }
0fb88c18 761 if (flags & OFPUTIL_FF_NO_PKT_COUNTS) {
2e1ae200
JR
762 ds_put_cstr(s, "no_packet_counts ");
763 }
0fb88c18 764 if (flags & OFPUTIL_FF_NO_BYT_COUNTS) {
2e1ae200
JR
765 ds_put_cstr(s, "no_byte_counts ");
766 }
adcf00ba
AZ
767 if (flags & OFPUTIL_FF_HIDDEN_FIELDS) {
768 ds_put_cstr(s, "allow_hidden_fields ");
769 }
770 if (flags & OFPUTIL_FF_NO_READONLY) {
771 ds_put_cstr(s, "no_readonly_table ");
772 }
2e1ae200
JR
773}
774
064af421 775static void
982697a4 776ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh, int verbosity)
064af421 777{
a9a2da38 778 struct ofputil_flow_mod fm;
f25d0cf3 779 struct ofpbuf ofpacts;
f904747b 780 bool need_priority;
90bf1e07 781 enum ofperr error;
982697a4 782 enum ofpraw raw;
981c5fdd
SH
783 enum ofputil_protocol protocol;
784
785 protocol = ofputil_protocol_from_ofp_version(oh->version);
786 protocol = ofputil_protocol_set_tid(protocol, true);
064af421 787
f25d0cf3 788 ofpbuf_init(&ofpacts, 64);
7e9f8266
BP
789 error = ofputil_decode_flow_mod(&fm, oh, protocol, &ofpacts,
790 OFPP_MAX, 255);
7fa91113 791 if (error) {
f25d0cf3 792 ofpbuf_uninit(&ofpacts);
7fa91113
BP
793 ofp_print_error(s, error);
794 return;
3ff4f871
BP
795 }
796
7fa91113
BP
797 ds_put_char(s, ' ');
798 switch (fm.command) {
064af421 799 case OFPFC_ADD:
7fa91113 800 ds_put_cstr(s, "ADD");
064af421
BP
801 break;
802 case OFPFC_MODIFY:
7fa91113 803 ds_put_cstr(s, "MOD");
064af421
BP
804 break;
805 case OFPFC_MODIFY_STRICT:
7fa91113 806 ds_put_cstr(s, "MOD_STRICT");
064af421
BP
807 break;
808 case OFPFC_DELETE:
7fa91113 809 ds_put_cstr(s, "DEL");
064af421
BP
810 break;
811 case OFPFC_DELETE_STRICT:
7fa91113 812 ds_put_cstr(s, "DEL_STRICT");
064af421
BP
813 break;
814 default:
7fa91113
BP
815 ds_put_format(s, "cmd:%d", fm.command);
816 }
6c1491fb 817 if (fm.table_id != 0) {
e896c2d4 818 ds_put_format(s, " table:%d", fm.table_id);
6c1491fb 819 }
7fa91113
BP
820
821 ds_put_char(s, ' ');
982697a4
BP
822 ofpraw_decode(&raw, oh);
823 if (verbosity >= 3 && raw == OFPRAW_OFPT10_FLOW_MOD) {
35805806 824 const struct ofp10_flow_mod *ofm = ofpmsg_body(oh);
eec25dc1 825 ofp10_match_print(s, &ofm->match, verbosity);
f904747b
BP
826
827 /* ofp_print_match() doesn't print priority. */
828 need_priority = true;
982697a4
BP
829 } else if (verbosity >= 3 && raw == OFPRAW_NXT_FLOW_MOD) {
830 const struct nx_flow_mod *nfm = ofpmsg_body(oh);
7fa91113 831 const void *nxm = nfm + 1;
f904747b
BP
832 char *nxm_s;
833
834 nxm_s = nx_match_to_string(nxm, ntohs(nfm->match_len));
7fa91113
BP
835 ds_put_cstr(s, nxm_s);
836 free(nxm_s);
f904747b
BP
837
838 /* nx_match_to_string() doesn't print priority. */
839 need_priority = true;
7fa91113 840 } else {
81a76618 841 match_format(&fm.match, s, fm.priority);
f904747b 842
81a76618 843 /* match_format() does print priority. */
f904747b 844 need_priority = false;
3ff4f871 845 }
7fa91113
BP
846
847 if (ds_last(s) != ' ') {
848 ds_put_char(s, ' ');
3ff4f871 849 }
b8266395 850 if (fm.new_cookie != htonll(0) && fm.new_cookie != OVS_BE64_MAX) {
623e1caf
JP
851 ds_put_format(s, "cookie:0x%"PRIx64" ", ntohll(fm.new_cookie));
852 }
853 if (fm.cookie_mask != htonll(0)) {
854 ds_put_format(s, "cookie:0x%"PRIx64"/0x%"PRIx64" ",
855 ntohll(fm.cookie), ntohll(fm.cookie_mask));
3ff4f871 856 }
7fa91113
BP
857 if (fm.idle_timeout != OFP_FLOW_PERMANENT) {
858 ds_put_format(s, "idle:%"PRIu16" ", fm.idle_timeout);
064af421 859 }
7fa91113
BP
860 if (fm.hard_timeout != OFP_FLOW_PERMANENT) {
861 ds_put_format(s, "hard:%"PRIu16" ", fm.hard_timeout);
3ff4f871 862 }
ca26eb44
RB
863 if (fm.importance != 0) {
864 ds_put_format(s, "importance:%"PRIu16" ", fm.importance);
865 }
81a76618
BP
866 if (fm.priority != OFP_DEFAULT_PRIORITY && need_priority) {
867 ds_put_format(s, "pri:%"PRIu16" ", fm.priority);
3ff4f871 868 }
7fa91113
BP
869 if (fm.buffer_id != UINT32_MAX) {
870 ds_put_format(s, "buf:0x%"PRIx32" ", fm.buffer_id);
3ff4f871 871 }
7f05e7ab 872 if (fm.out_port != OFPP_ANY) {
de0f16bc
BP
873 ds_put_format(s, "out_port:");
874 ofputil_format_port(fm.out_port, s);
875 ds_put_char(s, ' ');
876 }
0fb88c18
BP
877
878 if (oh->version == OFP10_VERSION || oh->version == OFP11_VERSION) {
879 /* Don't print the reset_counts flag for OF1.0 and OF1.1 because those
880 * versions don't really have such a flag and printing one is likely to
881 * confuse people. */
882 fm.flags &= ~OFPUTIL_FF_RESET_COUNTS;
7fa91113 883 }
0fb88c18 884 ofp_print_flow_flags(s, fm.flags);
7fa91113 885
455ecd77 886 ds_put_cstr(s, "actions=");
f25d0cf3
BP
887 ofpacts_format(fm.ofpacts, fm.ofpacts_len, s);
888 ofpbuf_uninit(&ofpacts);
064af421
BP
889}
890
09862ec6
BP
891static void
892ofp_print_duration(struct ds *string, unsigned int sec, unsigned int nsec)
893{
894 ds_put_format(string, "%u", sec);
b1634591
BP
895
896 /* If there are no fractional seconds, don't print any decimals.
897 *
898 * If the fractional seconds can be expressed exactly as milliseconds,
899 * print 3 decimals. Open vSwitch provides millisecond precision for most
900 * time measurements, so printing 3 decimals every time makes it easier to
901 * spot real changes in flow dumps that refresh themselves quickly.
902 *
903 * If the fractional seconds are more precise than milliseconds, print the
904 * number of decimals needed to express them exactly.
905 */
09862ec6 906 if (nsec > 0) {
b1634591
BP
907 unsigned int msec = nsec / 1000000;
908 if (msec * 1000000 == nsec) {
909 ds_put_format(string, ".%03u", msec);
910 } else {
911 ds_put_format(string, ".%09u", nsec);
912 while (string->string[string->length - 1] == '0') {
913 string->length--;
914 }
09862ec6
BP
915 }
916 }
917 ds_put_char(string, 's');
918}
919
8961699e
BP
920/* Returns a string form of 'reason'. The return value is either a statically
921 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
922 * 'bufsize' should be at least OFP_FLOW_REMOVED_REASON_BUFSIZE. */
923#define OFP_FLOW_REMOVED_REASON_BUFSIZE (INT_STRLEN(int) + 1)
80d5aefd 924static const char *
8961699e
BP
925ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason,
926 char *reasonbuf, size_t bufsize)
80d5aefd 927{
80d5aefd
BP
928 switch (reason) {
929 case OFPRR_IDLE_TIMEOUT:
930 return "idle";
931 case OFPRR_HARD_TIMEOUT:
932 return "hard";
933 case OFPRR_DELETE:
934 return "delete";
04f68eb2
SH
935 case OFPRR_GROUP_DELETE:
936 return "group_delete";
1d31ece9
BP
937 case OFPRR_EVICTION:
938 return "eviction";
638a19b0
JR
939 case OFPRR_METER_DELETE:
940 return "meter_delete";
f695ebfa 941 case OVS_OFPRR_NONE:
80d5aefd 942 default:
8961699e
BP
943 snprintf(reasonbuf, bufsize, "%d", (int) reason);
944 return reasonbuf;
80d5aefd
BP
945 }
946}
947
064af421 948static void
9b045a0c 949ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
064af421 950{
8961699e 951 char reasonbuf[OFP_FLOW_REMOVED_REASON_BUFSIZE];
9b045a0c 952 struct ofputil_flow_removed fr;
90bf1e07 953 enum ofperr error;
9b045a0c 954
b78f6b77 955 error = ofputil_decode_flow_removed(&fr, oh);
9b045a0c
BP
956 if (error) {
957 ofp_print_error(string, error);
958 return;
959 }
960
fbd76b2e 961 ds_put_char(string, ' ');
81a76618 962 match_format(&fr.match, string, fr.priority);
9b045a0c 963
80d5aefd 964 ds_put_format(string, " reason=%s",
8961699e
BP
965 ofp_flow_removed_reason_to_string(fr.reason, reasonbuf,
966 sizeof reasonbuf));
3ff4f871 967
95216219
SH
968 if (fr.table_id != 255) {
969 ds_put_format(string, " table_id=%"PRIu8, fr.table_id);
970 }
971
9b045a0c
BP
972 if (fr.cookie != htonll(0)) {
973 ds_put_format(string, " cookie:0x%"PRIx64, ntohll(fr.cookie));
3ff4f871 974 }
09862ec6 975 ds_put_cstr(string, " duration");
9b045a0c 976 ofp_print_duration(string, fr.duration_sec, fr.duration_nsec);
fa2bad0f
BP
977 ds_put_format(string, " idle%"PRIu16, fr.idle_timeout);
978 if (fr.hard_timeout) {
979 /* The hard timeout was only added in OF1.2, so only print it if it is
980 * actually in use to avoid gratuitous change to the formatting. */
981 ds_put_format(string, " hard%"PRIu16, fr.hard_timeout);
982 }
983 ds_put_format(string, " pkts%"PRIu64" bytes%"PRIu64"\n",
984 fr.packet_count, fr.byte_count);
064af421
BP
985}
986
987static void
9e1fd49b 988ofp_print_port_mod(struct ds *string, const struct ofp_header *oh)
064af421 989{
9e1fd49b
BP
990 struct ofputil_port_mod pm;
991 enum ofperr error;
992
18cc69d9 993 error = ofputil_decode_port_mod(oh, &pm, true);
9e1fd49b
BP
994 if (error) {
995 ofp_print_error(string, error);
996 return;
997 }
998
3e461c2c 999 ds_put_cstr(string, " port: ");
e1db42d6
JR
1000 ofputil_format_port(pm.port_no, string);
1001 ds_put_format(string, ": addr:"ETH_ADDR_FMT"\n",
1002 ETH_ADDR_ARGS(pm.hw_addr));
9e1fd49b 1003
e1db42d6 1004 ds_put_cstr(string, " config: ");
9e1fd49b
BP
1005 ofp_print_port_config(string, pm.config);
1006
e1db42d6 1007 ds_put_cstr(string, " mask: ");
9e1fd49b
BP
1008 ofp_print_port_config(string, pm.mask);
1009
e1db42d6 1010 ds_put_cstr(string, " advertise: ");
9e1fd49b
BP
1011 if (pm.advertise) {
1012 ofp_print_port_features(string, pm.advertise);
064af421 1013 } else {
e1db42d6 1014 ds_put_cstr(string, "UNCHANGED\n");
064af421
BP
1015 }
1016}
1017
82c22d34
BP
1018static const char *
1019ofputil_table_miss_to_string(enum ofputil_table_miss miss)
918f2b82 1020{
3c1bb396 1021 switch (miss) {
82c22d34
BP
1022 case OFPUTIL_TABLE_MISS_DEFAULT: return "default";
1023 case OFPUTIL_TABLE_MISS_CONTROLLER: return "controller";
1024 case OFPUTIL_TABLE_MISS_CONTINUE: return "continue";
1025 case OFPUTIL_TABLE_MISS_DROP: return "drop";
1026 default: return "***error***";
1027 }
1028}
1029
1030static const char *
1031ofputil_table_eviction_to_string(enum ofputil_table_eviction eviction)
1032{
1033 switch (eviction) {
1034 case OFPUTIL_TABLE_EVICTION_DEFAULT: return "default";
1035 case OFPUTIL_TABLE_EVICTION_ON: return "on";
1036 case OFPUTIL_TABLE_EVICTION_OFF: return "off";
1037 default: return "***error***";
1038 }
1039
1040}
1041
1042static const char *
1043ofputil_eviction_flag_to_string(uint32_t bit)
1044{
1045 enum ofp14_table_mod_prop_eviction_flag eviction_flag = bit;
1046
1047 switch (eviction_flag) {
1048 case OFPTMPEF14_OTHER: return "OTHER";
1049 case OFPTMPEF14_IMPORTANCE: return "IMPORTANCE";
1050 case OFPTMPEF14_LIFETIME: return "LIFETIME";
1051 }
1052
1053 return NULL;
1054}
1055
1056/* Appends to 'string' a description of the bitmap of OFPTMPEF14_* values in
1057 * 'eviction_flags'. */
1058static void
1059ofputil_put_eviction_flags(struct ds *string, uint32_t eviction_flags)
1060{
1061 if (eviction_flags != UINT32_MAX) {
1062 ofp_print_bit_names(string, eviction_flags,
1063 ofputil_eviction_flag_to_string, '|');
1064 } else {
1065 ds_put_cstr(string, "(default)");
918f2b82
AZ
1066 }
1067}
1068
de7d3c07
SJ
1069static const char *
1070ofputil_table_vacancy_to_string(enum ofputil_table_vacancy vacancy)
1071{
1072 switch (vacancy) {
1073 case OFPUTIL_TABLE_VACANCY_DEFAULT: return "default";
1074 case OFPUTIL_TABLE_VACANCY_ON: return "on";
1075 case OFPUTIL_TABLE_VACANCY_OFF: return "off";
1076 default: return "***error***";
1077 }
1078
1079}
1080
918f2b82
AZ
1081static void
1082ofp_print_table_mod(struct ds *string, const struct ofp_header *oh)
1083{
1084 struct ofputil_table_mod pm;
1085 enum ofperr error;
1086
1087 error = ofputil_decode_table_mod(oh, &pm);
1088 if (error) {
1089 ofp_print_error(string, error);
1090 return;
1091 }
1092
1093 if (pm.table_id == 0xff) {
1094 ds_put_cstr(string, " table_id: ALL_TABLES");
1095 } else {
1096 ds_put_format(string, " table_id=%"PRIu8, pm.table_id);
1097 }
1098
82c22d34
BP
1099 if (pm.miss != OFPUTIL_TABLE_MISS_DEFAULT) {
1100 ds_put_format(string, ", flow_miss_config=%s",
1101 ofputil_table_miss_to_string(pm.miss));
1102 }
1103 if (pm.eviction != OFPUTIL_TABLE_EVICTION_DEFAULT) {
1104 ds_put_format(string, ", eviction=%s",
1105 ofputil_table_eviction_to_string(pm.eviction));
1106 }
1107 if (pm.eviction_flags != UINT32_MAX) {
1108 ds_put_cstr(string, "eviction_flags=");
1109 ofputil_put_eviction_flags(string, pm.eviction_flags);
3c1bb396 1110 }
de7d3c07
SJ
1111 if (pm.vacancy != OFPUTIL_TABLE_VACANCY_DEFAULT) {
1112 ds_put_format(string, ", vacancy=%s",
1113 ofputil_table_vacancy_to_string(pm.vacancy));
1114 if (pm.vacancy == OFPUTIL_TABLE_VACANCY_ON) {
1115 ds_put_format(string, " vacancy:%"PRIu8""
1116 ",%"PRIu8"", pm.table_vacancy.vacancy_down,
1117 pm.table_vacancy.vacancy_up);
1118 }
1119 }
918f2b82
AZ
1120}
1121
03c72922
BP
1122/* This function will print the Table description properties. */
1123static void
1124ofp_print_table_desc(struct ds *string, const struct ofputil_table_desc *td)
1125{
1126 ds_put_format(string, "\n table %"PRIu8, td->table_id);
1127 ds_put_cstr(string, ":\n");
1128 ds_put_format(string, " eviction=%s eviction_flags=",
1129 ofputil_table_eviction_to_string(td->eviction));
1130 ofputil_put_eviction_flags(string, td->eviction_flags);
1131 ds_put_char(string, '\n');
bab86012
SJ
1132 ds_put_format(string, " vacancy=%s",
1133 ofputil_table_vacancy_to_string(td->vacancy));
1134 if (td->vacancy == OFPUTIL_TABLE_VACANCY_ON) {
1135 ds_put_format(string, " vacancy_down=%"PRIu8"%%",
1136 td->table_vacancy.vacancy_down);
1137 ds_put_format(string, " vacancy_up=%"PRIu8"%%",
1138 td->table_vacancy.vacancy_up);
1139 ds_put_format(string, " vacancy=%"PRIu8"%%",
1140 td->table_vacancy.vacancy);
1141 }
1142 ds_put_char(string, '\n');
03c72922
BP
1143}
1144
6c6eedc5
SJ
1145static void
1146ofp_print_table_status_message(struct ds *string, const struct ofp_header *oh)
1147{
1148 struct ofputil_table_status ts;
1149 enum ofperr error;
1150
1151 error = ofputil_decode_table_status(oh, &ts);
1152 if (error) {
1153 ofp_print_error(string, error);
1154 return;
1155 }
1156
1157 if (ts.reason == OFPTR_VACANCY_DOWN) {
1158 ds_put_format(string, " reason=VACANCY_DOWN");
1159 } else if (ts.reason == OFPTR_VACANCY_UP) {
1160 ds_put_format(string, " reason=VACANCY_UP");
1161 }
1162
1163 ds_put_format(string, "\ntable_desc:-");
1164 ofp_print_table_desc(string, &ts.desc);
1165}
1166
e8f9a7bb
VG
1167static void
1168ofp_print_queue_get_config_request(struct ds *string,
1169 const struct ofp_header *oh)
1170{
1171 enum ofperr error;
1172 ofp_port_t port;
e016fb63 1173 uint32_t queue;
e8f9a7bb 1174
e016fb63 1175 error = ofputil_decode_queue_get_config_request(oh, &port, &queue);
e8f9a7bb
VG
1176 if (error) {
1177 ofp_print_error(string, error);
1178 return;
1179 }
1180
1181 ds_put_cstr(string, " port=");
1182 ofputil_format_port(port, string);
e016fb63
BP
1183
1184 if (queue != OFPQ_ALL) {
1185 ds_put_cstr(string, " queue=");
1186 ofp_print_queue_name(string, queue);
1187 }
e8f9a7bb
VG
1188}
1189
1190static void
1191print_queue_rate(struct ds *string, const char *name, unsigned int rate)
1192{
1193 if (rate <= 1000) {
1194 ds_put_format(string, " %s:%u.%u%%", name, rate / 10, rate % 10);
1195 } else if (rate < UINT16_MAX) {
1196 ds_put_format(string, " %s:(disabled)", name);
1197 }
1198}
1199
a28239c0
BP
1200/* qsort comparison function. */
1201static int
1202compare_queues(const void *a_, const void *b_)
1203{
1204 const struct ofputil_queue_config *a = a_;
1205 const struct ofputil_queue_config *b = b_;
1206
1207 uint16_t ap = ofp_to_u16(a->port);
1208 uint16_t bp = ofp_to_u16(b->port);
1209 if (ap != bp) {
1210 return ap < bp ? -1 : 1;
1211 }
1212
1213 uint32_t aq = a->queue;
1214 uint32_t bq = b->queue;
1215 return aq < bq ? -1 : aq > bq;
1216}
1217
e8f9a7bb
VG
1218static void
1219ofp_print_queue_get_config_reply(struct ds *string,
1220 const struct ofp_header *oh)
1221{
0a2869d5 1222 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
e8f9a7bb 1223
a28239c0
BP
1224 struct ofputil_queue_config *queues = NULL;
1225 size_t allocated_queues = 0;
1226 size_t n = 0;
e8f9a7bb 1227
a28239c0
BP
1228 int retval = 0;
1229 for (;;) {
1230 if (n >= allocated_queues) {
1231 queues = x2nrealloc(queues, &allocated_queues, sizeof *queues);
1232 }
1233 retval = ofputil_pull_queue_get_config_reply(&b, &queues[n]);
e8f9a7bb 1234 if (retval) {
e8f9a7bb
VG
1235 break;
1236 }
a28239c0
BP
1237 n++;
1238 }
e8f9a7bb 1239
a28239c0
BP
1240 qsort(queues, n, sizeof *queues, compare_queues);
1241
1242 ds_put_char(string, ' ');
1243
1244 ofp_port_t port = 0;
1245 for (const struct ofputil_queue_config *q = queues; q < &queues[n]; q++) {
1246 if (q->port != port) {
1247 port = q->port;
e016fb63
BP
1248
1249 ds_put_cstr(string, "port=");
1250 ofputil_format_port(port, string);
1251 ds_put_char(string, '\n');
1252 }
1253
a28239c0
BP
1254 ds_put_format(string, "queue %"PRIu32":", q->queue);
1255 print_queue_rate(string, "min_rate", q->min_rate);
1256 print_queue_rate(string, "max_rate", q->max_rate);
e8f9a7bb
VG
1257 ds_put_char(string, '\n');
1258 }
a28239c0
BP
1259
1260 if (retval != EOF) {
1261 ofp_print_error(string, retval);
1262 }
1263 ds_chomp(string, ' ');
e8f9a7bb
VG
1264}
1265
638a19b0
JR
1266static void
1267ofp_print_meter_flags(struct ds *s, uint16_t flags)
1268{
1269 if (flags & OFPMF13_KBPS) {
1270 ds_put_cstr(s, "kbps ");
1271 }
1272 if (flags & OFPMF13_PKTPS) {
1273 ds_put_cstr(s, "pktps ");
1274 }
1275 if (flags & OFPMF13_BURST) {
1276 ds_put_cstr(s, "burst ");
1277 }
1278 if (flags & OFPMF13_STATS) {
1279 ds_put_cstr(s, "stats ");
1280 }
1281
1282 flags &= ~(OFPMF13_KBPS | OFPMF13_PKTPS | OFPMF13_BURST | OFPMF13_STATS);
1283 if (flags) {
1284 ds_put_format(s, "flags:0x%"PRIx16" ", flags);
1285 }
1286}
1287
1288static void
1289ofp_print_meter_band(struct ds *s, uint16_t flags,
1290 const struct ofputil_meter_band *mb)
1291{
1292 ds_put_cstr(s, "\ntype=");
1293 switch (mb->type) {
1294 case OFPMBT13_DROP:
1295 ds_put_cstr(s, "drop");
1296 break;
1297 case OFPMBT13_DSCP_REMARK:
1298 ds_put_cstr(s, "dscp_remark");
1299 break;
1300 default:
1301 ds_put_format(s, "%u", mb->type);
1302 }
1303
1304 ds_put_format(s, " rate=%"PRIu32, mb->rate);
1305
1306 if (flags & OFPMF13_BURST) {
1307 ds_put_format(s, " burst_size=%"PRIu32, mb->burst_size);
1308 }
1309 if (mb->type == OFPMBT13_DSCP_REMARK) {
1310 ds_put_format(s, " prec_level=%"PRIu8, mb->prec_level);
1311 }
1312}
1313
1314static void
1315ofp_print_meter_stats(struct ds *s, const struct ofputil_meter_stats *ms)
1316{
1317 uint16_t i;
1318
1319 ds_put_format(s, "meter:%"PRIu32" ", ms->meter_id);
1320 ds_put_format(s, "flow_count:%"PRIu32" ", ms->flow_count);
1321 ds_put_format(s, "packet_in_count:%"PRIu64" ", ms->packet_in_count);
1322 ds_put_format(s, "byte_in_count:%"PRIu64" ", ms->byte_in_count);
1323 ds_put_cstr(s, "duration:");
1324 ofp_print_duration(s, ms->duration_sec, ms->duration_nsec);
1325 ds_put_char(s, ' ');
1326
1327 ds_put_cstr(s, "bands:\n");
1328 for (i = 0; i < ms->n_bands; ++i) {
1329 ds_put_format(s, "%d: ", i);
1330 ds_put_format(s, "packet_count:%"PRIu64" ", ms->bands[i].packet_count);
1331 ds_put_format(s, "byte_count:%"PRIu64"\n", ms->bands[i].byte_count);
1332 }
1333}
1334
1335static void
1336ofp_print_meter_config(struct ds *s, const struct ofputil_meter_config *mc)
1337{
1338 uint16_t i;
1339
1340 ds_put_format(s, "meter=%"PRIu32" ", mc->meter_id);
1341
1342 ofp_print_meter_flags(s, mc->flags);
1343
1344 ds_put_cstr(s, "bands=");
1345 for (i = 0; i < mc->n_bands; ++i) {
1346 ofp_print_meter_band(s, mc->flags, &mc->bands[i]);
1347 }
1348 ds_put_char(s, '\n');
1349}
1350
1351static void
3c35db62 1352ofp_print_meter_mod__(struct ds *s, const struct ofputil_meter_mod *mm)
638a19b0 1353{
3c35db62 1354 switch (mm->command) {
638a19b0
JR
1355 case OFPMC13_ADD:
1356 ds_put_cstr(s, " ADD ");
1357 break;
1358 case OFPMC13_MODIFY:
1359 ds_put_cstr(s, " MOD ");
1360 break;
1361 case OFPMC13_DELETE:
1362 ds_put_cstr(s, " DEL ");
1363 break;
1364 default:
3c35db62 1365 ds_put_format(s, " cmd:%d ", mm->command);
638a19b0
JR
1366 }
1367
3c35db62
NR
1368 ofp_print_meter_config(s, &mm->meter);
1369}
1370
1371static void
1372ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh)
1373{
1374 struct ofputil_meter_mod mm;
1375 struct ofpbuf bands;
1376 enum ofperr error;
1377
1378 ofpbuf_init(&bands, 64);
1379 error = ofputil_decode_meter_mod(oh, &mm, &bands);
1380 if (error) {
1381 ofp_print_error(s, error);
1382 } else {
1383 ofp_print_meter_mod__(s, &mm);
1384 }
638a19b0
JR
1385 ofpbuf_uninit(&bands);
1386}
1387
1388static void
1389ofp_print_meter_stats_request(struct ds *s, const struct ofp_header *oh)
1390{
1391 uint32_t meter_id;
1392
1393 ofputil_decode_meter_request(oh, &meter_id);
1394
1395 ds_put_format(s, " meter=%"PRIu32, meter_id);
1396}
1397
1398static const char *
1399ofputil_meter_capabilities_to_name(uint32_t bit)
1400{
1401 enum ofp13_meter_flags flag = bit;
1402
1403 switch (flag) {
1404 case OFPMF13_KBPS: return "kbps";
1405 case OFPMF13_PKTPS: return "pktps";
1406 case OFPMF13_BURST: return "burst";
1407 case OFPMF13_STATS: return "stats";
1408 }
1409
1410 return NULL;
1411}
1412
1413static const char *
1414ofputil_meter_band_types_to_name(uint32_t bit)
1415{
638a19b0 1416 switch (bit) {
6e055a6c
BP
1417 case 1 << OFPMBT13_DROP: return "drop";
1418 case 1 << OFPMBT13_DSCP_REMARK: return "dscp_remark";
638a19b0
JR
1419 }
1420
1421 return NULL;
1422}
1423
1424static void
1425ofp_print_meter_features_reply(struct ds *s, const struct ofp_header *oh)
1426{
1427 struct ofputil_meter_features mf;
1428
1429 ofputil_decode_meter_features(oh, &mf);
1430
1431 ds_put_format(s, "\nmax_meter:%"PRIu32, mf.max_meters);
1432 ds_put_format(s, " max_bands:%"PRIu8, mf.max_bands);
1433 ds_put_format(s, " max_color:%"PRIu8"\n", mf.max_color);
1434
1435 ds_put_cstr(s, "band_types: ");
1436 ofp_print_bit_names(s, mf.band_types,
1437 ofputil_meter_band_types_to_name, ' ');
1438 ds_put_char(s, '\n');
1439
1440 ds_put_cstr(s, "capabilities: ");
1441 ofp_print_bit_names(s, mf.capabilities,
1442 ofputil_meter_capabilities_to_name, ' ');
1443 ds_put_char(s, '\n');
1444}
1445
1446static void
1447ofp_print_meter_config_reply(struct ds *s, const struct ofp_header *oh)
1448{
0a2869d5 1449 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
638a19b0 1450 struct ofpbuf bands;
638a19b0 1451
638a19b0
JR
1452 ofpbuf_init(&bands, 64);
1453 for (;;) {
1454 struct ofputil_meter_config mc;
1455 int retval;
1456
1457 retval = ofputil_decode_meter_config(&b, &mc, &bands);
1458 if (retval) {
1459 if (retval != EOF) {
1460 ofp_print_error(s, retval);
1461 }
1462 break;
1463 }
1464 ds_put_char(s, '\n');
1465 ofp_print_meter_config(s, &mc);
1466 }
1467 ofpbuf_uninit(&bands);
1468}
1469
1470static void
1471ofp_print_meter_stats_reply(struct ds *s, const struct ofp_header *oh)
1472{
0a2869d5 1473 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
638a19b0 1474 struct ofpbuf bands;
638a19b0 1475
638a19b0
JR
1476 ofpbuf_init(&bands, 64);
1477 for (;;) {
1478 struct ofputil_meter_stats ms;
1479 int retval;
1480
1481 retval = ofputil_decode_meter_stats(&b, &ms, &bands);
1482 if (retval) {
1483 if (retval != EOF) {
1484 ofp_print_error(s, retval);
1485 }
1486 break;
1487 }
1488 ds_put_char(s, '\n');
1489 ofp_print_meter_stats(s, &ms);
1490 }
1491 ofpbuf_uninit(&bands);
1492}
1493
7fa91113 1494static void
90bf1e07 1495ofp_print_error(struct ds *string, enum ofperr error)
7fa91113 1496{
7fa91113
BP
1497 if (string->length) {
1498 ds_put_char(string, ' ');
1499 }
90bf1e07 1500 ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error));
f74be05a
JP
1501}
1502
de6c85b0
SH
1503static void
1504ofp_print_hello(struct ds *string, const struct ofp_header *oh)
1505{
1506 uint32_t allowed_versions;
1507 bool ok;
1508
1509 ok = ofputil_decode_hello(oh, &allowed_versions);
1510
1511 ds_put_cstr(string, "\n version bitmap: ");
1512 ofputil_format_version_bitmap(string, allowed_versions);
1513
1514 if (!ok) {
1515 ds_put_cstr(string, "\n unknown data in hello:\n");
1516 ds_put_hex_dump(string, oh, ntohs(oh->length), 0, true);
1517 }
1518}
1519
064af421 1520static void
982697a4 1521ofp_print_error_msg(struct ds *string, const struct ofp_header *oh)
064af421 1522{
982697a4
BP
1523 size_t len = ntohs(oh->length);
1524 struct ofpbuf payload;
90bf1e07 1525 enum ofperr error;
064af421
BP
1526 char *s;
1527
982697a4 1528 error = ofperr_decode_msg(oh, &payload);
90bf1e07
BP
1529 if (!error) {
1530 ds_put_cstr(string, "***decode error***");
982697a4 1531 ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true);
dc4762ed 1532 return;
f74be05a
JP
1533 }
1534
90bf1e07 1535 ds_put_format(string, " %s\n", ofperr_get_name(error));
064af421 1536
90bf1e07 1537 if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) {
6fd6ed71 1538 ds_put_printable(string, payload.data, payload.size);
90bf1e07 1539 } else {
6fd6ed71 1540 s = ofp_to_string(payload.data, payload.size, 1);
064af421
BP
1541 ds_put_cstr(string, s);
1542 free(s);
064af421 1543 }
dea241f1 1544 ofpbuf_uninit(&payload);
064af421
BP
1545}
1546
064af421 1547static void
982697a4 1548ofp_print_port_status(struct ds *string, const struct ofp_header *oh)
064af421 1549{
9e1fd49b
BP
1550 struct ofputil_port_status ps;
1551 enum ofperr error;
1552
982697a4 1553 error = ofputil_decode_port_status(oh, &ps);
9e1fd49b
BP
1554 if (error) {
1555 ofp_print_error(string, error);
1556 return;
1557 }
1558
1559 if (ps.reason == OFPPR_ADD) {
064af421 1560 ds_put_format(string, " ADD:");
9e1fd49b 1561 } else if (ps.reason == OFPPR_DELETE) {
064af421 1562 ds_put_format(string, " DEL:");
9e1fd49b 1563 } else if (ps.reason == OFPPR_MODIFY) {
064af421
BP
1564 ds_put_format(string, " MOD:");
1565 }
1566
9e1fd49b 1567 ofp_print_phy_port(string, &ps.desc);
064af421
BP
1568}
1569
1570static void
982697a4 1571ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_header *oh)
064af421 1572{
982697a4
BP
1573 const struct ofp_desc_stats *ods = ofpmsg_body(oh);
1574
fbd76b2e 1575 ds_put_char(string, '\n');
d295e8e9 1576 ds_put_format(string, "Manufacturer: %.*s\n",
dd70b475
JP
1577 (int) sizeof ods->mfr_desc, ods->mfr_desc);
1578 ds_put_format(string, "Hardware: %.*s\n",
1579 (int) sizeof ods->hw_desc, ods->hw_desc);
1580 ds_put_format(string, "Software: %.*s\n",
1581 (int) sizeof ods->sw_desc, ods->sw_desc);
1582 ds_put_format(string, "Serial Num: %.*s\n",
1583 (int) sizeof ods->serial_num, ods->serial_num);
1584 ds_put_format(string, "DP Description: %.*s\n",
1585 (int) sizeof ods->dp_desc, ods->dp_desc);
064af421
BP
1586}
1587
1588static void
982697a4 1589ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh)
064af421 1590{
81d1ea94 1591 struct ofputil_flow_stats_request fsr;
90bf1e07 1592 enum ofperr error;
064af421 1593
982697a4 1594 error = ofputil_decode_flow_stats_request(&fsr, oh);
2af0c0ef
BP
1595 if (error) {
1596 ofp_print_error(string, error);
1597 return;
1598 }
1599
1600 if (fsr.table_id != 0xff) {
e896c2d4 1601 ds_put_format(string, " table=%"PRIu8, fsr.table_id);
064af421
BP
1602 }
1603
7f05e7ab 1604 if (fsr.out_port != OFPP_ANY) {
2af0c0ef 1605 ds_put_cstr(string, " out_port=");
39dc9082 1606 ofputil_format_port(fsr.out_port, string);
2af0c0ef
BP
1607 }
1608
1609 ds_put_char(string, ' ');
81a76618 1610 match_format(&fsr.match, string, OFP_DEFAULT_PRIORITY);
064af421
BP
1611}
1612
bdcc5925
BP
1613void
1614ofp_print_flow_stats(struct ds *string, struct ofputil_flow_stats *fs)
1615{
ab8e7f7d
QM
1616 ds_put_format(string, " %scookie=%s0x%"PRIx64", %sduration=%s",
1617 colors.param, colors.end, ntohll(fs->cookie),
1618 colors.param, colors.end);
bdcc5925
BP
1619
1620 ofp_print_duration(string, fs->duration_sec, fs->duration_nsec);
ab8e7f7d
QM
1621 ds_put_format(string, ", %stable=%s%"PRIu8", ",
1622 colors.special, colors.end, fs->table_id);
1623 ds_put_format(string, "%sn_packets=%s%"PRIu64", ",
1624 colors.param, colors.end, fs->packet_count);
1625 ds_put_format(string, "%sn_bytes=%s%"PRIu64", ",
1626 colors.param, colors.end, fs->byte_count);
bdcc5925 1627 if (fs->idle_timeout != OFP_FLOW_PERMANENT) {
ab8e7f7d
QM
1628 ds_put_format(string, "%sidle_timeout=%s%"PRIu16", ",
1629 colors.param, colors.end, fs->idle_timeout);
bdcc5925
BP
1630 }
1631 if (fs->hard_timeout != OFP_FLOW_PERMANENT) {
ab8e7f7d
QM
1632 ds_put_format(string, "%shard_timeout=%s%"PRIu16", ",
1633 colors.param, colors.end, fs->hard_timeout);
bdcc5925 1634 }
2e1ae200
JR
1635 if (fs->flags) {
1636 ofp_print_flow_flags(string, fs->flags);
1637 }
ca26eb44 1638 if (fs->importance != 0) {
ab8e7f7d
QM
1639 ds_put_format(string, "%simportance=%s%"PRIu16", ",
1640 colors.param, colors.end, fs->importance);
ca26eb44 1641 }
bdcc5925 1642 if (fs->idle_age >= 0) {
ab8e7f7d
QM
1643 ds_put_format(string, "%sidle_age=%s%d, ",
1644 colors.param, colors.end, fs->idle_age);
bdcc5925
BP
1645 }
1646 if (fs->hard_age >= 0 && fs->hard_age != fs->duration_sec) {
ab8e7f7d
QM
1647 ds_put_format(string, "%shard_age=%s%d, ",
1648 colors.param, colors.end, fs->hard_age);
bdcc5925
BP
1649 }
1650
81a76618 1651 match_format(&fs->match, string, fs->priority);
bdcc5925
BP
1652 if (string->string[string->length - 1] != ' ') {
1653 ds_put_char(string, ' ');
1654 }
1655
ab8e7f7d 1656 ds_put_format(string, "%sactions=%s", colors.actions, colors.end);
bdcc5925
BP
1657 ofpacts_format(fs->ofpacts, fs->ofpacts_len, string);
1658}
1659
064af421 1660static void
4ffd1b43 1661ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
064af421 1662{
0a2869d5 1663 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
f25d0cf3 1664 struct ofpbuf ofpacts;
064af421 1665
f25d0cf3 1666 ofpbuf_init(&ofpacts, 64);
4ffd1b43
BP
1667 for (;;) {
1668 struct ofputil_flow_stats fs;
1669 int retval;
fab8fadb 1670
f25d0cf3 1671 retval = ofputil_decode_flow_stats_reply(&fs, &b, true, &ofpacts);
4ffd1b43
BP
1672 if (retval) {
1673 if (retval != EOF) {
1674 ds_put_cstr(string, " ***parse error***");
064af421
BP
1675 }
1676 break;
1677 }
8961de6a 1678 ds_put_char(string, '\n');
bdcc5925
BP
1679 ofp_print_flow_stats(string, &fs);
1680 }
cb80d803 1681 ofpbuf_uninit(&ofpacts);
c6430da5
BP
1682}
1683
064af421 1684static void
982697a4 1685ofp_print_aggregate_stats_reply(struct ds *string, const struct ofp_header *oh)
064af421 1686{
982697a4
BP
1687 struct ofputil_aggregate_stats as;
1688 enum ofperr error;
064af421 1689
982697a4
BP
1690 error = ofputil_decode_aggregate_stats_reply(&as, oh);
1691 if (error) {
1692 ofp_print_error(string, error);
1693 return;
1694 }
1695
1696 ds_put_format(string, " packet_count=%"PRIu64, as.packet_count);
1697 ds_put_format(string, " byte_count=%"PRIu64, as.byte_count);
1698 ds_put_format(string, " flow_count=%"PRIu32, as.flow_count);
a2ad9ecd
BP
1699}
1700
f8e4867e
SH
1701static void
1702print_port_stat(struct ds *string, const char *leader, uint64_t stat, int more)
064af421
BP
1703{
1704 ds_put_cstr(string, leader);
c4617b3c 1705 if (stat != UINT64_MAX) {
064af421
BP
1706 ds_put_format(string, "%"PRIu64, stat);
1707 } else {
1708 ds_put_char(string, '?');
1709 }
1710 if (more) {
1711 ds_put_cstr(string, ", ");
1712 } else {
1713 ds_put_cstr(string, "\n");
1714 }
1715}
1716
d6e3feb5 1717static void
1718print_port_stat_cond(struct ds *string, const char *leader, uint64_t stat)
1719{
1720 if (stat != UINT64_MAX) {
1721 ds_put_format(string, "%s%"PRIu64", ", leader, stat);
1722 }
1723}
1724
abaad8cf 1725static void
982697a4 1726ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh)
abaad8cf 1727{
4e022ec0 1728 ofp_port_t ofp10_port;
f8e4867e
SH
1729 enum ofperr error;
1730
1731 error = ofputil_decode_port_stats_request(oh, &ofp10_port);
1732 if (error) {
1733 ofp_print_error(string, error);
1734 return;
1735 }
1736
e1db42d6
JR
1737 ds_put_cstr(string, " port_no=");
1738 ofputil_format_port(ofp10_port, string);
abaad8cf
JP
1739}
1740
064af421 1741static void
d1e2cf21
BP
1742ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
1743 int verbosity)
064af421 1744{
34582733 1745 ds_put_format(string, " %"PRIuSIZE" ports\n", ofputil_count_port_stats(oh));
064af421
BP
1746 if (verbosity < 1) {
1747 return;
1748 }
1749
0a2869d5 1750 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
982697a4 1751 for (;;) {
f8e4867e
SH
1752 struct ofputil_port_stats ps;
1753 int retval;
1754
1755 retval = ofputil_decode_port_stats(&ps, &b);
1756 if (retval) {
1757 if (retval != EOF) {
1758 ds_put_cstr(string, " ***parse error***");
1759 }
982697a4
BP
1760 return;
1761 }
1762
e1db42d6 1763 ds_put_cstr(string, " port ");
4e022ec0 1764 if (ofp_to_u16(ps.port_no) < 10) {
e1db42d6
JR
1765 ds_put_char(string, ' ');
1766 }
1767 ofputil_format_port(ps.port_no, string);
064af421 1768
f8e4867e
SH
1769 ds_put_cstr(string, ": rx ");
1770 print_port_stat(string, "pkts=", ps.stats.rx_packets, 1);
1771 print_port_stat(string, "bytes=", ps.stats.rx_bytes, 1);
1772 print_port_stat(string, "drop=", ps.stats.rx_dropped, 1);
1773 print_port_stat(string, "errs=", ps.stats.rx_errors, 1);
1774 print_port_stat(string, "frame=", ps.stats.rx_frame_errors, 1);
1775 print_port_stat(string, "over=", ps.stats.rx_over_errors, 1);
1776 print_port_stat(string, "crc=", ps.stats.rx_crc_errors, 0);
064af421
BP
1777
1778 ds_put_cstr(string, " tx ");
f8e4867e
SH
1779 print_port_stat(string, "pkts=", ps.stats.tx_packets, 1);
1780 print_port_stat(string, "bytes=", ps.stats.tx_bytes, 1);
1781 print_port_stat(string, "drop=", ps.stats.tx_dropped, 1);
1782 print_port_stat(string, "errs=", ps.stats.tx_errors, 1);
1783 print_port_stat(string, "coll=", ps.stats.collisions, 0);
65e0be10
BP
1784
1785 if (ps.duration_sec != UINT32_MAX) {
1786 ds_put_cstr(string, " duration=");
1787 ofp_print_duration(string, ps.duration_sec, ps.duration_nsec);
1788 ds_put_char(string, '\n');
1789 }
d6e3feb5 1790 struct ds string_ext_stats = DS_EMPTY_INITIALIZER;
1791
1792 ds_init(&string_ext_stats);
1793
1794 print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
1795 ps.stats.rx_1_to_64_packets);
1796 print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
1797 ps.stats.rx_65_to_127_packets);
1798 print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
1799 ps.stats.rx_128_to_255_packets);
1800 print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
1801 ps.stats.rx_256_to_511_packets);
1802 print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
1803 ps.stats.rx_512_to_1023_packets);
1804 print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
1805 ps.stats.rx_1024_to_1522_packets);
1806 print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
1807 ps.stats.rx_1523_to_max_packets);
1808 print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
1809 ps.stats.rx_broadcast_packets);
1810 print_port_stat_cond(&string_ext_stats, "undersized_errors=",
1811 ps.stats.rx_undersized_errors);
1812 print_port_stat_cond(&string_ext_stats, "oversize_errors=",
1813 ps.stats.rx_oversize_errors);
1814 print_port_stat_cond(&string_ext_stats, "rx_fragmented_errors=",
1815 ps.stats.rx_fragmented_errors);
1816 print_port_stat_cond(&string_ext_stats, "rx_jabber_errors=",
1817 ps.stats.rx_jabber_errors);
1818
1819 if (string_ext_stats.length != 0) {
1820 /* If at least one statistics counter is reported: */
1821 ds_put_cstr(string, " rx rfc2819 ");
1822 ds_put_buffer(string, string_ext_stats.string,
1823 string_ext_stats.length);
1824 ds_put_cstr(string, "\n");
1825 ds_destroy(&string_ext_stats);
1826 }
1827
1828 ds_init(&string_ext_stats);
1829
1830 print_port_stat_cond(&string_ext_stats, "1_to_64_packets=",
1831 ps.stats.tx_1_to_64_packets);
1832 print_port_stat_cond(&string_ext_stats, "65_to_127_packets=",
1833 ps.stats.tx_65_to_127_packets);
1834 print_port_stat_cond(&string_ext_stats, "128_to_255_packets=",
1835 ps.stats.tx_128_to_255_packets);
1836 print_port_stat_cond(&string_ext_stats, "256_to_511_packets=",
1837 ps.stats.tx_256_to_511_packets);
1838 print_port_stat_cond(&string_ext_stats, "512_to_1023_packets=",
1839 ps.stats.tx_512_to_1023_packets);
1840 print_port_stat_cond(&string_ext_stats, "1024_to_1522_packets=",
1841 ps.stats.tx_1024_to_1522_packets);
1842 print_port_stat_cond(&string_ext_stats, "1523_to_max_packets=",
1843 ps.stats.tx_1523_to_max_packets);
1844 print_port_stat_cond(&string_ext_stats, "multicast_packets=",
1845 ps.stats.tx_multicast_packets);
1846 print_port_stat_cond(&string_ext_stats, "broadcast_packets=",
1847 ps.stats.tx_broadcast_packets);
1848
1849 if (string_ext_stats.length != 0) {
1850 /* If at least one statistics counter is reported: */
1851 ds_put_cstr(string, " tx rfc2819 ");
1852 ds_put_buffer(string, string_ext_stats.string,
1853 string_ext_stats.length);
1854 ds_put_cstr(string, "\n");
1855 ds_destroy(&string_ext_stats);
1856 }
064af421
BP
1857 }
1858}
1859
1860static void
3c1bb396 1861ofp_print_table_stats_reply(struct ds *string, const struct ofp_header *oh)
26df8b3e 1862{
0a2869d5 1863 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
26df8b3e
SH
1864 ofpraw_pull_assert(&b);
1865
8811fc0a
BP
1866 struct ofputil_table_features prev_features;
1867 struct ofputil_table_stats prev_stats;
1868 for (int i = 0;; i++) {
3c1bb396
BP
1869 struct ofputil_table_features features;
1870 struct ofputil_table_stats stats;
1871 int retval;
982697a4 1872
3c1bb396
BP
1873 retval = ofputil_decode_table_stats_reply(&b, &stats, &features);
1874 if (retval) {
1875 if (retval != EOF) {
1876 ofp_print_error(string, retval);
1877 }
982697a4
BP
1878 return;
1879 }
1880
8811fc0a
BP
1881 ds_put_char(string, '\n');
1882 ofp_print_table_features(string,
1883 &features, i ? &prev_features : NULL,
1884 &stats, i ? &prev_stats : NULL);
1885 prev_features = features;
1886 prev_stats = stats;
26df8b3e
SH
1887 }
1888}
1889
d2805da2
BP
1890static void
1891ofp_print_queue_name(struct ds *string, uint32_t queue_id)
1892{
1893 if (queue_id == OFPQ_ALL) {
1894 ds_put_cstr(string, "ALL");
1895 } else {
1896 ds_put_format(string, "%"PRIu32, queue_id);
1897 }
1898}
1899
1900static void
982697a4 1901ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_header *oh)
d2805da2 1902{
64626975
SH
1903 struct ofputil_queue_stats_request oqsr;
1904 enum ofperr error;
1905
1906 error = ofputil_decode_queue_stats_request(oh, &oqsr);
1907 if (error) {
1908 ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error));
1909 return;
1910 }
982697a4 1911
3e461c2c 1912 ds_put_cstr(string, " port=");
64626975 1913 ofputil_format_port(oqsr.port_no, string);
d2805da2
BP
1914
1915 ds_put_cstr(string, " queue=");
64626975 1916 ofp_print_queue_name(string, oqsr.queue_id);
f8e4867e
SH
1917}
1918
d2805da2 1919static void
d1e2cf21
BP
1920ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
1921 int verbosity)
d2805da2 1922{
34582733 1923 ds_put_format(string, " %"PRIuSIZE" queues\n", ofputil_count_queue_stats(oh));
d2805da2
BP
1924 if (verbosity < 1) {
1925 return;
1926 }
1927
0a2869d5 1928 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
982697a4 1929 for (;;) {
64626975
SH
1930 struct ofputil_queue_stats qs;
1931 int retval;
1932
1933 retval = ofputil_decode_queue_stats(&qs, &b);
1934 if (retval) {
1935 if (retval != EOF) {
1936 ds_put_cstr(string, " ***parse error***");
1937 }
982697a4
BP
1938 return;
1939 }
1940
d2805da2 1941 ds_put_cstr(string, " port ");
64626975 1942 ofputil_format_port(qs.port_no, string);
d2805da2 1943 ds_put_cstr(string, " queue ");
64626975 1944 ofp_print_queue_name(string, qs.queue_id);
d2805da2
BP
1945 ds_put_cstr(string, ": ");
1946
6dc34a0d
BP
1947 print_port_stat(string, "bytes=", qs.tx_bytes, 1);
1948 print_port_stat(string, "pkts=", qs.tx_packets, 1);
1949 print_port_stat(string, "errors=", qs.tx_errors, 1);
1950
1951 ds_put_cstr(string, "duration=");
1952 if (qs.duration_sec != UINT32_MAX) {
1953 ofp_print_duration(string, qs.duration_sec, qs.duration_nsec);
1954 } else {
1955 ds_put_char(string, '?');
1956 }
1957 ds_put_char(string, '\n');
d2805da2
BP
1958 }
1959}
1960
70ae4f93
BP
1961static void
1962ofp_print_ofpst_port_desc_request(struct ds *string,
1963 const struct ofp_header *oh)
1964{
1965 enum ofperr error;
1966 ofp_port_t port;
1967
1968 error = ofputil_decode_port_desc_stats_request(oh, &port);
1969 if (error) {
1970 ofp_print_error(string, error);
1971 return;
1972 }
1973
1974 ds_put_cstr(string, " port=");
1975 ofputil_format_port(port, string);
1976}
1977
2be393ed
JP
1978static void
1979ofp_print_ofpst_port_desc_reply(struct ds *string,
1980 const struct ofp_header *oh)
1981{
0a2869d5 1982 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
982697a4 1983 ofpraw_pull_assert(&b);
2be393ed
JP
1984 ds_put_char(string, '\n');
1985 ofp_print_phy_ports(string, oh->version, &b);
1986}
1987
064af421 1988static void
5d40fc57 1989ofp_print_stats(struct ds *string, const struct ofp_header *oh)
064af421 1990{
982697a4 1991 uint16_t flags = ofpmp_flags(oh);
d1e2cf21 1992
982697a4 1993 if (flags) {
d1e2cf21 1994 ds_put_cstr(string, " flags=");
5d40fc57
SH
1995 if ((!ofpmsg_is_stat_request(oh) || oh->version >= OFP13_VERSION)
1996 && (flags & OFPSF_REPLY_MORE)) {
064af421
BP
1997 ds_put_cstr(string, "[more]");
1998 flags &= ~OFPSF_REPLY_MORE;
1999 }
2000 if (flags) {
d1e2cf21
BP
2001 ds_put_format(string, "[***unknown flags 0x%04"PRIx16"***]",
2002 flags);
064af421
BP
2003 }
2004 }
064af421
BP
2005}
2006
2007static void
d1e2cf21 2008ofp_print_echo(struct ds *string, const struct ofp_header *oh, int verbosity)
064af421 2009{
d1e2cf21 2010 size_t len = ntohs(oh->length);
064af421 2011
34582733 2012 ds_put_format(string, " %"PRIuSIZE" bytes of payload\n", len - sizeof *oh);
064af421 2013 if (verbosity > 1) {
d1e2cf21 2014 ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true);
064af421
BP
2015 }
2016}
2017
61fe3a7b 2018static void
00467f73
AC
2019ofp_print_role_generic(struct ds *string, enum ofp12_controller_role role,
2020 uint64_t generation_id)
61fe3a7b 2021{
61fe3a7b 2022 ds_put_cstr(string, " role=");
6ea4776b 2023
00467f73 2024 switch (role) {
f4f1ea7e
BP
2025 case OFPCR12_ROLE_NOCHANGE:
2026 ds_put_cstr(string, "nochange");
2027 break;
2028 case OFPCR12_ROLE_EQUAL:
6ea4776b
JR
2029 ds_put_cstr(string, "equal"); /* OF 1.2 wording */
2030 break;
f4f1ea7e 2031 case OFPCR12_ROLE_MASTER:
61fe3a7b 2032 ds_put_cstr(string, "master");
6ea4776b 2033 break;
f4f1ea7e 2034 case OFPCR12_ROLE_SLAVE:
61fe3a7b 2035 ds_put_cstr(string, "slave");
6ea4776b
JR
2036 break;
2037 default:
428b2edd 2038 OVS_NOT_REACHED();
6ea4776b
JR
2039 }
2040
00467f73
AC
2041 if (generation_id != UINT64_MAX) {
2042 ds_put_format(string, " generation_id=%"PRIu64, generation_id);
2043 }
2044}
2045
2046static void
2047ofp_print_role_message(struct ds *string, const struct ofp_header *oh)
2048{
2049 struct ofputil_role_request rr;
2050 enum ofperr error;
2051
2052 error = ofputil_decode_role_message(oh, &rr);
2053 if (error) {
2054 ofp_print_error(string, error);
2055 return;
2056 }
2057
2058 ofp_print_role_generic(string, rr.role, rr.have_generation_id ? rr.generation_id : UINT64_MAX);
2059}
2060
2061static void
2062ofp_print_role_status_message(struct ds *string, const struct ofp_header *oh)
2063{
2064 struct ofputil_role_status rs;
2065 enum ofperr error;
2066
2067 error = ofputil_decode_role_status(oh, &rs);
2068 if (error) {
2069 ofp_print_error(string, error);
2070 return;
2071 }
2072
2073 ofp_print_role_generic(string, rs.role, rs.generation_id);
2074
2075 ds_put_cstr(string, " reason=");
2076
2077 switch (rs.reason) {
2078 case OFPCRR_MASTER_REQUEST:
2079 ds_put_cstr(string, "master_request");
2080 break;
2081 case OFPCRR_CONFIG:
2082 ds_put_cstr(string, "configuration_changed");
2083 break;
2084 case OFPCRR_EXPERIMENTER:
2085 ds_put_cstr(string, "experimenter_data_changed");
2086 break;
d18cc1ee 2087 case OFPCRR_N_REASONS:
00467f73 2088 default:
428b2edd 2089 OVS_NOT_REACHED();
61fe3a7b
BP
2090 }
2091}
2092
6c1491fb
BP
2093static void
2094ofp_print_nxt_flow_mod_table_id(struct ds *string,
73dbf4ab 2095 const struct nx_flow_mod_table_id *nfmti)
6c1491fb
BP
2096{
2097 ds_put_format(string, " %s", nfmti->set ? "enable" : "disable");
2098}
2099
7fa91113
BP
2100static void
2101ofp_print_nxt_set_flow_format(struct ds *string,
73dbf4ab 2102 const struct nx_set_flow_format *nsff)
7fa91113
BP
2103{
2104 uint32_t format = ntohl(nsff->format);
2105
2106 ds_put_cstr(string, " format=");
27527aa0
BP
2107 if (ofputil_nx_flow_format_is_valid(format)) {
2108 ds_put_cstr(string, ofputil_nx_flow_format_to_string(format));
7fa91113
BP
2109 } else {
2110 ds_put_format(string, "%"PRIu32, format);
2111 }
2112}
2113
54834960
EJ
2114static void
2115ofp_print_nxt_set_packet_in_format(struct ds *string,
73dbf4ab 2116 const struct nx_set_packet_in_format *nspf)
54834960
EJ
2117{
2118 uint32_t format = ntohl(nspf->format);
2119
2120 ds_put_cstr(string, " format=");
2121 if (ofputil_packet_in_format_is_valid(format)) {
2122 ds_put_cstr(string, ofputil_packet_in_format_to_string(format));
2123 } else {
2124 ds_put_format(string, "%"PRIu32, format);
2125 }
2126}
2127
8961699e
BP
2128/* Returns a string form of 'reason'. The return value is either a statically
2129 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
2130 * 'bufsize' should be at least OFP_PORT_REASON_BUFSIZE. */
2131#define OFP_PORT_REASON_BUFSIZE (INT_STRLEN(int) + 1)
80d5aefd 2132static const char *
8961699e
BP
2133ofp_port_reason_to_string(enum ofp_port_reason reason,
2134 char *reasonbuf, size_t bufsize)
80d5aefd 2135{
80d5aefd
BP
2136 switch (reason) {
2137 case OFPPR_ADD:
2138 return "add";
2139
2140 case OFPPR_DELETE:
2141 return "delete";
2142
2143 case OFPPR_MODIFY:
2144 return "modify";
2145
d18cc1ee 2146 case OFPPR_N_REASONS:
80d5aefd 2147 default:
8961699e
BP
2148 snprintf(reasonbuf, bufsize, "%d", (int) reason);
2149 return reasonbuf;
80d5aefd
BP
2150 }
2151}
2152
98090482
NR
2153/* Returns a string form of 'reason'. The return value is either a statically
2154 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
2155 * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
2156static const char*
2157ofp_role_reason_to_string(enum ofp14_controller_role_reason reason,
2158 char *reasonbuf, size_t bufsize)
2159{
2160 switch (reason) {
2161 case OFPCRR_MASTER_REQUEST:
2162 return "master_request";
2163
2164 case OFPCRR_CONFIG:
2165 return "configuration_changed";
2166
2167 case OFPCRR_EXPERIMENTER:
2168 return "experimenter_data_changed";
2169
d18cc1ee 2170 case OFPCRR_N_REASONS:
98090482
NR
2171 default:
2172 snprintf(reasonbuf, bufsize, "%d", (int) reason);
2173 return reasonbuf;
2174 }
2175}
2176
2177/* Returns a string form of 'reason'. The return value is either a statically
2178 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
2179 * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
2180static const char*
2181ofp_table_reason_to_string(enum ofp14_table_reason reason,
2182 char *reasonbuf, size_t bufsize)
2183{
2184 switch (reason) {
2185 case OFPTR_VACANCY_DOWN:
2186 return "vacancy_down";
2187
2188 case OFPTR_VACANCY_UP:
2189 return "vacancy_up";
2190
2191 default:
2192 snprintf(reasonbuf, bufsize, "%d", (int) reason);
2193 return reasonbuf;
2194 }
2195}
2196
2197/* Returns a string form of 'reason'. The return value is either a statically
2198 * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
2199 * 'bufsize' should be at least OFP_ASYNC_CONFIG_REASON_BUFSIZE. */
2200static const char*
2201ofp_requestforward_reason_to_string(enum ofp14_requestforward_reason reason,
2202 char *reasonbuf, size_t bufsize)
2203{
2204 switch (reason) {
2205 case OFPRFR_GROUP_MOD:
2206 return "group_mod_request";
2207
2208 case OFPRFR_METER_MOD:
2209 return "meter_mod_request";
2210
d18cc1ee 2211 case OFPRFR_N_REASONS:
98090482
NR
2212 default:
2213 snprintf(reasonbuf, bufsize, "%d", (int) reason);
2214 return reasonbuf;
2215 }
2216}
2217
2218static const char *
2219ofp_async_config_reason_to_string(uint32_t reason,
2220 enum ofputil_async_msg_type type,
2221 char *reasonbuf, size_t bufsize)
2222{
2223 switch (type) {
2224 case OAM_PACKET_IN:
2225 return ofputil_packet_in_reason_to_string(reason, reasonbuf, bufsize);
2226
2227 case OAM_PORT_STATUS:
2228 return ofp_port_reason_to_string(reason, reasonbuf, bufsize);
2229
2230 case OAM_FLOW_REMOVED:
2231 return ofp_flow_removed_reason_to_string(reason, reasonbuf, bufsize);
2232
2233 case OAM_ROLE_STATUS:
2234 return ofp_role_reason_to_string(reason, reasonbuf, bufsize);
2235
2236 case OAM_TABLE_STATUS:
2237 return ofp_table_reason_to_string(reason, reasonbuf, bufsize);
2238
2239 case OAM_REQUESTFORWARD:
2240 return ofp_requestforward_reason_to_string(reason, reasonbuf, bufsize);
2241
2242 case OAM_N_TYPES:
2243 default:
2244 return "Unknown asynchronous configuration message type";
2245 }
2246}
2247
2248
2249#define OFP_ASYNC_CONFIG_REASON_BUFSIZE (INT_STRLEN(int) + 1)
80d5aefd 2250static void
904e5202
BP
2251ofp_print_set_async_config(struct ds *string, const struct ofp_header *oh,
2252 enum ofptype type)
80d5aefd 2253{
904e5202
BP
2254 struct ofputil_async_cfg basis = OFPUTIL_ASYNC_CFG_INIT;
2255 struct ofputil_async_cfg ac;
80d5aefd 2256
904e5202
BP
2257 bool is_reply = type == OFPTYPE_GET_ASYNC_REPLY;
2258 enum ofperr error = ofputil_decode_set_async_config(oh, is_reply,
2259 &basis, &ac);
2260 if (error) {
2261 ofp_print_error(string, error);
2262 return;
2263 }
8961699e 2264
904e5202
BP
2265 for (int i = 0; i < 2; i++) {
2266 ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave");
2267 for (uint32_t type = 0; type < OAM_N_TYPES; type++) {
2268 ds_put_format(string, "%16s:",
2269 ofputil_async_msg_type_to_string(type));
80d5aefd 2270
904e5202
BP
2271 uint32_t role = i == 0 ? ac.master[type] : ac.slave[type];
2272 for (int j = 0; j < 32; j++) {
2273 if (role & (1u << j)) {
2274 char reasonbuf[OFP_ASYNC_CONFIG_REASON_BUFSIZE];
98090482 2275 const char *reason;
8961699e 2276
904e5202
BP
2277 reason = ofp_async_config_reason_to_string(
2278 j, type, reasonbuf, sizeof reasonbuf);
9bfe9334
BP
2279 if (reason[0]) {
2280 ds_put_format(string, " %s", reason);
2281 }
98090482 2282 }
80d5aefd 2283 }
904e5202 2284 if (!role) {
98090482
NR
2285 ds_put_cstr(string, " (off)");
2286 }
2287 ds_put_char(string, '\n');
80d5aefd 2288 }
80d5aefd
BP
2289 }
2290}
2291
a7349929
BP
2292static void
2293ofp_print_nxt_set_controller_id(struct ds *string,
2294 const struct nx_controller_id *nci)
2295{
2296 ds_put_format(string, " id=%"PRIu16, ntohs(nci->controller_id));
2297}
2298
2b07c8b1
BP
2299static void
2300ofp_print_nxt_flow_monitor_cancel(struct ds *string,
2301 const struct ofp_header *oh)
2302{
2303 ds_put_format(string, " id=%"PRIu32,
2304 ofputil_decode_flow_monitor_cancel(oh));
2305}
2306
2307static const char *
2308nx_flow_monitor_flags_to_name(uint32_t bit)
2309{
2310 enum nx_flow_monitor_flags fmf = bit;
2311
2312 switch (fmf) {
2313 case NXFMF_INITIAL: return "initial";
2314 case NXFMF_ADD: return "add";
2315 case NXFMF_DELETE: return "delete";
2316 case NXFMF_MODIFY: return "modify";
2317 case NXFMF_ACTIONS: return "actions";
2318 case NXFMF_OWN: return "own";
2319 }
2320
2321 return NULL;
2322}
2323
2324static void
2325ofp_print_nxst_flow_monitor_request(struct ds *string,
2326 const struct ofp_header *oh)
2327{
0a2869d5 2328 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
2b07c8b1
BP
2329 for (;;) {
2330 struct ofputil_flow_monitor_request request;
2331 int retval;
2332
2333 retval = ofputil_decode_flow_monitor_request(&request, &b);
2334 if (retval) {
2335 if (retval != EOF) {
2336 ofp_print_error(string, retval);
2337 }
2338 return;
2339 }
2340
2341 ds_put_format(string, "\n id=%"PRIu32" flags=", request.id);
2342 ofp_print_bit_names(string, request.flags,
2343 nx_flow_monitor_flags_to_name, ',');
2344
2345 if (request.out_port != OFPP_NONE) {
2346 ds_put_cstr(string, " out_port=");
2347 ofputil_format_port(request.out_port, string);
2348 }
2349
2350 if (request.table_id != 0xff) {
2351 ds_put_format(string, " table=%"PRIu8, request.table_id);
2352 }
2353
2354 ds_put_char(string, ' ');
81a76618 2355 match_format(&request.match, string, OFP_DEFAULT_PRIORITY);
2b07c8b1
BP
2356 ds_chomp(string, ' ');
2357 }
2358}
2359
2360static void
2361ofp_print_nxst_flow_monitor_reply(struct ds *string,
2362 const struct ofp_header *oh)
2363{
2364 uint64_t ofpacts_stub[1024 / 8];
0a2869d5
BP
2365 struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
2366 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
2b07c8b1 2367
2b07c8b1 2368 for (;;) {
8961699e 2369 char reasonbuf[OFP_FLOW_REMOVED_REASON_BUFSIZE];
2b07c8b1 2370 struct ofputil_flow_update update;
81a76618 2371 struct match match;
2b07c8b1
BP
2372 int retval;
2373
2374 update.match = &match;
2375 retval = ofputil_decode_flow_update(&update, &b, &ofpacts);
2376 if (retval) {
2377 if (retval != EOF) {
2378 ofp_print_error(string, retval);
2379 }
2380 ofpbuf_uninit(&ofpacts);
2381 return;
2382 }
2383
2384 ds_put_cstr(string, "\n event=");
2385 switch (update.event) {
2386 case NXFME_ADDED:
2387 ds_put_cstr(string, "ADDED");
2388 break;
2389
2390 case NXFME_DELETED:
2391 ds_put_format(string, "DELETED reason=%s",
8961699e
BP
2392 ofp_flow_removed_reason_to_string(update.reason,
2393 reasonbuf,
2394 sizeof reasonbuf));
2b07c8b1
BP
2395 break;
2396
2397 case NXFME_MODIFIED:
2398 ds_put_cstr(string, "MODIFIED");
2399 break;
2400
2401 case NXFME_ABBREV:
2402 ds_put_format(string, "ABBREV xid=0x%"PRIx32, ntohl(update.xid));
2403 continue;
2404 }
2405
2406 ds_put_format(string, " table=%"PRIu8, update.table_id);
2407 if (update.idle_timeout != OFP_FLOW_PERMANENT) {
2408 ds_put_format(string, " idle_timeout=%"PRIu16,
2409 update.idle_timeout);
2410 }
2411 if (update.hard_timeout != OFP_FLOW_PERMANENT) {
2412 ds_put_format(string, " hard_timeout=%"PRIu16,
2413 update.hard_timeout);
2414 }
2415 ds_put_format(string, " cookie=%#"PRIx64, ntohll(update.cookie));
2416
2417 ds_put_char(string, ' ');
81a76618 2418 match_format(update.match, string, OFP_DEFAULT_PRIORITY);
2b07c8b1
BP
2419
2420 if (update.ofpacts_len) {
2421 if (string->string[string->length - 1] != ' ') {
2422 ds_put_char(string, ' ');
2423 }
455ecd77 2424 ds_put_cstr(string, "actions=");
2b07c8b1
BP
2425 ofpacts_format(update.ofpacts, update.ofpacts_len, string);
2426 }
2427 }
2428}
2429
bdcc5925
BP
2430void
2431ofp_print_version(const struct ofp_header *oh,
2432 struct ds *string)
d1e2cf21 2433{
3811e66b
BP
2434 switch (oh->version) {
2435 case OFP10_VERSION:
2436 break;
2437 case OFP11_VERSION:
2438 ds_put_cstr(string, " (OF1.1)");
4232ef77
SH
2439 break;
2440 case OFP12_VERSION:
2441 ds_put_cstr(string, " (OF1.2)");
3811e66b 2442 break;
2e1ae200
JR
2443 case OFP13_VERSION:
2444 ds_put_cstr(string, " (OF1.3)");
2445 break;
9620f50c
AC
2446 case OFP14_VERSION:
2447 ds_put_cstr(string, " (OF1.4)");
2448 break;
42dccab5
BP
2449 case OFP15_VERSION:
2450 ds_put_cstr(string, " (OF1.5)");
2451 break;
b79d45a1
BP
2452 case OFP16_VERSION:
2453 ds_put_cstr(string, " (OF1.6)");
2454 break;
3811e66b
BP
2455 default:
2456 ds_put_format(string, " (OF 0x%02"PRIx8")", oh->version);
2457 break;
2458 }
2459 ds_put_format(string, " (xid=0x%"PRIx32"):", ntohl(oh->xid));
bdcc5925 2460}
d1e2cf21 2461
f25b4a81 2462static void
982697a4
BP
2463ofp_header_to_string__(const struct ofp_header *oh, enum ofpraw raw,
2464 struct ds *string)
f25b4a81 2465{
982697a4 2466 ds_put_cstr(string, ofpraw_get_name(raw));
f25b4a81
BP
2467 ofp_print_version(oh, string);
2468}
2469
1c4c05af 2470static void
76c41209 2471ofp_print_bucket_id(struct ds *s, const char *label, uint32_t bucket_id,
1c4c05af
SH
2472 enum ofp_version ofp_version)
2473{
2474 if (ofp_version < OFP15_VERSION) {
2475 return;
2476 }
2477
76c41209 2478 ds_put_cstr(s, label);
1c4c05af
SH
2479
2480 switch (bucket_id) {
2481 case OFPG15_BUCKET_FIRST:
2482 ds_put_cstr(s, "first");
2483 break;
2484 case OFPG15_BUCKET_LAST:
2485 ds_put_cstr(s, "last");
2486 break;
2487 case OFPG15_BUCKET_ALL:
2488 ds_put_cstr(s, "all");
2489 break;
2490 default:
2491 ds_put_format(s, "%"PRIu32, bucket_id);
2492 break;
2493 }
2494
2495 ds_put_char(s, ',');
2496}
2497
7395c052
NZ
2498static void
2499ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type,
3c35db62
NR
2500 const struct ovs_list *p_buckets,
2501 const struct ofputil_group_props *props,
53eb84a5 2502 enum ofp_version ofp_version, bool suppress_type)
7395c052 2503{
7395c052
NZ
2504 struct ofputil_bucket *bucket;
2505
76c41209
SH
2506 ds_put_format(s, "group_id=%"PRIu32, group_id);
2507
2508 if (!suppress_type) {
2509 static const char *type_str[] = { "all", "select", "indirect",
2510 "ff", "unknown" };
2511 ds_put_format(s, ",type=%s", type_str[type > 4 ? 4 : type]);
2512 }
2513
53eb84a5 2514 if (props->selection_method[0]) {
68dfc25b 2515 ds_put_format(s, ",selection_method=%s", props->selection_method);
53eb84a5 2516 if (props->selection_method_param) {
68dfc25b 2517 ds_put_format(s, ",selection_method_param=%"PRIu64,
53eb84a5
SH
2518 props->selection_method_param);
2519 }
2520
68dfc25b
BP
2521 size_t n = bitmap_count1(props->fields.used.bm, MFF_N_IDS);
2522 if (n == 1) {
2523 ds_put_cstr(s, ",fields=");
2524 oxm_format_field_array(s, &props->fields);
2525 } else if (n > 1) {
2526 ds_put_cstr(s, ",fields(");
2527 oxm_format_field_array(s, &props->fields);
2528 ds_put_char(s, ')');
53eb84a5
SH
2529 }
2530 }
2531
7395c052
NZ
2532 if (!p_buckets) {
2533 return;
2534 }
2535
76c41209
SH
2536 ds_put_char(s, ',');
2537
7395c052 2538 LIST_FOR_EACH (bucket, list_node, p_buckets) {
76c41209 2539 ds_put_cstr(s, "bucket=");
7395c052 2540
76c41209 2541 ofp_print_bucket_id(s, "bucket_id:", bucket->bucket_id, ofp_version);
64e8c446 2542 if (bucket->weight != (type == OFPGT11_SELECT ? 1 : 0)) {
7395c052
NZ
2543 ds_put_format(s, "weight:%"PRIu16",", bucket->weight);
2544 }
2545 if (bucket->watch_port != OFPP_NONE) {
2546 ds_put_format(s, "watch_port:%"PRIu32",", bucket->watch_port);
2547 }
30ef36c6 2548 if (bucket->watch_group != OFPG_ANY) {
7395c052
NZ
2549 ds_put_format(s, "watch_group:%"PRIu32",", bucket->watch_group);
2550 }
2551
455ecd77 2552 ds_put_cstr(s, "actions=");
7395c052 2553 ofpacts_format(bucket->ofpacts, bucket->ofpacts_len, s);
76c41209 2554 ds_put_char(s, ',');
7395c052 2555 }
76c41209
SH
2556
2557 ds_chomp(s, ',');
7395c052
NZ
2558}
2559
19187a71
BP
2560static void
2561ofp_print_ofpst_group_desc_request(struct ds *string,
2562 const struct ofp_header *oh)
2563{
2564 uint32_t group_id = ofputil_decode_group_desc_request(oh);
2565 ds_put_cstr(string, " group_id=");
2566 ofputil_format_group(group_id, string);
2567}
2568
7395c052
NZ
2569static void
2570ofp_print_group_desc(struct ds *s, const struct ofp_header *oh)
2571{
0a2869d5 2572 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
7395c052
NZ
2573 for (;;) {
2574 struct ofputil_group_desc gd;
2575 int retval;
2576
a7a2d006 2577 retval = ofputil_decode_group_desc_reply(&gd, &b, oh->version);
7395c052
NZ
2578 if (retval) {
2579 if (retval != EOF) {
2580 ds_put_cstr(s, " ***parse error***");
2581 }
2582 break;
2583 }
2584
2585 ds_put_char(s, '\n');
2586 ds_put_char(s, ' ');
53eb84a5
SH
2587 ofp_print_group(s, gd.group_id, gd.type, &gd.buckets, &gd.props,
2588 oh->version, false);
fa03bb9e 2589 ofputil_bucket_list_destroy(&gd.buckets);
7395c052
NZ
2590 }
2591}
2592
2593static void
2594ofp_print_ofpst_group_request(struct ds *string, const struct ofp_header *oh)
2595{
2596 enum ofperr error;
2597 uint32_t group_id;
2598
2599 error = ofputil_decode_group_stats_request(oh, &group_id);
2600 if (error) {
2601 ofp_print_error(string, error);
2602 return;
2603 }
2604
2605 ds_put_cstr(string, " group_id=");
2606 ofputil_format_group(group_id, string);
2607}
2608
2609static void
2610ofp_print_group_stats(struct ds *s, const struct ofp_header *oh)
2611{
0a2869d5 2612 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
7395c052
NZ
2613 for (;;) {
2614 struct ofputil_group_stats gs;
2615 int retval;
2616
2617 retval = ofputil_decode_group_stats_reply(&b, &gs);
2618 if (retval) {
2619 if (retval != EOF) {
2620 ds_put_cstr(s, " ***parse error***");
2621 }
2622 break;
2623 }
2624
2625 ds_put_char(s, '\n');
2626
2627 ds_put_char(s, ' ');
2628 ds_put_format(s, "group_id=%"PRIu32",", gs.group_id);
2629
2630 if (gs.duration_sec != UINT32_MAX) {
2631 ds_put_cstr(s, "duration=");
2632 ofp_print_duration(s, gs.duration_sec, gs.duration_nsec);
2633 ds_put_char(s, ',');
2634 }
2635 ds_put_format(s, "ref_count=%"PRIu32",", gs.ref_count);
2636 ds_put_format(s, "packet_count=%"PRIu64",", gs.packet_count);
2637 ds_put_format(s, "byte_count=%"PRIu64"", gs.byte_count);
2638
0a2869d5 2639 for (uint32_t bucket_i = 0; bucket_i < gs.n_buckets; bucket_i++) {
7395c052
NZ
2640 if (gs.bucket_stats[bucket_i].packet_count != UINT64_MAX) {
2641 ds_put_format(s, ",bucket%"PRIu32":", bucket_i);
2642 ds_put_format(s, "packet_count=%"PRIu64",", gs.bucket_stats[bucket_i].packet_count);
2643 ds_put_format(s, "byte_count=%"PRIu64"", gs.bucket_stats[bucket_i].byte_count);
2644 }
2645 }
646b2a9c
SH
2646
2647 free(gs.bucket_stats);
7395c052
NZ
2648 }
2649}
2650
08d1e234
BP
2651static const char *
2652group_type_to_string(enum ofp11_group_type type)
2653{
2654 switch (type) {
2655 case OFPGT11_ALL: return "all";
2656 case OFPGT11_SELECT: return "select";
2657 case OFPGT11_INDIRECT: return "indirect";
2658 case OFPGT11_FF: return "fast failover";
2659 default: OVS_NOT_REACHED();
2660 }
2661}
2662
7395c052
NZ
2663static void
2664ofp_print_group_features(struct ds *string, const struct ofp_header *oh)
2665{
2666 struct ofputil_group_features features;
08d1e234 2667 int i;
7395c052
NZ
2668
2669 ofputil_decode_group_features_reply(oh, &features);
2670
2671 ds_put_format(string, "\n Group table:\n");
2672 ds_put_format(string, " Types: 0x%"PRIx32"\n", features.types);
2673 ds_put_format(string, " Capabilities: 0x%"PRIx32"\n",
2674 features.capabilities);
2675
08d1e234
BP
2676 for (i = 0; i < OFPGT12_N_TYPES; i++) {
2677 if (features.types & (1u << i)) {
2678 ds_put_format(string, " %s group:\n", group_type_to_string(i));
2679 ds_put_format(string, " max_groups=%#"PRIx32"\n",
2680 features.max_groups[i]);
2681 ds_put_format(string, " actions: ");
2682 ofpact_bitmap_format(features.ofpacts[i], string);
2683 ds_put_char(string, '\n');
2684 }
7395c052
NZ
2685 }
2686}
2687
2688static void
3c35db62
NR
2689ofp_print_group_mod__(struct ds *s, enum ofp_version ofp_version,
2690 const struct ofputil_group_mod *gm)
7395c052 2691{
76c41209 2692 bool bucket_command = false;
7395c052 2693
7395c052
NZ
2694 ds_put_char(s, '\n');
2695
2696 ds_put_char(s, ' ');
3c35db62 2697 switch (gm->command) {
7395c052
NZ
2698 case OFPGC11_ADD:
2699 ds_put_cstr(s, "ADD");
2700 break;
2701
2702 case OFPGC11_MODIFY:
2703 ds_put_cstr(s, "MOD");
2704 break;
2705
2706 case OFPGC11_DELETE:
2707 ds_put_cstr(s, "DEL");
2708 break;
2709
76c41209
SH
2710 case OFPGC15_INSERT_BUCKET:
2711 ds_put_cstr(s, "INSERT_BUCKET");
2712 bucket_command = true;
2713 break;
2714
2715 case OFPGC15_REMOVE_BUCKET:
2716 ds_put_cstr(s, "REMOVE_BUCKET");
2717 bucket_command = true;
2718 break;
2719
7395c052 2720 default:
3c35db62 2721 ds_put_format(s, "cmd:%"PRIu16"", gm->command);
7395c052
NZ
2722 }
2723 ds_put_char(s, ' ');
2724
76c41209
SH
2725 if (bucket_command) {
2726 ofp_print_bucket_id(s, "command_bucket_id:",
3c35db62 2727 gm->command_bucket_id, ofp_version);
76c41209
SH
2728 }
2729
3c35db62
NR
2730 ofp_print_group(s, gm->group_id, gm->type, &gm->buckets, &gm->props,
2731 ofp_version, bucket_command);
2732}
2733
2734static void
2735ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
2736{
2737 struct ofputil_group_mod gm;
2738 int error;
2739
2740 error = ofputil_decode_group_mod(oh, &gm);
2741 if (error) {
2742 ofp_print_error(s, error);
2743 return;
2744 }
2745 ofp_print_group_mod__(s, oh->version, &gm);
fa03bb9e 2746 ofputil_bucket_list_destroy(&gm.buckets);
7395c052
NZ
2747}
2748
5deff5aa
AW
2749static void
2750print_table_action_features(struct ds *s,
2751 const struct ofputil_table_action_features *taf)
2752{
3c1bb396
BP
2753 if (taf->ofpacts) {
2754 ds_put_cstr(s, " actions: ");
2755 ofpact_bitmap_format(taf->ofpacts, s);
2756 ds_put_char(s, '\n');
2757 }
5deff5aa 2758
abadfcb0 2759 if (!bitmap_is_all_zeros(taf->set_fields.bm, MFF_N_IDS)) {
5deff5aa
AW
2760 int i;
2761
3c1bb396 2762 ds_put_cstr(s, " supported on Set-Field:");
abadfcb0 2763 BITMAP_FOR_EACH_1 (i, MFF_N_IDS, taf->set_fields.bm) {
3c1bb396 2764 ds_put_format(s, " %s", mf_from_id(i)->name);
5deff5aa 2765 }
3c1bb396 2766 ds_put_char(s, '\n');
5deff5aa 2767 }
5deff5aa
AW
2768}
2769
2770static bool
2771table_action_features_equal(const struct ofputil_table_action_features *a,
2772 const struct ofputil_table_action_features *b)
2773{
08d1e234 2774 return (a->ofpacts == b->ofpacts
abadfcb0 2775 && bitmap_equal(a->set_fields.bm, b->set_fields.bm, MFF_N_IDS));
5deff5aa
AW
2776}
2777
3c1bb396
BP
2778static bool
2779table_action_features_empty(const struct ofputil_table_action_features *taf)
2780{
2781 return !taf->ofpacts && bitmap_is_all_zeros(taf->set_fields.bm, MFF_N_IDS);
2782}
2783
5deff5aa
AW
2784static void
2785print_table_instruction_features(
8811fc0a
BP
2786 struct ds *s,
2787 const struct ofputil_table_instruction_features *tif,
2788 const struct ofputil_table_instruction_features *prev_tif)
5deff5aa
AW
2789{
2790 int start, end;
2791
3c1bb396
BP
2792 if (!bitmap_is_all_zeros(tif->next, 255)) {
2793 ds_put_cstr(s, " next tables: ");
2794 for (start = bitmap_scan(tif->next, 1, 0, 255); start < 255;
2795 start = bitmap_scan(tif->next, 1, end, 255)) {
2796 end = bitmap_scan(tif->next, 0, start + 1, 255);
2797 if (end == start + 1) {
2798 ds_put_format(s, "%d,", start);
2799 } else {
2800 ds_put_format(s, "%d-%d,", start, end - 1);
2801 }
5deff5aa 2802 }
3c1bb396
BP
2803 ds_chomp(s, ',');
2804 if (ds_last(s) == ' ') {
2805 ds_put_cstr(s, "none");
2806 }
2807 ds_put_char(s, '\n');
5deff5aa 2808 }
5deff5aa 2809
5deff5aa 2810 if (tif->instructions) {
8811fc0a
BP
2811 if (prev_tif && tif->instructions == prev_tif->instructions) {
2812 ds_put_cstr(s, " (same instructions)\n");
2813 } else {
2814 ds_put_cstr(s, " instructions: ");
2815 int i;
5deff5aa 2816
8811fc0a
BP
2817 for (i = 0; i < 32; i++) {
2818 if (tif->instructions & (1u << i)) {
2819 ds_put_format(s, "%s,", ovs_instruction_name_from_type(i));
2820 }
5deff5aa 2821 }
8811fc0a
BP
2822 ds_chomp(s, ',');
2823 ds_put_char(s, '\n');
5deff5aa 2824 }
5deff5aa 2825 }
5deff5aa 2826
8811fc0a
BP
2827 if (prev_tif
2828 && table_action_features_equal(&tif->write, &prev_tif->write)
2829 && table_action_features_equal(&tif->apply, &prev_tif->apply)
2830 && !bitmap_is_all_zeros(tif->write.set_fields.bm, MFF_N_IDS)) {
2831 ds_put_cstr(s, " (same actions)\n");
2832 } else if (!table_action_features_equal(&tif->write, &tif->apply)) {
5deff5aa
AW
2833 ds_put_cstr(s, " Write-Actions features:\n");
2834 print_table_action_features(s, &tif->write);
2835 ds_put_cstr(s, " Apply-Actions features:\n");
2836 print_table_action_features(s, &tif->apply);
3c1bb396
BP
2837 } else if (tif->write.ofpacts
2838 || !bitmap_is_all_zeros(tif->write.set_fields.bm, MFF_N_IDS)) {
2839 ds_put_cstr(s, " Write-Actions and Apply-Actions features:\n");
2840 print_table_action_features(s, &tif->write);
5deff5aa
AW
2841 }
2842}
2843
2844static bool
2845table_instruction_features_equal(
2846 const struct ofputil_table_instruction_features *a,
2847 const struct ofputil_table_instruction_features *b)
2848{
2849 return (bitmap_equal(a->next, b->next, 255)
2850 && a->instructions == b->instructions
2851 && table_action_features_equal(&a->write, &b->write)
2852 && table_action_features_equal(&a->apply, &b->apply));
2853}
2854
3c1bb396
BP
2855static bool
2856table_instruction_features_empty(
2857 const struct ofputil_table_instruction_features *tif)
5deff5aa 2858{
3c1bb396
BP
2859 return (bitmap_is_all_zeros(tif->next, 255)
2860 && !tif->instructions
2861 && table_action_features_empty(&tif->write)
2862 && table_action_features_empty(&tif->apply));
2863}
5deff5aa 2864
8811fc0a
BP
2865static bool
2866table_features_equal(const struct ofputil_table_features *a,
2867 const struct ofputil_table_features *b)
2868{
2869 return (a->metadata_match == b->metadata_match
2870 && a->metadata_write == b->metadata_write
2871 && a->miss_config == b->miss_config
2872 && a->supports_eviction == b->supports_eviction
2873 && a->supports_vacancy_events == b->supports_vacancy_events
2874 && a->max_entries == b->max_entries
2875 && table_instruction_features_equal(&a->nonmiss, &b->nonmiss)
2876 && table_instruction_features_equal(&a->miss, &b->miss)
2877 && bitmap_equal(a->match.bm, b->match.bm, MFF_N_IDS));
2878}
2879
2880static bool
2881table_features_empty(const struct ofputil_table_features *tf)
2882{
2883 return (!tf->metadata_match
2884 && !tf->metadata_write
2885 && tf->miss_config == OFPUTIL_TABLE_MISS_DEFAULT
2886 && tf->supports_eviction < 0
2887 && tf->supports_vacancy_events < 0
2888 && !tf->max_entries
2889 && table_instruction_features_empty(&tf->nonmiss)
2890 && table_instruction_features_empty(&tf->miss)
2891 && bitmap_is_all_zeros(tf->match.bm, MFF_N_IDS));
2892}
2893
2894static bool
2895table_stats_equal(const struct ofputil_table_stats *a,
2896 const struct ofputil_table_stats *b)
2897{
2898 return (a->active_count == b->active_count
2899 && a->lookup_count == b->lookup_count
2900 && a->matched_count == b->matched_count);
2901}
2902
2903void
3c1bb396
BP
2904ofp_print_table_features(struct ds *s,
2905 const struct ofputil_table_features *features,
8811fc0a
BP
2906 const struct ofputil_table_features *prev_features,
2907 const struct ofputil_table_stats *stats,
2908 const struct ofputil_table_stats *prev_stats)
3c1bb396
BP
2909{
2910 int i;
5deff5aa 2911
8811fc0a 2912 ds_put_format(s, " table %"PRIu8, features->table_id);
3c1bb396
BP
2913 if (features->name[0]) {
2914 ds_put_format(s, " (\"%s\")", features->name);
2915 }
8811fc0a
BP
2916 ds_put_char(s, ':');
2917
2918 bool same_stats = prev_stats && table_stats_equal(stats, prev_stats);
2919 bool same_features = prev_features && table_features_equal(features,
2920 prev_features);
6c52e6d8 2921 if ((!stats || same_stats) && same_features) {
8811fc0a
BP
2922 ds_put_cstr(s, " ditto");
2923 return;
2924 }
2925 ds_put_char(s, '\n');
3c1bb396
BP
2926 if (stats) {
2927 ds_put_format(s, " active=%"PRIu32", ", stats->active_count);
2928 ds_put_format(s, "lookup=%"PRIu64", ", stats->lookup_count);
2929 ds_put_format(s, "matched=%"PRIu64"\n", stats->matched_count);
2930 }
8811fc0a
BP
2931 if (same_features) {
2932 if (!table_features_empty(features)) {
2933 ds_put_cstr(s, " (same features)\n");
2934 }
2935 return;
2936 }
2937 if (features->metadata_match || features->metadata_write) {
5deff5aa 2938 ds_put_format(s, " metadata: match=%#"PRIx64" write=%#"PRIx64"\n",
3c1bb396
BP
2939 ntohll(features->metadata_match),
2940 ntohll(features->metadata_write));
2941 }
5deff5aa 2942
3c1bb396 2943 if (features->miss_config != OFPUTIL_TABLE_MISS_DEFAULT) {
82c22d34
BP
2944 ds_put_format(s, " config=%s\n",
2945 ofputil_table_miss_to_string(features->miss_config));
2946 }
2947
2948 if (features->supports_eviction >= 0) {
2949 ds_put_format(s, " eviction: %ssupported\n",
2950 features->supports_eviction ? "" : "not ");
2951
2952 }
2953 if (features->supports_vacancy_events >= 0) {
2954 ds_put_format(s, " vacancy events: %ssupported\n",
2955 features->supports_vacancy_events ? "" : "not ");
2956
3c1bb396 2957 }
5deff5aa 2958
3c1bb396
BP
2959 if (features->max_entries) {
2960 ds_put_format(s, " max_entries=%"PRIu32"\n", features->max_entries);
2961 }
5deff5aa 2962
8811fc0a
BP
2963 const struct ofputil_table_instruction_features *prev_nonmiss
2964 = prev_features ? &prev_features->nonmiss : NULL;
2965 const struct ofputil_table_instruction_features *prev_miss
2966 = prev_features ? &prev_features->miss : NULL;
2967 if (prev_features
2968 && table_instruction_features_equal(&features->nonmiss, prev_nonmiss)
2969 && table_instruction_features_equal(&features->miss, prev_miss)) {
2970 if (!table_instruction_features_empty(&features->nonmiss)) {
2971 ds_put_cstr(s, " (same instructions)\n");
2972 }
2973 } else if (!table_instruction_features_equal(&features->nonmiss,
2974 &features->miss)) {
3c1bb396 2975 ds_put_cstr(s, " instructions (other than table miss):\n");
8811fc0a 2976 print_table_instruction_features(s, &features->nonmiss, prev_nonmiss);
3c1bb396 2977 ds_put_cstr(s, " instructions (table miss):\n");
8811fc0a 2978 print_table_instruction_features(s, &features->miss, prev_miss);
3c1bb396
BP
2979 } else if (!table_instruction_features_empty(&features->nonmiss)) {
2980 ds_put_cstr(s, " instructions (table miss and others):\n");
8811fc0a 2981 print_table_instruction_features(s, &features->nonmiss, prev_nonmiss);
3c1bb396 2982 }
5deff5aa 2983
8811fc0a
BP
2984 if (!bitmap_is_all_zeros(features->match.bm, MFF_N_IDS)) {
2985 if (prev_features
2986 && bitmap_equal(features->match.bm, prev_features->match.bm,
2987 MFF_N_IDS)) {
2988 ds_put_cstr(s, " (same matching)\n");
2989 } else {
2990 ds_put_cstr(s, " matching:\n");
2991 BITMAP_FOR_EACH_1 (i, MFF_N_IDS, features->match.bm) {
2992 const struct mf_field *f = mf_from_id(i);
2993 bool mask = bitmap_is_set(features->mask.bm, i);
2994 bool wildcard = bitmap_is_set(features->wildcard.bm, i);
2995
2996 ds_put_format(s, " %s: %s\n",
2997 f->name,
2998 (mask ? "arbitrary mask"
2999 : wildcard ? "exact match or wildcard"
3000 : "must exact match"));
3001 }
5deff5aa
AW
3002 }
3003 }
3004}
3005
3c1bb396
BP
3006static void
3007ofp_print_table_features_reply(struct ds *s, const struct ofp_header *oh)
3008{
0a2869d5 3009 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
3c1bb396 3010
8811fc0a
BP
3011 struct ofputil_table_features prev;
3012 for (int i = 0; ; i++) {
3c1bb396
BP
3013 struct ofputil_table_features tf;
3014 int retval;
3015
3016 retval = ofputil_decode_table_features(&b, &tf, true);
3017 if (retval) {
3018 if (retval != EOF) {
3019 ofp_print_error(s, retval);
3020 }
3021 return;
3022 }
8811fc0a
BP
3023
3024 ds_put_char(s, '\n');
3025 ofp_print_table_features(s, &tf, i ? &prev : NULL, NULL, NULL);
3026 prev = tf;
3c1bb396
BP
3027 }
3028}
3029
03c72922
BP
3030static void
3031ofp_print_table_desc_reply(struct ds *s, const struct ofp_header *oh)
3032{
0a2869d5 3033 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
03c72922
BP
3034 for (;;) {
3035 struct ofputil_table_desc td;
3036 int retval;
3037
3038 retval = ofputil_decode_table_desc(&b, &td, oh->version);
3039 if (retval) {
3040 if (retval != EOF) {
3041 ofp_print_error(s, retval);
3042 }
3043 return;
3044 }
3045 ofp_print_table_desc(s, &td);
3046 }
3047}
3048
777af88d
AC
3049static const char *
3050bundle_flags_to_name(uint32_t bit)
3051{
3052 switch (bit) {
3053 case OFPBF_ATOMIC:
3054 return "atomic";
3055 case OFPBF_ORDERED:
3056 return "ordered";
3057 default:
3058 return NULL;
3059 }
3060}
3061
3062static void
3063ofp_print_bundle_ctrl(struct ds *s, const struct ofp_header *oh)
3064{
3065 int error;
3066 struct ofputil_bundle_ctrl_msg bctrl;
3067
3068 error = ofputil_decode_bundle_ctrl(oh, &bctrl);
3069 if (error) {
3070 ofp_print_error(s, error);
3071 return;
3072 }
3073
3074 ds_put_char(s, '\n');
3075
3076 ds_put_format(s, " bundle_id=%#"PRIx32" type=", bctrl.bundle_id);
3077 switch (bctrl.type) {
3078 case OFPBCT_OPEN_REQUEST:
3079 ds_put_cstr(s, "OPEN_REQUEST");
3080 break;
3081 case OFPBCT_OPEN_REPLY:
3082 ds_put_cstr(s, "OPEN_REPLY");
3083 break;
3084 case OFPBCT_CLOSE_REQUEST:
3085 ds_put_cstr(s, "CLOSE_REQUEST");
3086 break;
3087 case OFPBCT_CLOSE_REPLY:
3088 ds_put_cstr(s, "CLOSE_REPLY");
3089 break;
3090 case OFPBCT_COMMIT_REQUEST:
3091 ds_put_cstr(s, "COMMIT_REQUEST");
3092 break;
3093 case OFPBCT_COMMIT_REPLY:
3094 ds_put_cstr(s, "COMMIT_REPLY");
3095 break;
3096 case OFPBCT_DISCARD_REQUEST:
3097 ds_put_cstr(s, "DISCARD_REQUEST");
3098 break;
3099 case OFPBCT_DISCARD_REPLY:
3100 ds_put_cstr(s, "DISCARD_REPLY");
3101 break;
3102 }
3103
3104 ds_put_cstr(s, " flags=");
3105 ofp_print_bit_names(s, bctrl.flags, bundle_flags_to_name, ' ');
3106}
3107
3108static void
3109ofp_print_bundle_add(struct ds *s, const struct ofp_header *oh, int verbosity)
3110{
3111 int error;
3112 struct ofputil_bundle_add_msg badd;
777af88d 3113
7ac27a04 3114 error = ofputil_decode_bundle_add(oh, &badd, NULL);
777af88d
AC
3115 if (error) {
3116 ofp_print_error(s, error);
3117 return;
3118 }
3119
3120 ds_put_char(s, '\n');
3121 ds_put_format(s, " bundle_id=%#"PRIx32, badd.bundle_id);
3122 ds_put_cstr(s, " flags=");
3123 ofp_print_bit_names(s, badd.flags, bundle_flags_to_name, ' ');
3124
3125 ds_put_char(s, '\n');
cf8fbeaa
WT
3126 char *msg = ofp_to_string(badd.msg, ntohs(badd.msg->length), verbosity);
3127 ds_put_and_free_cstr(s, msg);
777af88d
AC
3128}
3129
6159c531 3130static void
4e548ad9 3131print_tlv_table(struct ds *s, struct ovs_list *mappings)
6159c531 3132{
4e548ad9 3133 struct ofputil_tlv_map *map;
6159c531
JG
3134
3135 ds_put_cstr(s, " mapping table:\n");
3136 ds_put_cstr(s, " class\ttype\tlength\tmatch field\n");
3137 ds_put_cstr(s, " -----\t----\t------\t-----------");
3138
3139 LIST_FOR_EACH (map, list_node, mappings) {
3140 ds_put_char(s, '\n');
3141 ds_put_format(s, " 0x%"PRIx16"\t0x%"PRIx8"\t%"PRIu8"\ttun_metadata%"PRIu16,
3142 map->option_class, map->option_type, map->option_len,
3143 map->index);
3144 }
3145}
3146
3147static void
4e548ad9 3148ofp_print_tlv_table_mod(struct ds *s, const struct ofp_header *oh)
6159c531
JG
3149{
3150 int error;
4e548ad9 3151 struct ofputil_tlv_table_mod ttm;
6159c531 3152
4e548ad9 3153 error = ofputil_decode_tlv_table_mod(oh, &ttm);
6159c531
JG
3154 if (error) {
3155 ofp_print_error(s, error);
3156 return;
3157 }
3158
3159 ds_put_cstr(s, "\n ");
3160
4e548ad9
ML
3161 switch (ttm.command) {
3162 case NXTTMC_ADD:
6159c531
JG
3163 ds_put_cstr(s, "ADD");
3164 break;
4e548ad9 3165 case NXTTMC_DELETE:
6159c531
JG
3166 ds_put_cstr(s, "DEL");
3167 break;
4e548ad9 3168 case NXTTMC_CLEAR:
6159c531
JG
3169 ds_put_cstr(s, "CLEAR");
3170 break;
3171 }
3172
4e548ad9
ML
3173 if (ttm.command != NXTTMC_CLEAR) {
3174 print_tlv_table(s, &ttm.mappings);
6159c531
JG
3175 }
3176
4e548ad9 3177 ofputil_uninit_tlv_table(&ttm.mappings);
6159c531
JG
3178}
3179
3180static void
4e548ad9 3181ofp_print_tlv_table_reply(struct ds *s, const struct ofp_header *oh)
6159c531
JG
3182{
3183 int error;
4e548ad9
ML
3184 struct ofputil_tlv_table_reply ttr;
3185 struct ofputil_tlv_map *map;
6159c531
JG
3186 int allocated_space = 0;
3187
4e548ad9 3188 error = ofputil_decode_tlv_table_reply(oh, &ttr);
6159c531
JG
3189 if (error) {
3190 ofp_print_error(s, error);
3191 return;
3192 }
3193
3194 ds_put_char(s, '\n');
3195
4e548ad9 3196 LIST_FOR_EACH (map, list_node, &ttr.mappings) {
6159c531
JG
3197 allocated_space += map->option_len;
3198 }
3199
3200 ds_put_format(s, " max option space=%"PRIu32" max fields=%"PRIu16"\n",
4e548ad9 3201 ttr.max_option_space, ttr.max_fields);
6159c531
JG
3202 ds_put_format(s, " allocated option space=%d\n", allocated_space);
3203 ds_put_char(s, '\n');
4e548ad9 3204 print_tlv_table(s, &ttr.mappings);
6159c531 3205
4e548ad9 3206 ofputil_uninit_tlv_table(&ttr.mappings);
6159c531
JG
3207}
3208
3c35db62
NR
3209/* This function will print the request forward message. The reason for
3210 * request forward is taken from rf.request.type */
3211static void
3212ofp_print_requestforward(struct ds *string, const struct ofp_header *oh)
3213{
3214 struct ofputil_requestforward rf;
3215 enum ofperr error;
3216
3217 error = ofputil_decode_requestforward(oh, &rf);
3218 if (error) {
3219 ofp_print_error(string, error);
3220 return;
3221 }
3222
3223 ds_put_cstr(string, " reason=");
3224
3225 switch (rf.reason) {
3226 case OFPRFR_GROUP_MOD:
3227 ds_put_cstr(string, "group_mod");
3228 ofp_print_group_mod__(string, oh->version, rf.group_mod);
3229 break;
3230
3231 case OFPRFR_METER_MOD:
3232 ds_put_cstr(string, "meter_mod");
3233 ofp_print_meter_mod__(string, rf.meter_mod);
3234 break;
d18cc1ee
AA
3235
3236 case OFPRFR_N_REASONS:
3237 OVS_NOT_REACHED();
3c35db62
NR
3238 }
3239 ofputil_destroy_requestforward(&rf);
3240}
3241
fb8f22c1
BY
3242static void
3243print_ipfix_stat(struct ds *string, const char *leader, uint64_t stat, int more)
3244{
3245 ds_put_cstr(string, leader);
3246 if (stat != UINT64_MAX) {
3247 ds_put_format(string, "%"PRIu64, stat);
3248 } else {
3249 ds_put_char(string, '?');
3250 }
3251 if (more) {
3252 ds_put_cstr(string, ", ");
3253 } else {
3254 ds_put_cstr(string, "\n");
3255 }
3256}
3257
3258static void
3259ofp_print_nxst_ipfix_bridge_reply(struct ds *string, const struct ofp_header *oh)
3260{
3261 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
3262 for (;;) {
3263 struct ofputil_ipfix_stats is;
3264 int retval;
3265
3266 retval = ofputil_pull_ipfix_stats(&is, &b);
3267 if (retval) {
3268 if (retval != EOF) {
3269 ds_put_cstr(string, " ***parse error***");
3270 }
3271 return;
3272 }
3273
3274 ds_put_cstr(string, "\n bridge ipfix: ");
3275 print_ipfix_stat(string, "flows=", is.total_flows, 1);
3276 print_ipfix_stat(string, "current flows=", is.current_flows, 1);
3277 print_ipfix_stat(string, "sampled pkts=", is.pkts, 1);
3278 print_ipfix_stat(string, "ipv4 ok=", is.ipv4_pkts, 1);
3279 print_ipfix_stat(string, "ipv6 ok=", is.ipv6_pkts, 1);
3280 print_ipfix_stat(string, "tx pkts=", is.tx_pkts, 0);
3281 ds_put_cstr(string, " ");
3282 print_ipfix_stat(string, "pkts errs=", is.error_pkts, 1);
3283 print_ipfix_stat(string, "ipv4 errs=", is.ipv4_error_pkts, 1);
3284 print_ipfix_stat(string, "ipv6 errs=", is.ipv6_error_pkts, 1);
3285 print_ipfix_stat(string, "tx errs=", is.tx_errors, 0);
3286 }
3287}
3288
3289static void
3290ofp_print_nxst_ipfix_flow_reply(struct ds *string, const struct ofp_header *oh)
3291{
3292 ds_put_format(string, " %"PRIuSIZE" ids\n", ofputil_count_ipfix_stats(oh));
3293
3294 struct ofpbuf b = ofpbuf_const_initializer(oh, ntohs(oh->length));
3295 for (;;) {
3296 struct ofputil_ipfix_stats is;
3297 int retval;
3298
3299 retval = ofputil_pull_ipfix_stats(&is, &b);
3300 if (retval) {
3301 if (retval != EOF) {
3302 ds_put_cstr(string, " ***parse error***");
3303 }
3304 return;
3305 }
3306
3307 ds_put_cstr(string, " id");
3308 ds_put_format(string, " %3"PRIuSIZE": ", (size_t) is.collector_set_id);
3309 print_ipfix_stat(string, "flows=", is.total_flows, 1);
3310 print_ipfix_stat(string, "current flows=", is.current_flows, 1);
3311 print_ipfix_stat(string, "sampled pkts=", is.pkts, 1);
3312 print_ipfix_stat(string, "ipv4 ok=", is.ipv4_pkts, 1);
3313 print_ipfix_stat(string, "ipv6 ok=", is.ipv6_pkts, 1);
3314 print_ipfix_stat(string, "tx pkts=", is.tx_pkts, 0);
3315 ds_put_cstr(string, " ");
3316 print_ipfix_stat(string, "pkts errs=", is.error_pkts, 1);
3317 print_ipfix_stat(string, "ipv4 errs=", is.ipv4_error_pkts, 1);
3318 print_ipfix_stat(string, "ipv6 errs=", is.ipv6_error_pkts, 1);
3319 print_ipfix_stat(string, "tx errs=", is.tx_errors, 0);
3320 }
3321}
3322
3323
bdcc5925 3324static void
982697a4
BP
3325ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
3326 struct ds *string, int verbosity)
bdcc5925 3327{
bdcc5925
BP
3328 const void *msg = oh;
3329
982697a4 3330 ofp_header_to_string__(oh, raw, string);
2e1ae200 3331
904e5202
BP
3332 enum ofptype type = ofptype_from_ofpraw(raw);
3333 switch (type) {
261bd854 3334 case OFPTYPE_GROUP_STATS_REQUEST:
5d40fc57 3335 ofp_print_stats(string, oh);
7395c052
NZ
3336 ofp_print_ofpst_group_request(string, oh);
3337 break;
3338
261bd854 3339 case OFPTYPE_GROUP_STATS_REPLY:
7395c052
NZ
3340 ofp_print_group_stats(string, oh);
3341 break;
3342
261bd854 3343 case OFPTYPE_GROUP_DESC_STATS_REQUEST:
5d40fc57 3344 ofp_print_stats(string, oh);
19187a71 3345 ofp_print_ofpst_group_desc_request(string, oh);
7395c052
NZ
3346 break;
3347
261bd854 3348 case OFPTYPE_GROUP_DESC_STATS_REPLY:
7395c052
NZ
3349 ofp_print_group_desc(string, oh);
3350 break;
3351
261bd854 3352 case OFPTYPE_GROUP_FEATURES_STATS_REQUEST:
5d40fc57 3353 ofp_print_stats(string, oh);
7395c052
NZ
3354 break;
3355
261bd854 3356 case OFPTYPE_GROUP_FEATURES_STATS_REPLY:
7395c052
NZ
3357 ofp_print_group_features(string, oh);
3358 break;
3359
3360 case OFPTYPE_GROUP_MOD:
3361 ofp_print_group_mod(string, oh);
3362 break;
3363
261bd854
BP
3364 case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
3365 case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
3c1bb396 3366 ofp_print_table_features_reply(string, oh);
2e1ae200
JR
3367 break;
3368
03c72922
BP
3369 case OFPTYPE_TABLE_DESC_REQUEST:
3370 case OFPTYPE_TABLE_DESC_REPLY:
3371 ofp_print_table_desc_reply(string, oh);
3372 break;
3373
982697a4 3374 case OFPTYPE_HELLO:
de6c85b0 3375 ofp_print_hello(string, oh);
d1e2cf21
BP
3376 break;
3377
982697a4
BP
3378 case OFPTYPE_ERROR:
3379 ofp_print_error_msg(string, oh);
d1e2cf21
BP
3380 break;
3381
982697a4
BP
3382 case OFPTYPE_ECHO_REQUEST:
3383 case OFPTYPE_ECHO_REPLY:
d1e2cf21
BP
3384 ofp_print_echo(string, oh, verbosity);
3385 break;
3386
982697a4 3387 case OFPTYPE_FEATURES_REQUEST:
d1e2cf21
BP
3388 break;
3389
982697a4
BP
3390 case OFPTYPE_FEATURES_REPLY:
3391 ofp_print_switch_features(string, oh);
d1e2cf21
BP
3392 break;
3393
982697a4 3394 case OFPTYPE_GET_CONFIG_REQUEST:
d1e2cf21
BP
3395 break;
3396
982697a4 3397 case OFPTYPE_GET_CONFIG_REPLY:
ad99e2ed
BP
3398 ofp_print_get_config_reply(string, oh);
3399 break;
3400
982697a4 3401 case OFPTYPE_SET_CONFIG:
ad99e2ed 3402 ofp_print_set_config(string, oh);
d1e2cf21
BP
3403 break;
3404
982697a4
BP
3405 case OFPTYPE_PACKET_IN:
3406 ofp_print_packet_in(string, oh, verbosity);
d1e2cf21
BP
3407 break;
3408
982697a4
BP
3409 case OFPTYPE_FLOW_REMOVED:
3410 ofp_print_flow_removed(string, oh);
d1e2cf21
BP
3411 break;
3412
982697a4
BP
3413 case OFPTYPE_PORT_STATUS:
3414 ofp_print_port_status(string, oh);
d1e2cf21
BP
3415 break;
3416
982697a4
BP
3417 case OFPTYPE_PACKET_OUT:
3418 ofp_print_packet_out(string, oh, verbosity);
d1e2cf21
BP
3419 break;
3420
982697a4
BP
3421 case OFPTYPE_FLOW_MOD:
3422 ofp_print_flow_mod(string, oh, verbosity);
d1e2cf21
BP
3423 break;
3424
982697a4
BP
3425 case OFPTYPE_PORT_MOD:
3426 ofp_print_port_mod(string, oh);
d1e2cf21
BP
3427 break;
3428
918f2b82
AZ
3429 case OFPTYPE_TABLE_MOD:
3430 ofp_print_table_mod(string, oh);
3431 break;
3432
638a19b0
JR
3433 case OFPTYPE_METER_MOD:
3434 ofp_print_meter_mod(string, oh);
3435 break;
3436
982697a4
BP
3437 case OFPTYPE_BARRIER_REQUEST:
3438 case OFPTYPE_BARRIER_REPLY:
d1e2cf21
BP
3439 break;
3440
e8f9a7bb
VG
3441 case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
3442 ofp_print_queue_get_config_request(string, oh);
3443 break;
3444
3445 case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
3446 ofp_print_queue_get_config_reply(string, oh);
3447 break;
3448
6ea4776b
JR
3449 case OFPTYPE_ROLE_REQUEST:
3450 case OFPTYPE_ROLE_REPLY:
3451 ofp_print_role_message(string, oh);
3452 break;
252f3411 3453 case OFPTYPE_ROLE_STATUS:
00467f73 3454 ofp_print_role_status_message(string, oh);
252f3411 3455 break;
6ea4776b 3456
3c35db62
NR
3457 case OFPTYPE_REQUESTFORWARD:
3458 ofp_print_requestforward(string, oh);
3459 break;
3460
6c6eedc5
SJ
3461 case OFPTYPE_TABLE_STATUS:
3462 ofp_print_table_status_message(string, oh);
3463 break;
3464
261bd854
BP
3465 case OFPTYPE_METER_STATS_REQUEST:
3466 case OFPTYPE_METER_CONFIG_STATS_REQUEST:
5d40fc57 3467 ofp_print_stats(string, oh);
638a19b0
JR
3468 ofp_print_meter_stats_request(string, oh);
3469 break;
3470
261bd854 3471 case OFPTYPE_METER_STATS_REPLY:
5d40fc57 3472 ofp_print_stats(string, oh);
638a19b0
JR
3473 ofp_print_meter_stats_reply(string, oh);
3474 break;
3475
261bd854 3476 case OFPTYPE_METER_CONFIG_STATS_REPLY:
5d40fc57 3477 ofp_print_stats(string, oh);
638a19b0
JR
3478 ofp_print_meter_config_reply(string, oh);
3479 break;
3480
261bd854 3481 case OFPTYPE_METER_FEATURES_STATS_REPLY:
5d40fc57 3482 ofp_print_stats(string, oh);
638a19b0
JR
3483 ofp_print_meter_features_reply(string, oh);
3484 break;
3485
982697a4 3486 case OFPTYPE_DESC_STATS_REQUEST:
261bd854 3487 case OFPTYPE_METER_FEATURES_STATS_REQUEST:
5d40fc57 3488 ofp_print_stats(string, oh);
d1e2cf21
BP
3489 break;
3490
982697a4
BP
3491 case OFPTYPE_FLOW_STATS_REQUEST:
3492 case OFPTYPE_AGGREGATE_STATS_REQUEST:
5d40fc57 3493 ofp_print_stats(string, oh);
982697a4 3494 ofp_print_flow_stats_request(string, oh);
d1e2cf21
BP
3495 break;
3496
982697a4 3497 case OFPTYPE_TABLE_STATS_REQUEST:
5d40fc57 3498 ofp_print_stats(string, oh);
d1e2cf21
BP
3499 break;
3500
982697a4 3501 case OFPTYPE_PORT_STATS_REQUEST:
5d40fc57 3502 ofp_print_stats(string, oh);
982697a4 3503 ofp_print_ofpst_port_request(string, oh);
d1e2cf21
BP
3504 break;
3505
982697a4 3506 case OFPTYPE_QUEUE_STATS_REQUEST:
5d40fc57 3507 ofp_print_stats(string, oh);
982697a4 3508 ofp_print_ofpst_queue_request(string, oh);
d1e2cf21
BP
3509 break;
3510
982697a4 3511 case OFPTYPE_DESC_STATS_REPLY:
5d40fc57 3512 ofp_print_stats(string, oh);
982697a4 3513 ofp_print_ofpst_desc_reply(string, oh);
d1e2cf21
BP
3514 break;
3515
982697a4 3516 case OFPTYPE_FLOW_STATS_REPLY:
5d40fc57 3517 ofp_print_stats(string, oh);
4ffd1b43 3518 ofp_print_flow_stats_reply(string, oh);
d1e2cf21
BP
3519 break;
3520
982697a4 3521 case OFPTYPE_QUEUE_STATS_REPLY:
5d40fc57 3522 ofp_print_stats(string, oh);
d1e2cf21
BP
3523 ofp_print_ofpst_queue_reply(string, oh, verbosity);
3524 break;
3525
982697a4 3526 case OFPTYPE_PORT_STATS_REPLY:
5d40fc57 3527 ofp_print_stats(string, oh);
d1e2cf21
BP
3528 ofp_print_ofpst_port_reply(string, oh, verbosity);
3529 break;
3530
982697a4 3531 case OFPTYPE_TABLE_STATS_REPLY:
5d40fc57 3532 ofp_print_stats(string, oh);
3c1bb396 3533 ofp_print_table_stats_reply(string, oh);
d1e2cf21
BP
3534 break;
3535
982697a4 3536 case OFPTYPE_AGGREGATE_STATS_REPLY:
5d40fc57 3537 ofp_print_stats(string, oh);
982697a4 3538 ofp_print_aggregate_stats_reply(string, oh);
d1e2cf21 3539 break;
064af421 3540
70ae4f93 3541 case OFPTYPE_PORT_DESC_STATS_REQUEST:
5d40fc57 3542 ofp_print_stats(string, oh);
70ae4f93
BP
3543 ofp_print_ofpst_port_desc_request(string, oh);
3544 break;
3545
982697a4 3546 case OFPTYPE_PORT_DESC_STATS_REPLY:
5d40fc57 3547 ofp_print_stats(string, oh);
2be393ed
JP
3548 ofp_print_ofpst_port_desc_reply(string, oh);
3549 break;
3550
982697a4
BP
3551 case OFPTYPE_FLOW_MOD_TABLE_ID:
3552 ofp_print_nxt_flow_mod_table_id(string, ofpmsg_body(oh));
6c1491fb
BP
3553 break;
3554
982697a4
BP
3555 case OFPTYPE_SET_FLOW_FORMAT:
3556 ofp_print_nxt_set_flow_format(string, ofpmsg_body(oh));
7fa91113
BP
3557 break;
3558
982697a4
BP
3559 case OFPTYPE_SET_PACKET_IN_FORMAT:
3560 ofp_print_nxt_set_packet_in_format(string, ofpmsg_body(oh));
54834960
EJ
3561 break;
3562
982697a4 3563 case OFPTYPE_FLOW_AGE:
f27f2134
BP
3564 break;
3565
982697a4
BP
3566 case OFPTYPE_SET_CONTROLLER_ID:
3567 ofp_print_nxt_set_controller_id(string, ofpmsg_body(oh));
a7349929
BP
3568 break;
3569
db09e430 3570 case OFPTYPE_GET_ASYNC_REPLY:
982697a4 3571 case OFPTYPE_SET_ASYNC_CONFIG:
904e5202 3572 ofp_print_set_async_config(string, oh, type);
d1e2cf21 3573 break;
db09e430
AC
3574 case OFPTYPE_GET_ASYNC_REQUEST:
3575 break;
982697a4 3576 case OFPTYPE_FLOW_MONITOR_CANCEL:
2b07c8b1
BP
3577 ofp_print_nxt_flow_monitor_cancel(string, msg);
3578 break;
3579
982697a4
BP
3580 case OFPTYPE_FLOW_MONITOR_PAUSED:
3581 case OFPTYPE_FLOW_MONITOR_RESUMED:
2b07c8b1
BP
3582 break;
3583
982697a4 3584 case OFPTYPE_FLOW_MONITOR_STATS_REQUEST:
2b07c8b1
BP
3585 ofp_print_nxst_flow_monitor_request(string, msg);
3586 break;
3587
982697a4 3588 case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
2b07c8b1
BP
3589 ofp_print_nxst_flow_monitor_reply(string, msg);
3590 break;
777af88d
AC
3591
3592 case OFPTYPE_BUNDLE_CONTROL:
3593 ofp_print_bundle_ctrl(string, msg);
3594 break;
3595
3596 case OFPTYPE_BUNDLE_ADD_MESSAGE:
3597 ofp_print_bundle_add(string, msg, verbosity);
3598 break;
6159c531 3599
4e548ad9
ML
3600 case OFPTYPE_NXT_TLV_TABLE_MOD:
3601 ofp_print_tlv_table_mod(string, msg);
6159c531
JG
3602 break;
3603
4e548ad9 3604 case OFPTYPE_NXT_TLV_TABLE_REQUEST:
6159c531
JG
3605 break;
3606
4e548ad9
ML
3607 case OFPTYPE_NXT_TLV_TABLE_REPLY:
3608 ofp_print_tlv_table_reply(string, msg);
6159c531
JG
3609 break;
3610
77ab5fd2
BP
3611 case OFPTYPE_NXT_RESUME:
3612 ofp_print_packet_in(string, msg, verbosity);
3613 break;
fb8f22c1
BY
3614 case OFPTYPE_IPFIX_BRIDGE_STATS_REQUEST:
3615 break;
3616 case OFPTYPE_IPFIX_BRIDGE_STATS_REPLY:
3617 ofp_print_nxst_ipfix_bridge_reply(string, oh);
3618 break;
3619 case OFPTYPE_IPFIX_FLOW_STATS_REQUEST:
3620 break;
3621 case OFPTYPE_IPFIX_FLOW_STATS_REPLY:
3622 ofp_print_nxst_ipfix_flow_reply(string, oh);
3623 break;
246e61ea 3624 }
d1e2cf21 3625}
064af421
BP
3626
3627/* Composes and returns a string representing the OpenFlow packet of 'len'
3628 * bytes at 'oh' at the given 'verbosity' level. 0 is a minimal amount of
3629 * verbosity and higher numbers increase verbosity. The caller is responsible
3630 * for freeing the string. */
3631char *
3632ofp_to_string(const void *oh_, size_t len, int verbosity)
3633{
3634 struct ds string = DS_EMPTY_INITIALIZER;
3635 const struct ofp_header *oh = oh_;
064af421 3636
49ad0403
BP
3637 if (!len) {
3638 ds_put_cstr(&string, "OpenFlow message is empty\n");
3639 } else if (len < sizeof(struct ofp_header)) {
34582733 3640 ds_put_format(&string, "OpenFlow packet too short (only %"PRIuSIZE" bytes):\n",
49ad0403 3641 len);
d1e2cf21 3642 } else if (ntohs(oh->length) > len) {
f25b4a81 3643 enum ofperr error;
982697a4 3644 enum ofpraw raw;
f25b4a81 3645
982697a4 3646 error = ofpraw_decode_partial(&raw, oh, len);
f25b4a81 3647 if (!error) {
982697a4 3648 ofp_header_to_string__(oh, raw, &string);
f25b4a81
BP
3649 ds_put_char(&string, '\n');
3650 }
3651
d1e2cf21 3652 ds_put_format(&string,
34582733 3653 "(***truncated to %"PRIuSIZE" bytes from %"PRIu16"***)\n",
d1e2cf21
BP
3654 len, ntohs(oh->length));
3655 } else if (ntohs(oh->length) < len) {
3656 ds_put_format(&string,
34582733 3657 "(***only uses %"PRIu16" bytes out of %"PRIuSIZE"***)\n",
d1e2cf21
BP
3658 ntohs(oh->length), len);
3659 } else {
90bf1e07 3660 enum ofperr error;
982697a4 3661 enum ofpraw raw;
d1e2cf21 3662
982697a4 3663 error = ofpraw_decode(&raw, oh);
d1e2cf21 3664 if (!error) {
982697a4 3665 ofp_to_string__(oh, raw, &string, verbosity);
7fa91113
BP
3666 if (verbosity >= 5) {
3667 if (ds_last(&string) != '\n') {
3668 ds_put_char(&string, '\n');
3669 }
d1e2cf21
BP
3670 ds_put_hex_dump(&string, oh, len, 0, true);
3671 }
7fa91113 3672 if (ds_last(&string) != '\n') {
d1e2cf21
BP
3673 ds_put_char(&string, '\n');
3674 }
3675 return ds_steal_cstr(&string);
064af421 3676 }
064af421 3677
7fa91113 3678 ofp_print_error(&string, error);
064af421 3679 }
d1e2cf21
BP
3680 ds_put_hex_dump(&string, oh, len, 0, true);
3681 return ds_steal_cstr(&string);
064af421 3682}
064af421
BP
3683\f
3684static void
d295e8e9 3685print_and_free(FILE *stream, char *string)
064af421
BP
3686{
3687 fputs(string, stream);
3688 free(string);
3689}
3690
3691/* Pretty-print the OpenFlow packet of 'len' bytes at 'oh' to 'stream' at the
3692 * given 'verbosity' level. 0 is a minimal amount of verbosity and higher
3693 * numbers increase verbosity. */
3694void
3695ofp_print(FILE *stream, const void *oh, size_t len, int verbosity)
3696{
3697 print_and_free(stream, ofp_to_string(oh, len, verbosity));
3698}
3699
3700/* Dumps the contents of the Ethernet frame in the 'len' bytes starting at
897a8e07 3701 * 'data' to 'stream'. */
064af421 3702void
c499c75d 3703ofp_print_packet(FILE *stream, const void *data, size_t len)
064af421 3704{
c499c75d 3705 print_and_free(stream, ofp_packet_to_string(data, len));
064af421 3706}