struct flow flow;
ofpbuf_use_const(&buf, data, len);
- flow_extract(&buf, 0, 0, NULL, 0, &flow);
+ flow_extract(&buf, 0, 0, NULL, NULL, &flow);
flow_format(&ds, &flow);
if (buf.l7) {
struct udp_header *uh = buf.l4;
ds_put_format(&ds, " udp_csum:%"PRIx16,
ntohs(uh->udp_csum));
+ } else if (flow.nw_proto == IPPROTO_SCTP) {
+ struct sctp_header *sh = buf.l4;
+ ds_put_format(&ds, " sctp_csum:%"PRIx32,
+ ntohl(sh->sctp_csum));
}
}
ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
int verbosity)
{
+ char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];
struct ofputil_packet_in pin;
int error;
int i;
ds_put_format(string, " table_id=%"PRIu8, pin.table_id);
}
- if (pin.cookie) {
+ if (pin.cookie != OVS_BE64_MAX) {
ds_put_format(string, " cookie=0x%"PRIx64, ntohll(pin.cookie));
}
- ds_put_format(string, " total_len=%"PRIu16" in_port=", pin.total_len);
+ ds_put_format(string, " total_len=%zu in_port=", pin.total_len);
ofputil_format_port(pin.fmd.in_port, string);
if (pin.fmd.tun_id != htonll(0)) {
}
}
+ if (pin.fmd.pkt_mark != 0) {
+ ds_put_format(string, " pkt_mark=0x%"PRIx32, pin.fmd.pkt_mark);
+ }
+
ds_put_format(string, " (via %s)",
- ofputil_packet_in_reason_to_string(pin.reason));
+ ofputil_packet_in_reason_to_string(pin.reason, reasonbuf,
+ sizeof reasonbuf));
ds_put_format(string, " data_len=%zu", pin.packet_len);
if (pin.buffer_id == UINT32_MAX) {
ds_put_cstr(string, " in_port=");
ofputil_format_port(po.in_port, string);
- ds_put_char(string, ' ');
+ ds_put_cstr(string, " actions=");
ofpacts_format(po.ofpacts, po.ofpacts_len, string);
if (po.buffer_id == UINT32_MAX) {
{
const struct ofputil_phy_port *a = a_;
const struct ofputil_phy_port *b = b_;
- uint16_t ap = a->port_no;
- uint16_t bp = b->port_no;
+ uint16_t ap = ofp_to_u16(a->port_no);
+ uint16_t bp = ofp_to_u16(b->port_no);
return ap < bp ? -1 : ap > bp;
}
static void
print_wild_port(struct ds *string, const char *leader, int is_wild,
- int verbosity, uint16_t port)
+ int verbosity, ofp_port_t port)
{
if (is_wild && verbosity < 2) {
return;
ds_put_cstr(&f, "tcp,");
} else if (om->nw_proto == IPPROTO_UDP) {
ds_put_cstr(&f, "udp,");
+ } else if (om->nw_proto == IPPROTO_SCTP) {
+ ds_put_cstr(&f, "sctp,");
} else {
ds_put_cstr(&f, "ip,");
skip_proto = false;
}
}
print_wild_port(&f, "in_port=", w & OFPFW10_IN_PORT, verbosity,
- ntohs(om->in_port));
+ u16_to_ofp(ntohs(om->in_port)));
print_wild(&f, "dl_vlan=", w & OFPFW10_DL_VLAN, verbosity,
"%d", ntohs(om->dl_vlan));
print_wild(&f, "dl_vlan_pcp=", w & OFPFW10_DL_VLAN_PCP, verbosity,
}
static void
-ofp_print_flow_flags(struct ds *s, uint16_t flags)
+ofp_print_flow_flags(struct ds *s, enum ofputil_flow_mod_flags flags)
{
- if (flags & OFPFF_SEND_FLOW_REM) {
+ if (flags & OFPUTIL_FF_SEND_FLOW_REM) {
ds_put_cstr(s, "send_flow_rem ");
}
- if (flags & OFPFF_CHECK_OVERLAP) {
+ if (flags & OFPUTIL_FF_CHECK_OVERLAP) {
ds_put_cstr(s, "check_overlap ");
}
- if (flags & OFPFF12_RESET_COUNTS) {
+ if (flags & OFPUTIL_FF_RESET_COUNTS) {
ds_put_cstr(s, "reset_counts ");
}
- if (flags & OFPFF13_NO_PKT_COUNTS) {
+ if (flags & OFPUTIL_FF_NO_PKT_COUNTS) {
ds_put_cstr(s, "no_packet_counts ");
}
- if (flags & OFPFF13_NO_BYT_COUNTS) {
+ if (flags & OFPUTIL_FF_NO_BYT_COUNTS) {
ds_put_cstr(s, "no_byte_counts ");
}
-
- flags &= ~(OFPFF_SEND_FLOW_REM | OFPFF_CHECK_OVERLAP
- | OFPFF12_RESET_COUNTS
- | OFPFF13_NO_PKT_COUNTS | OFPFF13_NO_BYT_COUNTS);
- if (flags) {
- ds_put_format(s, "flags:0x%"PRIx16" ", flags);
- }
}
static void
if (ds_last(s) != ' ') {
ds_put_char(s, ' ');
}
- if (fm.new_cookie != htonll(0) && fm.new_cookie != htonll(UINT64_MAX)) {
+ if (fm.new_cookie != htonll(0) && fm.new_cookie != OVS_BE64_MAX) {
ds_put_format(s, "cookie:0x%"PRIx64" ", ntohll(fm.new_cookie));
}
if (fm.cookie_mask != htonll(0)) {
ofputil_format_port(fm.out_port, s);
ds_put_char(s, ' ');
}
- if (fm.flags != 0) {
- ofp_print_flow_flags(s, fm.flags);
+
+ if (oh->version == OFP10_VERSION || oh->version == OFP11_VERSION) {
+ /* Don't print the reset_counts flag for OF1.0 and OF1.1 because those
+ * versions don't really have such a flag and printing one is likely to
+ * confuse people. */
+ fm.flags &= ~OFPUTIL_FF_RESET_COUNTS;
}
+ ofp_print_flow_flags(s, fm.flags);
+ ds_put_cstr(s, "actions=");
ofpacts_format(fm.ofpacts, fm.ofpacts_len, s);
ofpbuf_uninit(&ofpacts);
}
ds_put_char(string, 's');
}
+/* Returns a string form of 'reason'. The return value is either a statically
+ * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
+ * 'bufsize' should be at least OFP_FLOW_REMOVED_REASON_BUFSIZE. */
+#define OFP_FLOW_REMOVED_REASON_BUFSIZE (INT_STRLEN(int) + 1)
static const char *
-ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason)
+ofp_flow_removed_reason_to_string(enum ofp_flow_removed_reason reason,
+ char *reasonbuf, size_t bufsize)
{
- static char s[32];
-
switch (reason) {
case OFPRR_IDLE_TIMEOUT:
return "idle";
return "group_delete";
case OFPRR_EVICTION:
return "eviction";
+ case OFPRR_METER_DELETE:
+ return "meter_delete";
default:
- sprintf(s, "%d", (int) reason);
- return s;
+ snprintf(reasonbuf, bufsize, "%d", (int) reason);
+ return reasonbuf;
}
}
static void
ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
{
+ char reasonbuf[OFP_FLOW_REMOVED_REASON_BUFSIZE];
struct ofputil_flow_removed fr;
enum ofperr error;
match_format(&fr.match, string, fr.priority);
ds_put_format(string, " reason=%s",
- ofp_flow_removed_reason_to_string(fr.reason));
+ ofp_flow_removed_reason_to_string(fr.reason, reasonbuf,
+ sizeof reasonbuf));
if (fr.table_id != 255) {
ds_put_format(string, " table_id=%"PRIu8, fr.table_id);
}
}
+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_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);
+}
+
static void
ofp_print_error(struct ds *string, enum ofperr error)
{
ds_put_char(string, ' ');
}
+ ds_put_cstr(string, "actions=");
ofpacts_format(fs->ofpacts, fs->ofpacts_len, string);
}
static void
ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh)
{
- uint16_t ofp10_port;
+ ofp_port_t ofp10_port;
enum ofperr error;
error = ofputil_decode_port_stats_request(oh, &ofp10_port);
}
ds_put_cstr(string, " port ");
- if (ps.port_no < 10) {
+ if (ofp_to_u16(ps.port_no) < 10) {
ds_put_char(string, ' ');
}
ofputil_format_port(ps.port_no, string);
print_port_stat(string, "drop=", ps.stats.tx_dropped, 1);
print_port_stat(string, "errs=", ps.stats.tx_errors, 1);
print_port_stat(string, "coll=", ps.stats.collisions, 0);
+
+ if (ps.duration_sec != UINT32_MAX) {
+ ds_put_cstr(string, " duration=");
+ ofp_print_duration(string, ps.duration_sec, ps.duration_nsec);
+ ds_put_char(string, '\n');
+ }
}
}
ofp_print_queue_name(string, qs.queue_id);
ds_put_cstr(string, ": ");
- print_port_stat(string, "bytes=", qs.stats.tx_bytes, 1);
- print_port_stat(string, "pkts=", qs.stats.tx_packets, 1);
- print_port_stat(string, "errors=", qs.stats.tx_errors, 0);
+ print_port_stat(string, "bytes=", qs.tx_bytes, 1);
+ print_port_stat(string, "pkts=", qs.tx_packets, 1);
+ print_port_stat(string, "errors=", qs.tx_errors, 1);
+
+ ds_put_cstr(string, "duration=");
+ if (qs.duration_sec != UINT32_MAX) {
+ ofp_print_duration(string, qs.duration_sec, qs.duration_nsec);
+ } else {
+ ds_put_char(string, '?');
+ }
+ ds_put_char(string, '\n');
}
}
}
}
+/* Returns a string form of 'reason'. The return value is either a statically
+ * allocated constant string or the 'bufsize'-byte buffer 'reasonbuf'.
+ * 'bufsize' should be at least OFP_PORT_REASON_BUFSIZE. */
+#define OFP_PORT_REASON_BUFSIZE (INT_STRLEN(int) + 1)
static const char *
-ofp_port_reason_to_string(enum ofp_port_reason reason)
+ofp_port_reason_to_string(enum ofp_port_reason reason,
+ char *reasonbuf, size_t bufsize)
{
- static char s[32];
-
switch (reason) {
case OFPPR_ADD:
return "add";
return "modify";
default:
- sprintf(s, "%d", (int) reason);
- return s;
+ snprintf(reasonbuf, bufsize, "%d", (int) reason);
+ return reasonbuf;
}
}
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));
+ char reasonbuf[OFPUTIL_PACKET_IN_REASON_BUFSIZE];
+ const char *reason;
+
+ reason = ofputil_packet_in_reason_to_string(j, reasonbuf,
+ sizeof reasonbuf);
+ ds_put_format(string, " %s", reason);
}
}
if (!nac->packet_in_mask[i]) {
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));
+ char reasonbuf[OFP_PORT_REASON_BUFSIZE];
+ const char *reason;
+
+ reason = ofp_port_reason_to_string(j, reasonbuf,
+ sizeof reasonbuf);
+ ds_put_format(string, " %s", reason);
}
}
if (!nac->port_status_mask[i]) {
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));
+ char reasonbuf[OFP_FLOW_REMOVED_REASON_BUFSIZE];
+ const char *reason;
+
+ reason = ofp_flow_removed_reason_to_string(j, reasonbuf,
+ sizeof reasonbuf);
+ ds_put_format(string, " %s", reason);
}
}
if (!nac->flow_removed_mask[i]) {
ofpbuf_use_const(&b, oh, ntohs(oh->length));
ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
for (;;) {
+ char reasonbuf[OFP_FLOW_REMOVED_REASON_BUFSIZE];
struct ofputil_flow_update update;
struct match match;
int retval;
case NXFME_DELETED:
ds_put_format(string, "DELETED reason=%s",
- ofp_flow_removed_reason_to_string(update.reason));
+ ofp_flow_removed_reason_to_string(update.reason,
+ reasonbuf,
+ sizeof reasonbuf));
break;
case NXFME_MODIFIED:
if (string->string[string->length - 1] != ' ') {
ds_put_char(string, ' ');
}
+ ds_put_cstr(string, "actions=");
ofpacts_format(update.ofpacts, update.ofpacts_len, string);
}
}
ds_put_cstr(string, "NOT IMPLEMENTED YET!\n");
}
+static void
+ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type,
+ struct list *p_buckets)
+{
+ static const char *type_str[] = { "all", "select", "indirect",
+ "ff", "unknown" };
+ struct ofputil_bucket *bucket;
+
+ ds_put_format(s, "group_id=%"PRIu32",type=%s",
+ group_id, type_str[type > 4 ? 4 : type]);
+ if (!p_buckets) {
+ return;
+ }
+
+ LIST_FOR_EACH (bucket, list_node, p_buckets) {
+ ds_put_cstr(s, ",bucket=");
+
+ if (bucket->weight != 1) {
+ ds_put_format(s, "weight:%"PRIu16",", bucket->weight);
+ }
+ if (bucket->watch_port != OFPP_NONE) {
+ ds_put_format(s, "watch_port:%"PRIu32",", bucket->watch_port);
+ }
+ if (bucket->watch_group != OFPG11_ANY) {
+ ds_put_format(s, "watch_group:%"PRIu32",", bucket->watch_group);
+ }
+
+ ds_put_cstr(s, "actions=");
+ ofpacts_format(bucket->ofpacts, bucket->ofpacts_len, s);
+ }
+}
+
+static void
+ofp_print_group_desc(struct ds *s, const struct ofp_header *oh)
+{
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ for (;;) {
+ struct ofputil_group_desc gd;
+ int retval;
+
+ retval = ofputil_decode_group_desc_reply(&gd, &b, oh->version);
+ if (retval) {
+ if (retval != EOF) {
+ ds_put_cstr(s, " ***parse error***");
+ }
+ break;
+ }
+
+ ds_put_char(s, '\n');
+ ds_put_char(s, ' ');
+ ofp_print_group(s, gd.group_id, gd.type, &gd.buckets);
+ }
+}
+
+static void
+ofp_print_ofpst_group_request(struct ds *string, const struct ofp_header *oh)
+{
+ enum ofperr error;
+ uint32_t group_id;
+
+ error = ofputil_decode_group_stats_request(oh, &group_id);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ ds_put_cstr(string, " group_id=");
+ ofputil_format_group(group_id, string);
+}
+
+static void
+ofp_print_group_stats(struct ds *s, const struct ofp_header *oh)
+{
+ struct ofpbuf b;
+ uint32_t bucket_i;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+
+ for (;;) {
+ struct ofputil_group_stats gs;
+ int retval;
+
+ retval = ofputil_decode_group_stats_reply(&b, &gs);
+ if (retval) {
+ if (retval != EOF) {
+ ds_put_cstr(s, " ***parse error***");
+ }
+ break;
+ }
+
+ ds_put_char(s, '\n');
+
+ ds_put_char(s, ' ');
+ ds_put_format(s, "group_id=%"PRIu32",", gs.group_id);
+
+ if (gs.duration_sec != UINT32_MAX) {
+ ds_put_cstr(s, "duration=");
+ ofp_print_duration(s, gs.duration_sec, gs.duration_nsec);
+ ds_put_char(s, ',');
+ }
+ ds_put_format(s, "ref_count=%"PRIu32",", gs.ref_count);
+ ds_put_format(s, "packet_count=%"PRIu64",", gs.packet_count);
+ ds_put_format(s, "byte_count=%"PRIu64"", gs.byte_count);
+
+ for (bucket_i = 0; bucket_i < gs.n_buckets; bucket_i++) {
+ if (gs.bucket_stats[bucket_i].packet_count != UINT64_MAX) {
+ ds_put_format(s, ",bucket%"PRIu32":", bucket_i);
+ ds_put_format(s, "packet_count=%"PRIu64",", gs.bucket_stats[bucket_i].packet_count);
+ ds_put_format(s, "byte_count=%"PRIu64"", gs.bucket_stats[bucket_i].byte_count);
+ }
+ }
+
+ free(gs.bucket_stats);
+ }
+}
+
+static void
+ofp_print_group_features(struct ds *string, const struct ofp_header *oh)
+{
+ struct ofputil_group_features features;
+
+ ofputil_decode_group_features_reply(oh, &features);
+
+ ds_put_format(string, "\n Group table:\n");
+ ds_put_format(string, " Types: 0x%"PRIx32"\n", features.types);
+ ds_put_format(string, " Capabilities: 0x%"PRIx32"\n",
+ features.capabilities);
+
+ if (features.types & (1u << OFPGT11_ALL)) {
+ ds_put_format(string, " All group :\n");
+ ds_put_format(string,
+ " max_groups = %#"PRIx32" actions=0x%08"PRIx32"\n",
+ features.max_groups[0], features.actions[0]);
+ }
+
+ if (features.types & (1u << OFPGT11_SELECT)) {
+ ds_put_format(string, " Select group :\n");
+ ds_put_format(string, " max_groups = %#"PRIx32" "
+ "actions=0x%08"PRIx32"\n",
+ features.max_groups[1], features.actions[1]);
+ }
+
+ if (features.types & (1u << OFPGT11_INDIRECT)) {
+ ds_put_format(string, " Indirect group :\n");
+ ds_put_format(string, " max_groups = %#"PRIx32" "
+ "actions=0x%08"PRIx32"\n",
+ features.max_groups[2], features.actions[2]);
+ }
+
+ if (features.types & (1u << OFPGT11_FF)) {
+ ds_put_format(string, " Fast Failover group :\n");
+ ds_put_format(string, " max_groups = %#"PRIx32" "
+ "actions=0x%08"PRIx32"\n",
+ features.max_groups[3], features.actions[3]);
+ }
+}
+
+static void
+ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
+{
+ struct ofputil_group_mod gm;
+ int error;
+
+ error = ofputil_decode_group_mod(oh, &gm);
+ if (error) {
+ ofp_print_error(s, error);
+ return;
+ }
+
+ ds_put_char(s, '\n');
+
+ ds_put_char(s, ' ');
+ switch (gm.command) {
+ case OFPGC11_ADD:
+ ds_put_cstr(s, "ADD");
+ break;
+
+ case OFPGC11_MODIFY:
+ ds_put_cstr(s, "MOD");
+ break;
+
+ case OFPGC11_DELETE:
+ ds_put_cstr(s, "DEL");
+ break;
+
+ default:
+ ds_put_format(s, "cmd:%"PRIu16"", gm.command);
+ }
+ ds_put_char(s, ' ');
+
+ ofp_print_group(s, gm.group_id, gm.type, &gm.buckets);
+}
+
static void
ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
struct ds *string, int verbosity)
ofp_header_to_string__(oh, raw, string);
switch (ofptype_from_ofpraw(raw)) {
- /* FIXME: Change the following once they are implemented: */
+ case OFPTYPE_GROUP_STATS_REQUEST:
+ ofp_print_stats_request(string, oh);
+ ofp_print_ofpst_group_request(string, oh);
+ break;
+
+ case OFPTYPE_GROUP_STATS_REPLY:
+ ofp_print_group_stats(string, oh);
+ break;
+
+ case OFPTYPE_GROUP_DESC_STATS_REQUEST:
+ ofp_print_stats_request(string, oh);
+ break;
+
+ case OFPTYPE_GROUP_DESC_STATS_REPLY:
+ ofp_print_group_desc(string, oh);
+ break;
+
+ case OFPTYPE_GROUP_FEATURES_STATS_REQUEST:
+ ofp_print_stats_request(string, oh);
+ break;
+
+ case OFPTYPE_GROUP_FEATURES_STATS_REPLY:
+ ofp_print_group_features(string, oh);
+ break;
+
+ case OFPTYPE_GROUP_MOD:
+ ofp_print_group_mod(string, oh);
+ break;
+
case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
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:
+ case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
+ case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
ofp_print_not_implemented(string);
break;
ofp_print_port_mod(string, oh);
break;
+ case OFPTYPE_TABLE_MOD:
+ ofp_print_table_mod(string, oh);
+ break;
+
+ case OFPTYPE_METER_MOD:
+ ofp_print_meter_mod(string, oh);
+ break;
+
case OFPTYPE_BARRIER_REQUEST:
case OFPTYPE_BARRIER_REPLY:
break;
ofp_print_role_message(string, oh);
break;
+ case OFPTYPE_METER_STATS_REQUEST:
+ case OFPTYPE_METER_CONFIG_STATS_REQUEST:
+ ofp_print_stats_request(string, oh);
+ ofp_print_meter_stats_request(string, oh);
+ break;
+
+ case OFPTYPE_METER_STATS_REPLY:
+ ofp_print_stats_reply(string, oh);
+ ofp_print_meter_stats_reply(string, oh);
+ break;
+
+ case OFPTYPE_METER_CONFIG_STATS_REPLY:
+ ofp_print_stats_reply(string, oh);
+ ofp_print_meter_config_reply(string, oh);
+ break;
+
+ case OFPTYPE_METER_FEATURES_STATS_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_STATS_REQUEST:
ofp_print_stats_request(string, oh);
break;
ofp_print_nxt_set_controller_id(string, ofpmsg_body(oh));
break;
+ case OFPTYPE_GET_ASYNC_REPLY:
case OFPTYPE_SET_ASYNC_CONFIG:
ofp_print_nxt_set_async_config(string, ofpmsg_body(oh));
break;
-
+ case OFPTYPE_GET_ASYNC_REQUEST:
+ break;
case OFPTYPE_FLOW_MONITOR_CANCEL:
ofp_print_nxt_flow_monitor_cancel(string, msg);
break;