Add support for OFPFC_MODIFY Flow Mod command.
[openvswitch] / lib / ofp-print.c
index c8d8ad3198665e583384f405dd72b453f9524857..95d180bd96a7c6b9d58f2adff37869b60311953b 100644 (file)
@@ -411,11 +411,8 @@ ofp_print_switch_features(struct ds *string, const void *oh, size_t len,
     int i;
 
     ds_put_format(string, "dp id:%"PRIx64"\n", ntohll(osf->datapath_id));
-    ds_put_format(string, "tables: exact:%d, compressed:%d, general:%d\n",
-           ntohl(osf->n_exact), 
-           ntohl(osf->n_compression), ntohl(osf->n_general));
-    ds_put_format(string, "buffers: size:%d, number:%d\n",
-           ntohl(osf->buffer_mb), ntohl(osf->n_buffers));
+    ds_put_format(string, "n_tables:%d, n_buffers:%d\n", osf->n_tables,
+            ntohl(osf->n_buffers));
     ds_put_format(string, "features: capabilities:%#x, actions:%#x\n",
            ntohl(osf->capabilities), ntohl(osf->actions));
 
@@ -502,22 +499,28 @@ static void ofp_print_match(struct ds *f, const struct ofp_match *om,
     bool skip_type = false;
     bool skip_proto = false;
 
-    if (!(w & OFPFW_DL_TYPE) &&om->dl_type == htons(ETH_TYPE_IP)) {
+    if (!(w & OFPFW_DL_TYPE)) {
         skip_type = true;
-        if (!(w & OFPFW_NW_PROTO)) {
-            skip_proto = true;
-            if (om->nw_proto == IP_TYPE_ICMP) {
-                ds_put_cstr(f, "icmp,");
-            } else if (om->nw_proto == IP_TYPE_TCP) {
-                ds_put_cstr(f, "tcp,");
-            } else if (om->nw_proto == IP_TYPE_UDP) {
-                ds_put_cstr(f, "udp,");
+        if (om->dl_type == htons(ETH_TYPE_IP)) {
+            if (!(w & OFPFW_NW_PROTO)) {
+                skip_proto = true;
+                if (om->nw_proto == IP_TYPE_ICMP) {
+                    ds_put_cstr(f, "icmp,");
+                } else if (om->nw_proto == IP_TYPE_TCP) {
+                    ds_put_cstr(f, "tcp,");
+                } else if (om->nw_proto == IP_TYPE_UDP) {
+                    ds_put_cstr(f, "udp,");
+                } else {
+                    ds_put_cstr(f, "ip,");
+                    skip_proto = false;
+                }
             } else {
                 ds_put_cstr(f, "ip,");
-                skip_proto = false;
             }
+        } else if (om->dl_type == htons(ETH_TYPE_ARP)) {
+            ds_put_cstr(f, "arp,");
         } else {
-            ds_put_cstr(f, "ip,");
+            skip_type = false;
         }
     }
     print_wild(f, "in_port=", w & OFPFW_IN_PORT, verbosity,
@@ -555,9 +558,24 @@ 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 hard:%d pri:%d buf:%#x", 
-            ntohs(ofm->command), ntohs(ofm->idle_timeout),
-            ntohs(ofm->hard_timeout),
+    switch (ntohs(ofm->command)) {
+    case OFPFC_ADD:
+        ds_put_cstr(string, " ADD: ");
+        break;
+    case OFPFC_MODIFY:
+        ds_put_cstr(string, " MOD: ");
+        break;
+    case OFPFC_DELETE:
+        ds_put_cstr(string, " DEL: ");
+        break;
+    case OFPFC_DELETE_STRICT:
+        ds_put_cstr(string, " DEL_STRICT: ");
+        break;
+    default:
+        ds_put_format(string, " cmd:%d ", ntohs(ofm->command));
+    }
+    ds_put_format(string, "idle:%d hard:%d pri:%d buf:%#x", 
+            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,
@@ -593,16 +611,82 @@ ofp_print_flow_expired(struct ds *string, const void *oh, size_t len,
          ntohll(ofe->byte_count));
 }
 
-/* Pretty-print the OFPT_ERROR_MSG packet of 'len' bytes at 'oh' to 'string'
+struct error_type {
+    int type;
+    int code;
+    const char *name;
+};
+
+static const struct error_type error_types[] = {
+#define ERROR_TYPE(TYPE) {TYPE, -1, #TYPE}
+#define ERROR_CODE(TYPE, CODE) {TYPE, CODE, #CODE}
+    ERROR_TYPE(OFPET_HELLO_FAILED),
+    ERROR_CODE(OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE),
+
+    ERROR_TYPE(OFPET_BAD_REQUEST),
+    ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VERSION),
+    ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE),
+    ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT),
+    ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VERSION),
+};
+#define N_ERROR_TYPES ARRAY_SIZE(error_types)
+
+static const char *
+lookup_error_type(int type)
+{
+    const struct error_type *t;
+
+    for (t = error_types; t < &error_types[N_ERROR_TYPES]; t++) {
+        if (t->type == type && t->code == -1) {
+            return t->name;
+        }
+    }
+    return "?";
+}
+
+static const char *
+lookup_error_code(int type, int code)
+{
+    const struct error_type *t;
+
+    for (t = error_types; t < &error_types[N_ERROR_TYPES]; t++) {
+        if (t->type == type && t->code == code) {
+            return t->name;
+        }
+    }
+    return "?";
+}
+
+/* Pretty-print the OFPT_ERROR packet of 'len' bytes at 'oh' to 'string'
  * at the given 'verbosity' level. */
 static void
 ofp_print_error_msg(struct ds *string, const void *oh, size_t len, 
                        int verbosity)
 {
     const struct ofp_error_msg *oem = oh;
+    int type = ntohs(oem->type);
+    int code = ntohs(oem->code);
+    char *s;
 
-    ds_put_format(string, 
-         " type%d code%d\n", ntohs(oem->type), ntohs(oem->code));
+    ds_put_format(string, " type%d(%s) code%d(%s) payload:\n",
+                  type, lookup_error_type(type),
+                  code, lookup_error_code(type, code));
+
+    switch (type) {
+    case OFPET_HELLO_FAILED:
+        ds_put_printable(string, (char *) oem->data, len - sizeof *oem);
+        break;
+
+    case OFPET_BAD_REQUEST:
+        s = ofp_to_string(oem->data, len - sizeof *oem, 1);
+        ds_put_cstr(string, s);
+        free(s);
+        break;
+
+    default:
+        ds_put_hex_dump(string, oem->data, len - sizeof *oem, 0, true);
+        break;
+    }
 }
 
 /* Pretty-print the OFPT_PORT_STATUS packet of 'len' bytes at 'oh' to 'string'
@@ -627,14 +711,15 @@ ofp_print_port_status(struct ds *string, const void *oh, size_t len,
 }
 
 static void
-ofp_version_stats_reply(struct ds *string, const void *body, size_t len,
+ofp_desc_stats_reply(struct ds *string, const void *body, size_t len,
                      int verbosity)
 {
-    const struct ofp_version_stats *vs = body;
+    const struct ofp_desc_stats *ods = 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);
+    ds_put_format(string, "Manufacturer: %s\n", ods->mfr_desc);
+    ds_put_format(string, "Hardware: %s\n", ods->hw_desc);
+    ds_put_format(string, "Software: %s\n", ods->sw_desc);
+    ds_put_format(string, "Serial Num: %s\n", ods->serial_num);
 }
 
 static void
@@ -800,15 +885,24 @@ ofp_table_stats_reply(struct ds *string, const void *body, size_t len,
         strncpy(name, ts->name, sizeof name);
         name[OFP_MAX_TABLE_NAME_LEN] = '\0';
 
-        ds_put_format(string, "  table %"PRIu8": ", ts->table_id);
-        ds_put_format(string, "name %-8s, ", name);
-        ds_put_format(string, "max %6"PRIu32", ", ntohl(ts->max_entries));
-        ds_put_format(string, "active %6"PRIu32", ", ntohl(ts->active_count));
-        ds_put_format(string, "matched %6"PRIu64"\n",
+        ds_put_format(string, "  %d: %-8s: ", ts->table_id, name);
+        ds_put_format(string, "wild=0x%05"PRIx32", ", ntohl(ts->wildcards));
+        ds_put_format(string, "max=%6"PRIu32", ", ntohl(ts->max_entries));
+        ds_put_format(string, "active=%6"PRIu32", ", ntohl(ts->active_count));
+        ds_put_format(string, "matched=%6"PRIu64"\n",
                       ntohll(ts->matched_count));
      }
 }
 
+static void
+vendor_stat(struct ds *string, const void *body, size_t len,
+            int verbosity UNUSED)
+{
+    ds_put_format(string, " vendor=%08"PRIx32, ntohl(*(uint32_t *) body));
+    ds_put_format(string, " %zu bytes additional data",
+                  len - sizeof(uint32_t));
+}
+
 enum stats_direction {
     REQUEST,
     REPLY
@@ -830,10 +924,10 @@ print_stats(struct ds *string, int type, const void *body, size_t body_len,
     };
 
     static const struct stats_type stats_types[] = {
-        [OFPST_VERSION] = {
-            "version",
+        [OFPST_DESC] = {
+            "description",
             { 0, 0, NULL },
-            { 0, SIZE_MAX, ofp_version_stats_reply },
+            { 0, SIZE_MAX, ofp_desc_stats_reply },
         },
         [OFPST_FLOW] = {
             "flow",
@@ -861,6 +955,11 @@ print_stats(struct ds *string, int type, const void *body, size_t body_len,
             { 0, 0, NULL, },
             { 0, SIZE_MAX, ofp_port_stats_reply },
         },
+        [OFPST_VENDOR] = {
+            "vendor-specific",
+            { sizeof(uint32_t), SIZE_MAX, vendor_stat },
+            { sizeof(uint32_t), SIZE_MAX, vendor_stat },
+        },
     };
 
     const struct stats_type *s;
@@ -941,6 +1040,11 @@ struct openflow_packet {
 };
 
 static const struct openflow_packet packets[] = {
+    [OFPT_HELLO] = {
+        "hello",
+        sizeof (struct ofp_header),
+        NULL,
+    },
     [OFPT_FEATURES_REQUEST] = {
         "features_request",
         sizeof (struct ofp_header),
@@ -996,7 +1100,7 @@ static const struct openflow_packet packets[] = {
         sizeof (struct ofp_port_status),
         ofp_print_port_status
     },
-    [OFPT_ERROR_MSG] = {
+    [OFPT_ERROR] = {
         "error_msg",
         sizeof (struct ofp_error_msg),
         ofp_print_error_msg,