+static void
+ofp_print_table_miss_config(struct ds *string, const uint32_t config)
+{
+ uint32_t table_miss_config = config & OFPTC11_TABLE_MISS_MASK;
+
+ switch (table_miss_config) {
+ case OFPTC11_TABLE_MISS_CONTROLLER:
+ ds_put_cstr(string, "controller\n");
+ break;
+ case OFPTC11_TABLE_MISS_CONTINUE:
+ ds_put_cstr(string, "continue\n");
+ break;
+ case OFPTC11_TABLE_MISS_DROP:
+ ds_put_cstr(string, "drop\n");
+ break;
+ default:
+ ds_put_cstr(string, "Unknown\n");
+ break;
+ }
+}
+
+static void
+ofp_print_table_mod(struct ds *string, const struct ofp_header *oh)
+{
+ struct ofputil_table_mod pm;
+ enum ofperr error;
+
+ error = ofputil_decode_table_mod(oh, &pm);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ if (pm.table_id == 0xff) {
+ ds_put_cstr(string, " table_id: ALL_TABLES");
+ } else {
+ ds_put_format(string, " table_id=%"PRIu8, pm.table_id);
+ }
+
+ ds_put_cstr(string, ", flow_miss_config=");
+ ofp_print_table_miss_config(string, pm.config);
+}
+
+static void
+ofp_print_queue_get_config_request(struct ds *string,
+ const struct ofp_header *oh)
+{
+ enum ofperr error;
+ ofp_port_t port;
+
+ error = ofputil_decode_queue_get_config_request(oh, &port);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ ds_put_cstr(string, " port=");
+ ofputil_format_port(port, string);
+}
+
+static void
+print_queue_rate(struct ds *string, const char *name, unsigned int rate)
+{
+ if (rate <= 1000) {
+ ds_put_format(string, " %s:%u.%u%%", name, rate / 10, rate % 10);
+ } else if (rate < UINT16_MAX) {
+ ds_put_format(string, " %s:(disabled)", name);
+ }
+}
+
+static void
+ofp_print_queue_get_config_reply(struct ds *string,
+ const struct ofp_header *oh)
+{
+ enum ofperr error;
+ struct ofpbuf b;
+ ofp_port_t port;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ error = ofputil_decode_queue_get_config_reply(&b, &port);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ ds_put_cstr(string, " port=");
+ ofputil_format_port(port, string);
+ ds_put_char(string, '\n');
+
+ for (;;) {
+ struct ofputil_queue_config queue;
+ int retval;
+
+ retval = ofputil_pull_queue_get_config_reply(&b, &queue);
+ if (retval) {
+ if (retval != EOF) {
+ ofp_print_error(string, retval);
+ }
+ break;
+ }
+
+ ds_put_format(string, "queue %"PRIu32":", queue.queue_id);
+ print_queue_rate(string, "min_rate", queue.min_rate);
+ print_queue_rate(string, "max_rate", queue.max_rate);
+ ds_put_char(string, '\n');
+ }
+}
+
+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)
+{
+ switch (bit) {
+ case 1 << OFPMBT13_DROP: return "drop";
+ case 1 << OFPMBT13_DSCP_REMARK: 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);
+}
+