void
ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 23);
/* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
>> OFPFW10_NW_DST_SHIFT);
if (!(ofpfw & OFPFW10_TP_SRC)) {
- wc->masks.tp_src = htons(UINT16_MAX);
+ wc->masks.tp_src = OVS_BE16_MAX;
}
if (!(ofpfw & OFPFW10_TP_DST)) {
- wc->masks.tp_dst = htons(UINT16_MAX);
+ wc->masks.tp_dst = OVS_BE16_MAX;
}
if (!(ofpfw & OFPFW10_DL_SRC)) {
memset(wc->masks.dl_dst, 0xff, ETH_ADDR_LEN);
}
if (!(ofpfw & OFPFW10_DL_TYPE)) {
- wc->masks.dl_type = htons(UINT16_MAX);
+ wc->masks.dl_type = OVS_BE16_MAX;
}
/* VLAN TCI mask. */
}
}
-/* Converts the ofp11_match in 'match' into a struct match in 'match. Returns
- * 0 if successful, otherwise an OFPERR_* value. */
+/* Converts the ofp11_match in 'ofmatch' into a struct match in 'match'.
+ * Returns 0 if successful, otherwise an OFPERR_* value. */
enum ofperr
ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch,
struct match *match)
if (ofmatch->dl_vlan == htons(OFPVID11_NONE)) {
/* Match only packets without a VLAN tag. */
match->flow.vlan_tci = htons(0);
- match->wc.masks.vlan_tci = htons(UINT16_MAX);
+ match->wc.masks.vlan_tci = OVS_BE16_MAX;
} else {
if (ofmatch->dl_vlan == htons(OFPVID11_ANY)) {
/* Match any packet with a VLAN tag regardless of VID. */
}
if (eth_type_mpls(match->flow.dl_type)) {
- enum { OFPFW11_MPLS_ALL = OFPFW11_MPLS_LABEL | OFPFW11_MPLS_TC };
-
- if ((wc & OFPFW11_MPLS_ALL) != OFPFW11_MPLS_ALL) {
- /* MPLS not supported. */
- return OFPERR_OFPBMC_BAD_TAG;
+ if (!(wc & OFPFW11_MPLS_LABEL)) {
+ match_set_mpls_label(match, ofmatch->mpls_label);
+ }
+ if (!(wc & OFPFW11_MPLS_TC)) {
+ match_set_mpls_tc(match, ofmatch->mpls_tc);
}
}
ofmatch->tp_dst = match->flow.tp_dst;
}
- /* MPLS not supported. */
- wc |= OFPFW11_MPLS_LABEL;
- wc |= OFPFW11_MPLS_TC;
+ if (!(match->wc.masks.mpls_lse & htonl(MPLS_LABEL_MASK))) {
+ wc |= OFPFW11_MPLS_LABEL;
+ } else {
+ ofmatch->mpls_label = htonl(mpls_lse_to_label(match->flow.mpls_lse));
+ }
+
+ if (!(match->wc.masks.mpls_lse & htonl(MPLS_TC_MASK))) {
+ wc |= OFPFW11_MPLS_TC;
+ } else {
+ ofmatch->mpls_tc = mpls_lse_to_tc(match->flow.mpls_lse);
+ }
ofmatch->metadata = match->flow.metadata;
ofmatch->metadata_mask = ~match->wc.masks.metadata;
ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
const struct ofp_header *oh,
enum ofputil_protocol protocol,
- struct ofpbuf *ofpacts)
+ struct ofpbuf *ofpacts,
+ ofp_port_t max_port, uint8_t max_table)
{
ovs_be16 raw_flags;
enum ofperr error;
return error;
}
- error = ofpacts_pull_openflow11_instructions(&b, b.size, ofpacts);
+ error = ofpacts_pull_openflow_instructions(&b, b.size, oh->version,
+ ofpacts);
if (error) {
return error;
}
} else {
fm->cookie = ofm->cookie;
fm->cookie_mask = ofm->cookie_mask;
- fm->new_cookie = htonll(UINT64_MAX);
+ fm->new_cookie = OVS_BE64_MAX;
}
fm->modify_cookie = false;
fm->command = ofm->command;
+
+ /* Get table ID.
+ *
+ * OF1.1 entirely forbids table_id == OFPTT_ALL.
+ * OF1.2+ allows table_id == OFPTT_ALL only for deletes. */
fm->table_id = ofm->table_id;
+ if (fm->table_id == OFPTT_ALL
+ && (oh->version == OFP11_VERSION
+ || (ofm->command != OFPFC_DELETE &&
+ ofm->command != OFPFC_DELETE_STRICT))) {
+ return OFPERR_OFPFMFC_BAD_TABLE_ID;
+ }
+
fm->idle_timeout = ntohs(ofm->idle_timeout);
fm->hard_timeout = ntohs(ofm->hard_timeout);
fm->buffer_id = ntohl(ofm->buffer_id);
ofputil_normalize_match(&fm->match);
/* Now get the actions. */
- error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
+ error = ofpacts_pull_openflow_actions(&b, b.size, oh->version,
+ ofpacts);
if (error) {
return error;
}
if (error) {
return error;
}
- error = ofpacts_pull_openflow10(&b, b.size, ofpacts);
+ error = ofpacts_pull_openflow_actions(&b, b.size, oh->version,
+ ofpacts);
if (error) {
return error;
}
NOT_REACHED();
}
- fm->modify_cookie = fm->new_cookie != htonll(UINT64_MAX);
+ fm->modify_cookie = fm->new_cookie != OVS_BE64_MAX;
if (protocol & OFPUTIL_P_TID) {
fm->command = command & 0xff;
fm->table_id = command >> 8;
: OFPERR_OFPFMFC_TABLE_FULL);
}
- return 0;
+ return ofpacts_check_consistency(fm->ofpacts, fm->ofpacts_len,
+ &fm->match.flow, max_port,
+ fm->table_id, max_table, protocol);
}
static enum ofperr
}
mb = ofpbuf_put_uninit(bands, sizeof *mb);
mb->type = ntohs(ombh->type);
+ if (mb->type != OFPMBT13_DROP && mb->type != OFPMBT13_DSCP_REMARK) {
+ return OFPERR_OFPMMFC_BAD_BAND;
+ }
mb->rate = ntohl(ombh->rate);
mb->burst_size = ntohl(ombh->burst_size);
mb->prec_level = (mb->type == OFPMBT13_DSCP_REMARK) ?
/* Translate the message. */
mm->command = ntohs(omm->command);
+ if (mm->command != OFPMC13_ADD &&
+ mm->command != OFPMC13_MODIFY &&
+ mm->command != OFPMC13_DELETE) {
+ return OFPERR_OFPMMFC_BAD_COMMAND;
+ }
mm->meter.meter_id = ntohl(omm->meter_id);
if (mm->command == OFPMC13_DELETE) {
enum ofperr error;
mm->meter.flags = ntohs(omm->flags);
+ if (mm->meter.flags & OFPMF13_KBPS &&
+ mm->meter.flags & OFPMF13_PKTPS) {
+ return OFPERR_OFPMMFC_BAD_FLAGS;
+ }
mm->meter.bands = bands->data;
error = ofputil_pull_bands(&b, b.size, &mm->meter.n_bands, bands);
ofm->cookie = fm->cookie;
}
ofm->cookie_mask = fm->cookie_mask;
- ofm->table_id = fm->table_id;
+ if (fm->table_id != OFPTT_ALL
+ || (protocol != OFPUTIL_P_OF11_STD
+ && (fm->command == OFPFC_DELETE ||
+ fm->command == OFPFC_DELETE_STRICT))) {
+ ofm->table_id = fm->table_id;
+ } else {
+ ofm->table_id = 0;
+ }
ofm->command = fm->command;
ofm->idle_timeout = htons(fm->idle_timeout);
ofm->hard_timeout = htons(fm->hard_timeout);
ofm->out_group = htonl(fm->out_group);
ofm->flags = raw_flags;
ofputil_put_ofp11_match(msg, &fm->match, protocol);
- ofpacts_put_openflow11_instructions(fm->ofpacts, fm->ofpacts_len, msg);
+ ofpacts_put_openflow_instructions(fm->ofpacts, fm->ofpacts_len, msg,
+ version);
break;
}
ofm->buffer_id = htonl(fm->buffer_id);
ofm->out_port = htons(ofp_to_u16(fm->out_port));
ofm->flags = raw_flags;
- ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg);
+ ofpacts_put_openflow_actions(fm->ofpacts, fm->ofpacts_len, msg,
+ version);
break;
}
nfm->out_port = htons(ofp_to_u16(fm->out_port));
nfm->flags = raw_flags;
nfm->match_len = htons(match_len);
- ofpacts_put_openflow10(fm->ofpacts, fm->ofpacts_len, msg);
+ ofpacts_put_openflow_actions(fm->ofpacts, fm->ofpacts_len, msg,
+ version);
break;
}
return 0;
}
+/* Constructs and returns an OFPT_QUEUE_GET_CONFIG request for the specified
+ * 'port', suitable for OpenFlow version 'version'. */
+struct ofpbuf *
+ofputil_encode_queue_get_config_request(enum ofp_version version,
+ ofp_port_t port)
+{
+ struct ofpbuf *request;
+
+ if (version == OFP10_VERSION) {
+ struct ofp10_queue_get_config_request *qgcr10;
+
+ request = ofpraw_alloc(OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST,
+ version, 0);
+ qgcr10 = ofpbuf_put_zeros(request, sizeof *qgcr10);
+ qgcr10->port = htons(ofp_to_u16(port));
+ } else {
+ struct ofp11_queue_get_config_request *qgcr11;
+
+ request = ofpraw_alloc(OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST,
+ version, 0);
+ qgcr11 = ofpbuf_put_zeros(request, sizeof *qgcr11);
+ qgcr11->port = ofputil_port_to_ofp11(port);
+ }
+
+ return request;
+}
+
+/* Parses OFPT_QUEUE_GET_CONFIG request 'oh', storing the port specified by the
+ * request into '*port'. Returns 0 if successful, otherwise an OpenFlow error
+ * code. */
+enum ofperr
+ofputil_decode_queue_get_config_request(const struct ofp_header *oh,
+ ofp_port_t *port)
+{
+ const struct ofp10_queue_get_config_request *qgcr10;
+ const struct ofp11_queue_get_config_request *qgcr11;
+ enum ofpraw raw;
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+
+ switch ((int) raw) {
+ case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST:
+ qgcr10 = b.data;
+ *port = u16_to_ofp(ntohs(qgcr10->port));
+ return 0;
+
+ case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST:
+ qgcr11 = b.data;
+ return ofputil_port_from_ofp11(qgcr11->port, port);
+ }
+
+ NOT_REACHED();
+}
+
+/* Constructs and returns the beginning of a reply to
+ * OFPT_QUEUE_GET_CONFIG_REQUEST 'oh'. The caller may append information about
+ * individual queues with ofputil_append_queue_get_config_reply(). */
+struct ofpbuf *
+ofputil_encode_queue_get_config_reply(const struct ofp_header *oh)
+{
+ struct ofp10_queue_get_config_reply *qgcr10;
+ struct ofp11_queue_get_config_reply *qgcr11;
+ struct ofpbuf *reply;
+ enum ofperr error;
+ struct ofpbuf b;
+ enum ofpraw raw;
+ ofp_port_t port;
+
+ error = ofputil_decode_queue_get_config_request(oh, &port);
+ ovs_assert(!error);
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+
+ switch ((int) raw) {
+ case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST:
+ reply = ofpraw_alloc_reply(OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY,
+ oh, 0);
+ qgcr10 = ofpbuf_put_zeros(reply, sizeof *qgcr10);
+ qgcr10->port = htons(ofp_to_u16(port));
+ break;
+
+ case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST:
+ reply = ofpraw_alloc_reply(OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY,
+ oh, 0);
+ qgcr11 = ofpbuf_put_zeros(reply, sizeof *qgcr11);
+ qgcr11->port = ofputil_port_to_ofp11(port);
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+
+ return reply;
+}
+
+static void
+put_queue_rate(struct ofpbuf *reply, enum ofp_queue_properties property,
+ uint16_t rate)
+{
+ if (rate != UINT16_MAX) {
+ struct ofp_queue_prop_rate *oqpr;
+
+ oqpr = ofpbuf_put_zeros(reply, sizeof *oqpr);
+ oqpr->prop_header.property = htons(property);
+ oqpr->prop_header.len = htons(sizeof *oqpr);
+ oqpr->rate = htons(rate);
+ }
+}
+
+/* Appends a queue description for 'queue_id' to the
+ * OFPT_QUEUE_GET_CONFIG_REPLY already in 'oh'. */
+void
+ofputil_append_queue_get_config_reply(struct ofpbuf *reply,
+ const struct ofputil_queue_config *oqc)
+{
+ const struct ofp_header *oh = reply->data;
+ size_t start_ofs, len_ofs;
+ ovs_be16 *len;
+
+ start_ofs = reply->size;
+ if (oh->version < OFP12_VERSION) {
+ struct ofp10_packet_queue *opq10;
+
+ opq10 = ofpbuf_put_zeros(reply, sizeof *opq10);
+ opq10->queue_id = htonl(oqc->queue_id);
+ len_ofs = (char *) &opq10->len - (char *) reply->data;
+ } else {
+ struct ofp11_queue_get_config_reply *qgcr11;
+ struct ofp12_packet_queue *opq12;
+ ovs_be32 port;
+
+ qgcr11 = reply->l3;
+ port = qgcr11->port;
+
+ opq12 = ofpbuf_put_zeros(reply, sizeof *opq12);
+ opq12->port = port;
+ opq12->queue_id = htonl(oqc->queue_id);
+ len_ofs = (char *) &opq12->len - (char *) reply->data;
+ }
+
+ put_queue_rate(reply, OFPQT_MIN_RATE, oqc->min_rate);
+ put_queue_rate(reply, OFPQT_MAX_RATE, oqc->max_rate);
+
+ len = ofpbuf_at(reply, len_ofs, sizeof *len);
+ *len = htons(reply->size - start_ofs);
+}
+
+/* Decodes the initial part of an OFPT_QUEUE_GET_CONFIG_REPLY from 'reply' and
+ * stores in '*port' the port that the reply is about. The caller may call
+ * ofputil_pull_queue_get_config_reply() to obtain information about individual
+ * queues included in the reply. Returns 0 if successful, otherwise an
+ * ofperr.*/
+enum ofperr
+ofputil_decode_queue_get_config_reply(struct ofpbuf *reply, ofp_port_t *port)
+{
+ const struct ofp10_queue_get_config_reply *qgcr10;
+ const struct ofp11_queue_get_config_reply *qgcr11;
+ enum ofpraw raw;
+
+ raw = ofpraw_pull_assert(reply);
+ switch ((int) raw) {
+ case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REPLY:
+ qgcr10 = ofpbuf_pull(reply, sizeof *qgcr10);
+ *port = u16_to_ofp(ntohs(qgcr10->port));
+ return 0;
+
+ case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REPLY:
+ qgcr11 = ofpbuf_pull(reply, sizeof *qgcr11);
+ return ofputil_port_from_ofp11(qgcr11->port, port);
+ }
+
+ NOT_REACHED();
+}
+
+static enum ofperr
+parse_queue_rate(const struct ofp_queue_prop_header *hdr, uint16_t *rate)
+{
+ const struct ofp_queue_prop_rate *oqpr;
+
+ if (hdr->len == htons(sizeof *oqpr)) {
+ oqpr = (const struct ofp_queue_prop_rate *) hdr;
+ *rate = ntohs(oqpr->rate);
+ return 0;
+ } else {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+}
+
+/* Decodes information about a queue from the OFPT_QUEUE_GET_CONFIG_REPLY in
+ * 'reply' and stores it in '*queue'. ofputil_decode_queue_get_config_reply()
+ * must already have pulled off the main header.
+ *
+ * This function returns EOF if the last queue has already been decoded, 0 if a
+ * queue was successfully decoded into '*queue', or an ofperr if there was a
+ * problem decoding 'reply'. */
+int
+ofputil_pull_queue_get_config_reply(struct ofpbuf *reply,
+ struct ofputil_queue_config *queue)
+{
+ const struct ofp_header *oh;
+ unsigned int opq_len;
+ unsigned int len;
+
+ if (!reply->size) {
+ return EOF;
+ }
+
+ queue->min_rate = UINT16_MAX;
+ queue->max_rate = UINT16_MAX;
+
+ oh = reply->l2;
+ if (oh->version < OFP12_VERSION) {
+ const struct ofp10_packet_queue *opq10;
+
+ opq10 = ofpbuf_try_pull(reply, sizeof *opq10);
+ if (!opq10) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ queue->queue_id = ntohl(opq10->queue_id);
+ len = ntohs(opq10->len);
+ opq_len = sizeof *opq10;
+ } else {
+ const struct ofp12_packet_queue *opq12;
+
+ opq12 = ofpbuf_try_pull(reply, sizeof *opq12);
+ if (!opq12) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ queue->queue_id = ntohl(opq12->queue_id);
+ len = ntohs(opq12->len);
+ opq_len = sizeof *opq12;
+ }
+
+ if (len < opq_len || len > reply->size + opq_len || len % 8) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ len -= opq_len;
+
+ while (len > 0) {
+ const struct ofp_queue_prop_header *hdr;
+ unsigned int property;
+ unsigned int prop_len;
+ enum ofperr error = 0;
+
+ hdr = ofpbuf_at_assert(reply, 0, sizeof *hdr);
+ prop_len = ntohs(hdr->len);
+ if (prop_len < sizeof *hdr || prop_len > reply->size || prop_len % 8) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ property = ntohs(hdr->property);
+ switch (property) {
+ case OFPQT_MIN_RATE:
+ error = parse_queue_rate(hdr, &queue->min_rate);
+ break;
+
+ case OFPQT_MAX_RATE:
+ error = parse_queue_rate(hdr, &queue->max_rate);
+ break;
+
+ default:
+ VLOG_INFO_RL(&bad_ofmsg_rl, "unknown queue property %u", property);
+ break;
+ }
+ if (error) {
+ return error;
+ }
+
+ ofpbuf_pull(reply, prop_len);
+ len -= prop_len;
+ }
+ return 0;
+}
+
/* Converts an OFPST_FLOW, OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE
* request 'oh', into an abstract flow_stats_request in 'fsr'. Returns 0 if
* successful, otherwise an OpenFlow error code. */
return EINVAL;
}
- if (ofpacts_pull_openflow11_instructions(msg, length - sizeof *ofs -
- padded_match_len, ofpacts)) {
+ if (ofpacts_pull_openflow_instructions(msg, length - sizeof *ofs -
+ padded_match_len, oh->version,
+ ofpacts)) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad instructions");
return EINVAL;
}
return EINVAL;
}
- if (ofpacts_pull_openflow10(msg, length - sizeof *ofs, ofpacts)) {
+ if (ofpacts_pull_openflow_actions(msg, length - sizeof *ofs,
+ oh->version, ofpacts)) {
return EINVAL;
}
}
actions_len = length - sizeof *nfs - ROUND_UP(match_len, 8);
- if (ofpacts_pull_openflow10(msg, actions_len, ofpacts)) {
+ if (ofpacts_pull_openflow_actions(msg, actions_len, oh->version,
+ ofpacts)) {
return EINVAL;
}
struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
size_t start_ofs = reply->size;
enum ofpraw raw;
+ enum ofp_version version = ((struct ofp_header *)reply->data)->version;
ofpraw_decode_partial(&raw, reply->data, reply->size);
if (raw == OFPRAW_OFPST11_FLOW_REPLY || raw == OFPRAW_OFPST13_FLOW_REPLY) {
- const struct ofp_header *oh = reply->data;
struct ofp11_flow_stats *ofs;
ofpbuf_put_uninit(reply, sizeof *ofs);
oxm_put_match(reply, &fs->match);
- ofpacts_put_openflow11_instructions(fs->ofpacts, fs->ofpacts_len,
- reply);
+ ofpacts_put_openflow_instructions(fs->ofpacts, fs->ofpacts_len, reply,
+ version);
ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
ofs->length = htons(reply->size - start_ofs);
ofs->idle_timeout = htons(fs->idle_timeout);
ofs->hard_timeout = htons(fs->hard_timeout);
if (raw == OFPRAW_OFPST13_FLOW_REPLY) {
- ofs->flags = ofputil_encode_flow_mod_flags(fs->flags, oh->version);
+ ofs->flags = ofputil_encode_flow_mod_flags(fs->flags, version);
} else {
ofs->flags = 0;
}
struct ofp10_flow_stats *ofs;
ofpbuf_put_uninit(reply, sizeof *ofs);
- ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply);
-
+ ofpacts_put_openflow_actions(fs->ofpacts, fs->ofpacts_len, reply,
+ version);
ofs = ofpbuf_at_assert(reply, start_ofs, sizeof *ofs);
ofs->length = htons(reply->size - start_ofs);
ofs->table_id = fs->table_id;
ofpbuf_put_uninit(reply, sizeof *nfs);
match_len = nx_put_match(reply, &fs->match, 0, 0);
- ofpacts_put_openflow10(fs->ofpacts, fs->ofpacts_len, reply);
-
+ ofpacts_put_openflow_actions(fs->ofpacts, fs->ofpacts_len, reply,
+ version);
nfs = ofpbuf_at_assert(reply, start_ofs, sizeof *nfs);
nfs->length = htons(reply->size - start_ofs);
nfs->table_id = fs->table_id;
struct ofpbuf b;
memset(pin, 0, sizeof *pin);
+ pin->cookie = OVS_BE64_MAX;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
raw = ofpraw_pull_assert(&b);
enum ofputil_protocol protocol,
enum nx_packet_in_format packet_in_format)
{
- size_t send_len = MIN(pin->send_len, pin->packet_len);
struct ofpbuf *packet;
/* Add OFPT_PACKET_IN. */
/* The final argument is just an estimate of the space required. */
packet = ofpraw_alloc_xid(packet_in_raw, packet_in_version,
htonl(0), (sizeof(struct flow_metadata) * 2
- + 2 + send_len));
+ + 2 + pin->packet_len));
ofpbuf_put_zeros(packet, packet_in_size);
oxm_put_match(packet, &match);
ofpbuf_put_zeros(packet, 2);
- ofpbuf_put(packet, pin->packet, send_len);
+ ofpbuf_put(packet, pin->packet, pin->packet_len);
opi = packet->l3;
opi->pi.buffer_id = htonl(pin->buffer_id);
struct ofp10_packet_in *opi;
packet = ofpraw_alloc_xid(OFPRAW_OFPT10_PACKET_IN, OFP10_VERSION,
- htonl(0), send_len);
+ htonl(0), pin->packet_len);
opi = ofpbuf_put_zeros(packet, offsetof(struct ofp10_packet_in, data));
opi->total_len = htons(pin->total_len);
opi->in_port = htons(ofp_to_u16(pin->fmd.in_port));
opi->reason = pin->reason;
opi->buffer_id = htonl(pin->buffer_id);
- ofpbuf_put(packet, pin->packet, send_len);
+ ofpbuf_put(packet, pin->packet, pin->packet_len);
} else if (packet_in_format == NXPIF_NXM) {
struct nx_packet_in *npi;
struct match match;
/* The final argument is just an estimate of the space required. */
packet = ofpraw_alloc_xid(OFPRAW_NXT_PACKET_IN, OFP10_VERSION,
htonl(0), (sizeof(struct flow_metadata) * 2
- + 2 + send_len));
+ + 2 + pin->packet_len));
ofpbuf_put_zeros(packet, sizeof *npi);
match_len = nx_put_match(packet, &match, 0, 0);
ofpbuf_put_zeros(packet, 2);
- ofpbuf_put(packet, pin->packet, send_len);
+ ofpbuf_put(packet, pin->packet, pin->packet_len);
npi = packet->l3;
npi->buffer_id = htonl(pin->buffer_id);
return error;
}
- error = ofpacts_pull_openflow11_actions(&b, ntohs(opo->actions_len),
- ofpacts);
+ error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len),
+ oh->version, ofpacts);
if (error) {
return error;
}
po->buffer_id = ntohl(opo->buffer_id);
po->in_port = u16_to_ofp(ntohs(opo->in_port));
- error = ofpacts_pull_openflow10(&b, ntohs(opo->actions_len), ofpacts);
+ error = ofpacts_pull_openflow_actions(&b, ntohs(opo->actions_len),
+ oh->version, ofpacts);
if (error) {
return error;
}
ofpmsg_update_length(b);
return b;
}
-\f
+
/* ofputil_port_mod */
/* Decodes the OpenFlow "port mod" message in '*oh' into an abstract form in
opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
break;
}
+ default:
+ NOT_REACHED();
+ }
+
+ return b;
+}
+
+/* ofputil_table_mod */
+
+/* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in
+ * '*pm'. Returns 0 if successful, otherwise an OFPERR_* value. */
+enum ofperr
+ofputil_decode_table_mod(const struct ofp_header *oh,
+ struct ofputil_table_mod *pm)
+{
+ enum ofpraw raw;
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+
+ if (raw == OFPRAW_OFPT11_TABLE_MOD) {
+ const struct ofp11_table_mod *otm = b.data;
+
+ pm->table_id = otm->table_id;
+ pm->config = ntohl(otm->config);
+ } else {
+ return OFPERR_OFPBRC_BAD_TYPE;
+ }
+
+ return 0;
+}
+
+/* Converts the abstract form of a "table mod" message in '*pm' into an OpenFlow
+ * message suitable for 'protocol', and returns that encoded form in a buffer
+ * owned by the caller. */
+struct ofpbuf *
+ofputil_encode_table_mod(const struct ofputil_table_mod *pm,
+ enum ofputil_protocol protocol)
+{
+ enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
+ struct ofpbuf *b;
+
+ switch (ofp_version) {
+ case OFP10_VERSION: {
+ ovs_fatal(0, "table mod needs OpenFlow 1.1 or later "
+ "(\'-O OpenFlow11\')");
+ break;
+ }
+ case OFP11_VERSION:
+ case OFP12_VERSION:
+ case OFP13_VERSION: {
+ struct ofp11_table_mod *otm;
+ b = ofpraw_alloc(OFPRAW_OFPT11_TABLE_MOD, ofp_version, 0);
+ otm = ofpbuf_put_zeros(b, sizeof *otm);
+ otm->table_id = pm->table_id;
+ otm->config = htonl(pm->config);
+ break;
+ }
default:
NOT_REACHED();
}
rr->role = ntohl(orr->role);
if (raw == OFPRAW_OFPT12_ROLE_REQUEST
? orr->role == htonl(OFPCR12_ROLE_NOCHANGE)
- : orr->generation_id == htonll(UINT64_MAX)) {
+ : orr->generation_id == OVS_BE64_MAX) {
rr->have_generation_id = false;
rr->generation_id = 0;
} else {
return buf;
}
\f
+struct ofpbuf *
+ofputil_encode_role_status(const struct ofputil_role_status *status,
+ enum ofputil_protocol protocol)
+{
+ struct ofpbuf *buf;
+ enum ofp_version version;
+ struct ofp14_role_status *rstatus;
+
+ version = ofputil_protocol_to_ofp_version(protocol);
+ buf = ofpraw_alloc_xid(OFPRAW_OFPT14_ROLE_STATUS, version, htonl(0), 0);
+ rstatus = ofpbuf_put_zeros(buf, sizeof *rstatus);
+ rstatus->role = htonl(status->role);
+ rstatus->reason = status->reason;
+ rstatus->generation_id = htonll(status->generation_id);
+
+ return buf;
+}
+
+enum ofperr
+ofputil_decode_role_status(const struct ofp_header *oh,
+ struct ofputil_role_status *rs)
+{
+ struct ofpbuf b;
+ enum ofpraw raw;
+ const struct ofp14_role_status *r;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+ ovs_assert(raw == OFPRAW_OFPT14_ROLE_STATUS);
+
+ r = b.l3;
+ if (r->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
+ r->role != htonl(OFPCR12_ROLE_EQUAL) &&
+ r->role != htonl(OFPCR12_ROLE_MASTER) &&
+ r->role != htonl(OFPCR12_ROLE_SLAVE)) {
+ return OFPERR_OFPRRFC_BAD_ROLE;
+ }
+
+ rs->role = ntohl(r->role);
+ rs->generation_id = ntohll(r->generation_id);
+ rs->reason = r->reason;
+
+ return 0;
+}
+
/* Table stats. */
static void
out->matched_count = in->matched_count;
}
+static void
+ofputil_put_ofp12_table_stats(const struct ofp12_table_stats *in,
+ struct ofpbuf *buf)
+{
+ struct ofp12_table_stats *out = ofpbuf_put(buf, in, sizeof *in);
+
+ /* Trim off OF1.3-only capabilities. */
+ out->match &= htonll(OFPXMT12_MASK);
+ out->wildcards &= htonll(OFPXMT12_MASK);
+ out->write_setfields &= htonll(OFPXMT12_MASK);
+ out->apply_setfields &= htonll(OFPXMT12_MASK);
+}
+
static void
ofputil_put_ofp13_table_stats(const struct ofp12_table_stats *in,
struct ofpbuf *buf)
reply = ofpraw_alloc_stats_reply(request, n * sizeof *stats);
- switch ((enum ofp_version) request->version) {
- case OFP10_VERSION:
- for (i = 0; i < n; i++) {
+ for (i = 0; i < n; i++) {
+ switch ((enum ofp_version) request->version) {
+ case OFP10_VERSION:
ofputil_put_ofp10_table_stats(&stats[i], reply);
- }
- break;
+ break;
- case OFP11_VERSION:
- for (i = 0; i < n; i++) {
+ case OFP11_VERSION:
ofputil_put_ofp11_table_stats(&stats[i], reply);
- }
- break;
+ break;
- case OFP12_VERSION:
- ofpbuf_put(reply, stats, n * sizeof *stats);
- break;
+ case OFP12_VERSION:
+ ofputil_put_ofp12_table_stats(&stats[i], reply);
+ break;
- case OFP13_VERSION:
- for (i = 0; i < n; i++) {
+ case OFP13_VERSION:
ofputil_put_ofp13_table_stats(&stats[i], reply);
- }
- break;
+ break;
- default:
- NOT_REACHED();
+ default:
+ NOT_REACHED();
+ }
}
return reply;
{
struct nx_flow_update_header *nfuh;
unsigned int length;
+ struct ofp_header *oh;
if (!msg->l2) {
msg->l2 = msg->data;
goto bad_len;
}
+ oh = msg->l2;
+
nfuh = msg->data;
update->event = ntohs(nfuh->event);
length = ntohs(nfuh->length);
}
actions_len = length - sizeof *nfuf - ROUND_UP(match_len, 8);
- error = ofpacts_pull_openflow10(msg, actions_len, ofpacts);
+ error = ofpacts_pull_openflow_actions(msg, actions_len, oh->version,
+ ofpacts);
if (error) {
return error;
}
struct nx_flow_update_header *nfuh;
struct ofpbuf *msg;
size_t start_ofs;
+ enum ofp_version version;
msg = ofpbuf_from_list(list_back(replies));
start_ofs = msg->size;
+ version = ((struct ofp_header *)msg->l2)->version;
if (update->event == NXFME_ABBREV) {
struct nx_flow_update_abbrev *nfua;
ofpbuf_put_zeros(msg, sizeof *nfuf);
match_len = nx_put_match(msg, update->match, htonll(0), htonll(0));
- ofpacts_put_openflow10(update->ofpacts, update->ofpacts_len, msg);
-
+ ofpacts_put_openflow_actions(update->ofpacts, update->ofpacts_len, msg,
+ version);
nfuf = ofpbuf_at_assert(msg, start_ofs, sizeof *nfuf);
nfuf->reason = htons(update->reason);
nfuf->priority = htons(update->priority);
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);
+ ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg,
+ ofp_version);
opo = msg->l3;
opo->buffer_id = htonl(po->buffer_id);
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);
-
+ len = ofpacts_put_openflow_actions(po->ofpacts, po->ofpacts_len, msg,
+ ofp_version);
opo = msg->l3;
opo->buffer_id = htonl(po->buffer_id);
opo->in_port = ofputil_port_to_ofp11(po->in_port);
: ofp_to_u16(ofp10_port) + OFPP11_OFFSET);
}
-/* Checks that 'port' is a valid output port for the OFPAT10_OUTPUT action, given
- * that the switch will never have more than 'max_ports' ports. Returns 0 if
- * 'port' is valid, otherwise an OpenFlow return code. */
-enum ofperr
-ofputil_check_output_port(ofp_port_t port, ofp_port_t max_ports)
-{
- switch (port) {
- case OFPP_IN_PORT:
- case OFPP_TABLE:
- case OFPP_NORMAL:
- case OFPP_FLOOD:
- case OFPP_ALL:
- case OFPP_CONTROLLER:
- case OFPP_NONE:
- case OFPP_LOCAL:
- return 0;
-
- default:
- if (ofp_to_u16(port) < ofp_to_u16(max_ports)) {
- return 0;
- }
- return OFPERR_OFPBAC_BAD_OUT_PORT;
- }
-}
-
#define OFPUTIL_NAMED_PORTS \
OFPUTIL_NAMED_PORT(IN_PORT) \
OFPUTIL_NAMED_PORT(TABLE) \
return b->size / ofputil_get_phy_port_size(ofp_version);
}
-/* Returns the 'enum ofputil_action_code' corresponding to 'name' (e.g. if
- * 'name' is "output" then the return value is OFPUTIL_OFPAT10_OUTPUT), or -1 if
- * 'name' is not the name of any action.
- *
- * ofp-util.def lists the mapping from names to action. */
-int
-ofputil_action_code_from_name(const char *name)
-{
- static const char *const names[OFPUTIL_N_ACTIONS] = {
- NULL,
+/* ofp-util.def lists the mapping from names to action. */
+static const char *const names[OFPUTIL_N_ACTIONS] = {
+ NULL,
#define OFPAT10_ACTION(ENUM, STRUCT, NAME) NAME,
#define OFPAT11_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
#define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) NAME,
#include "ofp-util.def"
- };
+};
+/* Returns the 'enum ofputil_action_code' corresponding to 'name' (e.g. if
+ * 'name' is "output" then the return value is OFPUTIL_OFPAT10_OUTPUT), or -1
+ * if 'name' is not the name of any action. */
+int
+ofputil_action_code_from_name(const char *name)
+{
const char *const *p;
for (p = names; p < &names[ARRAY_SIZE(names)]; p++) {
return -1;
}
+/* Returns name corresponding to the 'enum ofputil_action_code',
+ * or "Unkonwn action", if the name is not available. */
+const char *
+ofputil_action_name_from_code(enum ofputil_action_code code)
+{
+ return code < (int)OFPUTIL_N_ACTIONS && names[code] ? names[code]
+ : "Unknown action";
+}
+
/* Appends an action of the type specified by 'code' to 'buf' and returns the
* action. Initializes the parts of 'action' that identify it as having type
* <ENUM> and length 'sizeof *action' and zeros the rest. For actions that
}
if (!(may_match & MAY_MPLS)) {
wc.masks.mpls_lse = htonl(0);
- wc.masks.mpls_depth = 0;
}
/* Log any changes. */
}
/* Converts a group stats reply in 'msg' into an abstract ofputil_group_stats
- * in 'gs'.
+ * in 'gs'. Assigns freshly allocated memory to gs->bucket_stats for the
+ * caller to eventually free.
*
* Multiple group stats replies can be packed into a single OpenFlow message.
* Calling this function multiple times for a single 'msg' iterates through the
size_t length;
size_t i;
+ gs->bucket_stats = NULL;
error = (msg->l2
? ofpraw_decode(&raw, msg->l2)
: ofpraw_pull(&raw, msg));
return OFPERR_OFPBRC_BAD_LEN;
}
+ gs->bucket_stats = xmalloc(gs->n_buckets * sizeof *gs->bucket_stats);
for (i = 0; i < gs->n_buckets; i++) {
gs->bucket_stats[i].packet_count = ntohll(obc[i].packet_count);
gs->bucket_stats[i].byte_count = ntohll(obc[i].byte_count);
struct ofp11_group_desc_stats *ogds;
struct ofputil_bucket *bucket;
size_t start_ogds;
+ enum ofp_version version = ((struct ofp_header *)reply->data)->version;
start_ogds = reply->size;
ofpbuf_put_zeros(reply, sizeof *ogds);
start_ob = reply->size;
ofpbuf_put_zeros(reply, sizeof *ob);
- ofpacts_put_openflow11_actions(bucket->ofpacts,
- bucket->ofpacts_len, reply);
-
+ ofpacts_put_openflow_actions(bucket->ofpacts, bucket->ofpacts_len,
+ reply, version);
ob = ofpbuf_at_assert(reply, start_ob, sizeof *ob);
ob->len = htons(reply->size - start_ob);
ob->weight = htons(bucket->weight);
static enum ofperr
ofputil_pull_buckets(struct ofpbuf *msg, size_t buckets_length,
- struct list *buckets)
+ enum ofp_version version, struct list *buckets)
{
struct ofp11_bucket *ob;
buckets_length -= ob_len;
ofpbuf_init(&ofpacts, 0);
- error = ofpacts_pull_openflow11_actions(msg, ob_len - sizeof *ob,
- &ofpacts);
+ error = ofpacts_pull_openflow_actions(msg, ob_len - sizeof *ob,
+ version, &ofpacts);
if (error) {
ofpbuf_uninit(&ofpacts);
ofputil_bucket_list_destroy(buckets);
* otherwise a positive errno value. */
int
ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd,
- struct ofpbuf *msg)
+ struct ofpbuf *msg, enum ofp_version version)
{
struct ofp11_group_desc_stats *ogds;
size_t length;
return OFPERR_OFPBRC_BAD_LEN;
}
- return ofputil_pull_buckets(msg, length - sizeof *ogds, &gd->buckets);
+ return ofputil_pull_buckets(msg, length - sizeof *ogds, version,
+ &gd->buckets);
}
/* Converts abstract group mod 'gm' into a message for OpenFlow version
case OFP13_VERSION: {
b = ofpraw_alloc(OFPRAW_OFPT11_GROUP_MOD, ofp_version, 0);
start_ogm = b->size;
- ofpbuf_put_uninit(b, sizeof *ogm);
+ ofpbuf_put_zeros(b, sizeof *ogm);
LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
start_bucket = b->size;
- ofpbuf_put_uninit(b, sizeof *ob);
+ ofpbuf_put_zeros(b, sizeof *ob);
if (bucket->ofpacts && bucket->ofpacts_len) {
- ofpacts_put_openflow11_actions(bucket->ofpacts,
- bucket->ofpacts_len, b);
+ ofpacts_put_openflow_actions(bucket->ofpacts,
+ bucket->ofpacts_len, b,
+ ofp_version);
}
ob = ofpbuf_at_assert(b, start_bucket, sizeof *ob);
ob->len = htons(b->size - start_bucket);;
ogm = ofpbuf_at_assert(b, start_ogm, sizeof *ogm);
ogm->command = htons(gm->command);
ogm->type = gm->type;
- ogm->pad = 0;
ogm->group_id = htonl(gm->group_id);
break;
{
const struct ofp11_group_mod *ogm;
struct ofpbuf msg;
+ struct ofputil_bucket *bucket;
+ enum ofperr err;
ofpbuf_use_const(&msg, oh, ntohs(oh->length));
ofpraw_pull_assert(&msg);
gm->type = ogm->type;
gm->group_id = ntohl(ogm->group_id);
- return ofputil_pull_buckets(&msg, msg.size, &gm->buckets);
+ err = ofputil_pull_buckets(&msg, msg.size, oh->version, &gm->buckets);
+ if (err) {
+ return err;
+ }
+
+ LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
+ switch (gm->type) {
+ case OFPGT11_ALL:
+ case OFPGT11_INDIRECT:
+ if (ofputil_bucket_has_liveness(bucket)) {
+ return OFPERR_OFPGMFC_WATCH_UNSUPPORTED;
+ }
+ break;
+ case OFPGT11_SELECT:
+ break;
+ case OFPGT11_FF:
+ if (!ofputil_bucket_has_liveness(bucket)) {
+ return OFPERR_OFPGMFC_INVALID_GROUP;
+ }
+ break;
+ default:
+ NOT_REACHED();
+ }
+ }
+
+ return 0;
}
/* Parse a queue status request message into 'oqsr'.
qs13->duration_sec = htonl(oqs->duration_sec);
qs13->duration_nsec = htonl(oqs->duration_nsec);
} else {
- qs13->duration_sec = htonl(UINT32_MAX);
- qs13->duration_nsec = htonl(UINT32_MAX);
+ qs13->duration_sec = OVS_BE32_MAX;
+ qs13->duration_nsec = OVS_BE32_MAX;
}
}