static void
ofp_print_bit_names(struct ds *string, uint32_t bits,
- const char *(*bit_to_name)(uint32_t bit))
+ const char *(*bit_to_name)(uint32_t bit),
+ char separator)
{
int n = 0;
int i;
const char *name = bit_to_name(bit);
if (name) {
if (n++) {
- ds_put_char(string, ' ');
+ ds_put_char(string, separator);
}
ds_put_cstr(string, name);
bits &= ~bit;
if (bits) {
if (n) {
- ds_put_char(string, ' ');
+ ds_put_char(string, separator);
}
ds_put_format(string, "0x%"PRIx32, bits);
}
static void
ofp_print_port_features(struct ds *string, enum netdev_features features)
{
- ofp_print_bit_names(string, features, netdev_feature_to_name);
+ ofp_print_bit_names(string, features, netdev_feature_to_name, ' ');
ds_put_char(string, '\n');
}
static void
ofp_print_port_config(struct ds *string, enum ofputil_port_config config)
{
- ofp_print_bit_names(string, config, ofputil_port_config_to_name);
+ ofp_print_bit_names(string, config, ofputil_port_config_to_name, ' ');
ds_put_char(string, '\n');
}
: "STP_BLOCK"));
state &= ~OFPUTIL_PS_STP_MASK;
if (state) {
- ofp_print_bit_names(string, state, ofputil_port_state_to_name);
+ ofp_print_bit_names(string, state, ofputil_port_state_to_name,
+ ' ');
}
} else {
- ofp_print_bit_names(string, state, ofputil_port_state_to_name);
+ ofp_print_bit_names(string, state, ofputil_port_state_to_name, ' ');
}
ds_put_char(string, '\n');
}
ds_put_cstr(string, "capabilities: ");
ofp_print_bit_names(string, features.capabilities,
- ofputil_capabilities_to_name);
+ ofputil_capabilities_to_name, ' ');
ds_put_char(string, '\n');
ds_put_cstr(string, "actions: ");
ofp_print_bit_names(string, features.actions,
- ofputil_action_bitmap_to_name);
+ ofputil_action_bitmap_to_name, ' ');
ds_put_char(string, '\n');
ofp_print_phy_ports(string, osf->header.version, &b);
if (fm.buffer_id != UINT32_MAX) {
ds_put_format(s, "buf:0x%"PRIx32" ", fm.buffer_id);
}
+ if (fm.out_port != OFPP_NONE) {
+ ds_put_format(s, "out_port:");
+ ofputil_format_port(fm.out_port, s);
+ ds_put_char(s, ' ');
+ }
if (fm.flags != 0) {
uint16_t flags = fm.flags;
return "delete";
case OFPRR_GROUP_DELETE:
return "group_delete";
+ case OFPRR_EVICTION:
+ return "eviction";
default:
sprintf(s, "%d", (int) reason);
return s;
cls_rule_format(&fsr.match, string);
}
+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->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);
+ }
+
+ cls_rule_format(&fs->rule, string);
+ if (string->string[string->length - 1] != ' ') {
+ ds_put_char(string, ' ');
+ }
+
+ ofpacts_format(fs->ofpacts, fs->ofpacts_len, string);
+}
+
static void
ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
{
}
break;
}
-
ds_put_char(string, '\n');
-
- 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.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);
- }
-
- cls_rule_format(&fs.rule, string);
- if (string->string[string->length - 1] != ' ') {
- ds_put_char(string, ' ');
- }
- ofpacts_format(fs.ofpacts, fs.ofpacts_len, string);
- }
- ofpbuf_uninit(&ofpacts);
+ ofp_print_flow_stats(string, &fs);
+ }
}
static void
}
static void
-ofp_to_string__(const struct ofp_header *oh,
- const struct ofputil_msg_type *type, struct ds *string,
- int verbosity)
+ofp_print_nxt_flow_monitor_cancel(struct ds *string,
+ const struct ofp_header *oh)
{
- enum ofputil_msg_code code;
- const void *msg = oh;
+ ds_put_format(string, " id=%"PRIu32,
+ ofputil_decode_flow_monitor_cancel(oh));
+}
- ds_put_cstr(string, ofputil_msg_type_name(type));
+static const char *
+nx_flow_monitor_flags_to_name(uint32_t bit)
+{
+ enum nx_flow_monitor_flags fmf = bit;
+
+ switch (fmf) {
+ case NXFMF_INITIAL: return "initial";
+ case NXFMF_ADD: return "add";
+ case NXFMF_DELETE: return "delete";
+ case NXFMF_MODIFY: return "modify";
+ case NXFMF_ACTIONS: return "actions";
+ case NXFMF_OWN: return "own";
+ }
+
+ return NULL;
+}
+
+static void
+ofp_print_nxst_flow_monitor_request(struct ds *string,
+ const struct ofp_header *oh)
+{
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ for (;;) {
+ struct ofputil_flow_monitor_request request;
+ int retval;
+
+ retval = ofputil_decode_flow_monitor_request(&request, &b);
+ if (retval) {
+ if (retval != EOF) {
+ ofp_print_error(string, retval);
+ }
+ return;
+ }
+
+ ds_put_format(string, "\n id=%"PRIu32" flags=", request.id);
+ ofp_print_bit_names(string, request.flags,
+ nx_flow_monitor_flags_to_name, ',');
+
+ if (request.out_port != OFPP_NONE) {
+ ds_put_cstr(string, " out_port=");
+ ofputil_format_port(request.out_port, string);
+ }
+
+ if (request.table_id != 0xff) {
+ ds_put_format(string, " table=%"PRIu8, request.table_id);
+ }
+
+ ds_put_char(string, ' ');
+ cls_rule_format(&request.match, string);
+ ds_chomp(string, ' ');
+ }
+}
+
+static void
+ofp_print_nxst_flow_monitor_reply(struct ds *string,
+ const struct ofp_header *oh)
+{
+ uint64_t ofpacts_stub[1024 / 8];
+ struct ofpbuf ofpacts;
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ ofpbuf_use_stub(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
+ for (;;) {
+ struct ofputil_flow_update update;
+ struct cls_rule match;
+ int retval;
+
+ update.match = &match;
+ retval = ofputil_decode_flow_update(&update, &b, &ofpacts);
+ if (retval) {
+ if (retval != EOF) {
+ ofp_print_error(string, retval);
+ }
+ ofpbuf_uninit(&ofpacts);
+ return;
+ }
+
+ ds_put_cstr(string, "\n event=");
+ switch (update.event) {
+ case NXFME_ADDED:
+ ds_put_cstr(string, "ADDED");
+ break;
+
+ case NXFME_DELETED:
+ ds_put_format(string, "DELETED reason=%s",
+ ofp_flow_removed_reason_to_string(update.reason));
+ break;
+
+ case NXFME_MODIFIED:
+ ds_put_cstr(string, "MODIFIED");
+ break;
+
+ case NXFME_ABBREV:
+ ds_put_format(string, "ABBREV xid=0x%"PRIx32, ntohl(update.xid));
+ continue;
+ }
+
+ ds_put_format(string, " table=%"PRIu8, update.table_id);
+ if (update.idle_timeout != OFP_FLOW_PERMANENT) {
+ ds_put_format(string, " idle_timeout=%"PRIu16,
+ update.idle_timeout);
+ }
+ if (update.hard_timeout != OFP_FLOW_PERMANENT) {
+ ds_put_format(string, " hard_timeout=%"PRIu16,
+ update.hard_timeout);
+ }
+ ds_put_format(string, " cookie=%#"PRIx64, ntohll(update.cookie));
+
+ ds_put_char(string, ' ');
+ cls_rule_format(update.match, string);
+
+ if (update.ofpacts_len) {
+ if (string->string[string->length - 1] != ' ') {
+ ds_put_char(string, ' ');
+ }
+ ofpacts_format(update.ofpacts, update.ofpacts_len, string);
+ }
+ }
+}
+
+void
+ofp_print_version(const struct ofp_header *oh,
+ struct ds *string)
+{
switch (oh->version) {
case OFP10_VERSION:
break;
break;
}
ds_put_format(string, " (xid=0x%"PRIx32"):", ntohl(oh->xid));
+}
+
+static void
+ofp_header_to_string__(const struct ofp_header *oh,
+ const struct ofputil_msg_type *type, struct ds *string)
+{
+ ds_put_cstr(string, ofputil_msg_type_name(type));
+ ofp_print_version(oh, string);
+}
+static void
+ofp_to_string__(const struct ofp_header *oh,
+ const struct ofputil_msg_type *type, struct ds *string,
+ int verbosity)
+{
+ enum ofputil_msg_code code;
+ const void *msg = oh;
+
+ ofp_header_to_string__(oh, type, string);
code = ofputil_msg_type_code(type);
switch (code) {
case OFPUTIL_MSG_INVALID:
ofp_print_stats_reply(string, oh);
ofp_print_nxst_aggregate_reply(string, msg);
break;
+
+ case OFPUTIL_NXT_FLOW_MONITOR_CANCEL:
+ ofp_print_nxt_flow_monitor_cancel(string, msg);
+ break;
+
+ case OFPUTIL_NXT_FLOW_MONITOR_PAUSED:
+ case OFPUTIL_NXT_FLOW_MONITOR_RESUMED:
+ break;
+
+ case OFPUTIL_NXST_FLOW_MONITOR_REQUEST:
+ ofp_print_nxst_flow_monitor_request(string, msg);
+ break;
+
+ case OFPUTIL_NXST_FLOW_MONITOR_REPLY:
+ ofp_print_nxst_flow_monitor_reply(string, msg);
+ break;
}
}
ds_put_format(&string, "OpenFlow packet too short (only %zu bytes):\n",
len);
} else if (ntohs(oh->length) > len) {
+ const struct ofputil_msg_type *type;
+ enum ofperr error;
+
+ error = ofputil_decode_msg_type_partial(oh, len, &type);
+ if (!error) {
+ ofp_header_to_string__(oh, type, &string);
+ ds_put_char(&string, '\n');
+ }
+
ds_put_format(&string,
"(***truncated to %zu bytes from %"PRIu16"***)\n",
len, ntohs(oh->length));