ofp-util: Support for OpenFlow 1.3 meters.
[sliver-openvswitch.git] / lib / ofp-print.c
index 42fd9a6..76bd09c 100644 (file)
@@ -878,6 +878,8 @@ ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason,
         return "group_delete";
     case OFPRR_EVICTION:
         return "eviction";
+    case OFPRR_METER_DELETE:
+        return "meter_delete";
     default:
         snprintf(reasonbuf, bufsize, "%d", (int) reason);
         return reasonbuf;
@@ -954,6 +956,236 @@ ofp_print_port_mod(struct ds *string, const struct ofp_header *oh)
     }
 }
 
+static void
+ofp_print_meter_flags(struct ds *s, uint16_t flags)
+{
+    if (flags & OFPMF13_KBPS) {
+        ds_put_cstr(s, "kbps ");
+    }
+    if (flags & OFPMF13_PKTPS) {
+        ds_put_cstr(s, "pktps ");
+    }
+    if (flags & OFPMF13_BURST) {
+        ds_put_cstr(s, "burst ");
+    }
+    if (flags & OFPMF13_STATS) {
+        ds_put_cstr(s, "stats ");
+    }
+
+    flags &= ~(OFPMF13_KBPS | OFPMF13_PKTPS | OFPMF13_BURST | OFPMF13_STATS);
+    if (flags) {
+        ds_put_format(s, "flags:0x%"PRIx16" ", flags);
+    }
+}
+
+static void
+ofp_print_meter_band(struct ds *s, uint16_t flags,
+                     const struct ofputil_meter_band *mb)
+{
+    ds_put_cstr(s, "\ntype=");
+    switch (mb->type) {
+    case OFPMBT13_DROP:
+        ds_put_cstr(s, "drop");
+        break;
+    case OFPMBT13_DSCP_REMARK:
+        ds_put_cstr(s, "dscp_remark");
+        break;
+    default:
+        ds_put_format(s, "%u", mb->type);
+    }
+
+    ds_put_format(s, " rate=%"PRIu32, mb->rate);
+
+    if (flags & OFPMF13_BURST) {
+        ds_put_format(s, " burst_size=%"PRIu32, mb->burst_size);
+    }
+    if (mb->type == OFPMBT13_DSCP_REMARK) {
+        ds_put_format(s, " prec_level=%"PRIu8, mb->prec_level);
+    }
+}
+
+static void
+ofp_print_meter_stats(struct ds *s, const struct ofputil_meter_stats *ms)
+{
+    uint16_t i;
+
+    ds_put_format(s, "meter:%"PRIu32" ", ms->meter_id);
+    ds_put_format(s, "flow_count:%"PRIu32" ", ms->flow_count);
+    ds_put_format(s, "packet_in_count:%"PRIu64" ", ms->packet_in_count);
+    ds_put_format(s, "byte_in_count:%"PRIu64" ", ms->byte_in_count);
+    ds_put_cstr(s, "duration:");
+    ofp_print_duration(s, ms->duration_sec, ms->duration_nsec);
+    ds_put_char(s, ' ');
+
+    ds_put_cstr(s, "bands:\n");
+    for (i = 0; i < ms->n_bands; ++i) {
+        ds_put_format(s, "%d: ", i);
+        ds_put_format(s, "packet_count:%"PRIu64" ", ms->bands[i].packet_count);
+        ds_put_format(s, "byte_count:%"PRIu64"\n", ms->bands[i].byte_count);
+    }
+}
+
+static void
+ofp_print_meter_config(struct ds *s, const struct ofputil_meter_config *mc)
+{
+    uint16_t i;
+
+    ds_put_format(s, "meter=%"PRIu32" ", mc->meter_id);
+
+    ofp_print_meter_flags(s, mc->flags);
+
+    ds_put_cstr(s, "bands=");
+    for (i = 0; i < mc->n_bands; ++i) {
+        ofp_print_meter_band(s, mc->flags, &mc->bands[i]);
+    }
+    ds_put_char(s, '\n');
+}
+
+static void
+ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh)
+{
+    struct ofputil_meter_mod mm;
+    struct ofpbuf bands;
+    enum ofperr error;
+
+    ofpbuf_init(&bands, 64);
+    error = ofputil_decode_meter_mod(oh, &mm, &bands);
+    if (error) {
+        ofpbuf_uninit(&bands);
+        ofp_print_error(s, error);
+        return;
+    }
+
+    switch (mm.command) {
+    case OFPMC13_ADD:
+        ds_put_cstr(s, " ADD ");
+        break;
+    case OFPMC13_MODIFY:
+        ds_put_cstr(s, " MOD ");
+        break;
+    case OFPMC13_DELETE:
+        ds_put_cstr(s, " DEL ");
+        break;
+    default:
+        ds_put_format(s, " cmd:%d ", mm.command);
+    }
+
+    ofp_print_meter_config(s, &mm.meter);
+    ofpbuf_uninit(&bands);
+}
+
+static void
+ofp_print_meter_stats_request(struct ds *s, const struct ofp_header *oh)
+{
+    uint32_t meter_id;
+
+    ofputil_decode_meter_request(oh, &meter_id);
+
+    ds_put_format(s, " meter=%"PRIu32, meter_id);
+}
+
+static const char *
+ofputil_meter_capabilities_to_name(uint32_t bit)
+{
+    enum ofp13_meter_flags flag = bit;
+
+    switch (flag) {
+    case OFPMF13_KBPS:    return "kbps";
+    case OFPMF13_PKTPS:   return "pktps";
+    case OFPMF13_BURST:   return "burst";
+    case OFPMF13_STATS:   return "stats";
+    }
+
+    return NULL;
+}
+
+static const char *
+ofputil_meter_band_types_to_name(uint32_t bit)
+{
+    /*
+     * Note: Meter band types start from 1.  We assume that the lowest bit
+     * in the band_types corresponds to DROP band type (1).
+     */
+    switch (bit) {
+    case 1 << (OFPMBT13_DROP - 1):          return "drop";
+    case 1 << (OFPMBT13_DSCP_REMARK - 1):   return "dscp_remark";
+    }
+
+    return NULL;
+}
+
+static void
+ofp_print_meter_features_reply(struct ds *s, const struct ofp_header *oh)
+{
+    struct ofputil_meter_features mf;
+
+    ofputil_decode_meter_features(oh, &mf);
+
+    ds_put_format(s, "\nmax_meter:%"PRIu32, mf.max_meters);
+    ds_put_format(s, " max_bands:%"PRIu8, mf.max_bands);
+    ds_put_format(s, " max_color:%"PRIu8"\n", mf.max_color);
+
+    ds_put_cstr(s, "band_types: ");
+    ofp_print_bit_names(s, mf.band_types,
+                        ofputil_meter_band_types_to_name, ' ');
+    ds_put_char(s, '\n');
+
+    ds_put_cstr(s, "capabilities: ");
+    ofp_print_bit_names(s, mf.capabilities,
+                        ofputil_meter_capabilities_to_name, ' ');
+    ds_put_char(s, '\n');
+}
+
+static void
+ofp_print_meter_config_reply(struct ds *s, const struct ofp_header *oh)
+{
+    struct ofpbuf bands;
+    struct ofpbuf b;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    ofpbuf_init(&bands, 64);
+    for (;;) {
+        struct ofputil_meter_config mc;
+        int retval;
+
+        retval = ofputil_decode_meter_config(&b, &mc, &bands);
+        if (retval) {
+            if (retval != EOF) {
+                ofp_print_error(s, retval);
+            }
+            break;
+        }
+        ds_put_char(s, '\n');
+        ofp_print_meter_config(s, &mc);
+    }
+    ofpbuf_uninit(&bands);
+}
+
+static void
+ofp_print_meter_stats_reply(struct ds *s, const struct ofp_header *oh)
+{
+    struct ofpbuf bands;
+    struct ofpbuf b;
+
+    ofpbuf_use_const(&b, oh, ntohs(oh->length));
+    ofpbuf_init(&bands, 64);
+    for (;;) {
+        struct ofputil_meter_stats ms;
+        int retval;
+
+        retval = ofputil_decode_meter_stats(&b, &ms, &bands);
+        if (retval) {
+            if (retval != EOF) {
+                ofp_print_error(s, retval);
+            }
+            break;
+        }
+        ds_put_char(s, '\n');
+        ofp_print_meter_stats(s, &ms);
+    }
+    ofpbuf_uninit(&bands);
+}
+
 static void
 ofp_print_error(struct ds *string, enum ofperr error)
 {
@@ -1910,19 +2142,12 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
     case OFPTYPE_QUEUE_GET_CONFIG_REPLY:
     case OFPTYPE_GET_ASYNC_REQUEST:
     case OFPTYPE_GET_ASYNC_REPLY:
-    case OFPTYPE_METER_MOD:
     case OFPTYPE_GROUP_REQUEST:
     case OFPTYPE_GROUP_REPLY:
     case OFPTYPE_GROUP_DESC_REQUEST:
     case OFPTYPE_GROUP_DESC_REPLY:
     case OFPTYPE_GROUP_FEATURES_REQUEST:
     case OFPTYPE_GROUP_FEATURES_REPLY:
-    case OFPTYPE_METER_REQUEST:
-    case OFPTYPE_METER_REPLY:
-    case OFPTYPE_METER_CONFIG_REQUEST:
-    case OFPTYPE_METER_CONFIG_REPLY:
-    case OFPTYPE_METER_FEATURES_REQUEST:
-    case OFPTYPE_METER_FEATURES_REPLY:
     case OFPTYPE_TABLE_FEATURES_REQUEST:
     case OFPTYPE_TABLE_FEATURES_REPLY:
         ofp_print_not_implemented(string);
@@ -1980,6 +2205,10 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
         ofp_print_port_mod(string, oh);
         break;
 
+    case OFPTYPE_METER_MOD:
+        ofp_print_meter_mod(string, oh);
+        break;
+
     case OFPTYPE_BARRIER_REQUEST:
     case OFPTYPE_BARRIER_REPLY:
         break;
@@ -1989,8 +2218,30 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
         ofp_print_role_message(string, oh);
         break;
 
+    case OFPTYPE_METER_REQUEST:
+    case OFPTYPE_METER_CONFIG_REQUEST:
+        ofp_print_stats_request(string, oh);
+        ofp_print_meter_stats_request(string, oh);
+        break;
+
+    case OFPTYPE_METER_REPLY:
+        ofp_print_stats_reply(string, oh);
+        ofp_print_meter_stats_reply(string, oh);
+        break;
+
+    case OFPTYPE_METER_CONFIG_REPLY:
+        ofp_print_stats_reply(string, oh);
+        ofp_print_meter_config_reply(string, oh);
+        break;
+
+    case OFPTYPE_METER_FEATURES_REPLY:
+        ofp_print_stats_reply(string, oh);
+        ofp_print_meter_features_reply(string, oh);
+        break;
+
     case OFPTYPE_DESC_STATS_REQUEST:
     case OFPTYPE_PORT_DESC_STATS_REQUEST:
+    case OFPTYPE_METER_FEATURES_REQUEST:
         ofp_print_stats_request(string, oh);
         break;