+ 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);
+}
+
+static void
+ofp_print_error(struct ds *string, enum ofperr error)
+{
+ if (string->length) {
+ ds_put_char(string, ' ');
+ }
+ ds_put_format(string, "***decode error: %s***\n", ofperr_get_name(error));
+}
+
+static void
+ofp_print_hello(struct ds *string, const struct ofp_header *oh)
+{
+ uint32_t allowed_versions;
+ bool ok;
+
+ ok = ofputil_decode_hello(oh, &allowed_versions);
+
+ ds_put_cstr(string, "\n version bitmap: ");
+ ofputil_format_version_bitmap(string, allowed_versions);
+
+ if (!ok) {
+ ds_put_cstr(string, "\n unknown data in hello:\n");
+ ds_put_hex_dump(string, oh, ntohs(oh->length), 0, true);
+ }
+}
+
+static void
+ofp_print_error_msg(struct ds *string, const struct ofp_header *oh)
+{
+ size_t len = ntohs(oh->length);
+ struct ofpbuf payload;
+ enum ofperr error;
+ char *s;
+
+ error = ofperr_decode_msg(oh, &payload);
+ if (!error) {
+ ds_put_cstr(string, "***decode error***");
+ ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true);
+ return;
+ }
+
+ ds_put_format(string, " %s\n", ofperr_get_name(error));
+
+ if (error == OFPERR_OFPHFC_INCOMPATIBLE || error == OFPERR_OFPHFC_EPERM) {
+ ds_put_printable(string, payload.data, payload.size);
+ } else {
+ s = ofp_to_string(payload.data, payload.size, 1);
+ ds_put_cstr(string, s);
+ free(s);
+ }
+}
+
+static void
+ofp_print_port_status(struct ds *string, const struct ofp_header *oh)
+{
+ struct ofputil_port_status ps;
+ enum ofperr error;
+
+ error = ofputil_decode_port_status(oh, &ps);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ if (ps.reason == OFPPR_ADD) {
+ ds_put_format(string, " ADD:");
+ } else if (ps.reason == OFPPR_DELETE) {
+ ds_put_format(string, " DEL:");
+ } else if (ps.reason == OFPPR_MODIFY) {
+ ds_put_format(string, " MOD:");
+ }
+
+ ofp_print_phy_port(string, &ps.desc);
+}
+
+static void
+ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_header *oh)
+{
+ const struct ofp_desc_stats *ods = ofpmsg_body(oh);
+
+ ds_put_char(string, '\n');
+ ds_put_format(string, "Manufacturer: %.*s\n",
+ (int) sizeof ods->mfr_desc, ods->mfr_desc);
+ ds_put_format(string, "Hardware: %.*s\n",
+ (int) sizeof ods->hw_desc, ods->hw_desc);
+ ds_put_format(string, "Software: %.*s\n",
+ (int) sizeof ods->sw_desc, ods->sw_desc);
+ ds_put_format(string, "Serial Num: %.*s\n",
+ (int) sizeof ods->serial_num, ods->serial_num);
+ ds_put_format(string, "DP Description: %.*s\n",
+ (int) sizeof ods->dp_desc, ods->dp_desc);
+}
+
+static void
+ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh)
+{
+ struct ofputil_flow_stats_request fsr;
+ enum ofperr error;
+
+ error = ofputil_decode_flow_stats_request(&fsr, oh);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ if (fsr.table_id != 0xff) {
+ ds_put_format(string, " table=%"PRIu8, fsr.table_id);
+ }
+
+ if (fsr.out_port != OFPP_ANY) {
+ ds_put_cstr(string, " out_port=");
+ ofputil_format_port(fsr.out_port, string);
+ }
+
+ ds_put_char(string, ' ');
+ match_format(&fsr.match, string, OFP_DEFAULT_PRIORITY);
+}
+
+void
+ofp_print_flow_stats(struct ds *string, struct ofputil_flow_stats *fs)
+{
+ ds_put_format(string, " cookie=0x%"PRIx64", duration=",
+ ntohll(fs->cookie));
+
+ ofp_print_duration(string, fs->duration_sec, fs->duration_nsec);
+ ds_put_format(string, ", table=%"PRIu8", ", fs->table_id);
+ ds_put_format(string, "n_packets=%"PRIu64", ", fs->packet_count);
+ ds_put_format(string, "n_bytes=%"PRIu64", ", fs->byte_count);
+ if (fs->idle_timeout != OFP_FLOW_PERMANENT) {
+ ds_put_format(string, "idle_timeout=%"PRIu16", ", fs->idle_timeout);
+ }
+ if (fs->hard_timeout != OFP_FLOW_PERMANENT) {
+ ds_put_format(string, "hard_timeout=%"PRIu16", ", fs->hard_timeout);
+ }
+ if (fs->flags) {
+ ofp_print_flow_flags(string, fs->flags);
+ }
+ 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);
+ }
+
+ match_format(&fs->match, string, fs->priority);
+ if (string->string[string->length - 1] != ' ') {
+ ds_put_char(string, ' ');
+ }
+
+ ds_put_cstr(string, "actions=");
+ ofpacts_format(fs->ofpacts, fs->ofpacts_len, string);
+}
+
+static void
+ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
+{
+ struct ofpbuf ofpacts;
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ ofpbuf_init(&ofpacts, 64);
+ for (;;) {
+ struct ofputil_flow_stats fs;
+ int retval;
+
+ retval = ofputil_decode_flow_stats_reply(&fs, &b, true, &ofpacts);
+ if (retval) {
+ if (retval != EOF) {
+ ds_put_cstr(string, " ***parse error***");
+ }
+ break;
+ }
+ ds_put_char(string, '\n');
+ ofp_print_flow_stats(string, &fs);
+ }
+ ofpbuf_uninit(&ofpacts);
+}
+
+static void
+ofp_print_aggregate_stats_reply(struct ds *string, const struct ofp_header *oh)
+{
+ struct ofputil_aggregate_stats as;
+ enum ofperr error;
+
+ error = ofputil_decode_aggregate_stats_reply(&as, oh);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ ds_put_format(string, " packet_count=%"PRIu64, as.packet_count);
+ ds_put_format(string, " byte_count=%"PRIu64, as.byte_count);
+ ds_put_format(string, " flow_count=%"PRIu32, as.flow_count);
+}
+
+static void
+print_port_stat(struct ds *string, const char *leader, uint64_t stat, int more)
+{
+ ds_put_cstr(string, leader);
+ if (stat != UINT64_MAX) {
+ ds_put_format(string, "%"PRIu64, stat);
+ } else {
+ ds_put_char(string, '?');
+ }
+ if (more) {
+ ds_put_cstr(string, ", ");
+ } else {
+ ds_put_cstr(string, "\n");
+ }
+}
+
+static void
+ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh)
+{
+ ofp_port_t ofp10_port;
+ enum ofperr error;
+
+ error = ofputil_decode_port_stats_request(oh, &ofp10_port);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ ds_put_cstr(string, " port_no=");
+ ofputil_format_port(ofp10_port, string);