]> git.proxmox.com Git - mirror_ovs.git/blame - lib/ofp-print.c
Merge citrix branch into master.
[mirror_ovs.git] / lib / ofp-print.c
CommitLineData
064af421
BP
1/*
2 * Copyright (c) 2008, 2009 Nicira Networks.
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"
19#include "xtoxll.h"
20
21#include <errno.h>
22#include <inttypes.h>
23#include <netinet/in.h>
24#include <sys/wait.h>
25#include <stdarg.h>
26#include <stdlib.h>
27#include <ctype.h>
28
29#include "compiler.h"
30#include "dynamic-string.h"
31#include "flow.h"
32#include "ofpbuf.h"
33#include "openflow/openflow.h"
34#include "openflow/nicira-ext.h"
35#include "packets.h"
36#include "pcap.h"
37#include "util.h"
38
39static void ofp_print_port_name(struct ds *string, uint16_t port);
064af421
BP
40
41/* Returns a string that represents the contents of the Ethernet frame in the
42 * 'len' bytes starting at 'data' to 'stream' as output by tcpdump.
43 * 'total_len' specifies the full length of the Ethernet frame (of which 'len'
44 * bytes were captured).
45 *
46 * The caller must free the returned string.
47 *
48 * This starts and kills a tcpdump subprocess so it's quite expensive. */
49char *
50ofp_packet_to_string(const void *data, size_t len, size_t total_len UNUSED)
51{
52 struct ds ds = DS_EMPTY_INITIALIZER;
53 struct ofpbuf buf;
54
55 char command[128];
56 FILE *pcap;
57 FILE *tcpdump;
58 int status;
59 int c;
60
61 buf.data = (void *) data;
62 buf.size = len;
63
64 pcap = tmpfile();
65 if (!pcap) {
66 ovs_error(errno, "tmpfile");
67 return xstrdup("<error>");
68 }
69 pcap_write_header(pcap);
70 pcap_write(pcap, &buf);
71 fflush(pcap);
72 if (ferror(pcap)) {
73 ovs_error(errno, "error writing temporary file");
74 }
75 rewind(pcap);
76
77 snprintf(command, sizeof command, "/usr/sbin/tcpdump -e -n -r /dev/fd/%d 2>/dev/null",
78 fileno(pcap));
79 tcpdump = popen(command, "r");
80 fclose(pcap);
81 if (!tcpdump) {
82 ovs_error(errno, "exec(\"%s\")", command);
83 return xstrdup("<error>");
84 }
85
86 while ((c = getc(tcpdump)) != EOF) {
87 ds_put_char(&ds, c);
88 }
89
90 status = pclose(tcpdump);
91 if (WIFEXITED(status)) {
92 if (WEXITSTATUS(status))
93 ovs_error(0, "tcpdump exited with status %d", WEXITSTATUS(status));
94 } else if (WIFSIGNALED(status)) {
95 ovs_error(0, "tcpdump exited with signal %d", WTERMSIG(status));
96 }
97 return ds_cstr(&ds);
98}
99
100/* Pretty-print the OFPT_PACKET_IN packet of 'len' bytes at 'oh' to 'stream'
101 * at the given 'verbosity' level. */
102static void
103ofp_packet_in(struct ds *string, const void *oh, size_t len, int verbosity)
104{
105 const struct ofp_packet_in *op = oh;
106 size_t data_len;
107
108 ds_put_format(string, " total_len=%"PRIu16" in_port=",
109 ntohs(op->total_len));
110 ofp_print_port_name(string, ntohs(op->in_port));
111
112 if (op->reason == OFPR_ACTION)
113 ds_put_cstr(string, " (via action)");
114 else if (op->reason != OFPR_NO_MATCH)
115 ds_put_format(string, " (***reason %"PRIu8"***)", op->reason);
116
117 data_len = len - offsetof(struct ofp_packet_in, data);
118 ds_put_format(string, " data_len=%zu", data_len);
119 if (htonl(op->buffer_id) == UINT32_MAX) {
120 ds_put_format(string, " (unbuffered)");
121 if (ntohs(op->total_len) != data_len)
122 ds_put_format(string, " (***total_len != data_len***)");
123 } else {
124 ds_put_format(string, " buffer=0x%08"PRIx32, ntohl(op->buffer_id));
125 if (ntohs(op->total_len) < data_len)
126 ds_put_format(string, " (***total_len < data_len***)");
127 }
128 ds_put_char(string, '\n');
129
130 if (verbosity > 0) {
131 flow_t flow;
132 struct ofpbuf packet;
133 struct ofp_match match;
134 packet.data = (void *) op->data;
135 packet.size = data_len;
136 flow_extract(&packet, ntohs(op->in_port), &flow);
137 flow_to_match(&flow, 0, &match);
138 ofp_print_match(string, &match, verbosity);
139 ds_put_char(string, '\n');
140 }
141 if (verbosity > 1) {
142 char *packet = ofp_packet_to_string(op->data, data_len,
143 ntohs(op->total_len));
144 ds_put_cstr(string, packet);
145 free(packet);
146 }
147}
148
149static void ofp_print_port_name(struct ds *string, uint16_t port)
150{
151 const char *name;
152 switch (port) {
153 case OFPP_IN_PORT:
154 name = "IN_PORT";
155 break;
156 case OFPP_TABLE:
157 name = "TABLE";
158 break;
159 case OFPP_NORMAL:
160 name = "NORMAL";
161 break;
162 case OFPP_FLOOD:
163 name = "FLOOD";
164 break;
165 case OFPP_ALL:
166 name = "ALL";
167 break;
168 case OFPP_CONTROLLER:
169 name = "CONTROLLER";
170 break;
171 case OFPP_LOCAL:
172 name = "LOCAL";
173 break;
174 case OFPP_NONE:
175 name = "NONE";
176 break;
177 default:
178 ds_put_format(string, "%"PRIu16, port);
179 return;
180 }
181 ds_put_cstr(string, name);
182}
183
184static void
185ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
186{
187 switch (ntohs(nah->subtype)) {
188 case NXAST_RESUBMIT: {
189 const struct nx_action_resubmit *nar = (struct nx_action_resubmit *)nah;
190 ds_put_format(string, "resubmit:");
191 ofp_print_port_name(string, ntohs(nar->in_port));
192 break;
193 }
194
195 default:
196 ds_put_format(string, "***unknown Nicira action:%d***\n",
197 ntohs(nah->subtype));
198 }
199}
200
201static int
202ofp_print_action(struct ds *string, const struct ofp_action_header *ah,
203 size_t actions_len)
204{
205 uint16_t type;
206 size_t len;
207
208 struct openflow_action {
209 size_t min_size;
210 size_t max_size;
211 };
212
213 const struct openflow_action of_actions[] = {
214 [OFPAT_OUTPUT] = {
215 sizeof(struct ofp_action_output),
216 sizeof(struct ofp_action_output),
217 },
218 [OFPAT_SET_VLAN_VID] = {
219 sizeof(struct ofp_action_vlan_vid),
220 sizeof(struct ofp_action_vlan_vid),
221 },
222 [OFPAT_SET_VLAN_PCP] = {
223 sizeof(struct ofp_action_vlan_pcp),
224 sizeof(struct ofp_action_vlan_pcp),
225 },
226 [OFPAT_STRIP_VLAN] = {
227 sizeof(struct ofp_action_header),
228 sizeof(struct ofp_action_header),
229 },
230 [OFPAT_SET_DL_SRC] = {
231 sizeof(struct ofp_action_dl_addr),
232 sizeof(struct ofp_action_dl_addr),
233 },
234 [OFPAT_SET_DL_DST] = {
235 sizeof(struct ofp_action_dl_addr),
236 sizeof(struct ofp_action_dl_addr),
237 },
238 [OFPAT_SET_NW_SRC] = {
239 sizeof(struct ofp_action_nw_addr),
240 sizeof(struct ofp_action_nw_addr),
241 },
242 [OFPAT_SET_NW_DST] = {
243 sizeof(struct ofp_action_nw_addr),
244 sizeof(struct ofp_action_nw_addr),
245 },
246 [OFPAT_SET_TP_SRC] = {
247 sizeof(struct ofp_action_tp_port),
248 sizeof(struct ofp_action_tp_port),
249 },
250 [OFPAT_SET_TP_DST] = {
251 sizeof(struct ofp_action_tp_port),
252 sizeof(struct ofp_action_tp_port),
253 }
254 /* OFPAT_VENDOR is not here, since it would blow up the array size. */
255 };
256
257 if (actions_len < sizeof *ah) {
258 ds_put_format(string, "***action array too short for next action***\n");
259 return -1;
260 }
261
262 type = ntohs(ah->type);
263 len = ntohs(ah->len);
264 if (actions_len < len) {
265 ds_put_format(string, "***truncated action %"PRIu16"***\n", type);
266 return -1;
267 }
268
269 if ((len % 8) != 0) {
270 ds_put_format(string,
271 "***action %"PRIu16" length not a multiple of 8***\n",
272 type);
273 return -1;
274 }
275
276 if (type < ARRAY_SIZE(of_actions)) {
277 const struct openflow_action *act = &of_actions[type];
278 if ((len < act->min_size) || (len > act->max_size)) {
279 ds_put_format(string,
280 "***action %"PRIu16" wrong length: %zu***\n", type, len);
281 return -1;
282 }
283 }
284
285 switch (type) {
286 case OFPAT_OUTPUT: {
287 struct ofp_action_output *oa = (struct ofp_action_output *)ah;
288 uint16_t port = ntohs(oa->port);
289 if (port < OFPP_MAX) {
290 ds_put_format(string, "output:%"PRIu16, port);
291 } else {
292 ofp_print_port_name(string, port);
293 if (port == OFPP_CONTROLLER) {
294 if (oa->max_len) {
295 ds_put_format(string, ":%"PRIu16, ntohs(oa->max_len));
296 } else {
297 ds_put_cstr(string, ":all");
298 }
299 }
300 }
301 break;
302 }
303
304 case OFPAT_SET_VLAN_VID: {
305 struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah;
306 ds_put_format(string, "mod_vlan_vid:%"PRIu16, ntohs(va->vlan_vid));
307 break;
308 }
309
310 case OFPAT_SET_VLAN_PCP: {
311 struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah;
312 ds_put_format(string, "mod_vlan_pcp:%"PRIu8, va->vlan_pcp);
313 break;
314 }
315
316 case OFPAT_STRIP_VLAN:
317 ds_put_cstr(string, "strip_vlan");
318 break;
319
320 case OFPAT_SET_DL_SRC: {
321 struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah;
322 ds_put_format(string, "mod_dl_src:"ETH_ADDR_FMT,
323 ETH_ADDR_ARGS(da->dl_addr));
324 break;
325 }
326
327 case OFPAT_SET_DL_DST: {
328 struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah;
329 ds_put_format(string, "mod_dl_dst:"ETH_ADDR_FMT,
330 ETH_ADDR_ARGS(da->dl_addr));
331 break;
332 }
333
334 case OFPAT_SET_NW_SRC: {
335 struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah;
336 ds_put_format(string, "mod_nw_src:"IP_FMT, IP_ARGS(&na->nw_addr));
337 break;
338 }
339
340 case OFPAT_SET_NW_DST: {
341 struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah;
342 ds_put_format(string, "mod_nw_dst:"IP_FMT, IP_ARGS(&na->nw_addr));
343 break;
344 }
345
346 case OFPAT_SET_TP_SRC: {
347 struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah;
348 ds_put_format(string, "mod_tp_src:%d", ntohs(ta->tp_port));
349 break;
350 }
351
352 case OFPAT_SET_TP_DST: {
353 struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah;
354 ds_put_format(string, "mod_tp_dst:%d", ntohs(ta->tp_port));
355 break;
356 }
357
358 case OFPAT_VENDOR: {
359 struct ofp_action_vendor_header *avh
360 = (struct ofp_action_vendor_header *)ah;
361 if (len < sizeof *avh) {
362 ds_put_format(string, "***ofpat_vendor truncated***\n");
363 return -1;
364 }
365 if (avh->vendor == htonl(NX_VENDOR_ID)) {
366 ofp_print_nx_action(string, (struct nx_action_header *)avh);
367 } else {
368 ds_put_format(string, "vendor action:0x%x", ntohl(avh->vendor));
369 }
370 break;
371 }
372
373 default:
374 ds_put_format(string, "(decoder %"PRIu16" not implemented)", type);
375 break;
376 }
377
378 return len;
379}
380
4f2cad2c 381void
064af421
BP
382ofp_print_actions(struct ds *string, const struct ofp_action_header *action,
383 size_t actions_len)
384{
385 uint8_t *p = (uint8_t *)action;
386 int len = 0;
387
388 ds_put_cstr(string, "actions=");
389 if (!actions_len) {
390 ds_put_cstr(string, "drop");
391 }
392 while (actions_len > 0) {
393 if (len) {
394 ds_put_cstr(string, ",");
395 }
396 len = ofp_print_action(string, (struct ofp_action_header *)p,
397 actions_len);
398 if (len < 0) {
399 return;
400 }
401 p += len;
402 actions_len -= len;
403 }
404}
405
406/* Pretty-print the OFPT_PACKET_OUT packet of 'len' bytes at 'oh' to 'string'
407 * at the given 'verbosity' level. */
408static void ofp_packet_out(struct ds *string, const void *oh, size_t len,
409 int verbosity)
410{
411 const struct ofp_packet_out *opo = oh;
412 size_t actions_len = ntohs(opo->actions_len);
413
414 ds_put_cstr(string, " in_port=");
415 ofp_print_port_name(string, ntohs(opo->in_port));
416
417 ds_put_format(string, " actions_len=%zu ", actions_len);
418 if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) {
419 ds_put_format(string, "***packet too short for action length***\n");
420 return;
421 }
422 ofp_print_actions(string, opo->actions, actions_len);
423
424 if (ntohl(opo->buffer_id) == UINT32_MAX) {
425 int data_len = len - sizeof *opo - actions_len;
426 ds_put_format(string, " data_len=%d", data_len);
427 if (verbosity > 0 && len > sizeof *opo) {
428 char *packet = ofp_packet_to_string(
429 (uint8_t *)opo->actions + actions_len, data_len, data_len);
430 ds_put_char(string, '\n');
431 ds_put_cstr(string, packet);
432 free(packet);
433 }
434 } else {
435 ds_put_format(string, " buffer=0x%08"PRIx32, ntohl(opo->buffer_id));
436 }
437 ds_put_char(string, '\n');
438}
439
440/* qsort comparison function. */
441static int
442compare_ports(const void *a_, const void *b_)
443{
444 const struct ofp_phy_port *a = a_;
445 const struct ofp_phy_port *b = b_;
446 uint16_t ap = ntohs(a->port_no);
447 uint16_t bp = ntohs(b->port_no);
448
449 return ap < bp ? -1 : ap > bp;
450}
451
452static void ofp_print_port_features(struct ds *string, uint32_t features)
453{
454 if (features == 0) {
455 ds_put_cstr(string, "Unsupported\n");
456 return;
457 }
458 if (features & OFPPF_10MB_HD) {
459 ds_put_cstr(string, "10MB-HD ");
460 }
461 if (features & OFPPF_10MB_FD) {
462 ds_put_cstr(string, "10MB-FD ");
463 }
464 if (features & OFPPF_100MB_HD) {
465 ds_put_cstr(string, "100MB-HD ");
466 }
467 if (features & OFPPF_100MB_FD) {
468 ds_put_cstr(string, "100MB-FD ");
469 }
470 if (features & OFPPF_1GB_HD) {
471 ds_put_cstr(string, "1GB-HD ");
472 }
473 if (features & OFPPF_1GB_FD) {
474 ds_put_cstr(string, "1GB-FD ");
475 }
476 if (features & OFPPF_10GB_FD) {
477 ds_put_cstr(string, "10GB-FD ");
478 }
479 if (features & OFPPF_COPPER) {
480 ds_put_cstr(string, "COPPER ");
481 }
482 if (features & OFPPF_FIBER) {
483 ds_put_cstr(string, "FIBER ");
484 }
485 if (features & OFPPF_AUTONEG) {
486 ds_put_cstr(string, "AUTO_NEG ");
487 }
488 if (features & OFPPF_PAUSE) {
489 ds_put_cstr(string, "AUTO_PAUSE ");
490 }
491 if (features & OFPPF_PAUSE_ASYM) {
492 ds_put_cstr(string, "AUTO_PAUSE_ASYM ");
493 }
494 ds_put_char(string, '\n');
495}
496
497static void
498ofp_print_phy_port(struct ds *string, const struct ofp_phy_port *port)
499{
500 uint8_t name[OFP_MAX_PORT_NAME_LEN];
501 int j;
502
503 memcpy(name, port->name, sizeof name);
504 for (j = 0; j < sizeof name - 1; j++) {
505 if (!isprint(name[j])) {
506 break;
507 }
508 }
509 name[j] = '\0';
510
511 ds_put_char(string, ' ');
512 ofp_print_port_name(string, ntohs(port->port_no));
513 ds_put_format(string, "(%s): addr:"ETH_ADDR_FMT", config: %#x, state:%#x\n",
514 name, ETH_ADDR_ARGS(port->hw_addr), ntohl(port->config),
515 ntohl(port->state));
516 if (port->curr) {
517 ds_put_format(string, " current: ");
518 ofp_print_port_features(string, ntohl(port->curr));
519 }
520 if (port->advertised) {
521 ds_put_format(string, " advertised: ");
522 ofp_print_port_features(string, ntohl(port->advertised));
523 }
524 if (port->supported) {
525 ds_put_format(string, " supported: ");
526 ofp_print_port_features(string, ntohl(port->supported));
527 }
528 if (port->peer) {
529 ds_put_format(string, " peer: ");
530 ofp_print_port_features(string, ntohl(port->peer));
531 }
532}
533
534/* Pretty-print the struct ofp_switch_features of 'len' bytes at 'oh' to
535 * 'string' at the given 'verbosity' level. */
536static void
537ofp_print_switch_features(struct ds *string, const void *oh, size_t len,
538 int verbosity UNUSED)
539{
540 const struct ofp_switch_features *osf = oh;
541 struct ofp_phy_port *port_list;
542 int n_ports;
543 int i;
544
545 ds_put_format(string, " ver:0x%x, dpid:%"PRIx64"\n",
546 osf->header.version, ntohll(osf->datapath_id));
547 ds_put_format(string, "n_tables:%d, n_buffers:%d\n", osf->n_tables,
548 ntohl(osf->n_buffers));
549 ds_put_format(string, "features: capabilities:%#x, actions:%#x\n",
550 ntohl(osf->capabilities), ntohl(osf->actions));
551
552 if (ntohs(osf->header.length) >= sizeof *osf) {
553 len = MIN(len, ntohs(osf->header.length));
554 }
555 n_ports = (len - sizeof *osf) / sizeof *osf->ports;
556
557 port_list = xmemdup(osf->ports, len - sizeof *osf);
558 qsort(port_list, n_ports, sizeof *port_list, compare_ports);
559 for (i = 0; i < n_ports; i++) {
560 ofp_print_phy_port(string, &port_list[i]);
561 }
562 free(port_list);
563}
564
565/* Pretty-print the struct ofp_switch_config of 'len' bytes at 'oh' to 'string'
566 * at the given 'verbosity' level. */
567static void
568ofp_print_switch_config(struct ds *string, const void *oh, size_t len UNUSED,
569 int verbosity UNUSED)
570{
571 const struct ofp_switch_config *osc = oh;
572 uint16_t flags;
573
574 flags = ntohs(osc->flags);
575 if (flags & OFPC_SEND_FLOW_EXP) {
576 flags &= ~OFPC_SEND_FLOW_EXP;
577 ds_put_format(string, " (sending flow expirations)");
578 }
579 if (flags) {
580 ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
581 }
582
583 ds_put_format(string, " miss_send_len=%"PRIu16"\n", ntohs(osc->miss_send_len));
584}
585
586static void print_wild(struct ds *string, const char *leader, int is_wild,
587 int verbosity, const char *format, ...)
588 __attribute__((format(printf, 5, 6)));
589
590static void print_wild(struct ds *string, const char *leader, int is_wild,
591 int verbosity, const char *format, ...)
592{
593 if (is_wild && verbosity < 2) {
594 return;
595 }
596 ds_put_cstr(string, leader);
597 if (!is_wild) {
598 va_list args;
599
600 va_start(args, format);
601 ds_put_format_valist(string, format, args);
602 va_end(args);
603 } else {
604 ds_put_char(string, '*');
605 }
606 ds_put_char(string, ',');
607}
608
609static void
610print_ip_netmask(struct ds *string, const char *leader, uint32_t ip,
611 uint32_t wild_bits, int verbosity)
612{
613 if (wild_bits >= 32 && verbosity < 2) {
614 return;
615 }
616 ds_put_cstr(string, leader);
617 if (wild_bits < 32) {
618 ds_put_format(string, IP_FMT, IP_ARGS(&ip));
619 if (wild_bits) {
620 ds_put_format(string, "/%d", 32 - wild_bits);
621 }
622 } else {
623 ds_put_char(string, '*');
624 }
625 ds_put_char(string, ',');
626}
627
4f2cad2c 628void
064af421
BP
629ofp_print_match(struct ds *f, const struct ofp_match *om, int verbosity)
630{
631 char *s = ofp_match_to_string(om, verbosity);
632 ds_put_cstr(f, s);
633 free(s);
634}
635
636char *
637ofp_match_to_string(const struct ofp_match *om, int verbosity)
638{
639 struct ds f = DS_EMPTY_INITIALIZER;
640 uint32_t w = ntohl(om->wildcards);
641 bool skip_type = false;
642 bool skip_proto = false;
643
644 if (!(w & OFPFW_DL_TYPE)) {
645 skip_type = true;
646 if (om->dl_type == htons(ETH_TYPE_IP)) {
647 if (!(w & OFPFW_NW_PROTO)) {
648 skip_proto = true;
649 if (om->nw_proto == IP_TYPE_ICMP) {
650 ds_put_cstr(&f, "icmp,");
651 } else if (om->nw_proto == IP_TYPE_TCP) {
652 ds_put_cstr(&f, "tcp,");
653 } else if (om->nw_proto == IP_TYPE_UDP) {
654 ds_put_cstr(&f, "udp,");
655 } else {
656 ds_put_cstr(&f, "ip,");
657 skip_proto = false;
658 }
659 } else {
660 ds_put_cstr(&f, "ip,");
661 }
662 } else if (om->dl_type == htons(ETH_TYPE_ARP)) {
663 ds_put_cstr(&f, "arp,");
664 } else {
665 skip_type = false;
666 }
667 }
668 print_wild(&f, "in_port=", w & OFPFW_IN_PORT, verbosity,
669 "%d", ntohs(om->in_port));
670 print_wild(&f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity,
671 "0x%04x", ntohs(om->dl_vlan));
672 print_wild(&f, "dl_src=", w & OFPFW_DL_SRC, verbosity,
673 ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
674 print_wild(&f, "dl_dst=", w & OFPFW_DL_DST, verbosity,
675 ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_dst));
676 if (!skip_type) {
677 print_wild(&f, "dl_type=", w & OFPFW_DL_TYPE, verbosity,
678 "0x%04x", ntohs(om->dl_type));
679 }
680 print_ip_netmask(&f, "nw_src=", om->nw_src,
681 (w & OFPFW_NW_SRC_MASK) >> OFPFW_NW_SRC_SHIFT, verbosity);
682 print_ip_netmask(&f, "nw_dst=", om->nw_dst,
683 (w & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT, verbosity);
684 if (!skip_proto) {
685 print_wild(&f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity,
686 "%u", om->nw_proto);
687 }
688 if (om->nw_proto == IP_TYPE_ICMP) {
689 print_wild(&f, "icmp_type=", w & OFPFW_ICMP_TYPE, verbosity,
690 "%d", ntohs(om->icmp_type));
691 print_wild(&f, "icmp_code=", w & OFPFW_ICMP_CODE, verbosity,
692 "%d", ntohs(om->icmp_code));
693 } else {
694 print_wild(&f, "tp_src=", w & OFPFW_TP_SRC, verbosity,
695 "%d", ntohs(om->tp_src));
696 print_wild(&f, "tp_dst=", w & OFPFW_TP_DST, verbosity,
697 "%d", ntohs(om->tp_dst));
698 }
699 return ds_cstr(&f);
700}
701
702/* Pretty-print the OFPT_FLOW_MOD packet of 'len' bytes at 'oh' to 'string'
703 * at the given 'verbosity' level. */
704static void
705ofp_print_flow_mod(struct ds *string, const void *oh, size_t len,
706 int verbosity)
707{
708 const struct ofp_flow_mod *ofm = oh;
709
710 ofp_print_match(string, &ofm->match, verbosity);
711 switch (ntohs(ofm->command)) {
712 case OFPFC_ADD:
713 ds_put_cstr(string, " ADD: ");
714 break;
715 case OFPFC_MODIFY:
716 ds_put_cstr(string, " MOD: ");
717 break;
718 case OFPFC_MODIFY_STRICT:
719 ds_put_cstr(string, " MOD_STRICT: ");
720 break;
721 case OFPFC_DELETE:
722 ds_put_cstr(string, " DEL: ");
723 break;
724 case OFPFC_DELETE_STRICT:
725 ds_put_cstr(string, " DEL_STRICT: ");
726 break;
727 default:
728 ds_put_format(string, " cmd:%d ", ntohs(ofm->command));
729 }
730 ds_put_format(string, "idle:%d hard:%d pri:%d buf:%#x",
731 ntohs(ofm->idle_timeout), ntohs(ofm->hard_timeout),
732 ofm->match.wildcards ? ntohs(ofm->priority) : (uint16_t)-1,
733 ntohl(ofm->buffer_id));
734 ofp_print_actions(string, ofm->actions,
735 len - offsetof(struct ofp_flow_mod, actions));
736 ds_put_char(string, '\n');
737}
738
739/* Pretty-print the OFPT_FLOW_EXPIRED packet of 'len' bytes at 'oh' to 'string'
740 * at the given 'verbosity' level. */
741static void
742ofp_print_flow_expired(struct ds *string, const void *oh, size_t len UNUSED,
743 int verbosity)
744{
745 const struct ofp_flow_expired *ofe = oh;
746
747 ofp_print_match(string, &ofe->match, verbosity);
748 ds_put_cstr(string, " reason=");
749 switch (ofe->reason) {
750 case OFPER_IDLE_TIMEOUT:
751 ds_put_cstr(string, "idle");
752 break;
753 case OFPER_HARD_TIMEOUT:
754 ds_put_cstr(string, "hard");
755 break;
756 default:
757 ds_put_format(string, "**%"PRIu8"**", ofe->reason);
758 break;
759 }
760 ds_put_format(string,
761 " pri%"PRIu16" secs%"PRIu32" pkts%"PRIu64" bytes%"PRIu64"\n",
762 ofe->match.wildcards ? ntohs(ofe->priority) : (uint16_t)-1,
763 ntohl(ofe->duration), ntohll(ofe->packet_count),
764 ntohll(ofe->byte_count));
765}
766
767static void
768ofp_print_port_mod(struct ds *string, const void *oh, size_t len UNUSED,
769 int verbosity UNUSED)
770{
771 const struct ofp_port_mod *opm = oh;
772
773 ds_put_format(string, "port: %d: addr:"ETH_ADDR_FMT", config: %#x, mask:%#x\n",
774 ntohs(opm->port_no), ETH_ADDR_ARGS(opm->hw_addr),
775 ntohl(opm->config), ntohl(opm->mask));
776 ds_put_format(string, " advertise: ");
777 if (opm->advertise) {
778 ofp_print_port_features(string, ntohl(opm->advertise));
779 } else {
780 ds_put_format(string, "UNCHANGED\n");
781 }
782}
783
784struct error_type {
785 int type;
786 int code;
787 const char *name;
788};
789
790static const struct error_type error_types[] = {
791#define ERROR_TYPE(TYPE) {TYPE, -1, #TYPE}
792#define ERROR_CODE(TYPE, CODE) {TYPE, CODE, #CODE}
793 ERROR_TYPE(OFPET_HELLO_FAILED),
794 ERROR_CODE(OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE),
795
796 ERROR_TYPE(OFPET_BAD_REQUEST),
797 ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VERSION),
798 ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE),
799 ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT),
800 ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VERSION),
801
802 ERROR_TYPE(OFPET_BAD_ACTION),
803 ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE),
804 ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_LEN),
805 ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR),
806 ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE),
807 ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT),
808
809 ERROR_TYPE(OFPET_FLOW_MOD_FAILED),
810 ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL)
811};
812#define N_ERROR_TYPES ARRAY_SIZE(error_types)
813
814static const char *
815lookup_error_type(int type)
816{
817 const struct error_type *t;
818
819 for (t = error_types; t < &error_types[N_ERROR_TYPES]; t++) {
820 if (t->type == type && t->code == -1) {
821 return t->name;
822 }
823 }
824 return "?";
825}
826
827static const char *
828lookup_error_code(int type, int code)
829{
830 const struct error_type *t;
831
832 for (t = error_types; t < &error_types[N_ERROR_TYPES]; t++) {
833 if (t->type == type && t->code == code) {
834 return t->name;
835 }
836 }
837 return "?";
838}
839
840/* Pretty-print the OFPT_ERROR packet of 'len' bytes at 'oh' to 'string'
841 * at the given 'verbosity' level. */
842static void
843ofp_print_error_msg(struct ds *string, const void *oh, size_t len,
844 int verbosity UNUSED)
845{
846 const struct ofp_error_msg *oem = oh;
847 int type = ntohs(oem->type);
848 int code = ntohs(oem->code);
849 char *s;
850
851 ds_put_format(string, " type%d(%s) code%d(%s) payload:\n",
852 type, lookup_error_type(type),
853 code, lookup_error_code(type, code));
854
855 switch (type) {
856 case OFPET_HELLO_FAILED:
857 ds_put_printable(string, (char *) oem->data, len - sizeof *oem);
858 break;
859
860 case OFPET_BAD_REQUEST:
861 s = ofp_to_string(oem->data, len - sizeof *oem, 1);
862 ds_put_cstr(string, s);
863 free(s);
864 break;
865
866 default:
867 ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true);
868 break;
869 }
870}
871
872/* Pretty-print the OFPT_PORT_STATUS packet of 'len' bytes at 'oh' to 'string'
873 * at the given 'verbosity' level. */
874static void
875ofp_print_port_status(struct ds *string, const void *oh, size_t len UNUSED,
876 int verbosity UNUSED)
877{
878 const struct ofp_port_status *ops = oh;
879
880 if (ops->reason == OFPPR_ADD) {
881 ds_put_format(string, " ADD:");
882 } else if (ops->reason == OFPPR_DELETE) {
883 ds_put_format(string, " DEL:");
884 } else if (ops->reason == OFPPR_MODIFY) {
885 ds_put_format(string, " MOD:");
886 }
887
888 ofp_print_phy_port(string, &ops->desc);
889}
890
891static void
892ofp_desc_stats_reply(struct ds *string, const void *body, size_t len UNUSED,
893 int verbosity UNUSED)
894{
895 const struct ofp_desc_stats *ods = body;
896
897 ds_put_format(string, "Manufacturer: %s\n", ods->mfr_desc);
898 ds_put_format(string, "Hardware: %s\n", ods->hw_desc);
899 ds_put_format(string, "Software: %s\n", ods->sw_desc);
900 ds_put_format(string, "Serial Num: %s\n", ods->serial_num);
901}
902
903static void
904ofp_flow_stats_request(struct ds *string, const void *oh, size_t len UNUSED,
905 int verbosity)
906{
907 const struct ofp_flow_stats_request *fsr = oh;
908
909 if (fsr->table_id == 0xff) {
910 ds_put_format(string, " table_id=any, ");
911 } else {
912 ds_put_format(string, " table_id=%"PRIu8", ", fsr->table_id);
913 }
914
915 ofp_print_match(string, &fsr->match, verbosity);
916}
917
918static void
919ofp_flow_stats_reply(struct ds *string, const void *body_, size_t len,
920 int verbosity)
921{
922 const char *body = body_;
923 const char *pos = body;
924 for (;;) {
925 const struct ofp_flow_stats *fs;
926 ptrdiff_t bytes_left = body + len - pos;
927 size_t length;
928
929 if (bytes_left < sizeof *fs) {
930 if (bytes_left != 0) {
931 ds_put_format(string, " ***%td leftover bytes at end***",
932 bytes_left);
933 }
934 break;
935 }
936
937 fs = (const void *) pos;
938 length = ntohs(fs->length);
939 if (length < sizeof *fs) {
940 ds_put_format(string, " ***length=%zu shorter than minimum %zu***",
941 length, sizeof *fs);
942 break;
943 } else if (length > bytes_left) {
944 ds_put_format(string,
945 " ***length=%zu but only %td bytes left***",
946 length, bytes_left);
947 break;
948 } else if ((length - sizeof *fs) % sizeof fs->actions[0]) {
949 ds_put_format(string,
950 " ***length=%zu has %zu bytes leftover in "
951 "final action***",
952 length,
953 (length - sizeof *fs) % sizeof fs->actions[0]);
954 break;
955 }
956
957 ds_put_format(string, " duration=%"PRIu32"s, ", ntohl(fs->duration));
958 ds_put_format(string, "table_id=%"PRIu8", ", fs->table_id);
959 ds_put_format(string, "priority=%"PRIu16", ",
960 fs->match.wildcards ? ntohs(fs->priority) : (uint16_t)-1);
961 ds_put_format(string, "n_packets=%"PRIu64", ",
962 ntohll(fs->packet_count));
963 ds_put_format(string, "n_bytes=%"PRIu64", ", ntohll(fs->byte_count));
964 if (fs->idle_timeout != htons(OFP_FLOW_PERMANENT)) {
965 ds_put_format(string, "idle_timeout=%"PRIu16",",
966 ntohs(fs->idle_timeout));
967 }
968 if (fs->hard_timeout != htons(OFP_FLOW_PERMANENT)) {
969 ds_put_format(string, "hard_timeout=%"PRIu16",",
970 ntohs(fs->hard_timeout));
971 }
972 ofp_print_match(string, &fs->match, verbosity);
973 ofp_print_actions(string, fs->actions, length - sizeof *fs);
974 ds_put_char(string, '\n');
975
976 pos += length;
977 }
978}
979
980static void
981ofp_aggregate_stats_request(struct ds *string, const void *oh,
982 size_t len UNUSED, int verbosity)
983{
984 const struct ofp_aggregate_stats_request *asr = oh;
985
986 if (asr->table_id == 0xff) {
987 ds_put_format(string, " table_id=any, ");
988 } else {
989 ds_put_format(string, " table_id=%"PRIu8", ", asr->table_id);
990 }
991
992 ofp_print_match(string, &asr->match, verbosity);
993}
994
995static void
996ofp_aggregate_stats_reply(struct ds *string, const void *body_,
997 size_t len UNUSED, int verbosity UNUSED)
998{
999 const struct ofp_aggregate_stats_reply *asr = body_;
1000
1001 ds_put_format(string, " packet_count=%"PRIu64, ntohll(asr->packet_count));
1002 ds_put_format(string, " byte_count=%"PRIu64, ntohll(asr->byte_count));
1003 ds_put_format(string, " flow_count=%"PRIu32, ntohl(asr->flow_count));
1004}
1005
1006static void print_port_stat(struct ds *string, const char *leader,
1007 uint64_t stat, int more)
1008{
1009 ds_put_cstr(string, leader);
1010 if (stat != -1) {
1011 ds_put_format(string, "%"PRIu64, stat);
1012 } else {
1013 ds_put_char(string, '?');
1014 }
1015 if (more) {
1016 ds_put_cstr(string, ", ");
1017 } else {
1018 ds_put_cstr(string, "\n");
1019 }
1020}
1021
1022static void
1023ofp_port_stats_reply(struct ds *string, const void *body, size_t len,
1024 int verbosity)
1025{
1026 const struct ofp_port_stats *ps = body;
1027 size_t n = len / sizeof *ps;
1028 ds_put_format(string, " %zu ports\n", n);
1029 if (verbosity < 1) {
1030 return;
1031 }
1032
1033 for (; n--; ps++) {
1034 ds_put_format(string, " port %2"PRIu16": ", ntohs(ps->port_no));
1035
1036 ds_put_cstr(string, "rx ");
1037 print_port_stat(string, "pkts=", ntohll(ps->rx_packets), 1);
1038 print_port_stat(string, "bytes=", ntohll(ps->rx_bytes), 1);
1039 print_port_stat(string, "drop=", ntohll(ps->rx_dropped), 1);
1040 print_port_stat(string, "errs=", ntohll(ps->rx_errors), 1);
1041 print_port_stat(string, "frame=", ntohll(ps->rx_frame_err), 1);
1042 print_port_stat(string, "over=", ntohll(ps->rx_over_err), 1);
1043 print_port_stat(string, "crc=", ntohll(ps->rx_crc_err), 0);
1044
1045 ds_put_cstr(string, " tx ");
1046 print_port_stat(string, "pkts=", ntohll(ps->tx_packets), 1);
1047 print_port_stat(string, "bytes=", ntohll(ps->tx_bytes), 1);
1048 print_port_stat(string, "drop=", ntohll(ps->tx_dropped), 1);
1049 print_port_stat(string, "errs=", ntohll(ps->tx_errors), 1);
1050 print_port_stat(string, "coll=", ntohll(ps->collisions), 0);
1051 }
1052}
1053
1054static void
1055ofp_table_stats_reply(struct ds *string, const void *body, size_t len,
1056 int verbosity)
1057{
1058 const struct ofp_table_stats *ts = body;
1059 size_t n = len / sizeof *ts;
1060 ds_put_format(string, " %zu tables\n", n);
1061 if (verbosity < 1) {
1062 return;
1063 }
1064
1065 for (; n--; ts++) {
1066 char name[OFP_MAX_TABLE_NAME_LEN + 1];
1067 strncpy(name, ts->name, sizeof name);
1068 name[OFP_MAX_TABLE_NAME_LEN] = '\0';
1069
1070 ds_put_format(string, " %d: %-8s: ", ts->table_id, name);
1071 ds_put_format(string, "wild=0x%05"PRIx32", ", ntohl(ts->wildcards));
1072 ds_put_format(string, "max=%6"PRIu32", ", ntohl(ts->max_entries));
1073 ds_put_format(string, "active=%"PRIu32"\n", ntohl(ts->active_count));
1074 ds_put_cstr(string, " ");
1075 ds_put_format(string, "lookup=%"PRIu64", ",
1076 ntohll(ts->lookup_count));
1077 ds_put_format(string, "matched=%"PRIu64"\n",
1078 ntohll(ts->matched_count));
1079 }
1080}
1081
1082static void
1083vendor_stat(struct ds *string, const void *body, size_t len,
1084 int verbosity UNUSED)
1085{
1086 ds_put_format(string, " vendor=%08"PRIx32, ntohl(*(uint32_t *) body));
1087 ds_put_format(string, " %zu bytes additional data",
1088 len - sizeof(uint32_t));
1089}
1090
1091enum stats_direction {
1092 REQUEST,
1093 REPLY
1094};
1095
1096static void
1097print_stats(struct ds *string, int type, const void *body, size_t body_len,
1098 int verbosity, enum stats_direction direction)
1099{
1100 struct stats_msg {
1101 size_t min_body, max_body;
1102 void (*printer)(struct ds *, const void *, size_t len, int verbosity);
1103 };
1104
1105 struct stats_type {
1106 int type;
1107 const char *name;
1108 struct stats_msg request;
1109 struct stats_msg reply;
1110 };
1111
1112 static const struct stats_type stats_types[] = {
1113 {
1114 OFPST_DESC,
1115 "description",
1116 { 0, 0, NULL },
1117 { 0, SIZE_MAX, ofp_desc_stats_reply },
1118 },
1119 {
1120 OFPST_FLOW,
1121 "flow",
1122 { sizeof(struct ofp_flow_stats_request),
1123 sizeof(struct ofp_flow_stats_request),
1124 ofp_flow_stats_request },
1125 { 0, SIZE_MAX, ofp_flow_stats_reply },
1126 },
1127 {
1128 OFPST_AGGREGATE,
1129 "aggregate",
1130 { sizeof(struct ofp_aggregate_stats_request),
1131 sizeof(struct ofp_aggregate_stats_request),
1132 ofp_aggregate_stats_request },
1133 { sizeof(struct ofp_aggregate_stats_reply),
1134 sizeof(struct ofp_aggregate_stats_reply),
1135 ofp_aggregate_stats_reply },
1136 },
1137 {
1138 OFPST_TABLE,
1139 "table",
1140 { 0, 0, NULL },
1141 { 0, SIZE_MAX, ofp_table_stats_reply },
1142 },
1143 {
1144 OFPST_PORT,
1145 "port",
1146 { 0, 0, NULL, },
1147 { 0, SIZE_MAX, ofp_port_stats_reply },
1148 },
1149 {
1150 OFPST_VENDOR,
1151 "vendor-specific",
1152 { sizeof(uint32_t), SIZE_MAX, vendor_stat },
1153 { sizeof(uint32_t), SIZE_MAX, vendor_stat },
1154 },
1155 {
1156 -1,
1157 "unknown",
1158 { 0, 0, NULL, },
1159 { 0, 0, NULL, },
1160 },
1161 };
1162
1163 const struct stats_type *s;
1164 const struct stats_msg *m;
1165
1166 if (type >= ARRAY_SIZE(stats_types) || !stats_types[type].name) {
1167 ds_put_format(string, " ***unknown type %d***", type);
1168 return;
1169 }
1170 for (s = stats_types; s->type >= 0; s++) {
1171 if (s->type == type) {
1172 break;
1173 }
1174 }
1175 ds_put_format(string, " type=%d(%s)\n", type, s->name);
1176
1177 m = direction == REQUEST ? &s->request : &s->reply;
1178 if (body_len < m->min_body || body_len > m->max_body) {
1179 ds_put_format(string, " ***body_len=%zu not in %zu...%zu***",
1180 body_len, m->min_body, m->max_body);
1181 return;
1182 }
1183 if (m->printer) {
1184 m->printer(string, body, body_len, verbosity);
1185 }
1186}
1187
1188static void
1189ofp_stats_request(struct ds *string, const void *oh, size_t len, int verbosity)
1190{
1191 const struct ofp_stats_request *srq = oh;
1192
1193 if (srq->flags) {
1194 ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***",
1195 ntohs(srq->flags));
1196 }
1197
1198 print_stats(string, ntohs(srq->type), srq->body,
1199 len - offsetof(struct ofp_stats_request, body),
1200 verbosity, REQUEST);
1201}
1202
1203static void
1204ofp_stats_reply(struct ds *string, const void *oh, size_t len, int verbosity)
1205{
1206 const struct ofp_stats_reply *srp = oh;
1207
1208 ds_put_cstr(string, " flags=");
1209 if (!srp->flags) {
1210 ds_put_cstr(string, "none");
1211 } else {
1212 uint16_t flags = ntohs(srp->flags);
1213 if (flags & OFPSF_REPLY_MORE) {
1214 ds_put_cstr(string, "[more]");
1215 flags &= ~OFPSF_REPLY_MORE;
1216 }
1217 if (flags) {
1218 ds_put_format(string, "[***unknown flags 0x%04"PRIx16"***]", flags);
1219 }
1220 }
1221
1222 print_stats(string, ntohs(srp->type), srp->body,
1223 len - offsetof(struct ofp_stats_reply, body),
1224 verbosity, REPLY);
1225}
1226
1227static void
1228ofp_echo(struct ds *string, const void *oh, size_t len, int verbosity)
1229{
1230 const struct ofp_header *hdr = oh;
1231
1232 ds_put_format(string, " %zu bytes of payload\n", len - sizeof *hdr);
1233 if (verbosity > 1) {
1234 ds_put_hex_dump(string, hdr, len - sizeof *hdr, 0, true);
1235 }
1236}
1237
1238struct openflow_packet {
1239 uint8_t type;
1240 const char *name;
1241 size_t min_size;
1242 void (*printer)(struct ds *, const void *, size_t len, int verbosity);
1243};
1244
1245static const struct openflow_packet packets[] = {
1246 {
1247 OFPT_HELLO,
1248 "hello",
1249 sizeof (struct ofp_header),
1250 NULL,
1251 },
1252 {
1253 OFPT_FEATURES_REQUEST,
1254 "features_request",
1255 sizeof (struct ofp_header),
1256 NULL,
1257 },
1258 {
1259 OFPT_FEATURES_REPLY,
1260 "features_reply",
1261 sizeof (struct ofp_switch_features),
1262 ofp_print_switch_features,
1263 },
1264 {
1265 OFPT_GET_CONFIG_REQUEST,
1266 "get_config_request",
1267 sizeof (struct ofp_header),
1268 NULL,
1269 },
1270 {
1271 OFPT_GET_CONFIG_REPLY,
1272 "get_config_reply",
1273 sizeof (struct ofp_switch_config),
1274 ofp_print_switch_config,
1275 },
1276 {
1277 OFPT_SET_CONFIG,
1278 "set_config",
1279 sizeof (struct ofp_switch_config),
1280 ofp_print_switch_config,
1281 },
1282 {
1283 OFPT_PACKET_IN,
1284 "packet_in",
1285 offsetof(struct ofp_packet_in, data),
1286 ofp_packet_in,
1287 },
1288 {
1289 OFPT_PACKET_OUT,
1290 "packet_out",
1291 sizeof (struct ofp_packet_out),
1292 ofp_packet_out,
1293 },
1294 {
1295 OFPT_FLOW_MOD,
1296 "flow_mod",
1297 sizeof (struct ofp_flow_mod),
1298 ofp_print_flow_mod,
1299 },
1300 {
1301 OFPT_FLOW_EXPIRED,
1302 "flow_expired",
1303 sizeof (struct ofp_flow_expired),
1304 ofp_print_flow_expired,
1305 },
1306 {
1307 OFPT_PORT_MOD,
1308 "port_mod",
1309 sizeof (struct ofp_port_mod),
1310 ofp_print_port_mod,
1311 },
1312 {
1313 OFPT_PORT_STATUS,
1314 "port_status",
1315 sizeof (struct ofp_port_status),
1316 ofp_print_port_status
1317 },
1318 {
1319 OFPT_ERROR,
1320 "error_msg",
1321 sizeof (struct ofp_error_msg),
1322 ofp_print_error_msg,
1323 },
1324 {
1325 OFPT_STATS_REQUEST,
1326 "stats_request",
1327 sizeof (struct ofp_stats_request),
1328 ofp_stats_request,
1329 },
1330 {
1331 OFPT_STATS_REPLY,
1332 "stats_reply",
1333 sizeof (struct ofp_stats_reply),
1334 ofp_stats_reply,
1335 },
1336 {
1337 OFPT_ECHO_REQUEST,
1338 "echo_request",
1339 sizeof (struct ofp_header),
1340 ofp_echo,
1341 },
1342 {
1343 OFPT_ECHO_REPLY,
1344 "echo_reply",
1345 sizeof (struct ofp_header),
1346 ofp_echo,
1347 },
1348 {
1349 OFPT_VENDOR,
1350 "vendor",
1351 sizeof (struct ofp_vendor_header),
1352 NULL,
1353 },
1354};
1355
1356/* Composes and returns a string representing the OpenFlow packet of 'len'
1357 * bytes at 'oh' at the given 'verbosity' level. 0 is a minimal amount of
1358 * verbosity and higher numbers increase verbosity. The caller is responsible
1359 * for freeing the string. */
1360char *
1361ofp_to_string(const void *oh_, size_t len, int verbosity)
1362{
1363 struct ds string = DS_EMPTY_INITIALIZER;
1364 const struct ofp_header *oh = oh_;
1365 const struct openflow_packet *pkt;
1366
1367 if (len < sizeof(struct ofp_header)) {
1368 ds_put_cstr(&string, "OpenFlow packet too short:\n");
1369 ds_put_hex_dump(&string, oh, len, 0, true);
1370 return ds_cstr(&string);
1371 } else if (oh->version != OFP_VERSION) {
1372 ds_put_format(&string, "Bad OpenFlow version %"PRIu8":\n", oh->version);
1373 ds_put_hex_dump(&string, oh, len, 0, true);
1374 return ds_cstr(&string);
1375 }
1376
1377 for (pkt = packets; ; pkt++) {
1378 if (pkt >= &packets[ARRAY_SIZE(packets)]) {
1379 ds_put_format(&string, "Unknown OpenFlow packet type %"PRIu8":\n",
1380 oh->type);
1381 ds_put_hex_dump(&string, oh, len, 0, true);
1382 return ds_cstr(&string);
1383 } else if (oh->type == pkt->type) {
1384 break;
1385 }
1386 }
1387
1388 ds_put_format(&string, "%s (xid=0x%"PRIx32"):", pkt->name, oh->xid);
1389
1390 if (ntohs(oh->length) > len)
1391 ds_put_format(&string, " (***truncated to %zu bytes from %"PRIu16"***)",
1392 len, ntohs(oh->length));
1393 else if (ntohs(oh->length) < len) {
1394 ds_put_format(&string, " (***only uses %"PRIu16" bytes out of %zu***)\n",
1395 ntohs(oh->length), len);
1396 len = ntohs(oh->length);
1397 }
1398
1399 if (len < pkt->min_size) {
1400 ds_put_format(&string, " (***length=%zu < min_size=%zu***)\n",
1401 len, pkt->min_size);
1402 } else if (!pkt->printer) {
1403 if (len > sizeof *oh) {
1404 ds_put_format(&string, " length=%"PRIu16" (decoder not implemented)\n",
1405 ntohs(oh->length));
1406 }
1407 } else {
1408 pkt->printer(&string, oh, len, verbosity);
1409 }
1410 if (verbosity >= 3) {
1411 ds_put_hex_dump(&string, oh, len, 0, true);
1412 }
1413 if (string.string[string.length - 1] != '\n') {
1414 ds_put_char(&string, '\n');
1415 }
1416 return ds_cstr(&string);
1417}
1418
1419/* Returns the name for the specified OpenFlow message type as a string,
1420 * e.g. "OFPT_FEATURES_REPLY". If no name is known, the string returned is a
1421 * hex number, e.g. "0x55".
1422 *
1423 * The caller must free the returned string when it is no longer needed. */
1424char *
1425ofp_message_type_to_string(uint8_t type)
1426{
1427 struct ds s = DS_EMPTY_INITIALIZER;
1428 const struct openflow_packet *pkt;
1429 for (pkt = packets; ; pkt++) {
1430 if (pkt >= &packets[ARRAY_SIZE(packets)]) {
1431 ds_put_format(&s, "0x%02"PRIx8, type);
1432 break;
1433 } else if (type == pkt->type) {
1434 const char *p;
1435
1436 ds_put_cstr(&s, "OFPT_");
1437 for (p = pkt->name; *p; p++) {
1438 ds_put_char(&s, toupper((unsigned char) *p));
1439 }
1440 break;
1441 }
1442 }
1443 return ds_cstr(&s);
1444}
1445\f
1446static void
1447print_and_free(FILE *stream, char *string)
1448{
1449 fputs(string, stream);
1450 free(string);
1451}
1452
1453/* Pretty-print the OpenFlow packet of 'len' bytes at 'oh' to 'stream' at the
1454 * given 'verbosity' level. 0 is a minimal amount of verbosity and higher
1455 * numbers increase verbosity. */
1456void
1457ofp_print(FILE *stream, const void *oh, size_t len, int verbosity)
1458{
1459 print_and_free(stream, ofp_to_string(oh, len, verbosity));
1460}
1461
1462/* Dumps the contents of the Ethernet frame in the 'len' bytes starting at
1463 * 'data' to 'stream' using tcpdump. 'total_len' specifies the full length of
1464 * the Ethernet frame (of which 'len' bytes were captured).
1465 *
1466 * This starts and kills a tcpdump subprocess so it's quite expensive. */
1467void
1468ofp_print_packet(FILE *stream, const void *data, size_t len, size_t total_len)
1469{
1470 print_and_free(stream, ofp_packet_to_string(data, len, total_len));
1471}