Add ability to direct "packet-in"s to particular controllers.
[sliver-openvswitch.git] / lib / ofp-print.c
index 7bc26c9..f3758ce 100644 (file)
@@ -33,6 +33,7 @@
 #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"
@@ -120,20 +121,8 @@ ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
         }
     }
 
-    switch (pin.reason) {
-    case OFPR_NO_MATCH:
-        ds_put_cstr(string, " (via no_match)");
-        break;
-    case OFPR_ACTION:
-        ds_put_cstr(string, " (via action)");
-        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, " (via %s)",
+                  ofputil_packet_in_reason_to_string(pin.reason));
 
     ds_put_format(string, " data_len=%zu", pin.packet_len);
     if (pin.buffer_id == UINT32_MAX) {
@@ -187,6 +176,9 @@ 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;
+    const struct nx_action_fin_timeout *naft;
+    const struct nx_action_controller *nac;
+    struct mf_subfield subfield;
     uint16_t port;
 
     switch (code) {
@@ -319,9 +311,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;
 
@@ -333,9 +324,8 @@ 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:
@@ -350,6 +340,38 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
         ds_put_cstr(s, "exit");
         break;
 
+    case OFPUTIL_NXAST_FIN_TIMEOUT:
+        naft = (const struct nx_action_fin_timeout *) a;
+        ds_put_cstr(s, "fin_timeout(");
+        if (naft->fin_idle_timeout) {
+            ds_put_format(s, "idle_timeout=%"PRIu16",",
+                          ntohs(naft->fin_idle_timeout));
+        }
+        if (naft->fin_hard_timeout) {
+            ds_put_format(s, "hard_timeout=%"PRIu16",",
+                          ntohs(naft->fin_hard_timeout));
+        }
+        ds_chomp(s, ',');
+        ds_put_char(s, ')');
+        break;
+
+    case OFPUTIL_NXAST_CONTROLLER:
+        nac = (const struct nx_action_controller *) a;
+        ds_put_cstr(s, "controller(");
+        if (nac->reason != OFPR_ACTION) {
+            ds_put_format(s, "reason=%s,",
+                          ofputil_packet_in_reason_to_string(nac->reason));
+        }
+        if (nac->max_len != htons(UINT16_MAX)) {
+            ds_put_format(s, "max_len=%"PRIu16",", ntohs(nac->max_len));
+        }
+        if (nac->controller_id != htons(0)) {
+            ds_put_format(s, "id=%"PRIu16",", ntohs(nac->controller_id));
+        }
+        ds_chomp(s, ',');
+        ds_put_char(s, ')');
+        break;
+
     default:
         break;
     }
@@ -388,36 +410,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=%zu", 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');
 }
@@ -841,7 +858,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);
@@ -860,6 +892,24 @@ ofp_print_duration(struct ds *string, unsigned int sec, unsigned int nsec)
     ds_put_char(string, 's');
 }
 
+static const char *
+ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason)
+{
+    static char s[32];
+
+    switch (reason) {
+    case OFPRR_IDLE_TIMEOUT:
+        return "idle";
+    case OFPRR_HARD_TIMEOUT:
+        return "hard";
+    case OFPRR_DELETE:
+        return "delete";
+    default:
+        sprintf(s, "%d", (int) reason);
+        return s;
+    }
+}
+
 static void
 ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
 {
@@ -875,21 +925,8 @@ ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
     ds_put_char(string, ' ');
     cls_rule_format(&fr.rule, string);
 
-    ds_put_cstr(string, " reason=");
-    switch (fr.reason) {
-    case OFPRR_IDLE_TIMEOUT:
-        ds_put_cstr(string, "idle");
-        break;
-    case OFPRR_HARD_TIMEOUT:
-        ds_put_cstr(string, "hard");
-        break;
-    case OFPRR_DELETE:
-        ds_put_cstr(string, "delete");
-        break;
-    default:
-        ds_put_format(string, "**%"PRIu8"**", fr.reason);
-        break;
-    }
+    ds_put_format(string, " reason=%s",
+                  ofp_flow_removed_reason_to_string(fr.reason));
 
     if (fr.cookie != htonll(0)) {
         ds_put_format(string, " cookie:0x%"PRIx64, ntohll(fr.cookie));
@@ -1022,7 +1059,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***");
@@ -1044,6 +1081,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] != ' ') {
@@ -1297,6 +1340,82 @@ ofp_print_nxt_set_packet_in_format(struct ds *string,
     }
 }
 
+static const char *
+ofp_port_reason_to_string(enum ofp_port_reason reason)
+{
+    static char s[32];
+
+    switch (reason) {
+    case OFPPR_ADD:
+        return "add";
+
+    case OFPPR_DELETE:
+        return "delete";
+
+    case OFPPR_MODIFY:
+        return "modify";
+
+    default:
+        sprintf(s, "%d", (int) reason);
+        return s;
+    }
+}
+
+static void
+ofp_print_nxt_set_async_config(struct ds *string,
+                               const struct nx_async_config *nac)
+{
+    int i;
+
+    for (i = 0; i < 2; i++) {
+        int j;
+
+        ds_put_format(string, "\n %s:\n", i == 0 ? "master" : "slave");
+
+        ds_put_cstr(string, "       PACKET_IN:");
+        for (j = 0; j < 32; j++) {
+            if (nac->packet_in_mask[i] & htonl(1u << j)) {
+                ds_put_format(string, " %s",
+                              ofputil_packet_in_reason_to_string(j));
+            }
+        }
+        if (!nac->packet_in_mask[i]) {
+            ds_put_cstr(string, " (off)");
+        }
+        ds_put_char(string, '\n');
+
+        ds_put_cstr(string, "     PORT_STATUS:");
+        for (j = 0; j < 32; j++) {
+            if (nac->port_status_mask[i] & htonl(1u << j)) {
+                ds_put_format(string, " %s", ofp_port_reason_to_string(j));
+            }
+        }
+        if (!nac->port_status_mask[i]) {
+            ds_put_cstr(string, " (off)");
+        }
+        ds_put_char(string, '\n');
+
+        ds_put_cstr(string, "    FLOW_REMOVED:");
+        for (j = 0; j < 32; j++) {
+            if (nac->flow_removed_mask[i] & htonl(1u << j)) {
+                ds_put_format(string, " %s",
+                              ofp_flow_removed_reason_to_string(j));
+            }
+        }
+        if (!nac->flow_removed_mask[i]) {
+            ds_put_cstr(string, " (off)");
+        }
+        ds_put_char(string, '\n');
+    }
+}
+
+static void
+ofp_print_nxt_set_controller_id(struct ds *string,
+                                const struct nx_controller_id *nci)
+{
+    ds_put_format(string, " id=%"PRIu16, ntohs(nci->controller_id));
+}
+
 static void
 ofp_to_string__(const struct ofp_header *oh,
                 const struct ofputil_msg_type *type, struct ds *string,
@@ -1362,6 +1481,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;
 
@@ -1452,8 +1572,15 @@ 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_NXT_SET_CONTROLLER_ID:
+        ofp_print_nxt_set_controller_id(string, msg);
+        break;
+
+    case OFPUTIL_NXT_SET_ASYNC_CONFIG:
+        ofp_print_nxt_set_async_config(string, msg);
         break;
 
     case OFPUTIL_NXST_AGGREGATE_REPLY: