static void queue_tx(struct lswitch *, struct rconn *, struct ofpbuf *);
static void send_features_request(struct lswitch *, struct rconn *);
-typedef void packet_handler_func(struct lswitch *, struct rconn *, void *);
-static packet_handler_func process_switch_features;
-static packet_handler_func process_packet_in;
-static packet_handler_func process_echo_request;
+static void process_switch_features(struct lswitch *,
+ struct ofp_switch_features *);
+static void process_packet_in(struct lswitch *, struct rconn *,
+ const struct ofp_packet_in *);
+static void process_echo_request(struct lswitch *, struct rconn *,
+ const struct ofp_header *);
/* Creates and returns a new learning switch whose configuration is given by
* 'cfg'.
lswitch_process_packet(struct lswitch *sw, struct rconn *rconn,
const struct ofpbuf *msg)
{
- struct processor {
- uint8_t type;
- size_t min_size;
- packet_handler_func *handler;
- };
- static const struct processor processors[] = {
- {
- OFPT_ECHO_REQUEST,
- sizeof(struct ofp_header),
- process_echo_request
- },
- {
- OFPT_FEATURES_REPLY,
- sizeof(struct ofp_switch_features),
- process_switch_features
- },
- {
- OFPT_PACKET_IN,
- offsetof(struct ofp_packet_in, data),
- process_packet_in
- },
- {
- OFPT_FLOW_REMOVED,
- sizeof(struct ofp_flow_removed),
- NULL
- },
- };
- const size_t n_processors = ARRAY_SIZE(processors);
- const struct processor *p;
- struct ofp_header *oh;
-
- oh = msg->data;
+ const struct ofp_header *oh = msg->data;
+ const struct ofputil_msg_type *type;
+
if (sw->datapath_id == 0
&& oh->type != OFPT_ECHO_REQUEST
&& oh->type != OFPT_FEATURES_REPLY) {
return;
}
- for (p = processors; p < &processors[n_processors]; p++) {
- if (oh->type == p->type) {
- if (msg->size < p->min_size) {
- VLOG_WARN_RL(&rl, "%016llx: %s: too short (%zu bytes) for "
- "type %"PRIu8" (min %zu)", sw->datapath_id,
- rconn_get_name(rconn), msg->size, oh->type,
- p->min_size);
- return;
- }
- if (p->handler) {
- (p->handler)(sw, rconn, msg->data);
- }
- return;
+ ofputil_decode_msg_type(oh, &type);
+ switch (ofputil_msg_type_code(type)) {
+ case OFPUTIL_OFPT_ECHO_REQUEST:
+ process_echo_request(sw, rconn, msg->data);
+ break;
+
+ case OFPUTIL_OFPT_FEATURES_REPLY:
+ process_switch_features(sw, msg->data);
+ break;
+
+ case OFPUTIL_OFPT_PACKET_IN:
+ process_packet_in(sw, rconn, msg->data);
+ break;
+
+ case OFPUTIL_OFPT_FLOW_REMOVED:
+ /* Nothing to do. */
+ break;
+
+ case OFPUTIL_INVALID:
+ case OFPUTIL_OFPT_HELLO:
+ case OFPUTIL_OFPT_ERROR:
+ case OFPUTIL_OFPT_ECHO_REPLY:
+ case OFPUTIL_OFPT_FEATURES_REQUEST:
+ case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
+ case OFPUTIL_OFPT_GET_CONFIG_REPLY:
+ case OFPUTIL_OFPT_SET_CONFIG:
+ case OFPUTIL_OFPT_PORT_STATUS:
+ case OFPUTIL_OFPT_PACKET_OUT:
+ case OFPUTIL_OFPT_FLOW_MOD:
+ case OFPUTIL_OFPT_PORT_MOD:
+ case OFPUTIL_OFPT_BARRIER_REQUEST:
+ case OFPUTIL_OFPT_BARRIER_REPLY:
+ case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
+ case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
+ case OFPUTIL_OFPST_DESC_REQUEST:
+ case OFPUTIL_OFPST_FLOW_REQUEST:
+ case OFPUTIL_OFPST_AGGREGATE_REQUEST:
+ case OFPUTIL_OFPST_TABLE_REQUEST:
+ case OFPUTIL_OFPST_PORT_REQUEST:
+ case OFPUTIL_OFPST_QUEUE_REQUEST:
+ case OFPUTIL_OFPST_DESC_REPLY:
+ case OFPUTIL_OFPST_FLOW_REPLY:
+ case OFPUTIL_OFPST_QUEUE_REPLY:
+ case OFPUTIL_OFPST_PORT_REPLY:
+ case OFPUTIL_OFPST_TABLE_REPLY:
+ case OFPUTIL_OFPST_AGGREGATE_REPLY:
+ case OFPUTIL_NXT_STATUS_REQUEST:
+ case OFPUTIL_NXT_STATUS_REPLY:
+ case OFPUTIL_NXT_TUN_ID_FROM_COOKIE:
+ case OFPUTIL_NXT_ROLE_REQUEST:
+ case OFPUTIL_NXT_ROLE_REPLY:
+ case OFPUTIL_NXT_SET_FLOW_FORMAT:
+ case OFPUTIL_NXT_FLOW_MOD:
+ case OFPUTIL_NXT_FLOW_REMOVED:
+ case OFPUTIL_NXST_FLOW_REQUEST:
+ case OFPUTIL_NXST_AGGREGATE_REQUEST:
+ case OFPUTIL_NXST_FLOW_REPLY:
+ case OFPUTIL_NXST_AGGREGATE_REPLY:
+ default:
+ if (VLOG_IS_DBG_ENABLED()) {
+ char *s = ofp_to_string(msg->data, msg->size, 2);
+ VLOG_DBG_RL(&rl, "%016llx: OpenFlow packet ignored: %s",
+ sw->datapath_id, s);
+ free(s);
}
}
- if (VLOG_IS_DBG_ENABLED()) {
- char *s = ofp_to_string(msg->data, msg->size, 2);
- VLOG_DBG_RL(&rl, "%016llx: OpenFlow packet ignored: %s",
- sw->datapath_id, s);
- free(s);
- }
}
\f
static void
}
static void
-process_switch_features(struct lswitch *sw, struct rconn *rconn OVS_UNUSED,
- void *osf_)
+process_switch_features(struct lswitch *sw, struct ofp_switch_features *osf)
{
- struct ofp_switch_features *osf = osf_;
size_t n_ports;
size_t i;
- if (check_ofp_message_array(&osf->header, OFPT_FEATURES_REPLY,
- sizeof *osf, sizeof *osf->ports, &n_ports)) {
- return;
- }
-
sw->datapath_id = ntohll(osf->datapath_id);
+ n_ports = (ntohs(osf->header.length) - sizeof *osf) / sizeof *osf->ports;
for (i = 0; i < n_ports; i++) {
struct ofp_phy_port *opp = &osf->ports[i];
struct lswitch_port *lp;
}
static void
-process_packet_in(struct lswitch *sw, struct rconn *rconn, void *opi_)
+process_packet_in(struct lswitch *sw, struct rconn *rconn,
+ const struct ofp_packet_in *opi)
{
- struct ofp_packet_in *opi = opi_;
uint16_t in_port = ntohs(opi->in_port);
uint32_t queue_id;
uint16_t out_port;
/* Extract flow data from 'opi' into 'flow'. */
pkt_ofs = offsetof(struct ofp_packet_in, data);
pkt_len = ntohs(opi->header.length) - pkt_ofs;
- pkt.data = opi->data;
+ pkt.data = (void *) opi->data;
pkt.size = pkt_len;
flow_extract(&pkt, 0, in_port, &flow);
}
static void
-process_echo_request(struct lswitch *sw, struct rconn *rconn, void *rq_)
+process_echo_request(struct lswitch *sw, struct rconn *rconn,
+ const struct ofp_header *rq)
{
- struct ofp_header *rq = rq_;
queue_tx(sw, rconn, make_echo_reply(rq));
}
return ds_cstr(&ds);
}
-/* Pretty-print the OFPT_PACKET_IN packet of 'len' bytes at 'oh' to 'stream'
- * at the given 'verbosity' level. */
static void
-ofp_packet_in(struct ds *string, const void *oh, size_t len, int verbosity)
+ofp_print_packet_in(struct ds *string, const struct ofp_packet_in *op,
+ int verbosity)
{
- const struct ofp_packet_in *op = oh;
+ size_t len = ntohs(op->header.length);
size_t data_len;
ds_put_format(string, " total_len=%"PRIu16" in_port=",
}
}
-/* Pretty-print the OFPT_PACKET_OUT packet of 'len' bytes at 'oh' to 'string'
- * at the given 'verbosity' level. */
-static void ofp_packet_out(struct ds *string, const void *oh, size_t len,
- int verbosity)
+static void
+ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
+ int verbosity)
{
- const struct ofp_packet_out *opo = oh;
+ size_t len = ntohs(opo->header.length);
size_t actions_len = ntohs(opo->actions_len);
ds_put_cstr(string, " in_port=");
}
}
-/* Pretty-print the struct ofp_switch_features of 'len' bytes at 'oh' to
- * 'string' at the given 'verbosity' level. */
static void
-ofp_print_switch_features(struct ds *string, const void *oh, size_t len,
- int verbosity OVS_UNUSED)
+ofp_print_switch_features(struct ds *string,
+ const struct ofp_switch_features *osf)
{
- const struct ofp_switch_features *osf = oh;
+ size_t len = ntohs(osf->header.length);
struct ofp_phy_port *port_list;
int n_ports;
int i;
ds_put_format(string, "features: capabilities:%#x, actions:%#x\n",
ntohl(osf->capabilities), ntohl(osf->actions));
- if (ntohs(osf->header.length) >= sizeof *osf) {
- len = MIN(len, ntohs(osf->header.length));
- }
n_ports = (len - sizeof *osf) / sizeof *osf->ports;
port_list = xmemdup(osf->ports, len - sizeof *osf);
free(port_list);
}
-/* Pretty-print the struct ofp_switch_config of 'len' bytes at 'oh' to 'string'
- * at the given 'verbosity' level. */
static void
-ofp_print_switch_config(struct ds *string, const void *oh,
- size_t len OVS_UNUSED, int verbosity OVS_UNUSED)
+ofp_print_switch_config(struct ds *string, const struct ofp_switch_config *osc)
{
- const struct ofp_switch_config *osc = oh;
uint16_t flags;
flags = ntohs(osc->flags);
return ds_cstr(&f);
}
-/* Pretty-print the OFPT_FLOW_MOD packet of 'len' bytes at 'oh' to 'string'
- * at the given 'verbosity' level. */
static void
-ofp_print_flow_mod(struct ds *string, const void *oh, size_t len,
+ofp_print_flow_mod(struct ds *string, const struct ofp_flow_mod *ofm,
int verbosity)
{
- const struct ofp_flow_mod *ofm = oh;
+ size_t len = ntohs(ofm->header.length);
ds_put_char(string, ' ');
ofp_print_match(string, &ofm->match, verbosity);
ds_put_char(string, '\n');
}
-/* Pretty-print the OFPT_FLOW_REMOVED packet of 'len' bytes at 'oh' to 'string'
- * at the given 'verbosity' level. */
static void
-ofp_print_flow_removed(struct ds *string, const void *oh,
- size_t len OVS_UNUSED, int verbosity)
+ofp_print_flow_removed(struct ds *string, const struct ofp_flow_removed *ofr,
+ int verbosity)
{
- const struct ofp_flow_removed *ofr = oh;
-
ofp_print_match(string, &ofr->match, verbosity);
ds_put_cstr(string, " reason=");
switch (ofr->reason) {
}
static void
-ofp_print_port_mod(struct ds *string, const void *oh, size_t len OVS_UNUSED,
- int verbosity OVS_UNUSED)
+ofp_print_port_mod(struct ds *string, const struct ofp_port_mod *opm)
{
- const struct ofp_port_mod *opm = oh;
-
ds_put_format(string, "port: %d: addr:"ETH_ADDR_FMT", config: %#x, mask:%#x\n",
ntohs(opm->port_no), ETH_ADDR_ARGS(opm->hw_addr),
ntohl(opm->config), ntohl(opm->mask));
return "?";
}
-/* Pretty-print the OFPT_ERROR packet of 'len' bytes at 'oh' to 'string'
- * at the given 'verbosity' level. */
static void
-ofp_print_error_msg(struct ds *string, const void *oh, size_t len,
- int verbosity OVS_UNUSED)
+ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
{
- const struct ofp_error_msg *oem = oh;
+ size_t len = ntohs(oem->header.length);
int type = ntohs(oem->type);
int code = ntohs(oem->code);
char *s;
}
}
-/* Pretty-print the OFPT_PORT_STATUS packet of 'len' bytes at 'oh' to 'string'
- * at the given 'verbosity' level. */
static void
-ofp_print_port_status(struct ds *string, const void *oh, size_t len OVS_UNUSED,
- int verbosity OVS_UNUSED)
+ofp_print_port_status(struct ds *string, const struct ofp_port_status *ops)
{
- const struct ofp_port_status *ops = oh;
-
if (ops->reason == OFPPR_ADD) {
ds_put_format(string, " ADD:");
} else if (ops->reason == OFPPR_DELETE) {
}
static void
-ofp_desc_stats_reply(struct ds *string, const void *body,
- size_t len OVS_UNUSED, int verbosity OVS_UNUSED)
+ofp_print_ofpst_desc_reply(struct ds *string, const struct ofp_header *oh)
{
- const struct ofp_desc_stats *ods = body;
+ const struct ofp_desc_stats *ods = ofputil_stats_body(oh);
ds_put_format(string, "Manufacturer: %.*s\n",
(int) sizeof ods->mfr_desc, ods->mfr_desc);
}
static void
-ofp_flow_stats_request(struct ds *string, const void *oh,
- size_t len OVS_UNUSED, int verbosity)
+ofp_print_ofpst_flow_request(struct ds *string, const struct ofp_header *oh,
+ int verbosity)
{
- const struct ofp_flow_stats_request *fsr = oh;
+ const struct ofp_flow_stats_request *fsr = ofputil_stats_body(oh);
if (fsr->table_id == 0xff) {
ds_put_format(string, " table_id=any, ");
}
static void
-ofp_flow_stats_reply(struct ds *string, const void *body_, size_t len,
- int verbosity)
+ofp_print_ofpst_flow_reply(struct ds *string, const struct ofp_header *oh,
+ int verbosity)
{
- const char *body = body_;
+ size_t len = ofputil_stats_body_len(oh);
+ const char *body = ofputil_stats_body(oh);
const char *pos = body;
for (;;) {
const struct ofp_flow_stats *fs;
}
static void
-ofp_aggregate_stats_request(struct ds *string, const void *oh,
- size_t len OVS_UNUSED, int verbosity)
+ofp_print_ofpst_aggregate_request(struct ds *string,
+ const struct ofp_header *oh, int verbosity)
{
- const struct ofp_aggregate_stats_request *asr = oh;
+ const struct ofp_aggregate_stats_request *asr = ofputil_stats_body(oh);
if (asr->table_id == 0xff) {
ds_put_format(string, " table_id=any, ");
}
static void
-ofp_aggregate_stats_reply(struct ds *string, const void *body_,
- size_t len OVS_UNUSED, int verbosity OVS_UNUSED)
+ofp_print_ofpst_aggregate_reply(struct ds *string, const struct ofp_header *oh)
{
- const struct ofp_aggregate_stats_reply *asr = body_;
+ 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));
}
static void
-ofp_port_stats_request(struct ds *string, const void *body_,
- size_t len OVS_UNUSED, int verbosity OVS_UNUSED)
+ofp_print_ofpst_port_request(struct ds *string, const struct ofp_header *oh)
{
- const struct ofp_port_stats_request *psr = body_;
+ const struct ofp_port_stats_request *psr = ofputil_stats_body(oh);
ds_put_format(string, "port_no=%"PRIu16, ntohs(psr->port_no));
}
static void
-ofp_port_stats_reply(struct ds *string, const void *body, size_t len,
- int verbosity)
+ofp_print_ofpst_port_reply(struct ds *string, const struct ofp_header *oh,
+ int verbosity)
{
- const struct ofp_port_stats *ps = body;
- size_t n = len / sizeof *ps;
+ const struct ofp_port_stats *ps = ofputil_stats_body(oh);
+ size_t n = ofputil_stats_body_len(oh) / sizeof *ps;
ds_put_format(string, " %zu ports\n", n);
if (verbosity < 1) {
return;
}
static void
-ofp_table_stats_reply(struct ds *string, const void *body, size_t len,
- int verbosity)
+ofp_print_ofpst_table_reply(struct ds *string, const struct ofp_header *oh,
+ int verbosity)
{
- const struct ofp_table_stats *ts = body;
- size_t n = len / sizeof *ts;
+ const struct ofp_table_stats *ts = ofputil_stats_body(oh);
+ size_t n = ofputil_stats_body_len(oh) / sizeof *ts;
ds_put_format(string, " %zu tables\n", n);
if (verbosity < 1) {
return;
}
static void
-ofp_queue_stats_request(struct ds *string, const void *body_,
- size_t len OVS_UNUSED, int verbosity OVS_UNUSED)
+ofp_print_ofpst_queue_request(struct ds *string, const struct ofp_header *oh)
{
- const struct ofp_queue_stats_request *qsr = body_;
+ const struct ofp_queue_stats_request *qsr = ofputil_stats_body(oh);
ds_put_cstr(string, "port=");
ofp_print_port_name(string, ntohs(qsr->port_no));
}
static void
-ofp_queue_stats_reply(struct ds *string, const void *body, size_t len,
- int verbosity)
+ofp_print_ofpst_queue_reply(struct ds *string, const struct ofp_header *oh,
+ int verbosity)
{
- const struct ofp_queue_stats *qs = body;
- size_t n = len / sizeof *qs;
+ const struct ofp_queue_stats *qs = ofputil_stats_body(oh);
+ size_t n = ofputil_stats_body_len(oh) / sizeof *qs;
ds_put_format(string, " %zu queues\n", n);
if (verbosity < 1) {
return;
}
static void
-vendor_stat(struct ds *string, const void *body, size_t len,
- int verbosity OVS_UNUSED)
-{
- ds_put_format(string, " vendor=%08"PRIx32, ntohl(*(uint32_t *) body));
- ds_put_format(string, " %zu bytes additional data",
- len - sizeof(uint32_t));
-}
-
-enum stats_direction {
- REQUEST,
- REPLY
-};
-
-static void
-print_stats(struct ds *string, int type, const void *body, size_t body_len,
- int verbosity, enum stats_direction direction)
+ofp_print_stats_request(struct ds *string, const struct ofp_header *oh)
{
- struct stats_msg {
- size_t min_body, max_body;
- void (*printer)(struct ds *, const void *, size_t len, int verbosity);
- };
-
- struct stats_type {
- int type;
- const char *name;
- struct stats_msg request;
- struct stats_msg reply;
- };
-
- static const struct stats_type stats_types[] = {
- {
- OFPST_DESC,
- "description",
- { 0, 0, NULL },
- { 0, SIZE_MAX, ofp_desc_stats_reply },
- },
- {
- OFPST_FLOW,
- "flow",
- { sizeof(struct ofp_flow_stats_request),
- sizeof(struct ofp_flow_stats_request),
- ofp_flow_stats_request },
- { 0, SIZE_MAX, ofp_flow_stats_reply },
- },
- {
- OFPST_AGGREGATE,
- "aggregate",
- { sizeof(struct ofp_aggregate_stats_request),
- sizeof(struct ofp_aggregate_stats_request),
- ofp_aggregate_stats_request },
- { sizeof(struct ofp_aggregate_stats_reply),
- sizeof(struct ofp_aggregate_stats_reply),
- ofp_aggregate_stats_reply },
- },
- {
- OFPST_TABLE,
- "table",
- { 0, 0, NULL },
- { 0, SIZE_MAX, ofp_table_stats_reply },
- },
- {
- OFPST_PORT,
- "port",
- { sizeof(struct ofp_port_stats_request),
- sizeof(struct ofp_port_stats_request),
- ofp_port_stats_request },
- { 0, SIZE_MAX, ofp_port_stats_reply },
- },
- {
- OFPST_QUEUE,
- "queue",
- { sizeof(struct ofp_queue_stats_request),
- sizeof(struct ofp_queue_stats_request),
- ofp_queue_stats_request },
- { 0, SIZE_MAX, ofp_queue_stats_reply },
- },
- {
- OFPST_VENDOR,
- "vendor-specific",
- { sizeof(uint32_t), SIZE_MAX, vendor_stat },
- { sizeof(uint32_t), SIZE_MAX, vendor_stat },
- },
- {
- -1,
- "unknown",
- { 0, 0, NULL, },
- { 0, 0, NULL, },
- },
- };
-
- const struct stats_type *s;
- const struct stats_msg *m;
-
- if (type >= ARRAY_SIZE(stats_types) || !stats_types[type].name) {
- ds_put_format(string, " ***unknown type %d***", type);
- return;
- }
- for (s = stats_types; s->type >= 0; s++) {
- if (s->type == type) {
- break;
- }
- }
- ds_put_format(string, " type=%d(%s)\n", type, s->name);
-
- m = direction == REQUEST ? &s->request : &s->reply;
- if (body_len < m->min_body || body_len > m->max_body) {
- ds_put_format(string, " ***body_len=%zu not in %zu...%zu***",
- body_len, m->min_body, m->max_body);
- return;
- }
- if (m->printer) {
- m->printer(string, body, body_len, verbosity);
- }
-}
-
-static void
-ofp_stats_request(struct ds *string, const void *oh, size_t len, int verbosity)
-{
- const struct ofp_stats_request *srq = oh;
+ const struct ofp_stats_request *srq
+ = (const struct ofp_stats_request *) oh;
if (srq->flags) {
ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***",
ntohs(srq->flags));
}
-
- print_stats(string, ntohs(srq->type), srq->body,
- len - offsetof(struct ofp_stats_request, body),
- verbosity, REQUEST);
}
static void
-ofp_stats_reply(struct ds *string, const void *oh, size_t len, int verbosity)
+ofp_print_stats_reply(struct ds *string, const struct ofp_header *oh)
{
- const struct ofp_stats_reply *srp = oh;
+ const struct ofp_stats_reply *srp = (const struct ofp_stats_reply *) oh;
- ds_put_cstr(string, " flags=");
- if (!srp->flags) {
- ds_put_cstr(string, "none");
- } else {
+ if (srp->flags) {
uint16_t flags = ntohs(srp->flags);
+
+ ds_put_cstr(string, " flags=");
if (flags & OFPSF_REPLY_MORE) {
ds_put_cstr(string, "[more]");
flags &= ~OFPSF_REPLY_MORE;
}
if (flags) {
- ds_put_format(string, "[***unknown flags 0x%04"PRIx16"***]", flags);
+ ds_put_format(string, "[***unknown flags 0x%04"PRIx16"***]",
+ flags);
}
}
-
- print_stats(string, ntohs(srp->type), srp->body,
- len - offsetof(struct ofp_stats_reply, body),
- verbosity, REPLY);
}
static void
-ofp_echo(struct ds *string, const void *oh, size_t len, int verbosity)
+ofp_print_echo(struct ds *string, const struct ofp_header *oh, int verbosity)
{
- const struct ofp_header *hdr = oh;
+ size_t len = ntohs(oh->length);
- ds_put_format(string, " %zu bytes of payload\n", len - sizeof *hdr);
+ ds_put_format(string, " %zu bytes of payload\n", len - sizeof *oh);
if (verbosity > 1) {
- ds_put_hex_dump(string, hdr, len - sizeof *hdr, 0, true);
+ ds_put_hex_dump(string, oh + 1, len - sizeof *oh, 0, true);
}
}
-struct openflow_packet {
- uint8_t type;
- const char *name;
- size_t min_size;
- void (*printer)(struct ds *, const void *, size_t len, int verbosity);
-};
+static void
+ofp_to_string__(const struct ofp_header *oh,
+ const struct ofputil_msg_type *type, struct ds *string,
+ int verbosity)
+{
+ const void *msg = oh;
+
+ ds_put_format(string, "%s (xid=0x%"PRIx32"):",
+ ofputil_msg_type_name(type), ntohl(oh->xid));
+
+ switch (ofputil_msg_type_code(type)) {
+ case OFPUTIL_INVALID:
+ break;
+
+ case OFPUTIL_OFPT_HELLO:
+ break;
+
+ case OFPUTIL_OFPT_ERROR:
+ ofp_print_error_msg(string, msg);
+ break;
+
+ case OFPUTIL_OFPT_ECHO_REQUEST:
+ case OFPUTIL_OFPT_ECHO_REPLY:
+ ofp_print_echo(string, oh, verbosity);
+ break;
+
+ case OFPUTIL_OFPT_FEATURES_REQUEST:
+ break;
+
+ case OFPUTIL_OFPT_FEATURES_REPLY:
+ ofp_print_switch_features(string, msg);
+ break;
+
+ case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
+ break;
+
+ case OFPUTIL_OFPT_GET_CONFIG_REPLY:
+ case OFPUTIL_OFPT_SET_CONFIG:
+ ofp_print_switch_config(string, msg);
+ break;
+
+ case OFPUTIL_OFPT_PACKET_IN:
+ ofp_print_packet_in(string, msg, verbosity);
+ break;
+
+ case OFPUTIL_OFPT_FLOW_REMOVED:
+ ofp_print_flow_removed(string, msg, verbosity);
+ break;
+
+ case OFPUTIL_OFPT_PORT_STATUS:
+ ofp_print_port_status(string, msg);
+ break;
+
+ case OFPUTIL_OFPT_PACKET_OUT:
+ ofp_print_packet_out(string, msg, verbosity);
+ break;
+
+ case OFPUTIL_OFPT_FLOW_MOD:
+ ofp_print_flow_mod(string, msg, verbosity);
+ break;
+
+ case OFPUTIL_OFPT_PORT_MOD:
+ ofp_print_port_mod(string, msg);
+ break;
+
+ case OFPUTIL_OFPT_BARRIER_REQUEST:
+ case OFPUTIL_OFPT_BARRIER_REPLY:
+ break;
+
+ case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
+ case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
+ /* XXX */
+ break;
+
+ case OFPUTIL_OFPST_DESC_REQUEST:
+ ofp_print_stats_request(string, oh);
+ break;
+
+ case OFPUTIL_OFPST_FLOW_REQUEST:
+ ofp_print_stats_request(string, oh);
+ ofp_print_ofpst_flow_request(string, oh, verbosity);
+ break;
+
+ case OFPUTIL_OFPST_AGGREGATE_REQUEST:
+ ofp_print_stats_request(string, oh);
+ ofp_print_ofpst_aggregate_request(string, oh, verbosity);
+ break;
+
+ case OFPUTIL_OFPST_TABLE_REQUEST:
+ ofp_print_stats_request(string, oh);
+ break;
+
+ case OFPUTIL_OFPST_PORT_REQUEST:
+ ofp_print_stats_request(string, oh);
+ ofp_print_ofpst_port_request(string, oh);
+ break;
+
+ case OFPUTIL_OFPST_QUEUE_REQUEST:
+ ofp_print_stats_request(string, oh);
+ ofp_print_ofpst_queue_request(string, oh);
+ break;
+
+ case OFPUTIL_OFPST_DESC_REPLY:
+ ofp_print_stats_reply(string, oh);
+ ofp_print_ofpst_desc_reply(string, oh);
+ break;
+
+ case OFPUTIL_OFPST_FLOW_REPLY:
+ ofp_print_stats_reply(string, oh);
+ ofp_print_ofpst_flow_reply(string, oh, verbosity);
+ break;
+
+ case OFPUTIL_OFPST_QUEUE_REPLY:
+ ofp_print_stats_reply(string, oh);
+ ofp_print_ofpst_queue_reply(string, oh, verbosity);
+ break;
+
+ case OFPUTIL_OFPST_PORT_REPLY:
+ ofp_print_stats_reply(string, oh);
+ ofp_print_ofpst_port_reply(string, oh, verbosity);
+ break;
+
+ case OFPUTIL_OFPST_TABLE_REPLY:
+ ofp_print_stats_reply(string, oh);
+ ofp_print_ofpst_table_reply(string, oh, verbosity);
+ break;
+
+ case OFPUTIL_OFPST_AGGREGATE_REPLY:
+ ofp_print_stats_reply(string, oh);
+ ofp_print_ofpst_aggregate_reply(string, oh);
+ break;
-static const struct openflow_packet packets[] = {
- {
- OFPT_HELLO,
- "hello",
- sizeof (struct ofp_header),
- NULL,
- },
- {
- OFPT_FEATURES_REQUEST,
- "features_request",
- sizeof (struct ofp_header),
- NULL,
- },
- {
- OFPT_FEATURES_REPLY,
- "features_reply",
- sizeof (struct ofp_switch_features),
- ofp_print_switch_features,
- },
- {
- OFPT_GET_CONFIG_REQUEST,
- "get_config_request",
- sizeof (struct ofp_header),
- NULL,
- },
- {
- OFPT_GET_CONFIG_REPLY,
- "get_config_reply",
- sizeof (struct ofp_switch_config),
- ofp_print_switch_config,
- },
- {
- OFPT_SET_CONFIG,
- "set_config",
- sizeof (struct ofp_switch_config),
- ofp_print_switch_config,
- },
- {
- OFPT_PACKET_IN,
- "packet_in",
- offsetof(struct ofp_packet_in, data),
- ofp_packet_in,
- },
- {
- OFPT_PACKET_OUT,
- "packet_out",
- sizeof (struct ofp_packet_out),
- ofp_packet_out,
- },
- {
- OFPT_FLOW_MOD,
- "flow_mod",
- sizeof (struct ofp_flow_mod),
- ofp_print_flow_mod,
- },
- {
- OFPT_FLOW_REMOVED,
- "flow_removed",
- sizeof (struct ofp_flow_removed),
- ofp_print_flow_removed,
- },
- {
- OFPT_PORT_MOD,
- "port_mod",
- sizeof (struct ofp_port_mod),
- ofp_print_port_mod,
- },
- {
- OFPT_PORT_STATUS,
- "port_status",
- sizeof (struct ofp_port_status),
- ofp_print_port_status
- },
- {
- OFPT_ERROR,
- "error_msg",
- sizeof (struct ofp_error_msg),
- ofp_print_error_msg,
- },
- {
- OFPT_STATS_REQUEST,
- "stats_request",
- sizeof (struct ofp_stats_request),
- ofp_stats_request,
- },
- {
- OFPT_STATS_REPLY,
- "stats_reply",
- sizeof (struct ofp_stats_reply),
- ofp_stats_reply,
- },
- {
- OFPT_ECHO_REQUEST,
- "echo_request",
- sizeof (struct ofp_header),
- ofp_echo,
- },
- {
- OFPT_ECHO_REPLY,
- "echo_reply",
- sizeof (struct ofp_header),
- ofp_echo,
- },
- {
- OFPT_VENDOR,
- "vendor",
- sizeof (struct ofp_vendor_header),
- NULL,
- },
- {
- OFPT_BARRIER_REQUEST,
- "barrier_request",
- sizeof (struct ofp_header),
- NULL,
- },
- {
- OFPT_BARRIER_REPLY,
- "barrier_reply",
- sizeof (struct ofp_header),
- NULL,
+ case OFPUTIL_NXT_STATUS_REQUEST:
+ case OFPUTIL_NXT_STATUS_REPLY:
+ case OFPUTIL_NXT_TUN_ID_FROM_COOKIE:
+ case OFPUTIL_NXT_ROLE_REQUEST:
+ case OFPUTIL_NXT_ROLE_REPLY:
+ case OFPUTIL_NXT_SET_FLOW_FORMAT:
+ case OFPUTIL_NXT_FLOW_MOD:
+ case OFPUTIL_NXT_FLOW_REMOVED:
+ case OFPUTIL_NXST_FLOW_REQUEST:
+ case OFPUTIL_NXST_AGGREGATE_REQUEST:
+ case OFPUTIL_NXST_FLOW_REPLY:
+ case OFPUTIL_NXST_AGGREGATE_REPLY:
+ /* XXX */
+ break;
}
-};
+}
/* Composes and returns a string representing the OpenFlow packet of 'len'
* bytes at 'oh' at the given 'verbosity' level. 0 is a minimal amount of
{
struct ds string = DS_EMPTY_INITIALIZER;
const struct ofp_header *oh = oh_;
- const struct openflow_packet *pkt;
if (len < sizeof(struct ofp_header)) {
ds_put_cstr(&string, "OpenFlow packet too short:\n");
- ds_put_hex_dump(&string, oh, len, 0, true);
- return ds_cstr(&string);
} else if (oh->version != OFP_VERSION) {
- ds_put_format(&string, "Bad OpenFlow version %"PRIu8":\n", oh->version);
- ds_put_hex_dump(&string, oh, len, 0, true);
- return ds_cstr(&string);
- }
-
- for (pkt = packets; ; pkt++) {
- if (pkt >= &packets[ARRAY_SIZE(packets)]) {
- ds_put_format(&string, "Unknown OpenFlow packet type %"PRIu8":\n",
- oh->type);
- ds_put_hex_dump(&string, oh, len, 0, true);
- return ds_cstr(&string);
- } else if (oh->type == pkt->type) {
- break;
+ 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"***)",
+ len, ntohs(oh->length));
+ } else if (ntohs(oh->length) < len) {
+ ds_put_format(&string,
+ "(***only uses %"PRIu16" bytes out of %zu***)\n",
+ ntohs(oh->length), len);
+ } else {
+ const struct ofputil_msg_type *type;
+ int err_type, err_code;
+ int error;
+
+ error = ofputil_decode_msg_type(oh, &type);
+ if (!error) {
+ ofp_to_string__(oh, type, &string, verbosity);
+ if (verbosity >= 3) {
+ ds_put_hex_dump(&string, oh, len, 0, true);
+ }
+ if (string.string[string.length - 1] != '\n') {
+ ds_put_char(&string, '\n');
+ }
+ return ds_steal_cstr(&string);
}
- }
-
- ds_put_format(&string, "%s (xid=0x%"PRIx32"):", pkt->name, ntohl(oh->xid));
- if (ntohs(oh->length) > len)
- ds_put_format(&string, " (***truncated to %zu bytes from %"PRIu16"***)",
- len, ntohs(oh->length));
- else if (ntohs(oh->length) < len) {
- ds_put_format(&string, " (***only uses %"PRIu16" bytes out of %zu***)\n",
- ntohs(oh->length), len);
- len = ntohs(oh->length);
- }
-
- if (len < pkt->min_size) {
- ds_put_format(&string, " (***length=%zu < min_size=%zu***)\n",
- len, pkt->min_size);
- } else if (!pkt->printer) {
- if (len > sizeof *oh) {
- ds_put_format(&string, " length=%"PRIu16" (decoder not implemented)\n",
- ntohs(oh->length));
- }
- } else {
- pkt->printer(&string, oh, len, verbosity);
- }
- if (verbosity >= 3) {
- ds_put_hex_dump(&string, oh, len, 0, true);
- }
- if (string.string[string.length - 1] != '\n') {
- ds_put_char(&string, '\n');
+ err_type = get_ofp_err_type(error);
+ err_code = get_ofp_err_code(error);
+ ds_put_format(&string, "Bad OpenFlow message (%s, %s)\n",
+ lookup_error_type(err_type),
+ lookup_error_code(err_type, err_code));
}
- return ds_cstr(&string);
+ ds_put_hex_dump(&string, oh, len, 0, true);
+ return ds_steal_cstr(&string);
}
/* Returns the name for the specified OpenFlow message type as a string,
char *
ofp_message_type_to_string(uint8_t type)
{
- struct ds s = DS_EMPTY_INITIALIZER;
- const struct openflow_packet *pkt;
- for (pkt = packets; ; pkt++) {
- if (pkt >= &packets[ARRAY_SIZE(packets)]) {
- ds_put_format(&s, "0x%02"PRIx8, type);
- break;
- } else if (type == pkt->type) {
- const char *p;
+ const char *name;
- ds_put_cstr(&s, "OFPT_");
- for (p = pkt->name; *p; p++) {
- ds_put_char(&s, toupper((unsigned char) *p));
- }
- break;
- }
+ switch (type) {
+ case OFPT_HELLO:
+ name = "HELLO";
+ break;
+ case OFPT_ERROR:
+ name = "ERROR";
+ break;
+ case OFPT_ECHO_REQUEST:
+ name = "ECHO_REQUEST";
+ break;
+ case OFPT_ECHO_REPLY:
+ name = "ECHO_REPLY";
+ break;
+ case OFPT_VENDOR:
+ name = "VENDOR";
+ break;
+ case OFPT_FEATURES_REQUEST:
+ name = "FEATURES_REQUEST";
+ break;
+ case OFPT_FEATURES_REPLY:
+ name = "FEATURES_REPLY";
+ break;
+ case OFPT_GET_CONFIG_REQUEST:
+ name = "GET_CONFIG_REQUEST";
+ break;
+ case OFPT_GET_CONFIG_REPLY:
+ name = "GET_CONFIG_REPLY";
+ break;
+ case OFPT_SET_CONFIG:
+ name = "SET_CONFIG";
+ break;
+ case OFPT_PACKET_IN:
+ name = "PACKET_IN";
+ break;
+ case OFPT_FLOW_REMOVED:
+ name = "FLOW_REMOVED";
+ break;
+ case OFPT_PORT_STATUS:
+ name = "PORT_STATUS";
+ break;
+ case OFPT_PACKET_OUT:
+ name = "PACKET_OUT";
+ break;
+ case OFPT_FLOW_MOD:
+ name = "FLOW_MOD";
+ break;
+ case OFPT_PORT_MOD:
+ name = "PORT_MOD";
+ break;
+ case OFPT_STATS_REQUEST:
+ name = "STATS_REQUEST";
+ break;
+ case OFPT_STATS_REPLY:
+ name = "STATS_REPLY";
+ break;
+ case OFPT_BARRIER_REQUEST:
+ name = "BARRIER_REQUEST";
+ break;
+ case OFPT_BARRIER_REPLY:
+ name = "BARRIER_REPLY";
+ break;
+ case OFPT_QUEUE_GET_CONFIG_REQUEST:
+ name = "QUEUE_GET_CONFIG_REQUEST";
+ break;
+ case OFPT_QUEUE_GET_CONFIG_REPLY:
+ name = "QUEUE_GET_CONFIG_REPLY";
+ break;
+ default:
+ name = NULL;
+ break;
}
- return ds_cstr(&s);
+
+ return name ? xasprintf("OFPT_%s", name) : xasprintf("0x%02"PRIx8, type);
}
\f
static void
static uint32_t next_xid = 1;
return htonl(next_xid++);
}
+\f
+/* Basic parsing of OpenFlow messages. */
+
+struct ofputil_msg_type {
+ enum ofputil_msg_code code; /* OFPUTIL_*. */
+ uint32_t value; /* OFPT_*, OFPST_*, NXT_*, or NXST_*. */
+ const char *name; /* e.g. "OFPT_FLOW_REMOVED". */
+ unsigned int min_size; /* Minimum total message size in bytes. */
+ /* 0 if 'min_size' is the exact size that the message must be. Otherwise,
+ * the message may exceed 'min_size' by an even multiple of this value. */
+ unsigned int extra_multiple;
+};
+
+struct ofputil_msg_category {
+ const char *name; /* e.g. "OpenFlow message" */
+ const struct ofputil_msg_type *types;
+ size_t n_types;
+ int missing_error; /* ofp_mkerr() value for missing type. */
+};
+
+static bool
+ofputil_length_ok(const struct ofputil_msg_category *cat,
+ const struct ofputil_msg_type *type,
+ unsigned int size)
+{
+ switch (type->extra_multiple) {
+ case 0:
+ if (size != type->min_size) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "received %s %s with incorrect "
+ "length %u (expected length %u)",
+ cat->name, type->name, size, type->min_size);
+ return false;
+ }
+ return true;
+
+ case 1:
+ if (size < type->min_size) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "received %s %s with incorrect "
+ "length %u (expected length at least %u bytes)",
+ cat->name, type->name, size, type->min_size);
+ return false;
+ }
+ return true;
+
+ default:
+ if (size < type->min_size
+ || (size - type->min_size) % type->extra_multiple) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "received %s %s with incorrect "
+ "length %u (must be exactly %u bytes or longer "
+ "by an integer multiple of %u bytes)",
+ cat->name, type->name, size,
+ type->min_size, type->extra_multiple);
+ return false;
+ }
+ return true;
+ }
+}
+
+static int
+ofputil_lookup_openflow_message(const struct ofputil_msg_category *cat,
+ uint32_t value, unsigned int size,
+ const struct ofputil_msg_type **typep)
+{
+ const struct ofputil_msg_type *type;
+
+ for (type = cat->types; type < &cat->types[cat->n_types]; type++) {
+ if (type->value == value) {
+ if (!ofputil_length_ok(cat, type, size)) {
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+ }
+ *typep = type;
+ return 0;
+ }
+ }
+
+ VLOG_WARN_RL(&bad_ofmsg_rl, "received %s of unknown type %u",
+ cat->name, value);
+ return cat->missing_error;
+}
+
+static int
+ofputil_decode_vendor(const struct ofp_header *oh,
+ const struct ofputil_msg_type **typep)
+{
+ static const struct ofputil_msg_type nxt_messages[] = {
+ { OFPUTIL_NXT_STATUS_REQUEST,
+ NXT_STATUS_REQUEST, "NXT_STATUS_REQUEST",
+ sizeof(struct nicira_header), 1 },
+
+ { OFPUTIL_NXT_STATUS_REPLY,
+ NXT_STATUS_REPLY, "NXT_STATUS_REPLY",
+ sizeof(struct nicira_header), 1 },
+
+ { OFPUTIL_NXT_TUN_ID_FROM_COOKIE,
+ NXT_TUN_ID_FROM_COOKIE, "NXT_TUN_ID_FROM_COOKIE",
+ sizeof(struct nxt_tun_id_cookie), 0 },
+
+ { OFPUTIL_NXT_ROLE_REQUEST,
+ NXT_ROLE_REQUEST, "NXT_ROLE_REQUEST",
+ sizeof(struct nx_role_request), 0 },
+
+ { OFPUTIL_NXT_ROLE_REPLY,
+ NXT_ROLE_REPLY, "NXT_ROLE_REPLY",
+ sizeof(struct nx_role_request), 0 },
+
+ { OFPUTIL_NXT_SET_FLOW_FORMAT,
+ NXT_SET_FLOW_FORMAT, "NXT_SET_FLOW_FORMAT",
+ sizeof(struct nxt_set_flow_format), 0 },
+
+ { OFPUTIL_NXT_FLOW_MOD,
+ NXT_FLOW_MOD, "NXT_FLOW_MOD",
+ sizeof(struct nx_flow_mod), 8 },
+
+ { OFPUTIL_NXT_FLOW_REMOVED,
+ NXT_FLOW_REMOVED, "NXT_FLOW_REMOVED",
+ sizeof(struct nx_flow_removed), 8 },
+ };
+
+ static const struct ofputil_msg_category nxt_category = {
+ "Nicira extension message",
+ nxt_messages, ARRAY_SIZE(nxt_messages),
+ OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE)
+ };
+
+ const struct ofp_vendor_header *ovh;
+ const struct nicira_header *nh;
+
+ ovh = (const struct ofp_vendor_header *) oh;
+ if (ovh->vendor != htonl(NX_VENDOR_ID)) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "received vendor message for unknown "
+ "vendor %"PRIx32, ntohl(ovh->vendor));
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
+ }
+
+ if (ntohs(ovh->header.length) < sizeof(struct nicira_header)) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "received Nicira vendor message of "
+ "length %u (expected at least %zu)",
+ ntohs(ovh->header.length), sizeof(struct nicira_header));
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+ }
+
+ nh = (const struct nicira_header *) oh;
+ return ofputil_lookup_openflow_message(&nxt_category, ntohl(nh->subtype),
+ ntohs(oh->length), typep);
+}
+
+static int
+check_nxstats_msg(const struct ofp_header *oh)
+{
+ const struct ofp_stats_request *osr;
+ ovs_be32 vendor;
+
+ osr = (const struct ofp_stats_request *) oh;
+
+ memcpy(&vendor, osr->body, sizeof vendor);
+ if (vendor != htonl(NX_VENDOR_ID)) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "received vendor stats message for "
+ "unknown vendor %"PRIx32, ntohl(vendor));
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
+ }
+
+ if (ntohs(osr->header.length) < sizeof(struct nicira_stats_msg)) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "truncated Nicira stats message");
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+ }
+
+ return 0;
+}
+
+static int
+ofputil_decode_nxst_request(const struct ofp_header *oh,
+ const struct ofputil_msg_type **typep)
+{
+ static const struct ofputil_msg_type nxst_requests[] = {
+ { OFPUTIL_NXST_FLOW_REQUEST,
+ NXST_FLOW, "NXST_FLOW request",
+ sizeof(struct nx_flow_stats_request), 8 },
+
+ { OFPUTIL_NXST_AGGREGATE_REQUEST,
+ NXST_AGGREGATE, "NXST_AGGREGATE request",
+ sizeof(struct nx_aggregate_stats_request), 8 },
+ };
+
+ static const struct ofputil_msg_category nxst_request_category = {
+ "Nicira extension statistics",
+ nxst_requests, ARRAY_SIZE(nxst_requests),
+ OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE)
+ };
+
+ const struct nicira_stats_msg *nsm;
+ int error;
+
+ error = check_nxstats_msg(oh);
+ if (error) {
+ return error;
+ }
+
+ nsm = (struct nicira_stats_msg *) oh;
+ return ofputil_lookup_openflow_message(&nxst_request_category,
+ ntohl(nsm->subtype),
+ ntohs(oh->length), typep);
+}
+
+static int
+ofputil_decode_nxst_reply(const struct ofp_header *oh,
+ const struct ofputil_msg_type **typep)
+{
+ static const struct ofputil_msg_type nxst_replies[] = {
+ { OFPUTIL_NXST_FLOW_REPLY,
+ NXST_FLOW, "NXST_FLOW reply",
+ sizeof(struct nicira_stats_msg), 8 },
+
+ { OFPUTIL_NXST_AGGREGATE_REPLY,
+ NXST_AGGREGATE, "NXST_AGGREGATE reply",
+ sizeof(struct nx_aggregate_stats_reply), 0 },
+ };
+
+ static const struct ofputil_msg_category nxst_reply_category = {
+ "Nicira extension statistics",
+ nxst_replies, ARRAY_SIZE(nxst_replies),
+ OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE)
+ };
+
+ const struct nicira_stats_msg *nsm;
+ int error;
+
+ error = check_nxstats_msg(oh);
+ if (error) {
+ return error;
+ }
+
+ nsm = (struct nicira_stats_msg *) oh;
+ return ofputil_lookup_openflow_message(&nxst_reply_category,
+ ntohl(nsm->subtype),
+ ntohs(oh->length), typep);
+}
+
+static int
+ofputil_decode_ofpst_request(const struct ofp_header *oh,
+ const struct ofputil_msg_type **typep)
+{
+ enum { OSR_SIZE = sizeof(struct ofp_stats_request) };
+ static const struct ofputil_msg_type ofpst_requests[] = {
+ { OFPUTIL_OFPST_DESC_REQUEST,
+ OFPST_DESC, "OFPST_DESC request",
+ OSR_SIZE, 0 },
+
+ { OFPUTIL_OFPST_FLOW_REQUEST,
+ OFPST_FLOW, "OFPST_FLOW request",
+ OSR_SIZE + sizeof(struct ofp_flow_stats_request), 0 },
+
+ { OFPUTIL_OFPST_AGGREGATE_REQUEST,
+ OFPST_AGGREGATE, "OFPST_AGGREGATE request",
+ OSR_SIZE + sizeof(struct ofp_aggregate_stats_request), 0 },
+
+ { OFPUTIL_OFPST_TABLE_REQUEST,
+ OFPST_TABLE, "OFPST_TABLE request",
+ OSR_SIZE, 0 },
+
+ { OFPUTIL_OFPST_PORT_REQUEST,
+ OFPST_PORT, "OFPST_PORT request",
+ OSR_SIZE + sizeof(struct ofp_port_stats_request), 0 },
+
+ { OFPUTIL_OFPST_QUEUE_REQUEST,
+ OFPST_QUEUE, "OFPST_QUEUE request",
+ OSR_SIZE + sizeof(struct ofp_queue_stats_request), 0 },
+
+ { 0,
+ OFPST_VENDOR, "OFPST_VENDOR request",
+ OSR_SIZE + sizeof(uint32_t), 1 },
+ };
+
+ static const struct ofputil_msg_category ofpst_request_category = {
+ "OpenFlow statistics",
+ ofpst_requests, ARRAY_SIZE(ofpst_requests),
+ OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT)
+ };
+
+ const struct ofp_stats_request *osr;
+ int error;
+
+ osr = (const struct ofp_stats_request *) oh;
+ error = ofputil_lookup_openflow_message(&ofpst_request_category,
+ ntohs(osr->type),
+ ntohs(oh->length), typep);
+ if (!error && osr->type == htons(OFPST_VENDOR)) {
+ error = ofputil_decode_nxst_request(oh, typep);
+ }
+ return error;
+}
+
+static int
+ofputil_decode_ofpst_reply(const struct ofp_header *oh,
+ const struct ofputil_msg_type **typep)
+{
+ enum { OSR_SIZE = sizeof(struct ofp_stats_reply) };
+ static const struct ofputil_msg_type ofpst_replies[] = {
+ { OFPUTIL_OFPST_DESC_REPLY,
+ OFPST_DESC, "OFPST_DESC reply",
+ OSR_SIZE + sizeof(struct ofp_desc_stats), 0 },
+
+ { OFPUTIL_OFPST_FLOW_REPLY,
+ OFPST_FLOW, "OFPST_FLOW reply",
+ OSR_SIZE, 1 },
+
+ { OFPUTIL_OFPST_AGGREGATE_REPLY,
+ OFPST_AGGREGATE, "OFPST_AGGREGATE reply",
+ OSR_SIZE + sizeof(struct ofp_aggregate_stats_reply), 0 },
+
+ { OFPUTIL_OFPST_TABLE_REPLY,
+ OFPST_TABLE, "OFPST_TABLE reply",
+ OSR_SIZE, sizeof(struct ofp_table_stats) },
+
+ { OFPUTIL_OFPST_PORT_REPLY,
+ OFPST_PORT, "OFPST_PORT reply",
+ OSR_SIZE, sizeof(struct ofp_port_stats) },
+
+ { OFPUTIL_OFPST_QUEUE_REPLY,
+ OFPST_QUEUE, "OFPST_QUEUE reply",
+ OSR_SIZE, sizeof(struct ofp_queue_stats) },
+
+ { 0,
+ OFPST_VENDOR, "OFPST_VENDOR reply",
+ OSR_SIZE + sizeof(uint32_t), 1 },
+ };
+
+ static const struct ofputil_msg_category ofpst_reply_category = {
+ "OpenFlow statistics",
+ ofpst_replies, ARRAY_SIZE(ofpst_replies),
+ OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT)
+ };
+
+ const struct ofp_stats_reply *osr = (const struct ofp_stats_reply *) oh;
+ int error;
+
+ error = ofputil_lookup_openflow_message(&ofpst_reply_category,
+ ntohs(osr->type),
+ ntohs(oh->length), typep);
+ if (!error && osr->type == htons(OFPST_VENDOR)) {
+ error = ofputil_decode_nxst_reply(oh, typep);
+ }
+ return error;
+}
+
+/* Decodes the message type represented by 'oh'. Returns 0 if successful or
+ * an OpenFlow error code constructed with ofp_mkerr() on failure. Either
+ * way, stores in '*typep' a type structure that can be inspected with the
+ * ofputil_msg_type_*() functions.
+ *
+ * oh->length must indicate the correct length of the message (and must be at
+ * least sizeof(struct ofp_header)).
+ *
+ * Success indicates that 'oh' is at least as long as the minimum-length
+ * message of its type. */
+int
+ofputil_decode_msg_type(const struct ofp_header *oh,
+ const struct ofputil_msg_type **typep)
+{
+ static const struct ofputil_msg_type ofpt_messages[] = {
+ { OFPUTIL_OFPT_HELLO,
+ OFPT_HELLO, "OFPT_HELLO",
+ sizeof(struct ofp_hello), 1 },
+
+ { OFPUTIL_OFPT_ERROR,
+ OFPT_ERROR, "OFPT_ERROR",
+ sizeof(struct ofp_error_msg), 1 },
+
+ { OFPUTIL_OFPT_ECHO_REQUEST,
+ OFPT_ECHO_REQUEST, "OFPT_ECHO_REQUEST",
+ sizeof(struct ofp_header), 1 },
+
+ { OFPUTIL_OFPT_ECHO_REPLY,
+ OFPT_ECHO_REPLY, "OFPT_ECHO_REPLY",
+ sizeof(struct ofp_header), 1 },
+
+ { OFPUTIL_OFPT_FEATURES_REQUEST,
+ OFPT_FEATURES_REQUEST, "OFPT_FEATURES_REQUEST",
+ sizeof(struct ofp_header), 0 },
+
+ { OFPUTIL_OFPT_FEATURES_REPLY,
+ OFPT_FEATURES_REPLY, "OFPT_FEATURES_REPLY",
+ sizeof(struct ofp_switch_features), sizeof(struct ofp_phy_port) },
+
+ { OFPUTIL_OFPT_GET_CONFIG_REQUEST,
+ OFPT_GET_CONFIG_REQUEST, "OFPT_GET_CONFIG_REQUEST",
+ sizeof(struct ofp_header), 0 },
+
+ { OFPUTIL_OFPT_GET_CONFIG_REPLY,
+ OFPT_GET_CONFIG_REPLY, "OFPT_GET_CONFIG_REPLY",
+ sizeof(struct ofp_switch_config), 0 },
+
+ { OFPUTIL_OFPT_SET_CONFIG,
+ OFPT_SET_CONFIG, "OFPT_SET_CONFIG",
+ sizeof(struct ofp_switch_config), 0 },
+
+ { OFPUTIL_OFPT_PACKET_IN,
+ OFPT_PACKET_IN, "OFPT_PACKET_IN",
+ offsetof(struct ofp_packet_in, data), 1 },
+
+ { OFPUTIL_OFPT_FLOW_REMOVED,
+ OFPT_FLOW_REMOVED, "OFPT_FLOW_REMOVED",
+ sizeof(struct ofp_flow_removed), 0 },
+
+ { OFPUTIL_OFPT_PORT_STATUS,
+ OFPT_PORT_STATUS, "OFPT_PORT_STATUS",
+ sizeof(struct ofp_port_status), 0 },
+
+ { OFPUTIL_OFPT_PACKET_OUT,
+ OFPT_PACKET_OUT, "OFPT_PACKET_OUT",
+ sizeof(struct ofp_packet_out), 1 },
+
+ { OFPUTIL_OFPT_FLOW_MOD,
+ OFPT_FLOW_MOD, "OFPT_FLOW_MOD",
+ sizeof(struct ofp_flow_mod), 1 },
+
+ { OFPUTIL_OFPT_PORT_MOD,
+ OFPT_PORT_MOD, "OFPT_PORT_MOD",
+ sizeof(struct ofp_port_mod), 0 },
+
+ { 0,
+ OFPT_STATS_REQUEST, "OFPT_STATS_REQUEST",
+ sizeof(struct ofp_stats_request), 1 },
+
+ { 0,
+ OFPT_STATS_REPLY, "OFPT_STATS_REPLY",
+ sizeof(struct ofp_stats_reply), 1 },
+
+ { OFPUTIL_OFPT_BARRIER_REQUEST,
+ OFPT_BARRIER_REQUEST, "OFPT_BARRIER_REQUEST",
+ sizeof(struct ofp_header), 0 },
+
+ { OFPUTIL_OFPT_BARRIER_REPLY,
+ OFPT_BARRIER_REPLY, "OFPT_BARRIER_REPLY",
+ sizeof(struct ofp_header), 0 },
+
+ { 0,
+ OFPT_VENDOR, "OFPT_VENDOR",
+ sizeof(struct ofp_vendor_header), 1 },
+ };
+
+ static const struct ofputil_msg_category ofpt_category = {
+ "OpenFlow message",
+ ofpt_messages, ARRAY_SIZE(ofpt_messages),
+ OFP_MKERR(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE)
+ };
+
+ int error;
+
+ error = ofputil_lookup_openflow_message(&ofpt_category, oh->type,
+ ntohs(oh->length), typep);
+ if (!error) {
+ switch (oh->type) {
+ case OFPT_VENDOR:
+ error = ofputil_decode_vendor(oh, typep);
+ break;
+
+ case OFPT_STATS_REQUEST:
+ error = ofputil_decode_ofpst_request(oh, typep);
+ break;
+
+ case OFPT_STATS_REPLY:
+ error = ofputil_decode_ofpst_reply(oh, typep);
+
+ default:
+ break;
+ }
+ }
+ if (error) {
+ static const struct ofputil_msg_type ofputil_invalid_type = {
+ OFPUTIL_INVALID,
+ 0, "OFPUTIL_INVALID",
+ 0, 0
+ };
+
+ *typep = &ofputil_invalid_type;
+ }
+ return error;
+}
+/* Returns an OFPUTIL_* message type code for 'type'. */
+enum ofputil_msg_code
+ofputil_msg_type_code(const struct ofputil_msg_type *type)
+{
+ return type->code;
+}
+
+/* Returns a string representing the message type of 'type'. The string is the
+ * enumeration constant for the type, e.g. "OFPT_HELLO". For statistics
+ * messages, the constant is followed by "request" or "reply",
+ * e.g. "OFPST_AGGREGATE reply". */
+const char *
+ofputil_msg_type_name(const struct ofputil_msg_type *type)
+{
+ return type->name;
+}
+\f
/* Allocates and stores in '*bufferp' a new ofpbuf with a size of
* 'openflow_len', starting with an OpenFlow header with the given 'type' and
* an arbitrary transaction id. Allocated bytes beyond the header, if any, are
oh->length = htons(buffer->size);
}
+/* Returns the first byte of the 'body' member of the ofp_stats_request or
+ * ofp_stats_reply in 'oh'. */
+const void *
+ofputil_stats_body(const struct ofp_header *oh)
+{
+ assert(oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY);
+ return ((const struct ofp_stats_request *) oh)->body;
+}
+
+/* Returns the length of the 'body' member of the ofp_stats_request or
+ * ofp_stats_reply in 'oh'. */
+size_t
+ofputil_stats_body_len(const struct ofp_header *oh)
+{
+ assert(oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY);
+ return ntohs(oh->length) - sizeof(struct ofp_stats_request);
+}
+
struct ofpbuf *
make_flow_mod(uint16_t command, const struct cls_rule *rule,
size_t actions_len)
return out;
}
-static int
-check_message_type(uint8_t got_type, uint8_t want_type)
-{
- if (got_type != want_type) {
- char *want_type_name = ofp_message_type_to_string(want_type);
- char *got_type_name = ofp_message_type_to_string(got_type);
- VLOG_WARN_RL(&bad_ofmsg_rl,
- "received bad message type %s (expected %s)",
- got_type_name, want_type_name);
- free(want_type_name);
- free(got_type_name);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE);
- }
- return 0;
-}
-
-/* Checks that 'msg' has type 'type' and that it is exactly 'size' bytes long.
- * Returns 0 if the checks pass, otherwise an OpenFlow error code (produced
- * with ofp_mkerr()). */
-int
-check_ofp_message(const struct ofp_header *msg, uint8_t type, size_t size)
-{
- size_t got_size;
- int error;
-
- error = check_message_type(msg->type, type);
- if (error) {
- return error;
- }
-
- got_size = ntohs(msg->length);
- if (got_size != size) {
- char *type_name = ofp_message_type_to_string(type);
- VLOG_WARN_RL(&bad_ofmsg_rl,
- "received %s message of length %zu (expected %zu)",
- type_name, got_size, size);
- free(type_name);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
-
- return 0;
-}
-
-/* Checks that 'msg' has type 'type' and that 'msg' is 'size' plus a
- * nonnegative integer multiple of 'array_elt_size' bytes long. Returns 0 if
- * the checks pass, otherwise an OpenFlow error code (produced with
- * ofp_mkerr()).
- *
- * If 'n_array_elts' is nonnull, then '*n_array_elts' is set to the number of
- * 'array_elt_size' blocks in 'msg' past the first 'min_size' bytes, when
- * successful. */
-int
-check_ofp_message_array(const struct ofp_header *msg, uint8_t type,
- size_t min_size, size_t array_elt_size,
- size_t *n_array_elts)
-{
- size_t got_size;
- int error;
-
- assert(array_elt_size);
-
- error = check_message_type(msg->type, type);
- if (error) {
- return error;
- }
-
- got_size = ntohs(msg->length);
- if (got_size < min_size) {
- char *type_name = ofp_message_type_to_string(type);
- VLOG_WARN_RL(&bad_ofmsg_rl, "received %s message of length %zu "
- "(expected at least %zu)",
- type_name, got_size, min_size);
- free(type_name);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- if ((got_size - min_size) % array_elt_size) {
- char *type_name = ofp_message_type_to_string(type);
- VLOG_WARN_RL(&bad_ofmsg_rl,
- "received %s message of bad length %zu: the "
- "excess over %zu (%zu) is not evenly divisible by %zu "
- "(remainder is %zu)",
- type_name, got_size, min_size, got_size - min_size,
- array_elt_size, (got_size - min_size) % array_elt_size);
- free(type_name);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- if (n_array_elts) {
- *n_array_elts = (got_size - min_size) / array_elt_size;
- }
- return 0;
-}
-
const struct ofp_flow_stats *
flow_stats_first(struct flow_stats_iterator *iter,
const struct ofp_stats_reply *osr)
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include "classifier.h"
#include "flow.h"
#include "openflow/nicira-ext.h"
#include "openvswitch/types.h"
struct cls_rule;
struct ofpbuf;
-struct ofp_action_header;
/* Alignment of ofp_actions. */
#define OFP_ACTION_ALIGN 8
+/* Basic decoding and length validation of OpenFlow messages. */
+enum ofputil_msg_code {
+ OFPUTIL_INVALID,
+
+ /* OFPT_* messages. */
+ OFPUTIL_OFPT_HELLO,
+ OFPUTIL_OFPT_ERROR,
+ OFPUTIL_OFPT_ECHO_REQUEST,
+ OFPUTIL_OFPT_ECHO_REPLY,
+ OFPUTIL_OFPT_FEATURES_REQUEST,
+ OFPUTIL_OFPT_FEATURES_REPLY,
+ OFPUTIL_OFPT_GET_CONFIG_REQUEST,
+ OFPUTIL_OFPT_GET_CONFIG_REPLY,
+ OFPUTIL_OFPT_SET_CONFIG,
+ OFPUTIL_OFPT_PACKET_IN,
+ OFPUTIL_OFPT_FLOW_REMOVED,
+ OFPUTIL_OFPT_PORT_STATUS,
+ OFPUTIL_OFPT_PACKET_OUT,
+ OFPUTIL_OFPT_FLOW_MOD,
+ OFPUTIL_OFPT_PORT_MOD,
+ OFPUTIL_OFPT_BARRIER_REQUEST,
+ OFPUTIL_OFPT_BARRIER_REPLY,
+ OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST,
+ OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY,
+
+ /* OFPST_* stat requests. */
+ OFPUTIL_OFPST_DESC_REQUEST,
+ OFPUTIL_OFPST_FLOW_REQUEST,
+ OFPUTIL_OFPST_AGGREGATE_REQUEST,
+ OFPUTIL_OFPST_TABLE_REQUEST,
+ OFPUTIL_OFPST_PORT_REQUEST,
+ OFPUTIL_OFPST_QUEUE_REQUEST,
+
+ /* OFPST_* stat replies. */
+ OFPUTIL_OFPST_DESC_REPLY,
+ OFPUTIL_OFPST_FLOW_REPLY,
+ OFPUTIL_OFPST_QUEUE_REPLY,
+ OFPUTIL_OFPST_PORT_REPLY,
+ OFPUTIL_OFPST_TABLE_REPLY,
+ OFPUTIL_OFPST_AGGREGATE_REPLY,
+
+ /* NXT_* messages. */
+ OFPUTIL_NXT_STATUS_REQUEST,
+ OFPUTIL_NXT_STATUS_REPLY,
+ OFPUTIL_NXT_TUN_ID_FROM_COOKIE,
+ OFPUTIL_NXT_ROLE_REQUEST,
+ OFPUTIL_NXT_ROLE_REPLY,
+ OFPUTIL_NXT_SET_FLOW_FORMAT,
+ OFPUTIL_NXT_FLOW_MOD,
+ OFPUTIL_NXT_FLOW_REMOVED,
+
+ /* NXST_* stat requests. */
+ OFPUTIL_NXST_FLOW_REQUEST,
+ OFPUTIL_NXST_AGGREGATE_REQUEST,
+
+ /* NXST_* stat replies. */
+ OFPUTIL_NXST_FLOW_REPLY,
+ OFPUTIL_NXST_AGGREGATE_REPLY
+};
+
+struct ofputil_msg_type;
+int ofputil_decode_msg_type(const struct ofp_header *,
+ const struct ofputil_msg_type **);
+enum ofputil_msg_code ofputil_msg_type_code(const struct ofputil_msg_type *);
+const char *ofputil_msg_type_name(const struct ofputil_msg_type *);
+
/* Converting OFPFW_NW_SRC_MASK and OFPFW_NW_DST_MASK wildcard bit counts to
* and from IP bitmasks. */
ovs_be32 ofputil_wcbits_to_netmask(int wcbits);
void *put_openflow_xid(size_t openflow_len, uint8_t type, ovs_be32 xid,
struct ofpbuf *);
void update_openflow_length(struct ofpbuf *);
+
+const void *ofputil_stats_body(const struct ofp_header *);
+size_t ofputil_stats_body_len(const struct ofp_header *oh);
+
struct ofpbuf *make_flow_mod(uint16_t command, const struct cls_rule *,
size_t actions_len);
struct ofpbuf *make_add_flow(const struct cls_rule *, uint32_t buffer_id,
uint16_t in_port, uint16_t out_port);
struct ofpbuf *make_echo_request(void);
struct ofpbuf *make_echo_reply(const struct ofp_header *rq);
-int check_ofp_message(const struct ofp_header *, uint8_t type, size_t size);
-int check_ofp_message_array(const struct ofp_header *, uint8_t type,
- size_t size, size_t array_elt_size,
- size_t *n_array_elts);
struct flow_stats_iterator {
const uint8_t *pos, *end;
}
static int
-handle_echo_request(struct ofconn *ofconn, struct ofp_header *oh)
+handle_echo_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
- struct ofp_header *rq = oh;
- queue_tx(make_echo_reply(rq), ofconn, ofconn->reply_counter);
+ queue_tx(make_echo_reply(oh), ofconn, ofconn->reply_counter);
return 0;
}
static int
-handle_features_request(struct ofconn *ofconn, struct ofp_header *oh)
+handle_features_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofp_switch_features *osf;
struct ofpbuf *buf;
}
static int
-handle_get_config_request(struct ofconn *ofconn, struct ofp_header *oh)
+handle_get_config_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofpbuf *buf;
struct ofp_switch_config *osc;
}
static int
-handle_set_config(struct ofconn *ofconn, struct ofp_switch_config *osc)
+handle_set_config(struct ofconn *ofconn, const struct ofp_switch_config *osc)
{
- uint16_t flags;
- int error;
-
- error = check_ofp_message(&osc->header, OFPT_SET_CONFIG, sizeof *osc);
- if (error) {
- return error;
- }
- flags = ntohs(osc->flags);
+ uint16_t flags = ntohs(osc->flags);
if (ofconn->type == OFCONN_PRIMARY && ofconn->role != NX_ROLE_SLAVE) {
switch (flags & OFPC_FRAG_MASK) {
}
static int
-handle_packet_out(struct ofconn *ofconn, struct ofp_header *oh)
+handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofproto *p = ofconn->ofproto;
struct ofp_packet_out *opo;
}
/* Get ofp_packet_out. */
- request.data = oh;
+ request.data = (void *) oh;
request.size = ntohs(oh->length);
opo = ofpbuf_try_pull(&request, offsetof(struct ofp_packet_out, actions));
if (!opo) {
}
static int
-handle_port_mod(struct ofconn *ofconn, struct ofp_header *oh)
+handle_port_mod(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofproto *p = ofconn->ofproto;
- const struct ofp_port_mod *opm;
+ const struct ofp_port_mod *opm = (const struct ofp_port_mod *) oh;
struct ofport *port;
int error;
if (error) {
return error;
}
- error = check_ofp_message(oh, OFPT_PORT_MOD, sizeof *opm);
- if (error) {
- return error;
- }
- opm = (struct ofp_port_mod *) oh;
port = get_port(p, ofp_port_to_odp_port(ntohs(opm->port_no)));
if (!port) {
}
static struct ofpbuf *
-start_ofp_stats_reply(const struct ofp_stats_request *request, size_t body_len)
+start_ofp_stats_reply(const struct ofp_header *request, size_t body_len)
{
- return make_ofp_stats_reply(request->header.xid, request->type, body_len);
+ const struct ofp_stats_request *osr
+ = (const struct ofp_stats_request *) request;
+ return make_ofp_stats_reply(osr->header.xid, osr->type, body_len);
}
static void *
static int
handle_desc_stats_request(struct ofconn *ofconn,
- struct ofp_stats_request *request)
+ const struct ofp_header *request)
{
struct ofproto *p = ofconn->ofproto;
struct ofp_desc_stats *ods;
static int
handle_table_stats_request(struct ofconn *ofconn,
- struct ofp_stats_request *request)
+ const struct ofp_header *request)
{
struct ofproto *p = ofconn->ofproto;
struct ofp_table_stats *ots;
}
static int
-handle_port_stats_request(struct ofconn *ofconn, struct ofp_stats_request *osr,
- size_t arg_size)
+handle_port_stats_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofproto *p = ofconn->ofproto;
- struct ofp_port_stats_request *psr;
+ const struct ofp_port_stats_request *psr = ofputil_stats_body(oh);
struct ofp_port_stats *ops;
struct ofpbuf *msg;
struct ofport *port;
- if (arg_size != sizeof *psr) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- psr = (struct ofp_port_stats_request *) osr->body;
-
- msg = start_ofp_stats_reply(osr, sizeof *ops * 16);
+ msg = start_ofp_stats_reply(oh, sizeof *ops * 16);
if (psr->port_no != htons(OFPP_NONE)) {
port = get_port(p, ofp_port_to_odp_port(ntohs(psr->port_no)));
if (port) {
}
static int
-handle_flow_stats_request(struct ofconn *ofconn,
- const struct ofp_stats_request *osr, size_t arg_size)
+handle_flow_stats_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
- struct ofp_flow_stats_request *fsr;
+ const struct ofp_flow_stats_request *fsr = ofputil_stats_body(oh);
struct ofpbuf *reply;
- if (arg_size != sizeof *fsr) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- fsr = (struct ofp_flow_stats_request *) osr->body;
-
COVERAGE_INC(ofproto_flows_req);
- reply = start_ofp_stats_reply(osr, 1024);
+ reply = start_ofp_stats_reply(oh, 1024);
if (is_valid_table(fsr->table_id)) {
struct cls_cursor cursor;
struct cls_rule target;
}
static int
-handle_nxst_flow(struct ofconn *ofconn, struct ofpbuf *b)
+handle_nxst_flow(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct nx_flow_stats_request *nfsr;
struct cls_rule target;
struct ofpbuf *reply;
+ struct ofpbuf b;
int error;
+ b.data = (void *) oh;
+ b.size = ntohs(oh->length);
+
/* Dissect the message. */
- nfsr = ofpbuf_try_pull(b, sizeof *nfsr);
+ nfsr = ofpbuf_try_pull(&b, sizeof *nfsr);
if (!nfsr) {
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
- error = nx_pull_match(b, ntohs(nfsr->match_len), 0, &target);
+ error = nx_pull_match(&b, ntohs(nfsr->match_len), 0, &target);
if (error) {
return error;
}
+ if (b.size) {
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+ }
COVERAGE_INC(ofproto_flows_req);
reply = start_nxstats_reply(&nfsr->nsm, 1024);
static int
handle_aggregate_stats_request(struct ofconn *ofconn,
- const struct ofp_stats_request *osr,
- size_t arg_size)
+ const struct ofp_header *oh)
{
- struct ofp_aggregate_stats_request *request;
+ const struct ofp_aggregate_stats_request *request = ofputil_stats_body(oh);
struct ofp_aggregate_stats_reply *reply;
struct cls_rule target;
struct ofpbuf *msg;
- if (arg_size != sizeof *request) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- request = (struct ofp_aggregate_stats_request *) osr->body;
-
ofputil_cls_rule_from_match(&request->match, 0, NXFF_OPENFLOW10, 0,
&target);
- msg = start_ofp_stats_reply(osr, sizeof *reply);
+ msg = start_ofp_stats_reply(oh, sizeof *reply);
reply = append_ofp_stats_reply(sizeof *reply, ofconn, &msg);
query_aggregate_stats(ofconn->ofproto, &target, request->out_port,
request->table_id, reply);
}
static int
-handle_nxst_aggregate(struct ofconn *ofconn, struct ofpbuf *b)
+handle_nxst_aggregate(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct nx_aggregate_stats_request *request;
struct ofp_aggregate_stats_reply *reply;
struct cls_rule target;
+ struct ofpbuf b;
struct ofpbuf *buf;
int error;
+ b.data = (void *) oh;
+ b.size = ntohs(oh->length);
+
/* Dissect the message. */
- request = ofpbuf_try_pull(b, sizeof *request);
+ request = ofpbuf_try_pull(&b, sizeof *request);
if (!request) {
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
- error = nx_pull_match(b, ntohs(request->match_len), 0, &target);
+ error = nx_pull_match(&b, ntohs(request->match_len), 0, &target);
if (error) {
return error;
}
+ if (b.size) {
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+ }
/* Reply. */
COVERAGE_INC(ofproto_flows_req);
}
static int
-handle_queue_stats_request(struct ofconn *ofconn,
- const struct ofp_stats_request *osr,
- size_t arg_size)
+handle_queue_stats_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofproto *ofproto = ofconn->ofproto;
- struct ofp_queue_stats_request *qsr;
+ const struct ofp_queue_stats_request *qsr;
struct queue_stats_cbdata cbdata;
struct ofport *port;
unsigned int port_no;
uint32_t queue_id;
- if (arg_size != sizeof *qsr) {
+ qsr = ofputil_stats_body(oh);
+ if (!qsr) {
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
- qsr = (struct ofp_queue_stats_request *) osr->body;
COVERAGE_INC(ofproto_queue_req);
cbdata.ofconn = ofconn;
- cbdata.msg = start_ofp_stats_reply(osr, 128);
+ cbdata.msg = start_ofp_stats_reply(oh, 128);
port_no = ntohs(qsr->port_no);
queue_id = ntohl(qsr->queue_id);
return 0;
}
-static int
-handle_vendor_stats_request(struct ofconn *ofconn,
- struct ofp_stats_request *osr, size_t arg_size)
-{
- struct nicira_stats_msg *nsm;
- struct ofpbuf b;
- ovs_be32 vendor;
-
- if (arg_size < 4) {
- VLOG_WARN_RL(&rl, "truncated vendor stats request body");
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
-
- memcpy(&vendor, osr->body, sizeof vendor);
- if (vendor != htonl(NX_VENDOR_ID)) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
- }
-
- if (ntohs(osr->header.length) < sizeof(struct nicira_stats_msg)) {
- VLOG_WARN_RL(&rl, "truncated Nicira stats request");
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
-
- nsm = (struct nicira_stats_msg *) osr;
- b.data = nsm;
- b.size = ntohs(nsm->header.length);
- switch (ntohl(nsm->subtype)) {
- case NXST_FLOW:
- return handle_nxst_flow(ofconn, &b);
-
- case NXST_AGGREGATE:
- return handle_nxst_aggregate(ofconn, &b);
-
- default:
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
- }
-}
-
-static int
-handle_stats_request(struct ofconn *ofconn, struct ofp_header *oh)
-{
- struct ofp_stats_request *osr;
- size_t arg_size;
- int error;
-
- error = check_ofp_message_array(oh, OFPT_STATS_REQUEST, sizeof *osr,
- 1, &arg_size);
- if (error) {
- return error;
- }
- osr = (struct ofp_stats_request *) oh;
-
- switch (ntohs(osr->type)) {
- case OFPST_DESC:
- return handle_desc_stats_request(ofconn, osr);
-
- case OFPST_FLOW:
- return handle_flow_stats_request(ofconn, osr, arg_size);
-
- case OFPST_AGGREGATE:
- return handle_aggregate_stats_request(ofconn, osr, arg_size);
-
- case OFPST_TABLE:
- return handle_table_stats_request(ofconn, osr);
-
- case OFPST_PORT:
- return handle_port_stats_request(ofconn, osr, arg_size);
-
- case OFPST_QUEUE:
- return handle_queue_stats_request(ofconn, osr, arg_size);
-
- case OFPST_VENDOR:
- return handle_vendor_stats_request(ofconn, osr, arg_size);
-
- default:
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT);
- }
-}
-
static long long int
msec_from_nsec(uint64_t sec, uint32_t nsec)
{
}
static int
-handle_ofpt_flow_mod(struct ofconn *ofconn, struct ofp_header *oh)
+handle_ofpt_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofp_match orig_match;
struct ofp_flow_mod *ofm;
struct ofpbuf b;
int error;
- b.data = oh;
+ b.data = (void *) oh;
b.size = ntohs(oh->length);
/* Dissect the message. */
}
static int
-handle_nxt_flow_mod(struct ofconn *ofconn, struct ofp_header *oh)
+handle_nxt_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct nx_flow_mod *nfm;
struct flow_mod fm;
struct ofpbuf b;
int error;
- b.data = oh;
+ b.data = (void *) oh;
b.size = ntohs(oh->length);
/* Dissect the message. */
}
static int
-handle_tun_id_from_cookie(struct ofconn *ofconn, struct nxt_tun_id_cookie *msg)
+handle_tun_id_from_cookie(struct ofconn *ofconn, const struct ofp_header *oh)
{
- int error;
-
- error = check_ofp_message(&msg->header, OFPT_VENDOR, sizeof *msg);
- if (error) {
- return error;
- }
+ const struct nxt_tun_id_cookie *msg
+ = (const struct nxt_tun_id_cookie *) oh;
ofconn->flow_format = msg->set ? NXFF_TUN_ID_FROM_COOKIE : NXFF_OPENFLOW10;
return 0;
}
static int
-handle_role_request(struct ofconn *ofconn, struct nicira_header *msg)
+handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
- struct nx_role_request *nrr;
+ struct nx_role_request *nrr = (struct nx_role_request *) oh;
struct nx_role_request *reply;
struct ofpbuf *buf;
uint32_t role;
- if (ntohs(msg->header.length) != sizeof *nrr) {
- VLOG_WARN_RL(&rl, "received role request of length %u (expected %zu)",
- ntohs(msg->header.length), sizeof *nrr);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- nrr = (struct nx_role_request *) msg;
-
if (ofconn->type != OFCONN_PRIMARY) {
VLOG_WARN_RL(&rl, "ignoring role request on non-controller "
"connection");
}
ofconn->role = role;
- reply = make_nxmsg_xid(sizeof *reply, NXT_ROLE_REPLY, msg->header.xid,
- &buf);
+ reply = make_nxmsg_xid(sizeof *reply, NXT_ROLE_REPLY, oh->xid, &buf);
reply->role = htonl(role);
queue_tx(buf, ofconn, ofconn->reply_counter);
}
static int
-handle_nxt_set_flow_format(struct ofconn *ofconn,
- struct nxt_set_flow_format *msg)
+handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
{
+ const struct nxt_set_flow_format *msg
+ = (const struct nxt_set_flow_format *) oh;
uint32_t format;
- int error;
-
- error = check_ofp_message(&msg->header, OFPT_VENDOR, sizeof *msg);
- if (error) {
- return error;
- }
format = ntohl(msg->format);
if (format == NXFF_OPENFLOW10
}
static int
-handle_vendor(struct ofconn *ofconn, void *msg)
-{
- struct ofproto *p = ofconn->ofproto;
- struct ofp_vendor_header *ovh = msg;
- struct nicira_header *nh;
-
- if (ntohs(ovh->header.length) < sizeof(struct ofp_vendor_header)) {
- VLOG_WARN_RL(&rl, "received vendor message of length %u "
- "(expected at least %zu)",
- ntohs(ovh->header.length), sizeof(struct ofp_vendor_header));
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
- if (ovh->vendor != htonl(NX_VENDOR_ID)) {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
- }
- if (ntohs(ovh->header.length) < sizeof(struct nicira_header)) {
- VLOG_WARN_RL(&rl, "received Nicira vendor message of length %u "
- "(expected at least %zu)",
- ntohs(ovh->header.length), sizeof(struct nicira_header));
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
- }
-
- nh = msg;
- switch (ntohl(nh->subtype)) {
- case NXT_STATUS_REQUEST:
- return switch_status_handle_request(p->switch_status, ofconn->rconn,
- msg);
-
- case NXT_TUN_ID_FROM_COOKIE:
- return handle_tun_id_from_cookie(ofconn, msg);
-
- case NXT_ROLE_REQUEST:
- return handle_role_request(ofconn, msg);
-
- case NXT_SET_FLOW_FORMAT:
- return handle_nxt_set_flow_format(ofconn, msg);
-
- case NXT_FLOW_MOD:
- return handle_nxt_flow_mod(ofconn, &ovh->header);
- }
-
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
-}
-
-static int
-handle_barrier_request(struct ofconn *ofconn, struct ofp_header *oh)
+handle_barrier_request(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofp_header *ob;
struct ofpbuf *buf;
return 0;
}
-static void
-handle_openflow(struct ofconn *ofconn, struct ofpbuf *ofp_msg)
+static int
+handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
{
- struct ofp_header *oh = ofp_msg->data;
+ const struct ofp_header *oh = msg->data;
+ const struct ofputil_msg_type *type;
int error;
- COVERAGE_INC(ofproto_recv_openflow);
- switch (oh->type) {
- case OFPT_ECHO_REQUEST:
- error = handle_echo_request(ofconn, oh);
- break;
+ error = ofputil_decode_msg_type(oh, &type);
+ if (error) {
+ return error;
+ }
- case OFPT_ECHO_REPLY:
- error = 0;
- break;
+ switch (ofputil_msg_type_code(type)) {
+ /* OpenFlow requests. */
+ case OFPUTIL_OFPT_ECHO_REQUEST:
+ return handle_echo_request(ofconn, oh);
- case OFPT_FEATURES_REQUEST:
- error = handle_features_request(ofconn, oh);
- break;
+ case OFPUTIL_OFPT_FEATURES_REQUEST:
+ return handle_features_request(ofconn, oh);
- case OFPT_GET_CONFIG_REQUEST:
- error = handle_get_config_request(ofconn, oh);
- break;
+ case OFPUTIL_OFPT_GET_CONFIG_REQUEST:
+ return handle_get_config_request(ofconn, oh);
- case OFPT_SET_CONFIG:
- error = handle_set_config(ofconn, ofp_msg->data);
- break;
+ case OFPUTIL_OFPT_SET_CONFIG:
+ return handle_set_config(ofconn, msg->data);
- case OFPT_PACKET_OUT:
- error = handle_packet_out(ofconn, ofp_msg->data);
- break;
+ case OFPUTIL_OFPT_PACKET_OUT:
+ return handle_packet_out(ofconn, oh);
- case OFPT_PORT_MOD:
- error = handle_port_mod(ofconn, oh);
- break;
-
- case OFPT_FLOW_MOD:
- error = handle_ofpt_flow_mod(ofconn, ofp_msg->data);
- break;
+ case OFPUTIL_OFPT_PORT_MOD:
+ return handle_port_mod(ofconn, oh);
- case OFPT_STATS_REQUEST:
- error = handle_stats_request(ofconn, oh);
- break;
+ case OFPUTIL_OFPT_FLOW_MOD:
+ return handle_ofpt_flow_mod(ofconn, oh);
- case OFPT_VENDOR:
- error = handle_vendor(ofconn, ofp_msg->data);
- break;
+ case OFPUTIL_OFPT_BARRIER_REQUEST:
+ return handle_barrier_request(ofconn, oh);
- case OFPT_BARRIER_REQUEST:
- error = handle_barrier_request(ofconn, oh);
- break;
+ /* OpenFlow replies. */
+ case OFPUTIL_OFPT_ECHO_REPLY:
+ return 0;
+ /* Nicira extension requests. */
+ case OFPUTIL_NXT_STATUS_REQUEST:
+ return switch_status_handle_request(
+ ofconn->ofproto->switch_status, ofconn->rconn, oh);
+
+ case OFPUTIL_NXT_TUN_ID_FROM_COOKIE:
+ return handle_tun_id_from_cookie(ofconn, oh);
+
+ case OFPUTIL_NXT_ROLE_REQUEST:
+ return handle_role_request(ofconn, oh);
+
+ case OFPUTIL_NXT_SET_FLOW_FORMAT:
+ return handle_nxt_set_flow_format(ofconn, oh);
+
+ case OFPUTIL_NXT_FLOW_MOD:
+ return handle_nxt_flow_mod(ofconn, oh);
+
+ /* OpenFlow statistics requests. */
+ case OFPUTIL_OFPST_DESC_REQUEST:
+ return handle_desc_stats_request(ofconn, oh);
+
+ case OFPUTIL_OFPST_FLOW_REQUEST:
+ return handle_flow_stats_request(ofconn, oh);
+
+ case OFPUTIL_OFPST_AGGREGATE_REQUEST:
+ return handle_aggregate_stats_request(ofconn, oh);
+
+ case OFPUTIL_OFPST_TABLE_REQUEST:
+ return handle_table_stats_request(ofconn, oh);
+
+ case OFPUTIL_OFPST_PORT_REQUEST:
+ return handle_port_stats_request(ofconn, oh);
+
+ case OFPUTIL_OFPST_QUEUE_REQUEST:
+ return handle_queue_stats_request(ofconn, oh);
+
+ /* Nicira extension statistics requests. */
+ case OFPUTIL_NXST_FLOW_REQUEST:
+ return handle_nxst_flow(ofconn, oh);
+
+ case OFPUTIL_NXST_AGGREGATE_REQUEST:
+ return handle_nxst_aggregate(ofconn, oh);
+
+ case OFPUTIL_INVALID:
+ case OFPUTIL_OFPT_HELLO:
+ case OFPUTIL_OFPT_ERROR:
+ case OFPUTIL_OFPT_FEATURES_REPLY:
+ case OFPUTIL_OFPT_GET_CONFIG_REPLY:
+ case OFPUTIL_OFPT_PACKET_IN:
+ case OFPUTIL_OFPT_FLOW_REMOVED:
+ case OFPUTIL_OFPT_PORT_STATUS:
+ case OFPUTIL_OFPT_BARRIER_REPLY:
+ case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REQUEST:
+ case OFPUTIL_OFPT_QUEUE_GET_CONFIG_REPLY:
+ case OFPUTIL_OFPST_DESC_REPLY:
+ case OFPUTIL_OFPST_FLOW_REPLY:
+ case OFPUTIL_OFPST_QUEUE_REPLY:
+ case OFPUTIL_OFPST_PORT_REPLY:
+ case OFPUTIL_OFPST_TABLE_REPLY:
+ case OFPUTIL_OFPST_AGGREGATE_REPLY:
+ case OFPUTIL_NXT_STATUS_REPLY:
+ case OFPUTIL_NXT_ROLE_REPLY:
+ case OFPUTIL_NXT_FLOW_REMOVED:
+ case OFPUTIL_NXST_FLOW_REPLY:
+ case OFPUTIL_NXST_AGGREGATE_REPLY:
default:
if (VLOG_IS_WARN_ENABLED()) {
char *s = ofp_to_string(oh, ntohs(oh->length), 2);
VLOG_DBG_RL(&rl, "OpenFlow message ignored: %s", s);
free(s);
}
- error = ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE);
- break;
+ if (oh->type == OFPT_STATS_REQUEST || oh->type == OFPT_STATS_REPLY) {
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT);
+ } else {
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE);
+ }
}
+}
+static void
+handle_openflow(struct ofconn *ofconn, struct ofpbuf *ofp_msg)
+{
+ int error = handle_openflow__(ofconn, ofp_msg);
if (error) {
send_error_oh(ofconn, ofp_msg->data, error);
}
+ COVERAGE_INC(ofproto_recv_openflow);
}
\f
static void
int
switch_status_handle_request(struct switch_status *ss, struct rconn *rconn,
- struct nicira_header *request)
+ const struct ofp_header *oh)
{
+ const struct nicira_header *request = (const struct nicira_header *) oh;
struct status_category *c;
struct nicira_header *reply;
struct status_reply sr;
/*
- * Copyright (c) 2008, 2009 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "compiler.h"
-struct nicira_header;
-struct rconn;
+struct ofp_header;
struct ofproto;
+struct rconn;
struct status_reply;
struct switch_status *switch_status_create(const struct ofproto *);
void switch_status_destroy(struct switch_status *);
int switch_status_handle_request(struct switch_status *, struct rconn *,
- struct nicira_header *);
+ const struct ofp_header *);
typedef void status_cb_func(struct status_reply *, void *aux);
struct status_category *switch_status_register(struct switch_status *,
OFPROTO_START
AT_CHECK([ovs-ofctl -vANY:ANY:WARN show br0], [0], [stdout])
AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [dnl
-features_reply: ver:0x1, dpid:fedcba9876543210
+OFPT_FEATURES_REPLY: ver:0x1, dpid:fedcba9876543210
n_tables:2, n_buffers:256
features: capabilities:0x87, actions:0xfff
LOCAL(br0): addr:aa:55:aa:55:00:00, config: 0x1, state:0x1
-get_config_reply: miss_send_len=0
+OFPT_GET_CONFIG_REPLY: miss_send_len=0
])
OFPROTO_STOP
AT_CLEANUP
AT_CHECK([ovs-ofctl -vANY:ANY:WARN mod-port br0 br0 $command])
AT_CHECK([ovs-ofctl -vANY:ANY:WARN show br0], [0], [stdout])
AT_CHECK_UNQUOTED([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [dnl
-features_reply: ver:0x1, dpid:fedcba9876543210
+OFPT_FEATURES_REPLY: ver:0x1, dpid:fedcba9876543210
n_tables:2, n_buffers:256
features: capabilities:0x87, actions:0xfff
LOCAL(br0): addr:aa:55:aa:55:00:00, config: $config, state:$state
-get_config_reply: miss_send_len=0
+OFPT_GET_CONFIG_REPLY: miss_send_len=0
])
done
OFPROTO_STOP
])
AT_CHECK([ovs-ofctl parse-flows flows.txt], [0], [stdout])
AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [dnl
-flow_mod: tcp,tp_src=123, ADD: actions=FLOOD
-flow_mod: in_port=65534,dl_vlan=9,dl_src=00:0a:e4:25:6b:b0, ADD: actions=drop
-flow_mod: arp,nw_src=192.168.0.1, ADD: actions=drop_spoofed_arp,NORMAL
-flow_mod: udp,dl_vlan_pcp=7, ADD: idle:5 actions=strip_vlan,output:0
-flow_mod: tcp,nw_src=192.168.0.3,tp_dst=80, ADD: actions=set_queue:37,output:1
-flow_mod: udp,nw_src=192.168.0.3,tp_dst=53, ADD: actions=pop_queue,output:1
-flow_mod: ADD: cookie:0x123456789abcdef hard:10 pri:60000 actions=CONTROLLER:65535
-flow_mod: ADD: actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
-flow_mod: ADD: actions=drop
+OFPT_FLOW_MOD: tcp,tp_src=123, ADD: actions=FLOOD
+OFPT_FLOW_MOD: in_port=65534,dl_vlan=9,dl_src=00:0a:e4:25:6b:b0, ADD: actions=drop
+OFPT_FLOW_MOD: arp,nw_src=192.168.0.1, ADD: actions=drop_spoofed_arp,NORMAL
+OFPT_FLOW_MOD: udp,dl_vlan_pcp=7, ADD: idle:5 actions=strip_vlan,output:0
+OFPT_FLOW_MOD: tcp,nw_src=192.168.0.3,tp_dst=80, ADD: actions=set_queue:37,output:1
+OFPT_FLOW_MOD: udp,nw_src=192.168.0.3,tp_dst=53, ADD: actions=pop_queue,output:1
+OFPT_FLOW_MOD: ADD: cookie:0x123456789abcdef hard:10 pri:60000 actions=CONTROLLER:65535
+OFPT_FLOW_MOD: ADD: actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
+OFPT_FLOW_MOD: ADD: actions=drop
])
AT_CLEANUP