Add support for parsing and printing OFPFF_* flags.
[sliver-openvswitch.git] / lib / ofp-print.c
index 89267d8..f0c134f 100644 (file)
@@ -33,7 +33,9 @@
 #include "flow.h"
 #include "learn.h"
 #include "multipath.h"
+#include "meta-flow.h"
 #include "nx-match.h"
+#include "ofp-errors.h"
 #include "ofp-util.h"
 #include "ofpbuf.h"
 #include "openflow/openflow.h"
@@ -45,7 +47,7 @@
 #include "util.h"
 
 static void ofp_print_queue_name(struct ds *string, uint32_t port);
-static void ofp_print_error(struct ds *, int error);
+static void ofp_print_error(struct ds *, enum ofperr);
 
 
 /* Returns a string that represents the contents of the Ethernet frame in the
@@ -119,10 +121,19 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
         }
     }
 
-    if (pin.reason == OFPR_ACTION) {
+    switch (pin.reason) {
+    case OFPR_NO_MATCH:
+        ds_put_cstr(string, " (via no_match)");
+        break;
+    case OFPR_ACTION:
         ds_put_cstr(string, " (via action)");
-    } else if (pin.reason != OFPR_NO_MATCH) {
+        break;
+    case OFPR_INVALID_TTL:
+        ds_put_cstr(string, " (via invalid_ttl)");
+        break;
+    default:
         ds_put_format(string, " (***reason %"PRIu8"***)", pin.reason);
+        break;
     }
 
     ds_put_format(string, " data_len=%zu", pin.packet_len);
@@ -177,6 +188,7 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
     const struct nx_action_multipath *nam;
     const struct nx_action_autopath *naa;
     const struct nx_action_output_reg *naor;
+    struct mf_subfield subfield;
     uint16_t port;
 
     switch (code) {
@@ -309,9 +321,8 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
     case OFPUTIL_NXAST_AUTOPATH:
         naa = (const struct nx_action_autopath *)a;
         ds_put_format(s, "autopath(%u,", ntohl(naa->id));
-        nxm_format_field_bits(s, ntohl(naa->dst),
-                              nxm_decode_ofs(naa->ofs_nbits),
-                              nxm_decode_n_bits(naa->ofs_nbits));
+        nxm_decode(&subfield, naa->dst, naa->ofs_nbits);
+        mf_format_subfield(&subfield, s);
         ds_put_char(s, ')');
         break;
 
@@ -323,15 +334,18 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
     case OFPUTIL_NXAST_OUTPUT_REG:
         naor = (const struct nx_action_output_reg *) a;
         ds_put_cstr(s, "output:");
-        nxm_format_field_bits(s, ntohl(naor->src),
-                              nxm_decode_ofs(naor->ofs_nbits),
-                              nxm_decode_n_bits(naor->ofs_nbits));
+        nxm_decode(&subfield, naor->src, naor->ofs_nbits);
+        mf_format_subfield(&subfield, s);
         break;
 
     case OFPUTIL_NXAST_LEARN:
         learn_format((const struct nx_action_learn *) a, s);
         break;
 
+    case OFPUTIL_NXAST_DEC_TTL:
+        ds_put_cstr(s, "dec_ttl");
+        break;
+
     case OFPUTIL_NXAST_EXIT:
         ds_put_cstr(s, "exit");
         break;
@@ -374,36 +388,31 @@ static void
 ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
                      int verbosity)
 {
-    size_t len = ntohs(opo->header.length);
-    size_t actions_len = ntohs(opo->actions_len);
-
-    ds_put_cstr(string, " in_port=");
-    ofputil_format_port(ntohs(opo->in_port), string);
+    struct ofputil_packet_out po;
+    enum ofperr error;
 
-    ds_put_format(string, " actions_len=%zu ", actions_len);
-    if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) {
-        ds_put_format(string, "***packet too short for action length***\n");
+    error = ofputil_decode_packet_out(&po, opo);
+    if (error) {
+        ofp_print_error(string, error);
         return;
     }
-    if (actions_len % sizeof(union ofp_action)) {
-        ds_put_format(string, "***action length not a multiple of %zu***\n",
-                      sizeof(union ofp_action));
-    }
-    ofp_print_actions(string, (const union ofp_action *) opo->actions,
-                      actions_len / sizeof(union ofp_action));
 
-    if (ntohl(opo->buffer_id) == UINT32_MAX) {
-        int data_len = len - sizeof *opo - actions_len;
-        ds_put_format(string, " data_len=%d", data_len);
-        if (verbosity > 0 && len > sizeof *opo) {
-            char *packet = ofp_packet_to_string(
-                    (uint8_t *) opo->actions + actions_len, data_len);
+    ds_put_cstr(string, " in_port=");
+    ofputil_format_port(po.in_port, string);
+
+    ds_put_char(string, ' ');
+    ofp_print_actions(string, po.actions, po.n_actions);
+
+    if (po.buffer_id == UINT32_MAX) {
+        ds_put_format(string, " data_len=%d", po.packet_len);
+        if (verbosity > 0 && po.packet_len > 0) {
+            char *packet = ofp_packet_to_string(po.packet, po.packet_len);
             ds_put_char(string, '\n');
             ds_put_cstr(string, packet);
             free(packet);
         }
     } else {
-        ds_put_format(string, " buffer=0x%08"PRIx32, ntohl(opo->buffer_id));
+        ds_put_format(string, " buffer=0x%08"PRIx32, po.buffer_id);
     }
     ds_put_char(string, '\n');
 }
@@ -598,13 +607,18 @@ ofp_print_switch_features(struct ds *string,
 static void
 ofp_print_switch_config(struct ds *string, const struct ofp_switch_config *osc)
 {
-    uint16_t flags;
+    enum ofp_config_flags flags;
 
     flags = ntohs(osc->flags);
 
     ds_put_format(string, " frags=%s", ofputil_frag_handling_to_string(flags));
     flags &= ~OFPC_FRAG_MASK;
 
+    if (flags & OFPC_INVALID_TTL_TO_CONTROLLER) {
+        ds_put_format(string, " invalid_ttl_to_controller");
+        flags &= ~OFPC_INVALID_TTL_TO_CONTROLLER;
+    }
+
     if (flags) {
         ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
     }
@@ -746,7 +760,7 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
 {
     struct ofputil_flow_mod fm;
     bool need_priority;
-    int error;
+    enum ofperr error;
 
     error = ofputil_decode_flow_mod(&fm, oh, true);
     if (error) {
@@ -822,7 +836,22 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
         ds_put_format(s, "buf:0x%"PRIx32" ", fm.buffer_id);
     }
     if (fm.flags != 0) {
-        ds_put_format(s, "flags:0x%"PRIx16" ", fm.flags);
+        uint16_t flags = fm.flags;
+
+        if (flags & OFPFF_SEND_FLOW_REM) {
+            ds_put_cstr(s, "send_flow_rem ");
+        }
+        if (flags & OFPFF_CHECK_OVERLAP) {
+            ds_put_cstr(s, "check_overlap ");
+        }
+        if (flags & OFPFF_EMERG) {
+            ds_put_cstr(s, "emerg ");
+        }
+
+        flags &= ~(OFPFF_SEND_FLOW_REM | OFPFF_CHECK_OVERLAP | OFPFF_EMERG);
+        if (flags) {
+            ds_put_format(s, "flags:0x%"PRIx16" ", flags);
+        }
     }
 
     ofp_print_actions(s, fm.actions, fm.n_actions);
@@ -845,7 +874,7 @@ static void
 ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
 {
     struct ofputil_flow_removed fr;
-    int error;
+    enum ofperr error;
 
     error = ofputil_decode_flow_removed(&fr, oh);
     if (error) {
@@ -896,14 +925,12 @@ ofp_print_port_mod(struct ds *string, const struct ofp_port_mod *opm)
 }
 
 static void
-ofp_print_error(struct ds *string, int error)
+ofp_print_error(struct ds *string, enum ofperr error)
 {
     if (string->length) {
         ds_put_char(string, ' ');
     }
-    ds_put_cstr(string, "***decode error: ");
-    ofputil_format_error(string, error);
-    ds_put_cstr(string, "***\n");
+    ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error));
 }
 
 static void
@@ -912,32 +939,26 @@ ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
     size_t len = ntohs(oem->header.length);
     size_t payload_ofs, payload_len;
     const void *payload;
-    int error;
+    enum ofperr error;
     char *s;
 
-    error = ofputil_decode_error_msg(&oem->header, &payload_ofs);
-    if (!is_ofp_error(error)) {
-        ofp_print_error(string, error);
+    error = ofperr_decode_msg(&oem->header, &payload_ofs);
+    if (!error) {
+        ds_put_cstr(string, "***decode error***");
         ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true);
         return;
     }
 
-    ds_put_char(string, ' ');
-    ofputil_format_error(string, error);
-    ds_put_char(string, '\n');
+    ds_put_format(string, " %s\n", ofperr_get_name(error));
 
     payload = (const uint8_t *) oem + payload_ofs;
     payload_len = len - payload_ofs;
-    switch (get_ofp_err_type(error)) {
-    case OFPET_HELLO_FAILED:
+    if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) {
         ds_put_printable(string, payload, payload_len);
-        break;
-
-    default:
+    } else {
         s = ofp_to_string(payload, payload_len, 1);
         ds_put_cstr(string, s);
         free(s);
-        break;
     }
 }
 
@@ -976,7 +997,7 @@ ofp_print_flow_stats_request(struct ds *string,
                              const struct ofp_stats_msg *osm)
 {
     struct ofputil_flow_stats_request fsr;
-    int error;
+    enum ofperr error;
 
     error = ofputil_decode_flow_stats_request(&fsr, &osm->header);
     if (error) {
@@ -1011,7 +1032,7 @@ ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
         struct ofputil_flow_stats fs;
         int retval;
 
-        retval = ofputil_decode_flow_stats_reply(&fs, &b);
+        retval = ofputil_decode_flow_stats_reply(&fs, &b, true);
         if (retval) {
             if (retval != EOF) {
                 ds_put_cstr(string, " ***parse error***");
@@ -1033,6 +1054,12 @@ ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
         if (fs.hard_timeout != OFP_FLOW_PERMANENT) {
             ds_put_format(string, "hard_timeout=%"PRIu16",", fs.hard_timeout);
         }
+        if (fs.idle_age >= 0) {
+            ds_put_format(string, "idle_age=%d,", fs.idle_age);
+        }
+        if (fs.hard_age >= 0 && fs.hard_age != fs.duration_sec) {
+            ds_put_format(string, "hard_age=%d,", fs.hard_age);
+        }
 
         cls_rule_format(&fs.rule, string);
         if (string->string[string->length - 1] != ' ') {
@@ -1351,6 +1378,7 @@ ofp_to_string__(const struct ofp_header *oh,
         break;
 
     case OFPUTIL_OFPT_FLOW_MOD:
+    case OFPUTIL_NXT_FLOW_MOD:
         ofp_print_flow_mod(string, msg, code, verbosity);
         break;
 
@@ -1441,8 +1469,7 @@ ofp_to_string__(const struct ofp_header *oh,
         ofp_print_nxt_set_packet_in_format(string, msg);
         break;
 
-    case OFPUTIL_NXT_FLOW_MOD:
-        ofp_print_flow_mod(string, msg, code, verbosity);
+    case OFPUTIL_NXT_FLOW_AGE:
         break;
 
     case OFPUTIL_NXST_AGGREGATE_REPLY:
@@ -1467,9 +1494,6 @@ ofp_to_string(const void *oh_, size_t len, int verbosity)
     } else if (len < sizeof(struct ofp_header)) {
         ds_put_format(&string, "OpenFlow packet too short (only %zu bytes):\n",
                       len);
-    } else if (oh->version != OFP_VERSION) {
-        ds_put_format(&string, "Bad OpenFlow version %"PRIu8":\n",
-                      oh->version);
     } else if (ntohs(oh->length) > len) {
         ds_put_format(&string,
                       "(***truncated to %zu bytes from %"PRIu16"***)\n",
@@ -1480,7 +1504,7 @@ ofp_to_string(const void *oh_, size_t len, int verbosity)
                       ntohs(oh->length), len);
     } else {
         const struct ofputil_msg_type *type;
-        int error;
+        enum ofperr error;
 
         error = ofputil_decode_msg_type(oh, &type);
         if (!error) {