ofm->out_group = htonl(OFPG11_ANY);
ofm->flags = htons(fm->flags);
oxm_put_match(msg, &fm->cr);
- if (fm->ofpacts) {
- ofpacts_put_openflow11_instructions(fm->ofpacts, fm->ofpacts_len,
- msg);
- }
+ ofpacts_put_openflow11_instructions(fm->ofpacts, fm->ofpacts_len, msg);
break;
}
ofm->buffer_id = htonl(fm->buffer_id);
ofm->out_port = htons(fm->out_port);
ofm->flags = htons(fm->flags);
- if (fm->ofpacts) {
- ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg);
- }
+ ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg);
break;
}
nfm->out_port = htons(fm->out_port);
nfm->flags = htons(fm->flags);
nfm->match_len = htons(match_len);
- if (fm->ofpacts) {
- ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg);
- }
+ ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg);
break;
}
}
static enum ofperr
-ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
- const struct ofp10_flow_stats_request *ofsr,
- bool aggregate)
+ofputil_decode_ofpst10_flow_request(struct ofputil_flow_stats_request *fsr,
+ const struct ofp10_flow_stats_request *ofsr,
+ bool aggregate)
{
fsr->aggregate = aggregate;
ofputil_cls_rule_from_ofp10_match(&ofsr->match, 0, &fsr->match);
return 0;
}
+static enum ofperr
+ofputil_decode_ofpst11_flow_request(struct ofputil_flow_stats_request *fsr,
+ struct ofpbuf *b, bool aggregate)
+{
+ const struct ofp11_flow_stats_request *ofsr;
+ enum ofperr error;
+
+ ofsr = ofpbuf_pull(b, sizeof *ofsr);
+ fsr->aggregate = aggregate;
+ fsr->table_id = ofsr->table_id;
+ error = ofputil_port_from_ofp11(ofsr->out_port, &fsr->out_port);
+ if (error) {
+ return error;
+ }
+ if (ofsr->out_group != htonl(OFPG11_ANY)) {
+ return OFPERR_NXFMFC_GROUPS_NOT_SUPPORTED;
+ }
+ fsr->cookie = ofsr->cookie;
+ fsr->cookie_mask = ofsr->cookie_mask;
+ error = ofputil_pull_ofp11_match(b, 0, &fsr->match, NULL);
+ if (error) {
+ return error;
+ }
+
+ return 0;
+}
+
static enum ofperr
ofputil_decode_nxst_flow_request(struct ofputil_flow_stats_request *fsr,
struct ofpbuf *b, bool aggregate)
ofpbuf_use_const(&b, oh, ntohs(oh->length));
raw = ofpraw_pull_assert(&b);
switch ((int) raw) {
- case OFPRAW_OFPST_FLOW_REQUEST:
- return ofputil_decode_ofpst_flow_request(fsr, b.data, false);
+ case OFPRAW_OFPST10_FLOW_REQUEST:
+ return ofputil_decode_ofpst10_flow_request(fsr, b.data, false);
+
+ case OFPRAW_OFPST10_AGGREGATE_REQUEST:
+ return ofputil_decode_ofpst10_flow_request(fsr, b.data, true);
+
+ case OFPRAW_OFPST11_FLOW_REQUEST:
+ return ofputil_decode_ofpst11_flow_request(fsr, &b, false);
- case OFPRAW_OFPST_AGGREGATE_REQUEST:
- return ofputil_decode_ofpst_flow_request(fsr, b.data, true);
+ case OFPRAW_OFPST11_AGGREGATE_REQUEST:
+ return ofputil_decode_ofpst11_flow_request(fsr, &b, true);
case OFPRAW_NXST_FLOW_REQUEST:
return ofputil_decode_nxst_flow_request(fsr, &b, false);
enum ofpraw raw;
switch (protocol) {
+ case OFPUTIL_P_OF12: {
+ struct ofp11_flow_stats_request *ofsr;
+
+ raw = (fsr->aggregate
+ ? OFPRAW_OFPST11_AGGREGATE_REQUEST
+ : OFPRAW_OFPST11_FLOW_REQUEST);
+ msg = ofpraw_alloc(raw, OFP12_VERSION, NXM_TYPICAL_LEN);
+ ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr);
+ ofsr->table_id = fsr->table_id;
+ ofsr->out_port = ofputil_port_to_ofp11(fsr->out_port);
+ ofsr->out_group = htonl(OFPG11_ANY);
+ ofsr->cookie = fsr->cookie;
+ ofsr->cookie_mask = fsr->cookie_mask;
+ oxm_put_match(msg, &fsr->match);
+ break;
+ }
+
case OFPUTIL_P_OF10:
case OFPUTIL_P_OF10_TID: {
struct ofp10_flow_stats_request *ofsr;
raw = (fsr->aggregate
- ? OFPRAW_OFPST_AGGREGATE_REQUEST
- : OFPRAW_OFPST_FLOW_REQUEST);
+ ? OFPRAW_OFPST10_AGGREGATE_REQUEST
+ : OFPRAW_OFPST10_FLOW_REQUEST);
msg = ofpraw_alloc(raw, OFP10_VERSION, 0);
ofsr = ofpbuf_put_zeros(msg, sizeof *ofsr);
ofputil_cls_rule_to_ofp10_match(&fsr->match, &ofsr->match);
raw = (fsr->aggregate
? OFPRAW_NXST_AGGREGATE_REQUEST
: OFPRAW_NXST_FLOW_REQUEST);
- msg = ofpraw_alloc(raw, OFP10_VERSION, 0);
+ msg = ofpraw_alloc(raw, OFP10_VERSION, NXM_TYPICAL_LEN);
ofpbuf_put_zeros(msg, sizeof *nfsr);
match_len = nx_put_match(msg, &fsr->match,
fsr->cookie, fsr->cookie_mask);
break;
}
- case OFPUTIL_P_OF12:
default:
NOT_REACHED();
}
if (!msg->size) {
return EOF;
- } else if (raw == OFPRAW_OFPST_FLOW_REPLY) {
+ } else if (raw == OFPRAW_OFPST11_FLOW_REPLY) {
+ const struct ofp11_flow_stats *ofs;
+ size_t length;
+ uint16_t padded_match_len;
+
+ ofs = ofpbuf_try_pull(msg, sizeof *ofs);
+ if (!ofs) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply has %zu leftover "
+ "bytes at end", msg->size);
+ return EINVAL;
+ }
+
+ length = ntohs(ofs->length);
+ if (length < sizeof *ofs) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply claims invalid "
+ "length %zu", length);
+ return EINVAL;
+ }
+
+ if (ofputil_pull_ofp11_match(msg, ntohs(ofs->priority), &fs->rule,
+ &padded_match_len)) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad match");
+ return EINVAL;
+ }
+
+ if (ofpacts_pull_openflow11_instructions(msg, length - sizeof *ofs -
+ padded_match_len, ofpacts)) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad instructions");
+ return EINVAL;
+ }
+
+ fs->table_id = ofs->table_id;
+ fs->duration_sec = ntohl(ofs->duration_sec);
+ fs->duration_nsec = ntohl(ofs->duration_nsec);
+ fs->idle_timeout = ntohs(ofs->idle_timeout);
+ fs->hard_timeout = ntohs(ofs->hard_timeout);
+ fs->idle_age = -1;
+ fs->hard_age = -1;
+ fs->cookie = ofs->cookie;
+ fs->packet_count = ntohll(ofs->packet_count);
+ fs->byte_count = ntohll(ofs->byte_count);
+ } else if (raw == OFPRAW_OFPST10_FLOW_REPLY) {
const struct ofp10_flow_stats *ofs;
size_t length;
enum ofpraw raw;
ofpraw_decode_partial(&raw, reply->data, reply->size);
- if (raw == OFPRAW_OFPST_FLOW_REPLY) {
+ if (raw == OFPRAW_OFPST11_FLOW_REPLY) {
+ struct ofp11_flow_stats *ofs;
+
+ ofpbuf_put_uninit(reply, sizeof *ofs);
+ oxm_put_match(reply, &fs->rule);
+ ofpacts_put_openflow11_instructions(fs->ofpacts, fs->ofpacts_len,
+ reply);
+
+ ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
+ ofs->length = htons(reply->size - start_ofs);
+ ofs->table_id = fs->table_id;
+ ofs->pad = 0;
+ ofs->duration_sec = htonl(fs->duration_sec);
+ ofs->duration_nsec = htonl(fs->duration_nsec);
+ ofs->priority = htons(fs->rule.priority);
+ ofs->idle_timeout = htons(fs->idle_timeout);
+ ofs->hard_timeout = htons(fs->hard_timeout);
+ memset(ofs->pad2, 0, sizeof ofs->pad2);
+ ofs->cookie = fs->cookie;
+ ofs->packet_count = htonll(unknown_to_zero(fs->packet_count));
+ ofs->byte_count = htonll(unknown_to_zero(fs->byte_count));
+ } else if (raw == OFPRAW_OFPST10_FLOW_REPLY) {
struct ofp10_flow_stats *ofs;
ofpbuf_put_uninit(reply, sizeof *ofs);
enum ofpraw raw;
ofpraw_decode(&raw, request);
- if (raw == OFPRAW_OFPST_AGGREGATE_REQUEST) {
+ if (raw == OFPRAW_OFPST10_AGGREGATE_REQUEST) {
packet_count = unknown_to_zero(stats->packet_count);
byte_count = unknown_to_zero(stats->byte_count);
} else {
ofpbuf_use_const(&b, oh, ntohs(oh->length));
raw = ofpraw_pull_assert(&b);
- if (raw == OFPRAW_OFPT10_FLOW_REMOVED) {
+ if (raw == OFPRAW_OFPT11_FLOW_REMOVED) {
+ const struct ofp12_flow_removed *ofr;
+ enum ofperr error;
+
+ ofr = ofpbuf_pull(&b, sizeof *ofr);
+
+ error = ofputil_pull_ofp11_match(&b, ntohs(ofr->priority),
+ &fr->rule, NULL);
+ if (error) {
+ return error;
+ }
+
+ fr->cookie = ofr->cookie;
+ fr->reason = ofr->reason;
+ /* XXX: ofr->table_id is ignored */
+ fr->duration_sec = ntohl(ofr->duration_sec);
+ fr->duration_nsec = ntohl(ofr->duration_nsec);
+ fr->idle_timeout = ntohs(ofr->idle_timeout);
+ fr->hard_timeout = ntohs(ofr->hard_timeout);
+ fr->packet_count = ntohll(ofr->packet_count);
+ fr->byte_count = ntohll(ofr->byte_count);
+ } else if (raw == OFPRAW_OFPT10_FLOW_REMOVED) {
const struct ofp_flow_removed *ofr;
ofr = ofpbuf_pull(&b, sizeof *ofr);
fr->duration_sec = ntohl(ofr->duration_sec);
fr->duration_nsec = ntohl(ofr->duration_nsec);
fr->idle_timeout = ntohs(ofr->idle_timeout);
+ fr->hard_timeout = 0;
fr->packet_count = ntohll(ofr->packet_count);
fr->byte_count = ntohll(ofr->byte_count);
} else if (raw == OFPRAW_NXT_FLOW_REMOVED) {
fr->duration_sec = ntohl(nfr->duration_sec);
fr->duration_nsec = ntohl(nfr->duration_nsec);
fr->idle_timeout = ntohs(nfr->idle_timeout);
+ fr->hard_timeout = 0;
fr->packet_count = ntohll(nfr->packet_count);
fr->byte_count = ntohll(nfr->byte_count);
} else {
struct ofpbuf *msg;
switch (protocol) {
+ case OFPUTIL_P_OF12: {
+ struct ofp12_flow_removed *ofr;
+
+ msg = ofpraw_alloc_xid(OFPRAW_OFPT11_FLOW_REMOVED,
+ ofputil_protocol_to_ofp_version(protocol),
+ htonl(0), NXM_TYPICAL_LEN);
+ ofr = ofpbuf_put_zeros(msg, sizeof *ofr);
+ ofr->cookie = fr->cookie;
+ ofr->priority = htons(fr->rule.priority);
+ ofr->reason = fr->reason;
+ ofr->table_id = 0;
+ ofr->duration_sec = htonl(fr->duration_sec);
+ ofr->duration_nsec = htonl(fr->duration_nsec);
+ ofr->idle_timeout = htons(fr->idle_timeout);
+ ofr->hard_timeout = htons(fr->hard_timeout);
+ ofr->packet_count = htonll(fr->packet_count);
+ ofr->byte_count = htonll(fr->byte_count);
+ oxm_put_match(msg, &fr->rule);
+ break;
+ }
+
case OFPUTIL_P_OF10:
case OFPUTIL_P_OF10_TID: {
struct ofp_flow_removed *ofr;
break;
}
- case OFPUTIL_P_OF12:
default:
NOT_REACHED();
}
pin->packet_len = b->size;
pin->fmd.in_port = rule->flow.in_port;
-
pin->fmd.tun_id = rule->flow.tun_id;
- pin->fmd.tun_id_mask = rule->wc.tun_id_mask;
-
pin->fmd.metadata = rule->flow.metadata;
- pin->fmd.metadata_mask = rule->wc.metadata_mask;
-
memcpy(pin->fmd.regs, rule->flow.regs, sizeof pin->fmd.regs);
- memcpy(pin->fmd.reg_masks, rule->wc.reg_masks, sizeof pin->fmd.reg_masks);
}
enum ofperr
int i;
cls_rule_init_catchall(rule, 0);
- cls_rule_set_tun_id_masked(rule, pin->fmd.tun_id,
- pin->fmd.tun_id_mask);
- cls_rule_set_metadata_masked(rule, pin->fmd.metadata,
- pin->fmd.metadata_mask);
+ if (pin->fmd.tun_id != htonll(0)) {
+ cls_rule_set_tun_id(rule, pin->fmd.tun_id);
+ }
+ if (pin->fmd.metadata != htonll(0)) {
+ cls_rule_set_metadata(rule, pin->fmd.metadata);
+ }
for (i = 0; i < FLOW_N_REGS; i++) {
- cls_rule_set_reg_masked(rule, i, pin->fmd.regs[i],
- pin->fmd.reg_masks[i]);
+ if (pin->fmd.regs[i]) {
+ cls_rule_set_reg(rule, i, pin->fmd.regs[i]);
+ }
}
cls_rule_set_in_port(rule, pin->fmd.in_port);
const struct ofp_header *oh,
struct ofpbuf *ofpacts)
{
- const struct ofp_packet_out *opo;
- enum ofperr error;
+ enum ofperr bad_in_port_err;
enum ofpraw raw;
struct ofpbuf b;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
raw = ofpraw_pull_assert(&b);
- assert(raw == OFPRAW_OFPT10_PACKET_OUT);
- opo = ofpbuf_pull(&b, sizeof *opo);
- po->buffer_id = ntohl(opo->buffer_id);
- po->in_port = ntohs(opo->in_port);
+ if (raw == OFPRAW_OFPT11_PACKET_OUT) {
+ enum ofperr error;
+ const struct ofp11_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
+
+ po->buffer_id = ntohl(opo->buffer_id);
+ error = ofputil_port_from_ofp11(opo->in_port, &po->in_port);
+ if (error) {
+ return error;
+ }
+
+ error = ofpacts_pull_openflow11_actions(&b, ntohs(opo->actions_len),
+ ofpacts);
+ if (error) {
+ return error;
+ }
+
+ bad_in_port_err = OFPERR_OFPBMC_BAD_VALUE;
+ } else if (raw == OFPRAW_OFPT10_PACKET_OUT) {
+ enum ofperr error;
+ const struct ofp_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
+
+ po->buffer_id = ntohl(opo->buffer_id);
+ po->in_port = ntohs(opo->in_port);
+
+ error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts);
+ if (error) {
+ return error;
+ }
+
+ bad_in_port_err = OFPERR_NXBRC_BAD_IN_PORT;
+ } else {
+ NOT_REACHED();
+ }
+
if (po->in_port >= OFPP_MAX && po->in_port != OFPP_LOCAL
&& po->in_port != OFPP_NONE && po->in_port != OFPP_CONTROLLER) {
VLOG_WARN_RL(&bad_ofmsg_rl, "packet-out has bad input port %#"PRIx16,
po->in_port);
- return OFPERR_NXBRC_BAD_IN_PORT;
+ return bad_in_port_err;
}
- error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts);
- if (error) {
- return error;
- }
po->ofpacts = ofpacts->data;
po->ofpacts_len = ofpacts->size;
break;
}
- case OFP11_VERSION: {
+ case OFP11_VERSION:
+ case OFP12_VERSION: {
struct ofp11_port_mod *opm;
b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0);
opm = ofpbuf_put_zeros(b, sizeof *opm);
- opm->port_no = htonl(pm->port_no);
+ opm->port_no = ofputil_port_to_ofp11(pm->port_no);
memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
opm->config = htonl(pm->config & OFPPC11_ALL);
opm->mask = htonl(pm->mask & OFPPC11_ALL);
break;
}
- case OFP12_VERSION:
default:
NOT_REACHED();
}
}
\f
struct ofpbuf *
-ofputil_encode_packet_out(const struct ofputil_packet_out *po)
+ofputil_encode_packet_out(const struct ofputil_packet_out *po,
+ enum ofputil_protocol protocol)
{
- struct ofp_packet_out *opo;
- size_t actions_ofs;
+ enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
struct ofpbuf *msg;
size_t size;
size += po->packet_len;
}
- msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size);
- ofpbuf_put_zeros(msg, sizeof *opo);
- actions_ofs = msg->size;
- ofpacts_put_openflow10(po->ofpacts, po->ofpacts_len, msg);
+ switch (ofp_version) {
+ case OFP10_VERSION: {
+ struct ofp_packet_out *opo;
+ size_t actions_ofs;
+
+ msg = ofpraw_alloc(OFPRAW_OFPT10_PACKET_OUT, OFP10_VERSION, size);
+ ofpbuf_put_zeros(msg, sizeof *opo);
+ actions_ofs = msg->size;
+ ofpacts_put_openflow10(po->ofpacts, po->ofpacts_len, msg);
+
+ opo = msg->l3;
+ opo->buffer_id = htonl(po->buffer_id);
+ opo->in_port = htons(po->in_port);
+ opo->actions_len = htons(msg->size - actions_ofs);
+ break;
+ }
- opo = msg->l3;
- opo->buffer_id = htonl(po->buffer_id);
- opo->in_port = htons(po->in_port);
- opo->actions_len = htons(msg->size - actions_ofs);
+ case OFP11_VERSION:
+ case OFP12_VERSION: {
+ struct ofp11_packet_out *opo;
+ size_t len;
+
+ msg = ofpraw_alloc(OFPRAW_OFPT11_PACKET_OUT, ofp_version, size);
+ ofpbuf_put_zeros(msg, sizeof *opo);
+ len = ofpacts_put_openflow11_actions(po->ofpacts, po->ofpacts_len, msg);
+
+ opo = msg->l3;
+ opo->buffer_id = htonl(po->buffer_id);
+ opo->in_port = ofputil_port_to_ofp11(po->in_port);
+ opo->actions_len = htons(len);
+ break;
+ }
+
+ default:
+ NOT_REACHED();
+ }
if (po->buffer_id == UINT32_MAX) {
ofpbuf_put(msg, po->packet, po->packet_len);