]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ofp-print.c
ofproto: New feature to notify controllers of flow table changes.
[mirror_ovs.git] / lib / ofp-print.c
CommitLineData
064af421 1/*
e0edde6f 2 * Copyright (c) 2008, 2009, 2010, 2011, 2012 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>
18#include "ofp-print.h"
064af421
BP
19
20#include <errno.h>
21#include <inttypes.h>
7f3adc00 22#include <sys/types.h>
064af421
BP
23#include <netinet/in.h>
24#include <sys/wait.h>
25#include <stdarg.h>
26#include <stdlib.h>
27#include <ctype.h>
28
daff3353 29#include "bundle.h"
10a24935 30#include "byte-order.h"
064af421
BP
31#include "compiler.h"
32#include "dynamic-string.h"
33#include "flow.h"
75a75043 34#include "learn.h"
53ddd40a 35#include "multipath.h"
816fd533 36#include "meta-flow.h"
9e1fd49b 37#include "netdev.h"
7fa91113 38#include "nx-match.h"
f25d0cf3 39#include "ofp-actions.h"
90bf1e07 40#include "ofp-errors.h"
69b6be19 41#include "ofp-util.h"
064af421
BP
42#include "ofpbuf.h"
43#include "openflow/openflow.h"
44#include "openflow/nicira-ext.h"
45#include "packets.h"
46#include "pcap.h"
e41a9130 47#include "type-props.h"
c4617b3c 48#include "unaligned.h"
064af421
BP
49#include "util.h"
50
d2805da2 51static void ofp_print_queue_name(struct ds *string, uint32_t port);
90bf1e07 52static void ofp_print_error(struct ds *, enum ofperr);
7fa91113 53
064af421
BP
54
55/* Returns a string that represents the contents of the Ethernet frame in the
897a8e07 56 * 'len' bytes starting at 'data'. The caller must free the returned string.*/
064af421 57char *
c499c75d 58ofp_packet_to_string(const void *data, size_t len)
064af421
BP
59{
60 struct ds ds = DS_EMPTY_INITIALIZER;
61 struct ofpbuf buf;
897a8e07 62 struct flow flow;
064af421 63
0bc9407d 64 ofpbuf_use_const(&buf, data, len);
897a8e07
EJ
65 flow_extract(&buf, 0, 0, 0, &flow);
66 flow_format(&ds, &flow);
e50abca5
EJ
67
68 if (buf.l7) {
69 if (flow.nw_proto == IPPROTO_TCP) {
70 struct tcp_header *th = buf.l4;
71 ds_put_format(&ds, " tcp_csum:%"PRIx16,
72 ntohs(th->tcp_csum));
73 } else if (flow.nw_proto == IPPROTO_UDP) {
74 struct udp_header *uh = buf.l4;
75 ds_put_format(&ds, " udp_csum:%"PRIx16,
76 ntohs(uh->udp_csum));
77 }
78 }
79
897a8e07 80 ds_put_char(&ds, '\n');
064af421 81
064af421
BP
82 return ds_cstr(&ds);
83}
84
064af421 85static void
65120a8a 86ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
d1e2cf21 87 int verbosity)
064af421 88{
65120a8a
EJ
89 struct ofputil_packet_in pin;
90 int error;
5d6c3af0 91 int i;
064af421 92
65120a8a
EJ
93 error = ofputil_decode_packet_in(&pin, oh);
94 if (error) {
95 ofp_print_error(string, error);
96 return;
97 }
98
54834960
EJ
99 if (pin.table_id) {
100 ds_put_format(string, " table_id=%"PRIu8, pin.table_id);
101 }
102
103 if (pin.cookie) {
104 ds_put_format(string, " cookie=0x%"PRIx64, ntohll(pin.cookie));
105 }
106
65120a8a 107 ds_put_format(string, " total_len=%"PRIu16" in_port=", pin.total_len);
5d6c3af0
EJ
108 ofputil_format_port(pin.fmd.in_port, string);
109
110 if (pin.fmd.tun_id_mask) {
111 ds_put_format(string, " tun_id=0x%"PRIx64, ntohll(pin.fmd.tun_id));
112 if (pin.fmd.tun_id_mask != htonll(UINT64_MAX)) {
113 ds_put_format(string, "/0x%"PRIx64, ntohll(pin.fmd.tun_id_mask));
114 }
115 }
116
969fc56c
JS
117 if (pin.fmd.metadata_mask) {
118 ds_put_format(string, " metadata=0x%"PRIx64, ntohll(pin.fmd.metadata));
119 if (pin.fmd.metadata_mask != htonll(UINT64_MAX)) {
120 ds_put_format(string, "/0x%"PRIx64, ntohll(pin.fmd.metadata_mask));
121 }
122 }
123
5d6c3af0
EJ
124 for (i = 0; i < FLOW_N_REGS; i++) {
125 if (pin.fmd.reg_masks[i]) {
126 ds_put_format(string, " reg%d=0x%"PRIx32, i, pin.fmd.regs[i]);
127 if (pin.fmd.reg_masks[i] != UINT32_MAX) {
128 ds_put_format(string, "/0x%"PRIx32, pin.fmd.reg_masks[i]);
129 }
130 }
131 }
064af421 132
80d5aefd 133 ds_put_format(string, " (via %s)",
7c1a76a4 134 ofputil_packet_in_reason_to_string(pin.reason));
064af421 135
65120a8a
EJ
136 ds_put_format(string, " data_len=%zu", pin.packet_len);
137 if (pin.buffer_id == UINT32_MAX) {
064af421 138 ds_put_format(string, " (unbuffered)");
65120a8a 139 if (pin.total_len != pin.packet_len) {
064af421 140 ds_put_format(string, " (***total_len != data_len***)");
65120a8a 141 }
064af421 142 } else {
65120a8a
EJ
143 ds_put_format(string, " buffer=0x%08"PRIx32, pin.buffer_id);
144 if (pin.total_len < pin.packet_len) {
064af421 145 ds_put_format(string, " (***total_len < data_len***)");
65120a8a 146 }
064af421
BP
147 }
148 ds_put_char(string, '\n');
149
150 if (verbosity > 0) {
65120a8a 151 char *packet = ofp_packet_to_string(pin.packet, pin.packet_len);
064af421
BP
152 ds_put_cstr(string, packet);
153 free(packet);
154 }
155}
156
d1e2cf21
BP
157static void
158ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
159 int verbosity)
064af421 160{
c6a93eb7 161 struct ofputil_packet_out po;
f25d0cf3 162 struct ofpbuf ofpacts;
c6a93eb7 163 enum ofperr error;
064af421 164
f25d0cf3
BP
165 ofpbuf_init(&ofpacts, 64);
166 error = ofputil_decode_packet_out(&po, opo, &ofpacts);
c6a93eb7 167 if (error) {
f25d0cf3 168 ofpbuf_uninit(&ofpacts);
c6a93eb7 169 ofp_print_error(string, error);
064af421
BP
170 return;
171 }
c6a93eb7
BP
172
173 ds_put_cstr(string, " in_port=");
174 ofputil_format_port(po.in_port, string);
175
176 ds_put_char(string, ' ');
f25d0cf3 177 ofpacts_format(po.ofpacts, po.ofpacts_len, string);
c6a93eb7
BP
178
179 if (po.buffer_id == UINT32_MAX) {
29530977 180 ds_put_format(string, " data_len=%zu", po.packet_len);
c6a93eb7
BP
181 if (verbosity > 0 && po.packet_len > 0) {
182 char *packet = ofp_packet_to_string(po.packet, po.packet_len);
064af421
BP
183 ds_put_char(string, '\n');
184 ds_put_cstr(string, packet);
185 free(packet);
186 }
187 } else {
c6a93eb7 188 ds_put_format(string, " buffer=0x%08"PRIx32, po.buffer_id);
064af421
BP
189 }
190 ds_put_char(string, '\n');
f25d0cf3
BP
191
192 ofpbuf_uninit(&ofpacts);
064af421
BP
193}
194
195/* qsort comparison function. */
196static int
197compare_ports(const void *a_, const void *b_)
198{
9e1fd49b
BP
199 const struct ofputil_phy_port *a = a_;
200 const struct ofputil_phy_port *b = b_;
201 uint16_t ap = a->port_no;
202 uint16_t bp = b->port_no;
064af421
BP
203
204 return ap < bp ? -1 : ap > bp;
205}
206
0ab14c8e
BP
207static void
208ofp_print_bit_names(struct ds *string, uint32_t bits,
e8fa940e
BP
209 const char *(*bit_to_name)(uint32_t bit),
210 char separator)
064af421 211{
0ab14c8e 212 int n = 0;
9e1fd49b 213 int i;
0ab14c8e
BP
214
215 if (!bits) {
216 ds_put_cstr(string, "0");
064af421
BP
217 return;
218 }
0ab14c8e 219
9e1fd49b
BP
220 for (i = 0; i < 32; i++) {
221 uint32_t bit = UINT32_C(1) << i;
222
223 if (bits & bit) {
224 const char *name = bit_to_name(bit);
225 if (name) {
226 if (n++) {
e8fa940e 227 ds_put_char(string, separator);
9e1fd49b
BP
228 }
229 ds_put_cstr(string, name);
230 bits &= ~bit;
0ab14c8e 231 }
0ab14c8e 232 }
064af421 233 }
0ab14c8e
BP
234
235 if (bits) {
f5cd6874 236 if (n) {
e8fa940e 237 ds_put_char(string, separator);
0ab14c8e
BP
238 }
239 ds_put_format(string, "0x%"PRIx32, bits);
064af421 240 }
0ab14c8e
BP
241}
242
9e1fd49b
BP
243static const char *
244netdev_feature_to_name(uint32_t bit)
245{
246 enum netdev_features f = bit;
247
248 switch (f) {
249 case NETDEV_F_10MB_HD: return "10MB-HD";
250 case NETDEV_F_10MB_FD: return "10MB-FD";
251 case NETDEV_F_100MB_HD: return "100MB-HD";
252 case NETDEV_F_100MB_FD: return "100MB-FD";
253 case NETDEV_F_1GB_HD: return "1GB-HD";
254 case NETDEV_F_1GB_FD: return "1GB-FD";
255 case NETDEV_F_10GB_FD: return "10GB-FD";
256 case NETDEV_F_40GB_FD: return "40GB-FD";
257 case NETDEV_F_100GB_FD: return "100GB-FD";
258 case NETDEV_F_1TB_FD: return "1TB-FD";
259 case NETDEV_F_OTHER: return "OTHER";
260 case NETDEV_F_COPPER: return "COPPER";
261 case NETDEV_F_FIBER: return "FIBER";
262 case NETDEV_F_AUTONEG: return "AUTO_NEG";
263 case NETDEV_F_PAUSE: return "AUTO_PAUSE";
264 case NETDEV_F_PAUSE_ASYM: return "AUTO_PAUSE_ASYM";
265 }
266
267 return NULL;
268}
269
0ab14c8e 270static void
9e1fd49b 271ofp_print_port_features(struct ds *string, enum netdev_features features)
0ab14c8e 272{
e8fa940e 273 ofp_print_bit_names(string, features, netdev_feature_to_name, ' ');
0ab14c8e
BP
274 ds_put_char(string, '\n');
275}
276
9e1fd49b
BP
277static const char *
278ofputil_port_config_to_name(uint32_t bit)
279{
280 enum ofputil_port_config pc = bit;
281
282 switch (pc) {
283 case OFPUTIL_PC_PORT_DOWN: return "PORT_DOWN";
284 case OFPUTIL_PC_NO_STP: return "NO_STP";
285 case OFPUTIL_PC_NO_RECV: return "NO_RECV";
286 case OFPUTIL_PC_NO_RECV_STP: return "NO_RECV_STP";
287 case OFPUTIL_PC_NO_FLOOD: return "NO_FLOOD";
288 case OFPUTIL_PC_NO_FWD: return "NO_FWD";
289 case OFPUTIL_PC_NO_PACKET_IN: return "NO_PACKET_IN";
290 }
291
292 return NULL;
293}
294
0ab14c8e 295static void
9e1fd49b 296ofp_print_port_config(struct ds *string, enum ofputil_port_config config)
0ab14c8e 297{
e8fa940e 298 ofp_print_bit_names(string, config, ofputil_port_config_to_name, ' ');
0ab14c8e
BP
299 ds_put_char(string, '\n');
300}
301
9e1fd49b
BP
302static const char *
303ofputil_port_state_to_name(uint32_t bit)
304{
305 enum ofputil_port_state ps = bit;
306
307 switch (ps) {
308 case OFPUTIL_PS_LINK_DOWN: return "LINK_DOWN";
309 case OFPUTIL_PS_BLOCKED: return "BLOCKED";
310 case OFPUTIL_PS_LIVE: return "LIVE";
311
312 case OFPUTIL_PS_STP_LISTEN:
313 case OFPUTIL_PS_STP_LEARN:
314 case OFPUTIL_PS_STP_FORWARD:
315 case OFPUTIL_PS_STP_BLOCK:
316 /* Handled elsewhere. */
317 return NULL;
318 }
319
320 return NULL;
321}
322
0ab14c8e 323static void
9e1fd49b 324ofp_print_port_state(struct ds *string, enum ofputil_port_state state)
0ab14c8e 325{
9e1fd49b 326 enum ofputil_port_state stp_state;
0ab14c8e
BP
327
328 /* The STP state is a 2-bit field so it doesn't fit in with the bitmask
329 * pattern. We have to special case it.
330 *
331 * OVS doesn't support STP, so this field will always be 0 if we are
332 * talking to OVS, so we'd always print STP_LISTEN in that case.
333 * Therefore, we don't print anything at all if the value is STP_LISTEN, to
334 * avoid confusing users. */
9e1fd49b 335 stp_state = state & OFPUTIL_PS_STP_MASK;
0ab14c8e 336 if (stp_state) {
9e1fd49b
BP
337 ds_put_cstr(string,
338 (stp_state == OFPUTIL_PS_STP_LEARN ? "STP_LEARN"
339 : stp_state == OFPUTIL_PS_STP_FORWARD ? "STP_FORWARD"
340 : "STP_BLOCK"));
341 state &= ~OFPUTIL_PS_STP_MASK;
0ab14c8e 342 if (state) {
e8fa940e
BP
343 ofp_print_bit_names(string, state, ofputil_port_state_to_name,
344 ' ');
0ab14c8e
BP
345 }
346 } else {
e8fa940e 347 ofp_print_bit_names(string, state, ofputil_port_state_to_name, ' ');
064af421
BP
348 }
349 ds_put_char(string, '\n');
350}
351
352static void
9e1fd49b 353ofp_print_phy_port(struct ds *string, const struct ofputil_phy_port *port)
064af421 354{
9e1fd49b 355 char name[sizeof port->name];
064af421
BP
356 int j;
357
358 memcpy(name, port->name, sizeof name);
359 for (j = 0; j < sizeof name - 1; j++) {
858f2852 360 if (!isprint((unsigned char) name[j])) {
064af421
BP
361 break;
362 }
363 }
364 name[j] = '\0';
365
366 ds_put_char(string, ' ');
9e1fd49b 367 ofputil_format_port(port->port_no, string);
0ab14c8e
BP
368 ds_put_format(string, "(%s): addr:"ETH_ADDR_FMT"\n",
369 name, ETH_ADDR_ARGS(port->hw_addr));
370
371 ds_put_cstr(string, " config: ");
9e1fd49b 372 ofp_print_port_config(string, port->config);
0ab14c8e
BP
373
374 ds_put_cstr(string, " state: ");
9e1fd49b 375 ofp_print_port_state(string, port->state);
0ab14c8e 376
064af421
BP
377 if (port->curr) {
378 ds_put_format(string, " current: ");
9e1fd49b 379 ofp_print_port_features(string, port->curr);
064af421
BP
380 }
381 if (port->advertised) {
382 ds_put_format(string, " advertised: ");
9e1fd49b 383 ofp_print_port_features(string, port->advertised);
064af421
BP
384 }
385 if (port->supported) {
386 ds_put_format(string, " supported: ");
9e1fd49b 387 ofp_print_port_features(string, port->supported);
064af421
BP
388 }
389 if (port->peer) {
390 ds_put_format(string, " peer: ");
9e1fd49b
BP
391 ofp_print_port_features(string, port->peer);
392 }
393 ds_put_format(string, " speed: %"PRIu32" Mbps now, "
394 "%"PRIu32" Mbps max\n",
395 port->curr_speed / UINT32_C(1000),
396 port->max_speed / UINT32_C(1000));
397}
398
2be393ed
JP
399/* Given a buffer 'b' that contains an array of OpenFlow ports of type
400 * 'ofp_version', writes a detailed description of each port into
401 * 'string'. */
402static void
403ofp_print_phy_ports(struct ds *string, uint8_t ofp_version,
404 struct ofpbuf *b)
405{
406 size_t n_ports;
407 struct ofputil_phy_port *ports;
408 enum ofperr error;
409 size_t i;
410
411 n_ports = ofputil_count_phy_ports(ofp_version, b);
412
413 ports = xmalloc(n_ports * sizeof *ports);
414 for (i = 0; i < n_ports; i++) {
415 error = ofputil_pull_phy_port(ofp_version, b, &ports[i]);
416 if (error) {
417 ofp_print_error(string, error);
418 goto exit;
419 }
420 }
421 qsort(ports, n_ports, sizeof *ports, compare_ports);
422 for (i = 0; i < n_ports; i++) {
423 ofp_print_phy_port(string, &ports[i]);
424 }
425
426exit:
427 free(ports);
428}
429
9e1fd49b
BP
430static const char *
431ofputil_capabilities_to_name(uint32_t bit)
432{
433 enum ofputil_capabilities capabilities = bit;
434
435 switch (capabilities) {
436 case OFPUTIL_C_FLOW_STATS: return "FLOW_STATS";
437 case OFPUTIL_C_TABLE_STATS: return "TABLE_STATS";
438 case OFPUTIL_C_PORT_STATS: return "PORT_STATS";
439 case OFPUTIL_C_IP_REASM: return "IP_REASM";
440 case OFPUTIL_C_QUEUE_STATS: return "QUEUE_STATS";
441 case OFPUTIL_C_ARP_MATCH_IP: return "ARP_MATCH_IP";
442 case OFPUTIL_C_STP: return "STP";
443 case OFPUTIL_C_GROUP_STATS: return "GROUP_STATS";
444 }
445
446 return NULL;
447}
448
449static const char *
450ofputil_action_bitmap_to_name(uint32_t bit)
451{
452 enum ofputil_action_bitmap action = bit;
453
454 switch (action) {
455 case OFPUTIL_A_OUTPUT: return "OUTPUT";
456 case OFPUTIL_A_SET_VLAN_VID: return "SET_VLAN_VID";
457 case OFPUTIL_A_SET_VLAN_PCP: return "SET_VLAN_PCP";
458 case OFPUTIL_A_STRIP_VLAN: return "STRIP_VLAN";
459 case OFPUTIL_A_SET_DL_SRC: return "SET_DL_SRC";
460 case OFPUTIL_A_SET_DL_DST: return "SET_DL_DST";
461 case OFPUTIL_A_SET_NW_SRC: return "SET_NW_SRC";
462 case OFPUTIL_A_SET_NW_DST: return "SET_NW_DST";
463 case OFPUTIL_A_SET_NW_ECN: return "SET_NW_ECN";
464 case OFPUTIL_A_SET_NW_TOS: return "SET_NW_TOS";
465 case OFPUTIL_A_SET_TP_SRC: return "SET_TP_SRC";
466 case OFPUTIL_A_SET_TP_DST: return "SET_TP_DST";
467 case OFPUTIL_A_ENQUEUE: return "ENQUEUE";
468 case OFPUTIL_A_COPY_TTL_OUT: return "COPY_TTL_OUT";
469 case OFPUTIL_A_COPY_TTL_IN: return "COPY_TTL_IN";
470 case OFPUTIL_A_SET_MPLS_LABEL: return "SET_MPLS_LABEL";
471 case OFPUTIL_A_SET_MPLS_TC: return "SET_MPLS_TC";
472 case OFPUTIL_A_SET_MPLS_TTL: return "SET_MPLS_TTL";
473 case OFPUTIL_A_DEC_MPLS_TTL: return "DEC_MPLS_TTL";
474 case OFPUTIL_A_PUSH_VLAN: return "PUSH_VLAN";
475 case OFPUTIL_A_POP_VLAN: return "POP_VLAN";
476 case OFPUTIL_A_PUSH_MPLS: return "PUSH_MPLS";
477 case OFPUTIL_A_POP_MPLS: return "POP_MPLS";
478 case OFPUTIL_A_SET_QUEUE: return "SET_QUEUE";
479 case OFPUTIL_A_GROUP: return "GROUP";
480 case OFPUTIL_A_SET_NW_TTL: return "SET_NW_TTL";
481 case OFPUTIL_A_DEC_NW_TTL: return "DEC_NW_TTL";
064af421 482 }
9e1fd49b
BP
483
484 return NULL;
064af421
BP
485}
486
064af421 487static void
d1e2cf21
BP
488ofp_print_switch_features(struct ds *string,
489 const struct ofp_switch_features *osf)
064af421 490{
9e1fd49b 491 struct ofputil_switch_features features;
9e1fd49b
BP
492 enum ofperr error;
493 struct ofpbuf b;
064af421 494
9e1fd49b
BP
495 error = ofputil_decode_switch_features(osf, &features, &b);
496 if (error) {
497 ofp_print_error(string, error);
498 return;
499 }
064af421 500
9e1fd49b
BP
501 ds_put_format(string, " dpid:%016"PRIx64"\n", features.datapath_id);
502 ds_put_format(string, "n_tables:%"PRIu8", n_buffers:%"PRIu32"\n",
503 features.n_tables, features.n_buffers);
064af421 504
9e1fd49b
BP
505 ds_put_cstr(string, "capabilities: ");
506 ofp_print_bit_names(string, features.capabilities,
e8fa940e 507 ofputil_capabilities_to_name, ' ');
9e1fd49b
BP
508 ds_put_char(string, '\n');
509
510 ds_put_cstr(string, "actions: ");
511 ofp_print_bit_names(string, features.actions,
e8fa940e 512 ofputil_action_bitmap_to_name, ' ');
9e1fd49b
BP
513 ds_put_char(string, '\n');
514
2be393ed 515 ofp_print_phy_ports(string, osf->header.version, &b);
064af421
BP
516}
517
064af421 518static void
d1e2cf21 519ofp_print_switch_config(struct ds *string, const struct ofp_switch_config *osc)
064af421 520{
f0fd1a17 521 enum ofp_config_flags flags;
064af421
BP
522
523 flags = ntohs(osc->flags);
3b62feba 524
7257b535
BP
525 ds_put_format(string, " frags=%s", ofputil_frag_handling_to_string(flags));
526 flags &= ~OFPC_FRAG_MASK;
527
f0fd1a17
PS
528 if (flags & OFPC_INVALID_TTL_TO_CONTROLLER) {
529 ds_put_format(string, " invalid_ttl_to_controller");
530 flags &= ~OFPC_INVALID_TTL_TO_CONTROLLER;
531 }
532
064af421
BP
533 if (flags) {
534 ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
535 }
536
537 ds_put_format(string, " miss_send_len=%"PRIu16"\n", ntohs(osc->miss_send_len));
538}
539
540static void print_wild(struct ds *string, const char *leader, int is_wild,
d295e8e9 541 int verbosity, const char *format, ...)
064af421
BP
542 __attribute__((format(printf, 5, 6)));
543
544static void print_wild(struct ds *string, const char *leader, int is_wild,
d295e8e9 545 int verbosity, const char *format, ...)
064af421
BP
546{
547 if (is_wild && verbosity < 2) {
548 return;
549 }
550 ds_put_cstr(string, leader);
551 if (!is_wild) {
552 va_list args;
553
554 va_start(args, format);
555 ds_put_format_valist(string, format, args);
556 va_end(args);
557 } else {
558 ds_put_char(string, '*');
559 }
560 ds_put_char(string, ',');
561}
562
563static void
dbba996b 564print_ip_netmask(struct ds *string, const char *leader, ovs_be32 ip,
064af421
BP
565 uint32_t wild_bits, int verbosity)
566{
567 if (wild_bits >= 32 && verbosity < 2) {
568 return;
569 }
570 ds_put_cstr(string, leader);
571 if (wild_bits < 32) {
572 ds_put_format(string, IP_FMT, IP_ARGS(&ip));
573 if (wild_bits) {
574 ds_put_format(string, "/%d", 32 - wild_bits);
575 }
576 } else {
577 ds_put_char(string, '*');
578 }
579 ds_put_char(string, ',');
580}
581
4f2cad2c 582void
eec25dc1 583ofp10_match_print(struct ds *f, const struct ofp10_match *om, int verbosity)
064af421 584{
eec25dc1 585 char *s = ofp10_match_to_string(om, verbosity);
064af421
BP
586 ds_put_cstr(f, s);
587 free(s);
588}
589
590char *
eec25dc1 591ofp10_match_to_string(const struct ofp10_match *om, int verbosity)
064af421
BP
592{
593 struct ds f = DS_EMPTY_INITIALIZER;
594 uint32_t w = ntohl(om->wildcards);
595 bool skip_type = false;
596 bool skip_proto = false;
597
eec25dc1 598 if (!(w & OFPFW10_DL_TYPE)) {
064af421
BP
599 skip_type = true;
600 if (om->dl_type == htons(ETH_TYPE_IP)) {
eec25dc1 601 if (!(w & OFPFW10_NW_PROTO)) {
064af421 602 skip_proto = true;
6767a2cc 603 if (om->nw_proto == IPPROTO_ICMP) {
064af421 604 ds_put_cstr(&f, "icmp,");
6767a2cc 605 } else if (om->nw_proto == IPPROTO_TCP) {
064af421 606 ds_put_cstr(&f, "tcp,");
6767a2cc 607 } else if (om->nw_proto == IPPROTO_UDP) {
064af421
BP
608 ds_put_cstr(&f, "udp,");
609 } else {
610 ds_put_cstr(&f, "ip,");
611 skip_proto = false;
612 }
613 } else {
614 ds_put_cstr(&f, "ip,");
615 }
616 } else if (om->dl_type == htons(ETH_TYPE_ARP)) {
617 ds_put_cstr(&f, "arp,");
618 } else {
619 skip_type = false;
620 }
621 }
eec25dc1 622 print_wild(&f, "in_port=", w & OFPFW10_IN_PORT, verbosity,
064af421 623 "%d", ntohs(om->in_port));
eec25dc1 624 print_wild(&f, "dl_vlan=", w & OFPFW10_DL_VLAN, verbosity,
6a1f89c8 625 "%d", ntohs(om->dl_vlan));
eec25dc1 626 print_wild(&f, "dl_vlan_pcp=", w & OFPFW10_DL_VLAN_PCP, verbosity,
959a2ecd 627 "%d", om->dl_vlan_pcp);
eec25dc1 628 print_wild(&f, "dl_src=", w & OFPFW10_DL_SRC, verbosity,
064af421 629 ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
eec25dc1 630 print_wild(&f, "dl_dst=", w & OFPFW10_DL_DST, verbosity,
064af421
BP
631 ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_dst));
632 if (!skip_type) {
eec25dc1 633 print_wild(&f, "dl_type=", w & OFPFW10_DL_TYPE, verbosity,
064af421
BP
634 "0x%04x", ntohs(om->dl_type));
635 }
636 print_ip_netmask(&f, "nw_src=", om->nw_src,
eec25dc1
BP
637 (w & OFPFW10_NW_SRC_MASK) >> OFPFW10_NW_SRC_SHIFT,
638 verbosity);
064af421 639 print_ip_netmask(&f, "nw_dst=", om->nw_dst,
eec25dc1
BP
640 (w & OFPFW10_NW_DST_MASK) >> OFPFW10_NW_DST_SHIFT,
641 verbosity);
064af421 642 if (!skip_proto) {
fb892732 643 if (om->dl_type == htons(ETH_TYPE_ARP)) {
eec25dc1 644 print_wild(&f, "arp_op=", w & OFPFW10_NW_PROTO, verbosity,
fb892732
JP
645 "%u", om->nw_proto);
646 } else {
eec25dc1 647 print_wild(&f, "nw_proto=", w & OFPFW10_NW_PROTO, verbosity,
fb892732
JP
648 "%u", om->nw_proto);
649 }
064af421 650 }
eec25dc1 651 print_wild(&f, "nw_tos=", w & OFPFW10_NW_TOS, verbosity,
1a960c80 652 "%u", om->nw_tos);
6767a2cc 653 if (om->nw_proto == IPPROTO_ICMP) {
eec25dc1 654 print_wild(&f, "icmp_type=", w & OFPFW10_ICMP_TYPE, verbosity,
3ee8a9f0 655 "%d", ntohs(om->tp_src));
eec25dc1 656 print_wild(&f, "icmp_code=", w & OFPFW10_ICMP_CODE, verbosity,
3ee8a9f0 657 "%d", ntohs(om->tp_dst));
064af421 658 } else {
eec25dc1 659 print_wild(&f, "tp_src=", w & OFPFW10_TP_SRC, verbosity,
064af421 660 "%d", ntohs(om->tp_src));
eec25dc1 661 print_wild(&f, "tp_dst=", w & OFPFW10_TP_DST, verbosity,
064af421
BP
662 "%d", ntohs(om->tp_dst));
663 }
7fa91113
BP
664 if (ds_last(&f) == ',') {
665 f.length--;
666 }
064af421
BP
667 return ds_cstr(&f);
668}
669
064af421 670static void
7fa91113
BP
671ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
672 enum ofputil_msg_code code, int verbosity)
064af421 673{
a9a2da38 674 struct ofputil_flow_mod fm;
f25d0cf3 675 struct ofpbuf ofpacts;
f904747b 676 bool need_priority;
90bf1e07 677 enum ofperr error;
064af421 678
f25d0cf3
BP
679 ofpbuf_init(&ofpacts, 64);
680 error = ofputil_decode_flow_mod(&fm, oh, OFPUTIL_P_OF10_TID, &ofpacts);
7fa91113 681 if (error) {
f25d0cf3 682 ofpbuf_uninit(&ofpacts);
7fa91113
BP
683 ofp_print_error(s, error);
684 return;
3ff4f871
BP
685 }
686
7fa91113
BP
687 ds_put_char(s, ' ');
688 switch (fm.command) {
064af421 689 case OFPFC_ADD:
7fa91113 690 ds_put_cstr(s, "ADD");
064af421
BP
691 break;
692 case OFPFC_MODIFY:
7fa91113 693 ds_put_cstr(s, "MOD");
064af421
BP
694 break;
695 case OFPFC_MODIFY_STRICT:
7fa91113 696 ds_put_cstr(s, "MOD_STRICT");
064af421
BP
697 break;
698 case OFPFC_DELETE:
7fa91113 699 ds_put_cstr(s, "DEL");
064af421
BP
700 break;
701 case OFPFC_DELETE_STRICT:
7fa91113 702 ds_put_cstr(s, "DEL_STRICT");
064af421
BP
703 break;
704 default:
7fa91113
BP
705 ds_put_format(s, "cmd:%d", fm.command);
706 }
6c1491fb 707 if (fm.table_id != 0) {
e896c2d4 708 ds_put_format(s, " table:%d", fm.table_id);
6c1491fb 709 }
7fa91113
BP
710
711 ds_put_char(s, ' ');
712 if (verbosity >= 3 && code == OFPUTIL_OFPT_FLOW_MOD) {
713 const struct ofp_flow_mod *ofm = (const struct ofp_flow_mod *) oh;
eec25dc1 714 ofp10_match_print(s, &ofm->match, verbosity);
f904747b
BP
715
716 /* ofp_print_match() doesn't print priority. */
717 need_priority = true;
7fa91113
BP
718 } else if (verbosity >= 3 && code == OFPUTIL_NXT_FLOW_MOD) {
719 const struct nx_flow_mod *nfm = (const struct nx_flow_mod *) oh;
720 const void *nxm = nfm + 1;
f904747b
BP
721 char *nxm_s;
722
723 nxm_s = nx_match_to_string(nxm, ntohs(nfm->match_len));
7fa91113
BP
724 ds_put_cstr(s, nxm_s);
725 free(nxm_s);
f904747b
BP
726
727 /* nx_match_to_string() doesn't print priority. */
728 need_priority = true;
7fa91113
BP
729 } else {
730 cls_rule_format(&fm.cr, s);
f904747b
BP
731
732 /* cls_rule_format() does print priority. */
733 need_priority = false;
3ff4f871 734 }
7fa91113
BP
735
736 if (ds_last(s) != ' ') {
737 ds_put_char(s, ' ');
3ff4f871 738 }
623e1caf
JP
739 if (fm.new_cookie != htonll(0)) {
740 ds_put_format(s, "cookie:0x%"PRIx64" ", ntohll(fm.new_cookie));
741 }
742 if (fm.cookie_mask != htonll(0)) {
743 ds_put_format(s, "cookie:0x%"PRIx64"/0x%"PRIx64" ",
744 ntohll(fm.cookie), ntohll(fm.cookie_mask));
3ff4f871 745 }
7fa91113
BP
746 if (fm.idle_timeout != OFP_FLOW_PERMANENT) {
747 ds_put_format(s, "idle:%"PRIu16" ", fm.idle_timeout);
064af421 748 }
7fa91113
BP
749 if (fm.hard_timeout != OFP_FLOW_PERMANENT) {
750 ds_put_format(s, "hard:%"PRIu16" ", fm.hard_timeout);
3ff4f871 751 }
f904747b 752 if (fm.cr.priority != OFP_DEFAULT_PRIORITY && need_priority) {
7fa91113 753 ds_put_format(s, "pri:%"PRIu16" ", fm.cr.priority);
3ff4f871 754 }
7fa91113
BP
755 if (fm.buffer_id != UINT32_MAX) {
756 ds_put_format(s, "buf:0x%"PRIx32" ", fm.buffer_id);
3ff4f871 757 }
de0f16bc
BP
758 if (fm.out_port != OFPP_NONE) {
759 ds_put_format(s, "out_port:");
760 ofputil_format_port(fm.out_port, s);
761 ds_put_char(s, ' ');
762 }
7fa91113 763 if (fm.flags != 0) {
a993007b
BP
764 uint16_t flags = fm.flags;
765
766 if (flags & OFPFF_SEND_FLOW_REM) {
767 ds_put_cstr(s, "send_flow_rem ");
768 }
769 if (flags & OFPFF_CHECK_OVERLAP) {
770 ds_put_cstr(s, "check_overlap ");
771 }
772 if (flags & OFPFF_EMERG) {
773 ds_put_cstr(s, "emerg ");
774 }
775
776 flags &= ~(OFPFF_SEND_FLOW_REM | OFPFF_CHECK_OVERLAP | OFPFF_EMERG);
777 if (flags) {
778 ds_put_format(s, "flags:0x%"PRIx16" ", flags);
779 }
7fa91113
BP
780 }
781
f25d0cf3
BP
782 ofpacts_format(fm.ofpacts, fm.ofpacts_len, s);
783 ofpbuf_uninit(&ofpacts);
064af421
BP
784}
785
09862ec6
BP
786static void
787ofp_print_duration(struct ds *string, unsigned int sec, unsigned int nsec)
788{
789 ds_put_format(string, "%u", sec);
790 if (nsec > 0) {
791 ds_put_format(string, ".%09u", nsec);
792 while (string->string[string->length - 1] == '0') {
793 string->length--;
794 }
795 }
796 ds_put_char(string, 's');
797}
798
80d5aefd
BP
799static const char *
800ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason)
801{
802 static char s[32];
803
804 switch (reason) {
805 case OFPRR_IDLE_TIMEOUT:
806 return "idle";
807 case OFPRR_HARD_TIMEOUT:
808 return "hard";
809 case OFPRR_DELETE:
810 return "delete";
04f68eb2
SH
811 case OFPRR_GROUP_DELETE:
812 return "group_delete";
1d31ece9
BP
813 case OFPRR_EVICTION:
814 return "eviction";
80d5aefd
BP
815 default:
816 sprintf(s, "%d", (int) reason);
817 return s;
818 }
819}
820
064af421 821static void
9b045a0c 822ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
064af421 823{
9b045a0c 824 struct ofputil_flow_removed fr;
90bf1e07 825 enum ofperr error;
9b045a0c 826
b78f6b77 827 error = ofputil_decode_flow_removed(&fr, oh);
9b045a0c
BP
828 if (error) {
829 ofp_print_error(string, error);
830 return;
831 }
832
fbd76b2e 833 ds_put_char(string, ' ');
9b045a0c
BP
834 cls_rule_format(&fr.rule, string);
835
80d5aefd
BP
836 ds_put_format(string, " reason=%s",
837 ofp_flow_removed_reason_to_string(fr.reason));
3ff4f871 838
9b045a0c
BP
839 if (fr.cookie != htonll(0)) {
840 ds_put_format(string, " cookie:0x%"PRIx64, ntohll(fr.cookie));
3ff4f871 841 }
09862ec6 842 ds_put_cstr(string, " duration");
9b045a0c 843 ofp_print_duration(string, fr.duration_sec, fr.duration_nsec);
09862ec6 844 ds_put_format(string, " idle%"PRIu16" pkts%"PRIu64" bytes%"PRIu64"\n",
9b045a0c 845 fr.idle_timeout, fr.packet_count, fr.byte_count);
064af421
BP
846}
847
848static void
9e1fd49b 849ofp_print_port_mod(struct ds *string, const struct ofp_header *oh)
064af421 850{
9e1fd49b
BP
851 struct ofputil_port_mod pm;
852 enum ofperr error;
853
854 error = ofputil_decode_port_mod(oh, &pm);
855 if (error) {
856 ofp_print_error(string, error);
857 return;
858 }
859
860 ds_put_format(string, "port: %"PRIu16": addr:"ETH_ADDR_FMT"\n",
861 pm.port_no, ETH_ADDR_ARGS(pm.hw_addr));
862
863 ds_put_format(string, " config: ");
864 ofp_print_port_config(string, pm.config);
865
866 ds_put_format(string, " mask: ");
867 ofp_print_port_config(string, pm.mask);
868
064af421 869 ds_put_format(string, " advertise: ");
9e1fd49b
BP
870 if (pm.advertise) {
871 ofp_print_port_features(string, pm.advertise);
064af421
BP
872 } else {
873 ds_put_format(string, "UNCHANGED\n");
874 }
875}
876
7fa91113 877static void
90bf1e07 878ofp_print_error(struct ds *string, enum ofperr error)
7fa91113 879{
7fa91113
BP
880 if (string->length) {
881 ds_put_char(string, ' ');
882 }
90bf1e07 883 ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error));
f74be05a
JP
884}
885
064af421 886static void
d1e2cf21 887ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
064af421 888{
d1e2cf21 889 size_t len = ntohs(oem->header.length);
dc4762ed
BP
890 size_t payload_ofs, payload_len;
891 const void *payload;
90bf1e07 892 enum ofperr error;
064af421
BP
893 char *s;
894
90bf1e07
BP
895 error = ofperr_decode_msg(&oem->header, &payload_ofs);
896 if (!error) {
897 ds_put_cstr(string, "***decode error***");
dc4762ed
BP
898 ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true);
899 return;
f74be05a
JP
900 }
901
90bf1e07 902 ds_put_format(string, " %s\n", ofperr_get_name(error));
064af421 903
dc4762ed
BP
904 payload = (const uint8_t *) oem + payload_ofs;
905 payload_len = len - payload_ofs;
90bf1e07 906 if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) {
dc4762ed 907 ds_put_printable(string, payload, payload_len);
90bf1e07 908 } else {
dc4762ed 909 s = ofp_to_string(payload, payload_len, 1);
064af421
BP
910 ds_put_cstr(string, s);
911 free(s);
064af421
BP
912 }
913}
914
064af421 915static void
d1e2cf21 916ofp_print_port_status(struct ds *string, const struct ofp_port_status *ops)
064af421 917{
9e1fd49b
BP
918 struct ofputil_port_status ps;
919 enum ofperr error;
920
921 error = ofputil_decode_port_status(ops, &ps);
922 if (error) {
923 ofp_print_error(string, error);
924 return;
925 }
926
927 if (ps.reason == OFPPR_ADD) {
064af421 928 ds_put_format(string, " ADD:");
9e1fd49b 929 } else if (ps.reason == OFPPR_DELETE) {
064af421 930 ds_put_format(string, " DEL:");
9e1fd49b 931 } else if (ps.reason == OFPPR_MODIFY) {
064af421
BP
932 ds_put_format(string, " MOD:");
933 }
934
9e1fd49b 935 ofp_print_phy_port(string, &ps.desc);
064af421
BP
936}
937
938static void
63f2140a 939ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_desc_stats *ods)
064af421 940{
fbd76b2e 941 ds_put_char(string, '\n');
d295e8e9 942 ds_put_format(string, "Manufacturer: %.*s\n",
dd70b475
JP
943 (int) sizeof ods->mfr_desc, ods->mfr_desc);
944 ds_put_format(string, "Hardware: %.*s\n",
945 (int) sizeof ods->hw_desc, ods->hw_desc);
946 ds_put_format(string, "Software: %.*s\n",
947 (int) sizeof ods->sw_desc, ods->sw_desc);
948 ds_put_format(string, "Serial Num: %.*s\n",
949 (int) sizeof ods->serial_num, ods->serial_num);
950 ds_put_format(string, "DP Description: %.*s\n",
951 (int) sizeof ods->dp_desc, ods->dp_desc);
064af421
BP
952}
953
954static void
76c93b22
BP
955ofp_print_flow_stats_request(struct ds *string,
956 const struct ofp_stats_msg *osm)
064af421 957{
81d1ea94 958 struct ofputil_flow_stats_request fsr;
90bf1e07 959 enum ofperr error;
064af421 960
76c93b22 961 error = ofputil_decode_flow_stats_request(&fsr, &osm->header);
2af0c0ef
BP
962 if (error) {
963 ofp_print_error(string, error);
964 return;
965 }
966
967 if (fsr.table_id != 0xff) {
e896c2d4 968 ds_put_format(string, " table=%"PRIu8, fsr.table_id);
064af421
BP
969 }
970
2af0c0ef
BP
971 if (fsr.out_port != OFPP_NONE) {
972 ds_put_cstr(string, " out_port=");
39dc9082 973 ofputil_format_port(fsr.out_port, string);
2af0c0ef
BP
974 }
975
54ae6fa8
BP
976 /* A flow stats request doesn't include a priority, but cls_rule_format()
977 * will print one unless it is OFP_DEFAULT_PRIORITY. */
978 fsr.match.priority = OFP_DEFAULT_PRIORITY;
979
2af0c0ef
BP
980 ds_put_char(string, ' ');
981 cls_rule_format(&fsr.match, string);
064af421
BP
982}
983
bdcc5925
BP
984void
985ofp_print_flow_stats(struct ds *string, struct ofputil_flow_stats *fs)
986{
987 ds_put_format(string, " cookie=0x%"PRIx64", duration=",
988 ntohll(fs->cookie));
989
990 ofp_print_duration(string, fs->duration_sec, fs->duration_nsec);
991 ds_put_format(string, ", table=%"PRIu8", ", fs->table_id);
992 ds_put_format(string, "n_packets=%"PRIu64", ", fs->packet_count);
993 ds_put_format(string, "n_bytes=%"PRIu64", ", fs->byte_count);
994 if (fs->idle_timeout != OFP_FLOW_PERMANENT) {
995 ds_put_format(string, "idle_timeout=%"PRIu16", ", fs->idle_timeout);
996 }
997 if (fs->hard_timeout != OFP_FLOW_PERMANENT) {
998 ds_put_format(string, "hard_timeout=%"PRIu16", ", fs->hard_timeout);
999 }
1000 if (fs->idle_age >= 0) {
1001 ds_put_format(string, "idle_age=%d, ", fs->idle_age);
1002 }
1003 if (fs->hard_age >= 0 && fs->hard_age != fs->duration_sec) {
1004 ds_put_format(string, "hard_age=%d, ", fs->hard_age);
1005 }
1006
1007 cls_rule_format(&fs->rule, string);
1008 if (string->string[string->length - 1] != ' ') {
1009 ds_put_char(string, ' ');
1010 }
1011
1012 ofpacts_format(fs->ofpacts, fs->ofpacts_len, string);
1013}
1014
064af421 1015static void
4ffd1b43 1016ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
064af421 1017{
f25d0cf3 1018 struct ofpbuf ofpacts;
4ffd1b43 1019 struct ofpbuf b;
064af421 1020
4ffd1b43 1021 ofpbuf_use_const(&b, oh, ntohs(oh->length));
f25d0cf3 1022 ofpbuf_init(&ofpacts, 64);
4ffd1b43
BP
1023 for (;;) {
1024 struct ofputil_flow_stats fs;
1025 int retval;
fab8fadb 1026
f25d0cf3 1027 retval = ofputil_decode_flow_stats_reply(&fs, &b, true, &ofpacts);
4ffd1b43
BP
1028 if (retval) {
1029 if (retval != EOF) {
1030 ds_put_cstr(string, " ***parse error***");
064af421
BP
1031 }
1032 break;
1033 }
8961de6a 1034 ds_put_char(string, '\n');
bdcc5925
BP
1035 ofp_print_flow_stats(string, &fs);
1036 }
c6430da5
BP
1037}
1038
064af421 1039static void
63f2140a
BP
1040ofp_print_ofpst_aggregate_reply(struct ds *string,
1041 const struct ofp_aggregate_stats_reply *asr)
064af421 1042{
c4617b3c
BP
1043 ds_put_format(string, " packet_count=%"PRIu64,
1044 ntohll(get_32aligned_be64(&asr->packet_count)));
1045 ds_put_format(string, " byte_count=%"PRIu64,
1046 ntohll(get_32aligned_be64(&asr->byte_count)));
064af421
BP
1047 ds_put_format(string, " flow_count=%"PRIu32, ntohl(asr->flow_count));
1048}
1049
a2ad9ecd
BP
1050static void
1051ofp_print_nxst_aggregate_reply(struct ds *string,
1052 const struct nx_aggregate_stats_reply *nasr)
1053{
675baf0c
BP
1054 ds_put_format(string, " packet_count=%"PRIu64, ntohll(nasr->packet_count));
1055 ds_put_format(string, " byte_count=%"PRIu64, ntohll(nasr->byte_count));
1056 ds_put_format(string, " flow_count=%"PRIu32, ntohl(nasr->flow_count));
a2ad9ecd
BP
1057}
1058
d295e8e9 1059static void print_port_stat(struct ds *string, const char *leader,
c4617b3c 1060 const ovs_32aligned_be64 *statp, int more)
064af421 1061{
c4617b3c
BP
1062 uint64_t stat = ntohll(get_32aligned_be64(statp));
1063
064af421 1064 ds_put_cstr(string, leader);
c4617b3c 1065 if (stat != UINT64_MAX) {
064af421
BP
1066 ds_put_format(string, "%"PRIu64, stat);
1067 } else {
1068 ds_put_char(string, '?');
1069 }
1070 if (more) {
1071 ds_put_cstr(string, ", ");
1072 } else {
1073 ds_put_cstr(string, "\n");
1074 }
1075}
1076
abaad8cf 1077static void
63f2140a
BP
1078ofp_print_ofpst_port_request(struct ds *string,
1079 const struct ofp_port_stats_request *psr)
abaad8cf 1080{
fbd76b2e 1081 ds_put_format(string, " port_no=%"PRIu16, ntohs(psr->port_no));
abaad8cf
JP
1082}
1083
064af421 1084static void
d1e2cf21
BP
1085ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
1086 int verbosity)
064af421 1087{
d1e2cf21
BP
1088 const struct ofp_port_stats *ps = ofputil_stats_body(oh);
1089 size_t n = ofputil_stats_body_len(oh) / sizeof *ps;
064af421
BP
1090 ds_put_format(string, " %zu ports\n", n);
1091 if (verbosity < 1) {
1092 return;
1093 }
1094
1095 for (; n--; ps++) {
1096 ds_put_format(string, " port %2"PRIu16": ", ntohs(ps->port_no));
1097
1098 ds_put_cstr(string, "rx ");
c4617b3c
BP
1099 print_port_stat(string, "pkts=", &ps->rx_packets, 1);
1100 print_port_stat(string, "bytes=", &ps->rx_bytes, 1);
1101 print_port_stat(string, "drop=", &ps->rx_dropped, 1);
1102 print_port_stat(string, "errs=", &ps->rx_errors, 1);
1103 print_port_stat(string, "frame=", &ps->rx_frame_err, 1);
1104 print_port_stat(string, "over=", &ps->rx_over_err, 1);
1105 print_port_stat(string, "crc=", &ps->rx_crc_err, 0);
064af421
BP
1106
1107 ds_put_cstr(string, " tx ");
c4617b3c
BP
1108 print_port_stat(string, "pkts=", &ps->tx_packets, 1);
1109 print_port_stat(string, "bytes=", &ps->tx_bytes, 1);
1110 print_port_stat(string, "drop=", &ps->tx_dropped, 1);
1111 print_port_stat(string, "errs=", &ps->tx_errors, 1);
1112 print_port_stat(string, "coll=", &ps->collisions, 0);
064af421
BP
1113 }
1114}
1115
1116static void
d1e2cf21
BP
1117ofp_print_ofpst_table_reply(struct ds *string, const struct ofp_header *oh,
1118 int verbosity)
064af421 1119{
d1e2cf21
BP
1120 const struct ofp_table_stats *ts = ofputil_stats_body(oh);
1121 size_t n = ofputil_stats_body_len(oh) / sizeof *ts;
064af421
BP
1122 ds_put_format(string, " %zu tables\n", n);
1123 if (verbosity < 1) {
1124 return;
1125 }
1126
1127 for (; n--; ts++) {
1128 char name[OFP_MAX_TABLE_NAME_LEN + 1];
e868fb3d 1129 ovs_strlcpy(name, ts->name, sizeof name);
064af421
BP
1130
1131 ds_put_format(string, " %d: %-8s: ", ts->table_id, name);
1132 ds_put_format(string, "wild=0x%05"PRIx32", ", ntohl(ts->wildcards));
1133 ds_put_format(string, "max=%6"PRIu32", ", ntohl(ts->max_entries));
1134 ds_put_format(string, "active=%"PRIu32"\n", ntohl(ts->active_count));
1135 ds_put_cstr(string, " ");
d295e8e9 1136 ds_put_format(string, "lookup=%"PRIu64", ",
c4617b3c 1137 ntohll(get_32aligned_be64(&ts->lookup_count)));
064af421 1138 ds_put_format(string, "matched=%"PRIu64"\n",
c4617b3c 1139 ntohll(get_32aligned_be64(&ts->matched_count)));
064af421
BP
1140 }
1141}
1142
d2805da2
BP
1143static void
1144ofp_print_queue_name(struct ds *string, uint32_t queue_id)
1145{
1146 if (queue_id == OFPQ_ALL) {
1147 ds_put_cstr(string, "ALL");
1148 } else {
1149 ds_put_format(string, "%"PRIu32, queue_id);
1150 }
1151}
1152
1153static void
63f2140a
BP
1154ofp_print_ofpst_queue_request(struct ds *string,
1155 const struct ofp_queue_stats_request *qsr)
d2805da2 1156{
d2805da2 1157 ds_put_cstr(string, "port=");
39dc9082 1158 ofputil_format_port(ntohs(qsr->port_no), string);
d2805da2
BP
1159
1160 ds_put_cstr(string, " queue=");
1161 ofp_print_queue_name(string, ntohl(qsr->queue_id));
1162}
1163
1164static void
d1e2cf21
BP
1165ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
1166 int verbosity)
d2805da2 1167{
d1e2cf21
BP
1168 const struct ofp_queue_stats *qs = ofputil_stats_body(oh);
1169 size_t n = ofputil_stats_body_len(oh) / sizeof *qs;
d2805da2
BP
1170 ds_put_format(string, " %zu queues\n", n);
1171 if (verbosity < 1) {
1172 return;
1173 }
1174
1175 for (; n--; qs++) {
1176 ds_put_cstr(string, " port ");
39dc9082 1177 ofputil_format_port(ntohs(qs->port_no), string);
d2805da2
BP
1178 ds_put_cstr(string, " queue ");
1179 ofp_print_queue_name(string, ntohl(qs->queue_id));
1180 ds_put_cstr(string, ": ");
1181
c4617b3c
BP
1182 print_port_stat(string, "bytes=", &qs->tx_bytes, 1);
1183 print_port_stat(string, "pkts=", &qs->tx_packets, 1);
1184 print_port_stat(string, "errors=", &qs->tx_errors, 0);
d2805da2
BP
1185 }
1186}
1187
2be393ed
JP
1188static void
1189ofp_print_ofpst_port_desc_reply(struct ds *string,
1190 const struct ofp_header *oh)
1191{
1192 struct ofpbuf b;
1193
1194 ofpbuf_use_const(&b, oh, ntohs(oh->length));
1195 ofpbuf_pull(&b, sizeof(struct ofp_stats_msg));
1196 ds_put_char(string, '\n');
1197 ofp_print_phy_ports(string, oh->version, &b);
1198}
1199
064af421 1200static void
d1e2cf21 1201ofp_print_stats_request(struct ds *string, const struct ofp_header *oh)
064af421 1202{
28c8bad1 1203 const struct ofp_stats_msg *srq = (const struct ofp_stats_msg *) oh;
064af421
BP
1204
1205 if (srq->flags) {
1206 ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***",
1207 ntohs(srq->flags));
1208 }
064af421
BP
1209}
1210
1211static void
d1e2cf21 1212ofp_print_stats_reply(struct ds *string, const struct ofp_header *oh)
064af421 1213{
28c8bad1 1214 const struct ofp_stats_msg *srp = (const struct ofp_stats_msg *) oh;
064af421 1215
d1e2cf21 1216 if (srp->flags) {
064af421 1217 uint16_t flags = ntohs(srp->flags);
d1e2cf21
BP
1218
1219 ds_put_cstr(string, " flags=");
064af421
BP
1220 if (flags & OFPSF_REPLY_MORE) {
1221 ds_put_cstr(string, "[more]");
1222 flags &= ~OFPSF_REPLY_MORE;
1223 }
1224 if (flags) {
d1e2cf21
BP
1225 ds_put_format(string, "[***unknown flags 0x%04"PRIx16"***]",
1226 flags);
064af421
BP
1227 }
1228 }
064af421
BP
1229}
1230
1231static void
d1e2cf21 1232ofp_print_echo(struct ds *string, const struct ofp_header *oh, int verbosity)
064af421 1233{
d1e2cf21 1234 size_t len = ntohs(oh->length);
064af421 1235
d1e2cf21 1236 ds_put_format(string, " %zu bytes of payload\n", len - sizeof *oh);
064af421 1237 if (verbosity > 1) {
d1e2cf21 1238 ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true);
064af421
BP
1239 }
1240}
1241
61fe3a7b
BP
1242static void
1243ofp_print_nxt_role_message(struct ds *string,
1244 const struct nx_role_request *nrr)
1245{
1246 unsigned int role = ntohl(nrr->role);
1247
1248 ds_put_cstr(string, " role=");
1249 if (role == NX_ROLE_OTHER) {
1250 ds_put_cstr(string, "other");
1251 } else if (role == NX_ROLE_MASTER) {
1252 ds_put_cstr(string, "master");
1253 } else if (role == NX_ROLE_SLAVE) {
1254 ds_put_cstr(string, "slave");
1255 } else {
1256 ds_put_format(string, "%u", role);
1257 }
1258}
1259
6c1491fb
BP
1260static void
1261ofp_print_nxt_flow_mod_table_id(struct ds *string,
73dbf4ab 1262 const struct nx_flow_mod_table_id *nfmti)
6c1491fb
BP
1263{
1264 ds_put_format(string, " %s", nfmti->set ? "enable" : "disable");
1265}
1266
7fa91113
BP
1267static void
1268ofp_print_nxt_set_flow_format(struct ds *string,
73dbf4ab 1269 const struct nx_set_flow_format *nsff)
7fa91113
BP
1270{
1271 uint32_t format = ntohl(nsff->format);
1272
1273 ds_put_cstr(string, " format=");
27527aa0
BP
1274 if (ofputil_nx_flow_format_is_valid(format)) {
1275 ds_put_cstr(string, ofputil_nx_flow_format_to_string(format));
7fa91113
BP
1276 } else {
1277 ds_put_format(string, "%"PRIu32, format);
1278 }
1279}
1280
54834960
EJ
1281static void
1282ofp_print_nxt_set_packet_in_format(struct ds *string,
73dbf4ab 1283 const struct nx_set_packet_in_format *nspf)
54834960
EJ
1284{
1285 uint32_t format = ntohl(nspf->format);
1286
1287 ds_put_cstr(string, " format=");
1288 if (ofputil_packet_in_format_is_valid(format)) {
1289 ds_put_cstr(string, ofputil_packet_in_format_to_string(format));
1290 } else {
1291 ds_put_format(string, "%"PRIu32, format);
1292 }
1293}
1294
80d5aefd
BP
1295static const char *
1296ofp_port_reason_to_string(enum ofp_port_reason reason)
1297{
1298 static char s[32];
1299
1300 switch (reason) {
1301 case OFPPR_ADD:
1302 return "add";
1303
1304 case OFPPR_DELETE:
1305 return "delete";
1306
1307 case OFPPR_MODIFY:
1308 return "modify";
1309
1310 default:
1311 sprintf(s, "%d", (int) reason);
1312 return s;
1313 }
1314}
1315
1316static void
1317ofp_print_nxt_set_async_config(struct ds *string,
1318 const struct nx_async_config *nac)
1319{
1320 int i;
1321
1322 for (i = 0; i < 2; i++) {
1323 int j;
1324
1325 ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave");
1326
1327 ds_put_cstr(string, " PACKET_IN:");
1328 for (j = 0; j < 32; j++) {
1329 if (nac->packet_in_mask[i] & htonl(1u << j)) {
1330 ds_put_format(string, " %s",
7c1a76a4 1331 ofputil_packet_in_reason_to_string(j));
80d5aefd
BP
1332 }
1333 }
1334 if (!nac->packet_in_mask[i]) {
1335 ds_put_cstr(string, " (off)");
1336 }
1337 ds_put_char(string, '\n');
1338
1339 ds_put_cstr(string, " PORT_STATUS:");
1340 for (j = 0; j < 32; j++) {
1341 if (nac->port_status_mask[i] & htonl(1u << j)) {
1342 ds_put_format(string, " %s", ofp_port_reason_to_string(j));
1343 }
1344 }
1345 if (!nac->port_status_mask[i]) {
1346 ds_put_cstr(string, " (off)");
1347 }
1348 ds_put_char(string, '\n');
1349
1350 ds_put_cstr(string, " FLOW_REMOVED:");
1351 for (j = 0; j < 32; j++) {
1352 if (nac->flow_removed_mask[i] & htonl(1u << j)) {
1353 ds_put_format(string, " %s",
1354 ofp_flow_removed_reason_to_string(j));
1355 }
1356 }
1357 if (!nac->flow_removed_mask[i]) {
1358 ds_put_cstr(string, " (off)");
1359 }
1360 ds_put_char(string, '\n');
1361 }
1362}
1363
a7349929
BP
1364static void
1365ofp_print_nxt_set_controller_id(struct ds *string,
1366 const struct nx_controller_id *nci)
1367{
1368 ds_put_format(string, " id=%"PRIu16, ntohs(nci->controller_id));
1369}
1370
2b07c8b1
BP
1371static void
1372ofp_print_nxt_flow_monitor_cancel(struct ds *string,
1373 const struct ofp_header *oh)
1374{
1375 ds_put_format(string, " id=%"PRIu32,
1376 ofputil_decode_flow_monitor_cancel(oh));
1377}
1378
1379static const char *
1380nx_flow_monitor_flags_to_name(uint32_t bit)
1381{
1382 enum nx_flow_monitor_flags fmf = bit;
1383
1384 switch (fmf) {
1385 case NXFMF_INITIAL: return "initial";
1386 case NXFMF_ADD: return "add";
1387 case NXFMF_DELETE: return "delete";
1388 case NXFMF_MODIFY: return "modify";
1389 case NXFMF_ACTIONS: return "actions";
1390 case NXFMF_OWN: return "own";
1391 }
1392
1393 return NULL;
1394}
1395
1396static void
1397ofp_print_nxst_flow_monitor_request(struct ds *string,
1398 const struct ofp_header *oh)
1399{
1400 struct ofpbuf b;
1401
1402 ofpbuf_use_const(&b, oh, ntohs(oh->length));
1403 for (;;) {
1404 struct ofputil_flow_monitor_request request;
1405 int retval;
1406
1407 retval = ofputil_decode_flow_monitor_request(&request, &b);
1408 if (retval) {
1409 if (retval != EOF) {
1410 ofp_print_error(string, retval);
1411 }
1412 return;
1413 }
1414
1415 ds_put_format(string, "\n id=%"PRIu32" flags=", request.id);
1416 ofp_print_bit_names(string, request.flags,
1417 nx_flow_monitor_flags_to_name, ',');
1418
1419 if (request.out_port != OFPP_NONE) {
1420 ds_put_cstr(string, " out_port=");
1421 ofputil_format_port(request.out_port, string);
1422 }
1423
1424 if (request.table_id != 0xff) {
1425 ds_put_format(string, " table=%"PRIu8, request.table_id);
1426 }
1427
1428 ds_put_char(string, ' ');
1429 cls_rule_format(&request.match, string);
1430 ds_chomp(string, ' ');
1431 }
1432}
1433
1434static void
1435ofp_print_nxst_flow_monitor_reply(struct ds *string,
1436 const struct ofp_header *oh)
1437{
1438 uint64_t ofpacts_stub[1024 / 8];
1439 struct ofpbuf ofpacts;
1440 struct ofpbuf b;
1441
1442 ofpbuf_use_const(&b, oh, ntohs(oh->length));
1443 ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
1444 for (;;) {
1445 struct ofputil_flow_update update;
1446 struct cls_rule match;
1447 int retval;
1448
1449 update.match = &match;
1450 retval = ofputil_decode_flow_update(&update, &b, &ofpacts);
1451 if (retval) {
1452 if (retval != EOF) {
1453 ofp_print_error(string, retval);
1454 }
1455 ofpbuf_uninit(&ofpacts);
1456 return;
1457 }
1458
1459 ds_put_cstr(string, "\n event=");
1460 switch (update.event) {
1461 case NXFME_ADDED:
1462 ds_put_cstr(string, "ADDED");
1463 break;
1464
1465 case NXFME_DELETED:
1466 ds_put_format(string, "DELETED reason=%s",
1467 ofp_flow_removed_reason_to_string(update.reason));
1468 break;
1469
1470 case NXFME_MODIFIED:
1471 ds_put_cstr(string, "MODIFIED");
1472 break;
1473
1474 case NXFME_ABBREV:
1475 ds_put_format(string, "ABBREV xid=0x%"PRIx32, ntohl(update.xid));
1476 continue;
1477 }
1478
1479 ds_put_format(string, " table=%"PRIu8, update.table_id);
1480 if (update.idle_timeout != OFP_FLOW_PERMANENT) {
1481 ds_put_format(string, " idle_timeout=%"PRIu16,
1482 update.idle_timeout);
1483 }
1484 if (update.hard_timeout != OFP_FLOW_PERMANENT) {
1485 ds_put_format(string, " hard_timeout=%"PRIu16,
1486 update.hard_timeout);
1487 }
1488 ds_put_format(string, " cookie=%#"PRIx64, ntohll(update.cookie));
1489
1490 ds_put_char(string, ' ');
1491 cls_rule_format(update.match, string);
1492
1493 if (update.ofpacts_len) {
1494 if (string->string[string->length - 1] != ' ') {
1495 ds_put_char(string, ' ');
1496 }
1497 ofpacts_format(update.ofpacts, update.ofpacts_len, string);
1498 }
1499 }
1500}
1501
bdcc5925
BP
1502void
1503ofp_print_version(const struct ofp_header *oh,
1504 struct ds *string)
d1e2cf21 1505{
3811e66b
BP
1506 switch (oh->version) {
1507 case OFP10_VERSION:
1508 break;
1509 case OFP11_VERSION:
1510 ds_put_cstr(string, " (OF1.1)");
4232ef77
SH
1511 break;
1512 case OFP12_VERSION:
1513 ds_put_cstr(string, " (OF1.2)");
3811e66b
BP
1514 break;
1515 default:
1516 ds_put_format(string, " (OF 0x%02"PRIx8")", oh->version);
1517 break;
1518 }
1519 ds_put_format(string, " (xid=0x%"PRIx32"):", ntohl(oh->xid));
bdcc5925 1520}
d1e2cf21 1521
bdcc5925
BP
1522static void
1523ofp_to_string__(const struct ofp_header *oh,
1524 const struct ofputil_msg_type *type, struct ds *string,
1525 int verbosity)
1526{
1527 enum ofputil_msg_code code;
1528 const void *msg = oh;
1529
1530 ds_put_cstr(string, ofputil_msg_type_name(type));
1531 ofp_print_version(oh, string);
7fa91113
BP
1532 code = ofputil_msg_type_code(type);
1533 switch (code) {
8f93e93c 1534 case OFPUTIL_MSG_INVALID:
d1e2cf21
BP
1535 break;
1536
1537 case OFPUTIL_OFPT_HELLO:
dc4762ed
BP
1538 ds_put_char(string, '\n');
1539 ds_put_hex_dump(string, oh + 1, ntohs(oh->length) - sizeof *oh,
1540 0, true);
d1e2cf21
BP
1541 break;
1542
1543 case OFPUTIL_OFPT_ERROR:
1544 ofp_print_error_msg(string, msg);
1545 break;
1546
1547 case OFPUTIL_OFPT_ECHO_REQUEST:
1548 case OFPUTIL_OFPT_ECHO_REPLY:
1549 ofp_print_echo(string, oh, verbosity);
1550 break;
1551
1552 case OFPUTIL_OFPT_FEATURES_REQUEST:
1553 break;
1554
1555 case OFPUTIL_OFPT_FEATURES_REPLY:
1556 ofp_print_switch_features(string, msg);
1557 break;
1558
1559 case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
1560 break;
1561
1562 case OFPUTIL_OFPT_GET_CONFIG_REPLY:
1563 case OFPUTIL_OFPT_SET_CONFIG:
1564 ofp_print_switch_config(string, msg);
1565 break;
1566
1567 case OFPUTIL_OFPT_PACKET_IN:
54834960 1568 case OFPUTIL_NXT_PACKET_IN:
d1e2cf21
BP
1569 ofp_print_packet_in(string, msg, verbosity);
1570 break;
1571
1572 case OFPUTIL_OFPT_FLOW_REMOVED:
9b045a0c
BP
1573 case OFPUTIL_NXT_FLOW_REMOVED:
1574 ofp_print_flow_removed(string, msg);
d1e2cf21
BP
1575 break;
1576
1577 case OFPUTIL_OFPT_PORT_STATUS:
1578 ofp_print_port_status(string, msg);
1579 break;
1580
1581 case OFPUTIL_OFPT_PACKET_OUT:
1582 ofp_print_packet_out(string, msg, verbosity);
1583 break;
1584
1585 case OFPUTIL_OFPT_FLOW_MOD:
3370cd3c 1586 case OFPUTIL_NXT_FLOW_MOD:
7fa91113 1587 ofp_print_flow_mod(string, msg, code, verbosity);
d1e2cf21
BP
1588 break;
1589
1590 case OFPUTIL_OFPT_PORT_MOD:
1591 ofp_print_port_mod(string, msg);
1592 break;
1593
1594 case OFPUTIL_OFPT_BARRIER_REQUEST:
1595 case OFPUTIL_OFPT_BARRIER_REPLY:
1596 break;
1597
1598 case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
1599 case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
1600 /* XXX */
1601 break;
1602
1603 case OFPUTIL_OFPST_DESC_REQUEST:
2be393ed 1604 case OFPUTIL_OFPST_PORT_DESC_REQUEST:
d1e2cf21
BP
1605 ofp_print_stats_request(string, oh);
1606 break;
1607
1608 case OFPUTIL_OFPST_FLOW_REQUEST:
2af0c0ef 1609 case OFPUTIL_NXST_FLOW_REQUEST:
d1e2cf21 1610 case OFPUTIL_OFPST_AGGREGATE_REQUEST:
2af0c0ef 1611 case OFPUTIL_NXST_AGGREGATE_REQUEST:
d1e2cf21 1612 ofp_print_stats_request(string, oh);
76c93b22 1613 ofp_print_flow_stats_request(string, msg);
d1e2cf21
BP
1614 break;
1615
1616 case OFPUTIL_OFPST_TABLE_REQUEST:
1617 ofp_print_stats_request(string, oh);
1618 break;
1619
1620 case OFPUTIL_OFPST_PORT_REQUEST:
1621 ofp_print_stats_request(string, oh);
63f2140a 1622 ofp_print_ofpst_port_request(string, msg);
d1e2cf21
BP
1623 break;
1624
1625 case OFPUTIL_OFPST_QUEUE_REQUEST:
1626 ofp_print_stats_request(string, oh);
63f2140a 1627 ofp_print_ofpst_queue_request(string, msg);
d1e2cf21
BP
1628 break;
1629
1630 case OFPUTIL_OFPST_DESC_REPLY:
1631 ofp_print_stats_reply(string, oh);
63f2140a 1632 ofp_print_ofpst_desc_reply(string, msg);
d1e2cf21
BP
1633 break;
1634
1635 case OFPUTIL_OFPST_FLOW_REPLY:
4ffd1b43 1636 case OFPUTIL_NXST_FLOW_REPLY:
d1e2cf21 1637 ofp_print_stats_reply(string, oh);
4ffd1b43 1638 ofp_print_flow_stats_reply(string, oh);
d1e2cf21
BP
1639 break;
1640
1641 case OFPUTIL_OFPST_QUEUE_REPLY:
1642 ofp_print_stats_reply(string, oh);
1643 ofp_print_ofpst_queue_reply(string, oh, verbosity);
1644 break;
1645
1646 case OFPUTIL_OFPST_PORT_REPLY:
1647 ofp_print_stats_reply(string, oh);
1648 ofp_print_ofpst_port_reply(string, oh, verbosity);
1649 break;
1650
1651 case OFPUTIL_OFPST_TABLE_REPLY:
1652 ofp_print_stats_reply(string, oh);
1653 ofp_print_ofpst_table_reply(string, oh, verbosity);
1654 break;
1655
1656 case OFPUTIL_OFPST_AGGREGATE_REPLY:
1657 ofp_print_stats_reply(string, oh);
63f2140a 1658 ofp_print_ofpst_aggregate_reply(string, msg);
d1e2cf21 1659 break;
064af421 1660
2be393ed
JP
1661 case OFPUTIL_OFPST_PORT_DESC_REPLY:
1662 ofp_print_stats_reply(string, oh);
1663 ofp_print_ofpst_port_desc_reply(string, oh);
1664 break;
1665
d1e2cf21
BP
1666 case OFPUTIL_NXT_ROLE_REQUEST:
1667 case OFPUTIL_NXT_ROLE_REPLY:
61fe3a7b 1668 ofp_print_nxt_role_message(string, msg);
7fa91113
BP
1669 break;
1670
6c1491fb
BP
1671 case OFPUTIL_NXT_FLOW_MOD_TABLE_ID:
1672 ofp_print_nxt_flow_mod_table_id(string, msg);
1673 break;
1674
d1e2cf21 1675 case OFPUTIL_NXT_SET_FLOW_FORMAT:
7fa91113
BP
1676 ofp_print_nxt_set_flow_format(string, msg);
1677 break;
1678
54834960
EJ
1679 case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
1680 ofp_print_nxt_set_packet_in_format(string, msg);
1681 break;
1682
f27f2134
BP
1683 case OFPUTIL_NXT_FLOW_AGE:
1684 break;
1685
a7349929
BP
1686 case OFPUTIL_NXT_SET_CONTROLLER_ID:
1687 ofp_print_nxt_set_controller_id(string, msg);
1688 break;
1689
80d5aefd
BP
1690 case OFPUTIL_NXT_SET_ASYNC_CONFIG:
1691 ofp_print_nxt_set_async_config(string, msg);
1692 break;
1693
d1e2cf21 1694 case OFPUTIL_NXST_AGGREGATE_REPLY:
a2ad9ecd 1695 ofp_print_stats_reply(string, oh);
9b045a0c 1696 ofp_print_nxst_aggregate_reply(string, msg);
d1e2cf21 1697 break;
2b07c8b1
BP
1698
1699 case OFPUTIL_NXT_FLOW_MONITOR_CANCEL:
1700 ofp_print_nxt_flow_monitor_cancel(string, msg);
1701 break;
1702
1703 case OFPUTIL_NXT_FLOW_MONITOR_PAUSED:
1704 case OFPUTIL_NXT_FLOW_MONITOR_RESUMED:
1705 break;
1706
1707 case OFPUTIL_NXST_FLOW_MONITOR_REQUEST:
1708 ofp_print_nxst_flow_monitor_request(string, msg);
1709 break;
1710
1711 case OFPUTIL_NXST_FLOW_MONITOR_REPLY:
1712 ofp_print_nxst_flow_monitor_reply(string, msg);
1713 break;
246e61ea 1714 }
d1e2cf21 1715}
064af421
BP
1716
1717/* Composes and returns a string representing the OpenFlow packet of 'len'
1718 * bytes at 'oh' at the given 'verbosity' level. 0 is a minimal amount of
1719 * verbosity and higher numbers increase verbosity. The caller is responsible
1720 * for freeing the string. */
1721char *
1722ofp_to_string(const void *oh_, size_t len, int verbosity)
1723{
1724 struct ds string = DS_EMPTY_INITIALIZER;
1725 const struct ofp_header *oh = oh_;
064af421 1726
49ad0403
BP
1727 if (!len) {
1728 ds_put_cstr(&string, "OpenFlow message is empty\n");
1729 } else if (len < sizeof(struct ofp_header)) {
1730 ds_put_format(&string, "OpenFlow packet too short (only %zu bytes):\n",
1731 len);
d1e2cf21
BP
1732 } else if (ntohs(oh->length) > len) {
1733 ds_put_format(&string,
49ad0403 1734 "(***truncated to %zu bytes from %"PRIu16"***)\n",
d1e2cf21
BP
1735 len, ntohs(oh->length));
1736 } else if (ntohs(oh->length) < len) {
1737 ds_put_format(&string,
1738 "(***only uses %"PRIu16" bytes out of %zu***)\n",
1739 ntohs(oh->length), len);
1740 } else {
1741 const struct ofputil_msg_type *type;
90bf1e07 1742 enum ofperr error;
d1e2cf21
BP
1743
1744 error = ofputil_decode_msg_type(oh, &type);
1745 if (!error) {
1746 ofp_to_string__(oh, type, &string, verbosity);
7fa91113
BP
1747 if (verbosity >= 5) {
1748 if (ds_last(&string) != '\n') {
1749 ds_put_char(&string, '\n');
1750 }
d1e2cf21
BP
1751 ds_put_hex_dump(&string, oh, len, 0, true);
1752 }
7fa91113 1753 if (ds_last(&string) != '\n') {
d1e2cf21
BP
1754 ds_put_char(&string, '\n');
1755 }
1756 return ds_steal_cstr(&string);
064af421 1757 }
064af421 1758
7fa91113 1759 ofp_print_error(&string, error);
064af421 1760 }
d1e2cf21
BP
1761 ds_put_hex_dump(&string, oh, len, 0, true);
1762 return ds_steal_cstr(&string);
064af421 1763}
064af421
BP
1764\f
1765static void
d295e8e9 1766print_and_free(FILE *stream, char *string)
064af421
BP
1767{
1768 fputs(string, stream);
1769 free(string);
1770}
1771
1772/* Pretty-print the OpenFlow packet of 'len' bytes at 'oh' to 'stream' at the
1773 * given 'verbosity' level. 0 is a minimal amount of verbosity and higher
1774 * numbers increase verbosity. */
1775void
1776ofp_print(FILE *stream, const void *oh, size_t len, int verbosity)
1777{
1778 print_and_free(stream, ofp_to_string(oh, len, verbosity));
1779}
1780
1781/* Dumps the contents of the Ethernet frame in the 'len' bytes starting at
897a8e07 1782 * 'data' to 'stream'. */
064af421 1783void
c499c75d 1784ofp_print_packet(FILE *stream, const void *data, size_t len)
064af421 1785{
c499c75d 1786 print_and_free(stream, ofp_packet_to_string(data, len));
064af421 1787}