#include "compiler.h"
#include "dynamic-string.h"
#include "flow.h"
+#include "multipath.h"
#include "nx-match.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "openflow/nicira-ext.h"
#include "packets.h"
#include "pcap.h"
+#include "type-props.h"
#include "util.h"
static void ofp_print_port_name(struct ds *string, uint16_t port);
ds_put_cstr(string, name);
}
+
static void
print_note(struct ds *string, const struct nx_action_note *nan)
{
}
}
+static int
+nx_action_len(enum nx_action_subtype subtype)
+{
+ switch (subtype) {
+ case NXAST_SNAT__OBSOLETE: return -1;
+ case NXAST_RESUBMIT: return sizeof(struct nx_action_resubmit);
+ case NXAST_SET_TUNNEL: return sizeof(struct nx_action_set_tunnel);
+ case NXAST_DROP_SPOOFED_ARP:
+ return sizeof(struct nx_action_drop_spoofed_arp);
+ case NXAST_SET_QUEUE: return sizeof(struct nx_action_set_queue);
+ case NXAST_POP_QUEUE: return sizeof(struct nx_action_pop_queue);
+ case NXAST_REG_MOVE: return sizeof(struct nx_action_reg_move);
+ case NXAST_REG_LOAD: return sizeof(struct nx_action_reg_load);
+ case NXAST_NOTE: return -1;
+ case NXAST_SET_TUNNEL64: return sizeof(struct nx_action_set_tunnel64);
+ case NXAST_MULTIPATH: return sizeof(struct nx_action_multipath);
+ default: return -1;
+ }
+}
+
static void
ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
{
- switch (ntohs(nah->subtype)) {
- case NXAST_RESUBMIT: {
- const struct nx_action_resubmit *nar = (struct nx_action_resubmit *)nah;
- ds_put_format(string, "resubmit:");
- ofp_print_port_name(string, ntohs(nar->in_port));
- break;
- }
+ uint16_t subtype = ntohs(nah->subtype);
+ int required_len = nx_action_len(subtype);
+ int len = ntohs(nah->len);
- case NXAST_SET_TUNNEL: {
- const struct nx_action_set_tunnel *nast =
- (struct nx_action_set_tunnel *)nah;
- ds_put_format(string, "set_tunnel:%#"PRIx32, ntohl(nast->tun_id));
- break;
+ if (required_len != -1 && required_len != len) {
+ ds_put_format(string, "***Nicira action %"PRIu16" wrong length: %d***",
+ subtype, len);
+ return;
}
- case NXAST_DROP_SPOOFED_ARP:
- ds_put_cstr(string, "drop_spoofed_arp");
- break;
+ if (subtype <= TYPE_MAXIMUM(enum nx_action_subtype)) {
+ const struct nx_action_set_tunnel64 *nast64;
+ const struct nx_action_set_tunnel *nast;
+ const struct nx_action_set_queue *nasq;
+ const struct nx_action_resubmit *nar;
+ const struct nx_action_reg_move *move;
+ const struct nx_action_reg_load *load;
+ const struct nx_action_multipath *nam;
+
+ switch ((enum nx_action_subtype) subtype) {
+ case NXAST_RESUBMIT:
+ nar = (struct nx_action_resubmit *)nah;
+ ds_put_format(string, "resubmit:");
+ ofp_print_port_name(string, ntohs(nar->in_port));
+ return;
- case NXAST_SET_QUEUE: {
- const struct nx_action_set_queue *nasq =
- (struct nx_action_set_queue *)nah;
- ds_put_format(string, "set_queue:%u", ntohl(nasq->queue_id));
- break;
- }
+ case NXAST_SET_TUNNEL:
+ nast = (struct nx_action_set_tunnel *)nah;
+ ds_put_format(string, "set_tunnel:%#"PRIx32, ntohl(nast->tun_id));
+ return;
- case NXAST_POP_QUEUE:
- ds_put_cstr(string, "pop_queue");
- break;
+ case NXAST_DROP_SPOOFED_ARP:
+ ds_put_cstr(string, "drop_spoofed_arp");
+ return;
- case NXAST_NOTE:
- print_note(string, (const struct nx_action_note *) nah);
- break;
+ case NXAST_SET_QUEUE:
+ nasq = (struct nx_action_set_queue *)nah;
+ ds_put_format(string, "set_queue:%u", ntohl(nasq->queue_id));
+ return;
- default:
- ds_put_format(string, "***unknown Nicira action:%d***",
- ntohs(nah->subtype));
+ case NXAST_POP_QUEUE:
+ ds_put_cstr(string, "pop_queue");
+ return;
+
+ case NXAST_NOTE:
+ print_note(string, (const struct nx_action_note *) nah);
+ return;
+
+ case NXAST_REG_MOVE:
+ move = (const struct nx_action_reg_move *) nah;
+ nxm_format_reg_move(move, string);
+ return;
+
+ case NXAST_REG_LOAD:
+ load = (const struct nx_action_reg_load *) nah;
+ nxm_format_reg_load(load, string);
+ return;
+
+ case NXAST_SET_TUNNEL64:
+ nast64 = (const struct nx_action_set_tunnel64 *) nah;
+ ds_put_format(string, "set_tunnel64:%#"PRIx64,
+ ntohll(nast64->tun_id));
+ return;
+
+ case NXAST_MULTIPATH:
+ nam = (const struct nx_action_multipath *) nah;
+ multipath_format(nam, string);
+ return;
+
+ case NXAST_SNAT__OBSOLETE:
+ default:
+ break;
+ }
+ }
+
+ ds_put_format(string, "***unknown Nicira action:%"PRIu16"***", subtype);
+}
+
+static int
+ofp_action_len(enum ofp_action_type type)
+{
+ switch (type) {
+ case OFPAT_OUTPUT: return sizeof(struct ofp_action_output);
+ case OFPAT_SET_VLAN_VID: return sizeof(struct ofp_action_vlan_vid);
+ case OFPAT_SET_VLAN_PCP: return sizeof(struct ofp_action_vlan_pcp);
+ case OFPAT_STRIP_VLAN: return sizeof(struct ofp_action_header);
+ case OFPAT_SET_DL_SRC: return sizeof(struct ofp_action_dl_addr);
+ case OFPAT_SET_DL_DST: return sizeof(struct ofp_action_dl_addr);
+ case OFPAT_SET_NW_SRC: return sizeof(struct ofp_action_nw_addr);
+ case OFPAT_SET_NW_DST: return sizeof(struct ofp_action_nw_addr);
+ case OFPAT_SET_NW_TOS: return sizeof(struct ofp_action_nw_tos);
+ case OFPAT_SET_TP_SRC: return sizeof(struct ofp_action_tp_port);
+ case OFPAT_SET_TP_DST: return sizeof(struct ofp_action_tp_port);
+ case OFPAT_ENQUEUE: return sizeof(struct ofp_action_enqueue);
+ case OFPAT_VENDOR: return -1;
+ default: return -1;
}
}
ofp_print_action(struct ds *string, const struct ofp_action_header *ah,
size_t actions_len)
{
- uint16_t type;
+ enum ofp_action_type type;
+ int required_len;
size_t len;
- struct openflow_action {
- size_t min_size;
- size_t max_size;
- };
-
- const struct openflow_action of_actions[] = {
- [OFPAT_OUTPUT] = {
- sizeof(struct ofp_action_output),
- sizeof(struct ofp_action_output),
- },
- [OFPAT_SET_VLAN_VID] = {
- sizeof(struct ofp_action_vlan_vid),
- sizeof(struct ofp_action_vlan_vid),
- },
- [OFPAT_SET_VLAN_PCP] = {
- sizeof(struct ofp_action_vlan_pcp),
- sizeof(struct ofp_action_vlan_pcp),
- },
- [OFPAT_STRIP_VLAN] = {
- sizeof(struct ofp_action_header),
- sizeof(struct ofp_action_header),
- },
- [OFPAT_SET_DL_SRC] = {
- sizeof(struct ofp_action_dl_addr),
- sizeof(struct ofp_action_dl_addr),
- },
- [OFPAT_SET_DL_DST] = {
- sizeof(struct ofp_action_dl_addr),
- sizeof(struct ofp_action_dl_addr),
- },
- [OFPAT_SET_NW_SRC] = {
- sizeof(struct ofp_action_nw_addr),
- sizeof(struct ofp_action_nw_addr),
- },
- [OFPAT_SET_NW_DST] = {
- sizeof(struct ofp_action_nw_addr),
- sizeof(struct ofp_action_nw_addr),
- },
- [OFPAT_SET_NW_TOS] = {
- sizeof(struct ofp_action_nw_tos),
- sizeof(struct ofp_action_nw_tos),
- },
- [OFPAT_SET_TP_SRC] = {
- sizeof(struct ofp_action_tp_port),
- sizeof(struct ofp_action_tp_port),
- },
- [OFPAT_SET_TP_DST] = {
- sizeof(struct ofp_action_tp_port),
- sizeof(struct ofp_action_tp_port),
- }
- /* OFPAT_VENDOR is not here, since it would blow up the array size. */
- };
-
if (actions_len < sizeof *ah) {
ds_put_format(string, "***action array too short for next action***\n");
return -1;
type = ntohs(ah->type);
len = ntohs(ah->len);
if (actions_len < len) {
- ds_put_format(string, "***truncated action %"PRIu16"***\n", type);
+ ds_put_format(string, "***truncated action %d***\n", (int) type);
return -1;
}
if ((len % OFP_ACTION_ALIGN) != 0) {
ds_put_format(string,
- "***action %"PRIu16" length not a multiple of %d***\n",
- type, OFP_ACTION_ALIGN);
+ "***action %d length not a multiple of %d***\n",
+ (int) type, OFP_ACTION_ALIGN);
return -1;
}
- if (type < ARRAY_SIZE(of_actions)) {
- const struct openflow_action *act = &of_actions[type];
- if ((len < act->min_size) || (len > act->max_size)) {
- ds_put_format(string,
- "***action %"PRIu16" wrong length: %zu***\n", type, len);
- return -1;
- }
+ required_len = ofp_action_len(type);
+ if (required_len >= 0 && len != required_len) {
+ ds_put_format(string,
+ "***action %d wrong length: %zu***\n", (int) type, len);
+ return -1;
}
switch (type) {
}
default:
- ds_put_format(string, "(decoder %"PRIu16" not implemented)", type);
+ ds_put_format(string, "(decoder %d not implemented)", (int) type);
break;
}
enum ofputil_msg_code code, int verbosity)
{
struct flow_mod fm;
+ bool need_priority;
int error;
error = ofputil_decode_flow_mod(&fm, oh, NXFF_OPENFLOW10);
ds_put_char(s, ' ');
if (verbosity >= 3 && code == OFPUTIL_OFPT_FLOW_MOD) {
const struct ofp_flow_mod *ofm = (const struct ofp_flow_mod *) oh;
-
ofp_print_match(s, &ofm->match, verbosity);
+
+ /* ofp_print_match() doesn't print priority. */
+ need_priority = true;
} else if (verbosity >= 3 && code == OFPUTIL_NXT_FLOW_MOD) {
const struct nx_flow_mod *nfm = (const struct nx_flow_mod *) oh;
const void *nxm = nfm + 1;
- char *nxm_s = nx_match_to_string(nxm, ntohs(nfm->match_len));
+ char *nxm_s;
+
+ nxm_s = nx_match_to_string(nxm, ntohs(nfm->match_len));
ds_put_cstr(s, nxm_s);
free(nxm_s);
+
+ /* nx_match_to_string() doesn't print priority. */
+ need_priority = true;
} else {
cls_rule_format(&fm.cr, s);
+
+ /* cls_rule_format() does print priority. */
+ need_priority = false;
}
if (ds_last(s) != ' ') {
if (fm.hard_timeout != OFP_FLOW_PERMANENT) {
ds_put_format(s, "hard:%"PRIu16" ", fm.hard_timeout);
}
- if (fm.cr.priority != OFP_DEFAULT_PRIORITY && verbosity >= 3) {
+ if (fm.cr.priority != OFP_DEFAULT_PRIORITY && need_priority) {
ds_put_format(s, "pri:%"PRIu16" ", fm.cr.priority);
}
if (fm.buffer_id != UINT32_MAX) {
}
static void
-ofp_print_flow_removed(struct ds *string, const struct ofp_flow_removed *ofr,
- int verbosity)
+ofp_print_duration(struct ds *string, unsigned int sec, unsigned int nsec)
+{
+ ds_put_format(string, "%u", sec);
+ if (nsec > 0) {
+ ds_put_format(string, ".%09u", nsec);
+ while (string->string[string->length - 1] == '0') {
+ string->length--;
+ }
+ }
+ ds_put_char(string, 's');
+}
+
+static void
+ofp_print_flow_removed(struct ds *string, const struct ofp_header *oh)
{
- ofp_print_match(string, &ofr->match, verbosity);
+ struct ofputil_flow_removed fr;
+ int error;
+
+ error = ofputil_decode_flow_removed(&fr, oh, NXFF_OPENFLOW10);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ cls_rule_format(&fr.rule, string);
+
ds_put_cstr(string, " reason=");
- switch (ofr->reason) {
+ switch (fr.reason) {
case OFPRR_IDLE_TIMEOUT:
ds_put_cstr(string, "idle");
break;
ds_put_cstr(string, "delete");
break;
default:
- ds_put_format(string, "**%"PRIu8"**", ofr->reason);
+ ds_put_format(string, "**%"PRIu8"**", fr.reason);
break;
}
- if (ofr->cookie != htonll(0)) {
- ds_put_format(string, " cookie:0x%"PRIx64, ntohll(ofr->cookie));
- }
- if (ofr->priority != htons(32768)) {
- ds_put_format(string, " pri:%"PRIu16, ntohs(ofr->priority));
+ if (fr.cookie != htonll(0)) {
+ ds_put_format(string, " cookie:0x%"PRIx64, ntohll(fr.cookie));
}
- ds_put_format(string, " secs%"PRIu32" nsecs%"PRIu32
- " idle%"PRIu16" pkts%"PRIu64" bytes%"PRIu64"\n",
- ntohl(ofr->duration_sec), ntohl(ofr->duration_nsec),
- ntohs(ofr->idle_timeout), ntohll(ofr->packet_count),
- ntohll(ofr->byte_count));
+ ds_put_cstr(string, " duration");
+ ofp_print_duration(string, fr.duration_sec, fr.duration_nsec);
+ ds_put_format(string, " idle%"PRIu16" pkts%"PRIu64" bytes%"PRIu64"\n",
+ fr.idle_timeout, fr.packet_count, fr.byte_count);
}
static void
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BUFFER_EMPTY),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BUFFER_UNKNOWN),
+ /* Nicira error extensions. */
+ ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_INVALID),
+ ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_TYPE),
+ ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_VALUE),
+ ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_MASK),
+ ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_BAD_PREREQ),
+ ERROR_CODE(OFPET_BAD_REQUEST, NXBRC_NXM_DUP_TYPE),
ERROR_TYPE(OFPET_BAD_ACTION),
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE),
ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_EPERM),
ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_EMERG_TIMEOUT),
ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_BAD_COMMAND),
+ /* Nicira error extenstions. */
+ ERROR_CODE(OFPET_FLOW_MOD_FAILED, NXFMFC_HARDWARE),
+ ERROR_CODE(OFPET_FLOW_MOD_FAILED, NXFMFC_BAD_TABLE_ID),
ERROR_TYPE(OFPET_PORT_MOD_FAILED),
ERROR_CODE(OFPET_PORT_MOD_FAILED, OFPPMFC_BAD_PORT),
if (string->length) {
ds_put_char(string, ' ');
}
- ds_put_format(string, " ***decode error type:%d(%s) code:%d(%s)***",
+ ds_put_format(string, " ***decode error type:%d(%s) code:%d(%s)***\n",
type, lookup_error_type(type),
code, lookup_error_code(type, code));
}
+static void
+ofp_print_nx_error_msg(struct ds *string, const struct ofp_error_msg *oem)
+{
+ size_t len = ntohs(oem->header.length);
+ const struct nx_vendor_error *nve = (struct nx_vendor_error *)oem->data;
+ int vendor = ntohl(nve->vendor);
+ int type = ntohs(nve->type);
+ int code = ntohs(nve->code);
+
+ ds_put_format(string, " vendor:%x type:%d(%s) code:%d(%s) payload:\n",
+ vendor,
+ type, lookup_error_type(type),
+ code, lookup_error_code(type, code));
+
+ ds_put_hex_dump(string, nve + 1, len - sizeof *oem - sizeof *nve,
+ 0, true);
+}
+
static void
ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
{
int code = ntohs(oem->code);
char *s;
+
+ if (type == NXET_VENDOR && code == NXVC_VENDOR_ERROR) {
+ if (len < sizeof *oem + sizeof(struct nx_vendor_error)) {
+ ds_put_format(string,
+ "(***truncated extended error message is %zu bytes "
+ "when it should be at least %zu***)\n",
+ len, sizeof(struct nx_vendor_error));
+ return;
+ }
+
+ return ofp_print_nx_error_msg(string, oem);
+ }
+
ds_put_format(string, " type:%d(%s) code:%d(%s) payload:\n",
type, lookup_error_type(type),
code, lookup_error_code(type, code));
}
static void
-ofp_print_ofpst_flow_request(struct ds *string, const struct ofp_header *oh,
- int verbosity)
+ofp_print_flow_stats_request(struct ds *string, const struct ofp_header *oh)
{
- const struct ofp_flow_stats_request *fsr = ofputil_stats_body(oh);
+ struct flow_stats_request fsr;
+ int error;
- if (fsr->table_id == 0xff) {
- ds_put_format(string, " table_id=any, ");
- } else {
- ds_put_format(string, " table_id=%"PRIu8", ", fsr->table_id);
+ error = ofputil_decode_flow_stats_request(&fsr, oh, NXFF_OPENFLOW10);
+ if (error) {
+ ofp_print_error(string, error);
+ return;
+ }
+
+ if (fsr.table_id != 0xff) {
+ ds_put_format(string, " table_id=%"PRIu8, fsr.table_id);
}
- ofp_print_match(string, &fsr->match, verbosity);
+ if (fsr.out_port != OFPP_NONE) {
+ ds_put_cstr(string, " out_port=");
+ ofp_print_port_name(string, fsr.out_port);
+ }
+
+ ds_put_char(string, ' ');
+ cls_rule_format(&fsr.match, string);
}
static void
break;
}
- ds_put_format(string, " cookie=0x%"PRIx64", ", ntohll(fs->cookie));
- ds_put_format(string, "duration_sec=%"PRIu32"s, ",
- ntohl(fs->duration_sec));
- ds_put_format(string, "duration_nsec=%"PRIu32"ns, ",
- ntohl(fs->duration_nsec));
- ds_put_format(string, "table_id=%"PRIu8", ", fs->table_id);
- ds_put_format(string, "priority=%"PRIu16", ",
- fs->match.wildcards ? ntohs(fs->priority) : (uint16_t)-1);
+ ds_put_format(string, " cookie=0x%"PRIx64", duration=",
+ ntohll(fs->cookie));
+ ofp_print_duration(string, ntohl(fs->duration_sec),
+ ntohl(fs->duration_nsec));
+ ds_put_format(string, ", table_id=%"PRIu8", ", fs->table_id);
+ ds_put_format(string, "priority=%"PRIu16", ", ntohs(fs->priority));
ds_put_format(string, "n_packets=%"PRIu64", ",
ntohll(fs->packet_count));
ds_put_format(string, "n_bytes=%"PRIu64", ", ntohll(fs->byte_count));
ntohs(fs->hard_timeout));
}
ofp_print_match(string, &fs->match, verbosity);
+ ds_put_char(string, ' ');
ofp_print_actions(string, fs->actions, length - sizeof *fs);
pos += length;
}
static void
-ofp_print_ofpst_aggregate_request(struct ds *string,
- const struct ofp_header *oh, int verbosity)
+ofp_print_nxst_flow_reply(struct ds *string, const struct ofp_header *oh)
{
- const struct ofp_aggregate_stats_request *asr = ofputil_stats_body(oh);
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, ofputil_nxstats_body(oh),
+ ofputil_nxstats_body_len(oh));
+ while (b.size > 0) {
+ const struct nx_flow_stats *fs;
+ union ofp_action *actions;
+ struct cls_rule rule;
+ size_t actions_len, n_actions;
+ size_t length;
+ int match_len;
+ int error;
- if (asr->table_id == 0xff) {
- ds_put_format(string, " table_id=any, ");
- } else {
- ds_put_format(string, " table_id=%"PRIu8", ", asr->table_id);
- }
+ ds_put_char(string, '\n');
+
+ fs = ofpbuf_try_pull(&b, sizeof *fs);
+ if (!fs) {
+ ds_put_format(string, " ***%td leftover bytes at end***", b.size);
+ break;
+ }
+
+ length = ntohs(fs->length);
+ if (length < sizeof *fs) {
+ ds_put_format(string, " ***nx_flow_stats claims length %zu***",
+ length);
+ break;
+ }
+
+ match_len = ntohs(fs->match_len);
+ if (match_len > length - sizeof *fs) {
+ ds_put_format(string, " ***length=%zu match_len=%d***",
+ length, match_len);
+ break;
+ }
+
+ ds_put_format(string, " cookie=0x%"PRIx64", duration=",
+ ntohll(fs->cookie));
+ ofp_print_duration(string, ntohl(fs->duration_sec),
+ ntohl(fs->duration_nsec));
+ ds_put_format(string, ", table_id=%"PRIu8", ", fs->table_id);
+ ds_put_format(string, "n_packets=%"PRIu64", ",
+ ntohll(fs->packet_count));
+ ds_put_format(string, "n_bytes=%"PRIu64", ", ntohll(fs->byte_count));
+ if (fs->idle_timeout != htons(OFP_FLOW_PERMANENT)) {
+ ds_put_format(string, "idle_timeout=%"PRIu16",",
+ ntohs(fs->idle_timeout));
+ }
+ if (fs->hard_timeout != htons(OFP_FLOW_PERMANENT)) {
+ ds_put_format(string, "hard_timeout=%"PRIu16",",
+ ntohs(fs->hard_timeout));
+ }
+
+ error = nx_pull_match(&b, match_len, ntohs(fs->priority), &rule);
+ if (error) {
+ ofp_print_error(string, error);
+ break;
+ }
+
+ actions_len = length - sizeof *fs - ROUND_UP(match_len, 8);
+ error = ofputil_pull_actions(&b, actions_len, &actions, &n_actions);
+ if (error) {
+ ofp_print_error(string, error);
+ break;
+ }
- ofp_print_match(string, &asr->match, verbosity);
+ cls_rule_format(&rule, string);
+ ds_put_char(string, ' ');
+ ofp_print_actions(string, (const struct ofp_action_header *) actions,
+ n_actions * sizeof *actions);
+ }
}
static void
-ofp_print_ofpst_aggregate_reply(struct ds *string, const struct ofp_header *oh)
+ofp_print_ofp_aggregate_stats_reply (
+ struct ds *string, const struct ofp_aggregate_stats_reply *asr)
{
- const struct ofp_aggregate_stats_reply *asr = ofputil_stats_body(oh);
-
ds_put_format(string, " packet_count=%"PRIu64, ntohll(asr->packet_count));
ds_put_format(string, " byte_count=%"PRIu64, ntohll(asr->byte_count));
ds_put_format(string, " flow_count=%"PRIu32, ntohl(asr->flow_count));
}
+static void
+ofp_print_ofpst_aggregate_reply(struct ds *string, const struct ofp_header *oh)
+{
+ ofp_print_ofp_aggregate_stats_reply(string, ofputil_stats_body(oh));
+}
+
+static void
+ofp_print_nxst_aggregate_reply(struct ds *string,
+ const struct nx_aggregate_stats_reply *nasr)
+{
+ ofp_print_ofp_aggregate_stats_reply(string, &nasr->asr);
+}
+
static void print_port_stat(struct ds *string, const char *leader,
uint64_t stat, int more)
{
}
}
+static void
+ofp_print_nxt_status_message(struct ds *string, const struct ofp_header *oh)
+{
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ ofpbuf_pull(&b, sizeof *oh);
+ ds_put_char(string, '"');
+ ds_put_printable(string, b.data, b.size);
+ ds_put_char(string, '"');
+}
+
static void
ofp_print_nxt_tun_id_from_cookie(struct ds *string,
const struct nxt_tun_id_cookie *ntic)
ds_put_format(string, " set=%"PRIu8, ntic->set);
}
+static void
+ofp_print_nxt_role_message(struct ds *string,
+ const struct nx_role_request *nrr)
+{
+ unsigned int role = ntohl(nrr->role);
+
+ ds_put_cstr(string, " role=");
+ if (role == NX_ROLE_OTHER) {
+ ds_put_cstr(string, "other");
+ } else if (role == NX_ROLE_MASTER) {
+ ds_put_cstr(string, "master");
+ } else if (role == NX_ROLE_SLAVE) {
+ ds_put_cstr(string, "slave");
+ } else {
+ ds_put_format(string, "%u", role);
+ }
+}
+
static void
ofp_print_nxt_set_flow_format(struct ds *string,
const struct nxt_set_flow_format *nsff)
break;
case OFPUTIL_OFPT_FLOW_REMOVED:
- ofp_print_flow_removed(string, msg, verbosity);
+ case OFPUTIL_NXT_FLOW_REMOVED:
+ ofp_print_flow_removed(string, msg);
break;
case OFPUTIL_OFPT_PORT_STATUS:
break;
case OFPUTIL_OFPST_FLOW_REQUEST:
- ofp_print_stats_request(string, oh);
- ofp_print_ofpst_flow_request(string, oh, verbosity);
- break;
-
+ case OFPUTIL_NXST_FLOW_REQUEST:
case OFPUTIL_OFPST_AGGREGATE_REQUEST:
+ case OFPUTIL_NXST_AGGREGATE_REQUEST:
ofp_print_stats_request(string, oh);
- ofp_print_ofpst_aggregate_request(string, oh, verbosity);
+ ofp_print_flow_stats_request(string, oh);
break;
case OFPUTIL_OFPST_TABLE_REQUEST:
case OFPUTIL_NXT_STATUS_REQUEST:
case OFPUTIL_NXT_STATUS_REPLY:
- /* XXX */
+ ofp_print_nxt_status_message(string, oh);
break;
case OFPUTIL_NXT_TUN_ID_FROM_COOKIE:
case OFPUTIL_NXT_ROLE_REQUEST:
case OFPUTIL_NXT_ROLE_REPLY:
- /* XXX */
+ ofp_print_nxt_role_message(string, msg);
break;
case OFPUTIL_NXT_SET_FLOW_FORMAT:
ofp_print_flow_mod(string, msg, code, verbosity);
break;
- case OFPUTIL_NXT_FLOW_REMOVED:
- case OFPUTIL_NXST_FLOW_REQUEST:
- case OFPUTIL_NXST_AGGREGATE_REQUEST:
case OFPUTIL_NXST_FLOW_REPLY:
+ ofp_print_nxst_flow_reply(string, oh);
+ break;
+
case OFPUTIL_NXST_AGGREGATE_REPLY:
- /* XXX */
+ ofp_print_stats_reply(string, oh);
+ ofp_print_nxst_aggregate_reply(string, msg);
break;
}
}
struct ds string = DS_EMPTY_INITIALIZER;
const struct ofp_header *oh = oh_;
- if (len < sizeof(struct ofp_header)) {
- ds_put_cstr(&string, "OpenFlow packet too short:\n");
+ if (!len) {
+ ds_put_cstr(&string, "OpenFlow message is empty\n");
+ } else if (len < sizeof(struct ofp_header)) {
+ ds_put_format(&string, "OpenFlow packet too short (only %zu bytes):\n",
+ len);
} else if (oh->version != OFP_VERSION) {
ds_put_format(&string, "Bad OpenFlow version %"PRIu8":\n",
oh->version);
} else if (ntohs(oh->length) > len) {
ds_put_format(&string,
- "(***truncated to %zu bytes from %"PRIu16"***)",
+ "(***truncated to %zu bytes from %"PRIu16"***)\n",
len, ntohs(oh->length));
} else if (ntohs(oh->length) < len) {
ds_put_format(&string,