Fix dump-flows to be usable by add-flows.
[sliver-openvswitch.git] / lib / ofp-print.c
index d1a8f8d..f462449 100644 (file)
@@ -31,6 +31,7 @@
  * derivatives without specific, written prior permission.
  */
 
+#include <config.h>
 #include "ofp-print.h"
 #include "xtoxll.h"
 
@@ -167,7 +168,7 @@ ofp_packet_in(struct ds *string, const void *oh, size_t len, int verbosity)
         if (ntohs(op->total_len) != data_len)
             ds_put_format(string, " (***total_len != data_len***)");
     } else {
-        ds_put_format(string, " buffer=%08"PRIx32, ntohl(op->buffer_id));
+        ds_put_format(string, " buffer=0x%08"PRIx32, ntohl(op->buffer_id));
         if (ntohs(op->total_len) < data_len)
             ds_put_format(string, " (***total_len < data_len***)");
     }
@@ -185,6 +186,9 @@ static void ofp_print_port_name(struct ds *string, uint16_t port)
 {
     const char *name;
     switch (port) {
+    case OFPP_IN_PORT:
+        name = "IN_PORT";
+        break;
     case OFPP_TABLE:
         name = "TABLE";
         break;
@@ -256,11 +260,11 @@ ofp_print_action(struct ds *string, const struct ofp_action *a)
         break;
 
     case OFPAT_SET_NW_SRC:
-        ds_put_format(string, "mod_nw_src:"IP_FMT, IP_ARGS(a->arg.nw_addr));
+        ds_put_format(string, "mod_nw_src:"IP_FMT, IP_ARGS(&a->arg.nw_addr));
         break;
 
     case OFPAT_SET_NW_DST:
-        ds_put_format(string, "mod_nw_dst:"IP_FMT, IP_ARGS(a->arg.nw_addr));
+        ds_put_format(string, "mod_nw_dst:"IP_FMT, IP_ARGS(&a->arg.nw_addr));
         break;
 
     case OFPAT_SET_TP_SRC:
@@ -306,23 +310,31 @@ static void ofp_packet_out(struct ds *string, const void *oh, size_t len,
                            int verbosity) 
 {
     const struct ofp_packet_out *opo = oh;
+    int n_actions = ntohs(opo->n_actions);
+    int act_len = n_actions * sizeof opo->actions[0];
 
     ds_put_cstr(string, " in_port=");
     ofp_print_port_name(string, ntohs(opo->in_port));
 
+    ds_put_format(string, " n_actions=%d ", n_actions);
+    if (act_len > (ntohs(opo->header.length) - sizeof *opo)) {
+        ds_put_format(string, "***packet too short for number of actions***\n");
+        return;
+    }
+    ofp_print_actions(string, opo->actions, act_len);
+
     if (ntohl(opo->buffer_id) == UINT32_MAX) {
-        ds_put_cstr(string, " out_port=");
-        ofp_print_port_name(string, ntohs(opo->out_port));
+        int data_len = len - sizeof *opo - act_len;
+        ds_put_format(string, " data_len=%d", data_len);
         if (verbosity > 0 && len > sizeof *opo) {
-            char *packet = ofp_packet_to_string(opo->u.data, len - sizeof *opo,
-                                                len - sizeof *opo);
+            char *packet = ofp_packet_to_string(&opo->actions[n_actions], 
+                                                data_len, data_len);
             ds_put_char(string, '\n');
             ds_put_cstr(string, packet);
             free(packet);
         }
     } else {
-        ds_put_format(string, " buffer=%08"PRIx32, ntohl(opo->buffer_id));
-        ofp_print_actions(string, opo->u.actions, len - sizeof *opo);
+        ds_put_format(string, " buffer=0x%08"PRIx32, ntohl(opo->buffer_id));
     }
     ds_put_char(string, '\n');
 }
@@ -408,7 +420,7 @@ ofp_print_switch_config(struct ds *string, const void *oh, size_t len,
         ds_put_format(string, " (sending flow expirations)");
     }
     if (flags) {
-        ds_put_format(string, " ***unknown flags %04"PRIx16"***", flags);
+        ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
     }
 
     ds_put_format(string, " miss_send_len=%"PRIu16"\n", ntohs(osc->miss_send_len));
@@ -434,6 +446,7 @@ static void print_wild(struct ds *string, const char *leader, int is_wild,
     } else {
         ds_put_char(string, '*');
     }
+    ds_put_char(string, ',');
 }
 
 /* Pretty-print the ofp_match structure */
@@ -443,25 +456,25 @@ static void ofp_print_match(struct ds *f, const struct ofp_match *om,
     uint16_t w = ntohs(om->wildcards);
 
     print_wild(f, "in_port=", w & OFPFW_IN_PORT, verbosity,
-               "%d,", ntohs(om->in_port));
+               "%d", ntohs(om->in_port));
     print_wild(f, "dl_vlan=", w & OFPFW_DL_VLAN, verbosity,
-               "%04x,", ntohs(om->dl_vlan));
+               "0x%04x", ntohs(om->dl_vlan));
     print_wild(f, "dl_src=", w & OFPFW_DL_SRC, verbosity,
-               ETH_ADDR_FMT",", ETH_ADDR_ARGS(om->dl_src));
+               ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_src));
     print_wild(f, "dl_dst=", w & OFPFW_DL_DST, verbosity,
-               ETH_ADDR_FMT",", ETH_ADDR_ARGS(om->dl_dst));
+               ETH_ADDR_FMT, ETH_ADDR_ARGS(om->dl_dst));
     print_wild(f, "dl_type=", w & OFPFW_DL_TYPE, verbosity,
-               "%04x,", ntohs(om->dl_type));
+               "0x%04x", ntohs(om->dl_type));
     print_wild(f, "nw_src=", w & OFPFW_NW_SRC, verbosity,
-               IP_FMT",", IP_ARGS(&om->nw_src));
+               IP_FMT, IP_ARGS(&om->nw_src));
     print_wild(f, "nw_dst=", w & OFPFW_NW_DST, verbosity,
-               IP_FMT",", IP_ARGS(&om->nw_dst));
+               IP_FMT, IP_ARGS(&om->nw_dst));
     print_wild(f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity,
-               "%u,", om->nw_proto);
+               "%u", om->nw_proto);
     print_wild(f, "tp_src=", w & OFPFW_TP_SRC, verbosity,
-               "%d,", ntohs(om->tp_src));
+               "%d", ntohs(om->tp_src));
     print_wild(f, "tp_dst=", w & OFPFW_TP_DST, verbosity,
-               "%d,", ntohs(om->tp_dst));
+               "%d", ntohs(om->tp_dst));
 }
 
 /* Pretty-print the OFPT_FLOW_MOD packet of 'len' bytes at 'oh' to 'string'
@@ -473,8 +486,9 @@ ofp_print_flow_mod(struct ds *string, const void *oh, size_t len,
     const struct ofp_flow_mod *ofm = oh;
 
     ofp_print_match(string, &ofm->match, verbosity);
-    ds_put_format(string, " cmd:%d idle:%d pri:%d buf:%#x", 
-            ntohs(ofm->command), ntohs(ofm->max_idle), 
+    ds_put_format(string, " cmd:%d idle:%d hard:%d pri:%d buf:%#x", 
+            ntohs(ofm->command), ntohs(ofm->idle_timeout),
+            ntohs(ofm->hard_timeout),
             ofm->match.wildcards ? ntohs(ofm->priority) : (uint16_t)-1,
             ntohl(ofm->buffer_id));
     ofp_print_actions(string, ofm->actions,
@@ -491,6 +505,18 @@ ofp_print_flow_expired(struct ds *string, const void *oh, size_t len,
     const struct ofp_flow_expired *ofe = oh;
 
     ofp_print_match(string, &ofe->match, verbosity);
+    ds_put_cstr(string, " reason=");
+    switch (ofe->reason) {
+    case OFPER_IDLE_TIMEOUT:
+        ds_put_cstr(string, "idle");
+        break;
+    case OFPER_HARD_TIMEOUT:
+        ds_put_cstr(string, "hard");
+        break;
+    default:
+        ds_put_format(string, "**%"PRIu8"**", ofe->reason);
+        break;
+    }
     ds_put_format(string, 
          " pri%"PRIu16" secs%"PRIu32" pkts%"PRIu64" bytes%"PRIu64"\n", 
          ofe->match.wildcards ? ntohs(ofe->priority) : (uint16_t)-1,
@@ -531,6 +557,17 @@ ofp_print_port_status(struct ds *string, const void *oh, size_t len,
     ofp_print_phy_port(string, &ops->desc);
 }
 
+static void
+ofp_version_stats_reply(struct ds *string, const void *body, size_t len,
+                     int verbosity)
+{
+    const struct ofp_version_stats *vs = body;
+
+    ds_put_format(string, "Manufacturer: %s\n", vs->mfr_desc);
+    ds_put_format(string, "Hardware: %s\n", vs->hw_desc);
+    ds_put_format(string, "Software: %s\n", vs->sw_desc);
+}
+
 static void
 ofp_flow_stats_request(struct ds *string, const void *oh, size_t len,
                       int verbosity) 
@@ -592,7 +629,10 @@ ofp_flow_stats_reply(struct ds *string, const void *body_, size_t len,
         ds_put_format(string, "n_packets=%"PRIu64", ",
                     ntohll(fs->packet_count));
         ds_put_format(string, "n_bytes=%"PRIu64", ", ntohll(fs->byte_count));
-        ds_put_format(string, "max_idle=%"PRIu16",", ntohs(fs->max_idle));
+        ds_put_format(string, "idle_timeout=%"PRIu16",",
+                      ntohs(fs->idle_timeout));
+        ds_put_format(string, "hard_timeout=%"PRIu16",",
+                      ntohs(fs->hard_timeout));
         ofp_print_match(string, &fs->match, verbosity);
         ofp_print_actions(string, fs->actions, length - sizeof *fs);
         ds_put_char(string, '\n');
@@ -627,6 +667,22 @@ ofp_aggregate_stats_reply(struct ds *string, const void *body_, size_t len,
     ds_put_format(string, " flow_count=%"PRIu32, ntohl(asr->flow_count));
 }
 
+static void print_port_stat(struct ds *string, const char *leader, 
+                            uint64_t stat, int more)
+{
+    ds_put_cstr(string, leader);
+    if (stat != -1) {
+        ds_put_format(string, "%"PRIu64, stat);
+    } else {
+        ds_put_char(string, '?');
+    }
+    if (more) {
+        ds_put_cstr(string, ", ");
+    } else {
+        ds_put_cstr(string, "\n");
+    }
+}
+
 static void
 ofp_port_stats_reply(struct ds *string, const void *body, size_t len,
                      int verbosity)
@@ -639,10 +695,23 @@ ofp_port_stats_reply(struct ds *string, const void *body, size_t len,
     }
 
     for (; n--; ps++) {
-        ds_put_format(string, "  port %"PRIu16": ", ntohs(ps->port_no));
-        ds_put_format(string, "rx %"PRIu64", ", ntohll(ps->rx_count));
-        ds_put_format(string, "tx %"PRIu64", ", ntohll(ps->tx_count));
-        ds_put_format(string, "dropped %"PRIu64"\n", ntohll(ps->drop_count));
+        ds_put_format(string, "  port %2"PRIu16": ", ntohs(ps->port_no));
+
+        ds_put_cstr(string, "rx ");
+        print_port_stat(string, "pkts=", ntohll(ps->rx_packets), 1);
+        print_port_stat(string, "bytes=", ntohll(ps->rx_bytes), 1);
+        print_port_stat(string, "drop=", ntohll(ps->rx_dropped), 1);
+        print_port_stat(string, "errs=", ntohll(ps->rx_errors), 1);
+        print_port_stat(string, "frame=", ntohll(ps->rx_frame_err), 1);
+        print_port_stat(string, "over=", ntohll(ps->rx_over_err), 1);
+        print_port_stat(string, "crc=", ntohll(ps->rx_crc_err), 0);
+
+        ds_put_cstr(string, "           tx ");
+        print_port_stat(string, "pkts=", ntohll(ps->tx_packets), 1);
+        print_port_stat(string, "bytes=", ntohll(ps->tx_bytes), 1);
+        print_port_stat(string, "drop=", ntohll(ps->tx_dropped), 1);
+        print_port_stat(string, "errs=", ntohll(ps->tx_errors), 1);
+        print_port_stat(string, "coll=", ntohll(ps->collisions), 0);
     }
 }
 
@@ -692,6 +761,11 @@ print_stats(struct ds *string, int type, const void *body, size_t body_len,
     };
 
     static const struct stats_type stats_types[] = {
+        [OFPST_VERSION] = {
+            "version",
+            { 0, 0, NULL },
+            { 0, SIZE_MAX, ofp_version_stats_reply },
+        },
         [OFPST_FLOW] = {
             "flow",
             { sizeof(struct ofp_flow_stats_request),
@@ -747,7 +821,7 @@ ofp_stats_request(struct ds *string, const void *oh, size_t len, int verbosity)
     const struct ofp_stats_request *srq = oh;
 
     if (srq->flags) {
-        ds_put_format(string, " ***unknown flags %04"PRIx16"***",
+        ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***",
                       ntohs(srq->flags));
     }
 
@@ -771,7 +845,7 @@ ofp_stats_reply(struct ds *string, const void *oh, size_t len, int verbosity)
             flags &= ~OFPSF_REPLY_MORE;
         }
         if (flags) {
-            ds_put_format(string, "[***unknown%04"PRIx16"***]", flags);
+            ds_put_format(string, "[***unknown flags 0x%04"PRIx16"***]", flags);
         }
     }
 
@@ -780,6 +854,17 @@ ofp_stats_reply(struct ds *string, const void *oh, size_t len, int verbosity)
                 verbosity, REPLY);
 }
 
+static void
+ofp_echo(struct ds *string, const void *oh, size_t len, int verbosity)
+{
+    const struct ofp_header *hdr = oh;
+
+    ds_put_format(string, " %zu bytes of payload\n", len - sizeof *hdr);
+    if (verbosity > 1) {
+        ds_put_hex_dump(string, hdr, len - sizeof *hdr, 0, true); 
+    }
+}
+
 struct openflow_packet {
     const char *name;
     size_t min_size;
@@ -857,6 +942,16 @@ static const struct openflow_packet packets[] = {
         sizeof (struct ofp_stats_reply),
         ofp_stats_reply,
     },
+    [OFPT_ECHO_REQUEST] = {
+        "echo_request",
+        sizeof (struct ofp_header),
+        ofp_echo,
+    },
+    [OFPT_ECHO_REPLY] = {
+        "echo_reply",
+        sizeof (struct ofp_header),
+        ofp_echo,
+    },
 };
 
 /* Composes and returns a string representing the OpenFlow packet of 'len'
@@ -886,7 +981,7 @@ ofp_to_string(const void *oh_, size_t len, int verbosity)
     }
 
     pkt = &packets[oh->type];
-    ds_put_format(&string, "%s (xid=%"PRIx32"):", pkt->name, oh->xid);
+    ds_put_format(&string, "%s (xid=0x%"PRIx32"):", pkt->name, oh->xid);
 
     if (ntohs(oh->length) > len)
         ds_put_format(&string, " (***truncated to %zu bytes from %"PRIu16"***)",