/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "ofp-actions.h"
#include "ofp-errors.h"
#include "ofp-msgs.h"
+#include "ofp-prop.h"
#include "ofp-util.h"
#include "ofpbuf.h"
#include "openflow/netronome-ext.h"
* in the peer and so there's not much point in showing a lot of them. */
static struct vlog_rate_limit bad_ofmsg_rl = VLOG_RATE_LIMIT_INIT(1, 5);
+static enum ofputil_table_vacancy ofputil_decode_table_vacancy(
+ ovs_be32 config, enum ofp_version);
static enum ofputil_table_eviction ofputil_decode_table_eviction(
ovs_be32 config, enum ofp_version);
static ovs_be32 ofputil_encode_table_config(enum ofputil_table_miss,
enum ofputil_table_eviction,
+ enum ofputil_table_vacancy,
enum ofp_version);
-struct ofp_prop_header {
- ovs_be16 type;
- ovs_be16 len;
-};
-
-struct ofp_prop_experimenter {
- ovs_be16 type; /* OFP*_EXPERIMENTER. */
- ovs_be16 length; /* Length in bytes of this property. */
- ovs_be32 experimenter; /* Experimenter ID which takes the same form as
- * in struct ofp_experimenter_header. */
- ovs_be32 exp_type; /* Experimenter defined. */
-};
-
-/* Pulls a property, beginning with struct ofp_prop_header, from the beginning
- * of 'msg'. Stores the type of the property in '*typep' and, if 'property' is
- * nonnull, the entire property, including the header, in '*property'. Returns
- * 0 if successful, otherwise an error code.
- *
- * This function pulls the property's stated size padded out to a multiple of
- * 'alignment' bytes. The common case in OpenFlow is an 'alignment' of 8, so
- * you can use ofputil_pull_property() for that case. */
-static enum ofperr
-ofputil_pull_property__(struct ofpbuf *msg, struct ofpbuf *property,
- unsigned int alignment, uint16_t *typep)
-{
- struct ofp_prop_header *oph;
- unsigned int padded_len;
- unsigned int len;
-
- if (msg->size < sizeof *oph) {
- return OFPERR_OFPBPC_BAD_LEN;
- }
-
- oph = msg->data;
- len = ntohs(oph->len);
- padded_len = ROUND_UP(len, alignment);
- if (len < sizeof *oph || padded_len > msg->size) {
- return OFPERR_OFPBPC_BAD_LEN;
- }
-
- *typep = ntohs(oph->type);
- if (property) {
- ofpbuf_use_const(property, msg->data, len);
- }
- ofpbuf_pull(msg, padded_len);
- return 0;
-}
-
-/* Pulls a property, beginning with struct ofp_prop_header, from the beginning
- * of 'msg'. Stores the type of the property in '*typep' and, if 'property' is
- * nonnull, the entire property, including the header, in '*property'. Returns
- * 0 if successful, otherwise an error code.
- *
- * This function pulls the property's stated size padded out to a multiple of
- * 8 bytes, which is the common case for OpenFlow properties. */
static enum ofperr
-ofputil_pull_property(struct ofpbuf *msg, struct ofpbuf *property,
- uint16_t *typep)
-{
- return ofputil_pull_property__(msg, property, 8, typep);
-}
-
-static void OVS_PRINTF_FORMAT(2, 3)
-log_property(bool loose, const char *message, ...)
+ofputil_check_mask(uint16_t type, uint32_t mask)
{
- enum vlog_level level = loose ? VLL_DBG : VLL_WARN;
- if (!vlog_should_drop(THIS_MODULE, level, &bad_ofmsg_rl)) {
- va_list args;
-
- va_start(args, message);
- vlog_valist(THIS_MODULE, level, message, args);
- va_end(args);
- }
-}
+ switch (type) {
+ case OFPACPT_PACKET_IN_SLAVE:
+ case OFPACPT_PACKET_IN_MASTER:
+ if (mask > MAXIMUM_MASK_PACKET_IN) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ break;
-static size_t
-start_property(struct ofpbuf *msg, uint16_t type)
-{
- size_t start_ofs = msg->size;
- struct ofp_prop_header *oph;
+ case OFPACPT_FLOW_REMOVED_SLAVE:
+ case OFPACPT_FLOW_REMOVED_MASTER:
+ if (mask > MAXIMUM_MASK_FLOW_REMOVED) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ break;
- oph = ofpbuf_put_uninit(msg, sizeof *oph);
- oph->type = htons(type);
- oph->len = htons(4); /* May be updated later by end_property(). */
- return start_ofs;
-}
+ case OFPACPT_PORT_STATUS_SLAVE:
+ case OFPACPT_PORT_STATUS_MASTER:
+ if (mask > MAXIMUM_MASK_PORT_STATUS) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ break;
-static void
-end_property(struct ofpbuf *msg, size_t start_ofs)
-{
- struct ofp_prop_header *oph;
+ case OFPACPT_ROLE_STATUS_SLAVE:
+ case OFPACPT_ROLE_STATUS_MASTER:
+ if (mask > MAXIMUM_MASK_ROLE_STATUS) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ break;
- oph = ofpbuf_at_assert(msg, start_ofs, sizeof *oph);
- oph->len = htons(msg->size - start_ofs);
- ofpbuf_padto(msg, ROUND_UP(msg->size, 8));
-}
+ case OFPACPT_TABLE_STATUS_SLAVE:
+ case OFPACPT_TABLE_STATUS_MASTER:
+ if ((mask < MINIMUM_MASK_TABLE_STATUS && mask != 0) |
+ (mask > MAXIMUM_MASK_TABLE_STATUS)) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ break;
-static void
-put_bitmap_properties(struct ofpbuf *msg, uint64_t bitmap)
-{
- for (; bitmap; bitmap = zero_rightmost_1bit(bitmap)) {
- start_property(msg, rightmost_1bit_idx(bitmap));
+ case OFPACPT_REQUESTFORWARD_SLAVE:
+ case OFPACPT_REQUESTFORWARD_MASTER:
+ if (mask > MAXIMUM_MASK_REQUESTFORWARD) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ break;
}
+ return 0;
}
/* Given the wildcard bit count in the least-significant 6 of 'wcbits', returns
void
ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 33);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
/* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
}
if (!(ofpfw & OFPFW10_DL_SRC)) {
- memset(wc->masks.dl_src, 0xff, ETH_ADDR_LEN);
+ WC_MASK_FIELD(wc, dl_src);
}
if (!(ofpfw & OFPFW10_DL_DST)) {
- memset(wc->masks.dl_dst, 0xff, ETH_ADDR_LEN);
+ WC_MASK_FIELD(wc, dl_dst);
}
if (!(ofpfw & OFPFW10_DL_TYPE)) {
wc->masks.dl_type = OVS_BE16_MAX;
match->flow.dl_type = ofputil_dl_type_from_openflow(ofmatch->dl_type);
match->flow.tp_src = ofmatch->tp_src;
match->flow.tp_dst = ofmatch->tp_dst;
- memcpy(match->flow.dl_src, ofmatch->dl_src, ETH_ADDR_LEN);
- memcpy(match->flow.dl_dst, ofmatch->dl_dst, ETH_ADDR_LEN);
+ match->flow.dl_src = ofmatch->dl_src;
+ match->flow.dl_dst = ofmatch->dl_dst;
match->flow.nw_tos = ofmatch->nw_tos & IP_DSCP_MASK;
match->flow.nw_proto = ofmatch->nw_proto;
} else if (match->wc.masks.vlan_tci & htons(VLAN_CFI)
&& !(match->flow.vlan_tci & htons(VLAN_CFI))) {
ofmatch->dl_vlan = htons(OFP10_VLAN_NONE);
- ofpfw |= OFPFW10_DL_VLAN_PCP;
} else {
if (!(match->wc.masks.vlan_tci & htons(VLAN_VID_MASK))) {
ofpfw |= OFPFW10_DL_VLAN;
/* Compose most of the match structure. */
ofmatch->wildcards = htonl(ofpfw);
ofmatch->in_port = htons(ofp_to_u16(match->flow.in_port.ofp_port));
- memcpy(ofmatch->dl_src, match->flow.dl_src, ETH_ADDR_LEN);
- memcpy(ofmatch->dl_dst, match->flow.dl_dst, ETH_ADDR_LEN);
+ ofmatch->dl_src = match->flow.dl_src;
+ ofmatch->dl_dst = match->flow.dl_dst;
ofmatch->dl_type = ofputil_dl_type_to_openflow(match->flow.dl_type);
ofmatch->nw_src = match->flow.nw_src;
ofmatch->nw_dst = match->flow.nw_dst;
struct match *match)
{
uint16_t wc = ntohl(ofmatch->wildcards);
- uint8_t dl_src_mask[ETH_ADDR_LEN];
- uint8_t dl_dst_mask[ETH_ADDR_LEN];
bool ipv4, arp, rarp;
- int i;
match_init_catchall(match);
match_set_in_port(match, ofp_port);
}
- for (i = 0; i < ETH_ADDR_LEN; i++) {
- dl_src_mask[i] = ~ofmatch->dl_src_mask[i];
- }
- match_set_dl_src_masked(match, ofmatch->dl_src, dl_src_mask);
-
- for (i = 0; i < ETH_ADDR_LEN; i++) {
- dl_dst_mask[i] = ~ofmatch->dl_dst_mask[i];
- }
- match_set_dl_dst_masked(match, ofmatch->dl_dst, dl_dst_mask);
+ match_set_dl_src_masked(match, ofmatch->dl_src,
+ eth_addr_invert(ofmatch->dl_src_mask));
+ match_set_dl_dst_masked(match, ofmatch->dl_dst,
+ eth_addr_invert(ofmatch->dl_dst_mask));
if (!(wc & OFPFW11_DL_VLAN)) {
if (ofmatch->dl_vlan == htons(OFPVID11_NONE)) {
struct ofp11_match *ofmatch)
{
uint32_t wc = 0;
- int i;
memset(ofmatch, 0, sizeof *ofmatch);
ofmatch->omh.type = htons(OFPMT_STANDARD);
ofmatch->in_port = ofputil_port_to_ofp11(match->flow.in_port.ofp_port);
}
- memcpy(ofmatch->dl_src, match->flow.dl_src, ETH_ADDR_LEN);
- for (i = 0; i < ETH_ADDR_LEN; i++) {
- ofmatch->dl_src_mask[i] = ~match->wc.masks.dl_src[i];
- }
-
- memcpy(ofmatch->dl_dst, match->flow.dl_dst, ETH_ADDR_LEN);
- for (i = 0; i < ETH_ADDR_LEN; i++) {
- ofmatch->dl_dst_mask[i] = ~match->wc.masks.dl_dst[i];
- }
+ ofmatch->dl_src = match->flow.dl_src;
+ ofmatch->dl_src_mask = eth_addr_invert(match->wc.masks.dl_src);
+ ofmatch->dl_dst = match->flow.dl_dst;
+ ofmatch->dl_dst_mask = eth_addr_invert(match->wc.masks.dl_dst);
if (match->wc.masks.vlan_tci == htons(0)) {
wc |= OFPFW11_DL_VLAN | OFPFW11_DL_VLAN_PCP;
fm->out_group = (ofm->command == OFPFC_DELETE ||
ofm->command == OFPFC_DELETE_STRICT
? ntohl(ofm->out_group)
- : OFPG11_ANY);
+ : OFPG_ANY);
raw_flags = ofm->flags;
} else {
uint16_t command;
fm->importance = 0;
fm->buffer_id = ntohl(ofm->buffer_id);
fm->out_port = u16_to_ofp(ntohs(ofm->out_port));
- fm->out_group = OFPG11_ANY;
+ fm->out_group = OFPG_ANY;
raw_flags = ofm->flags;
} else if (raw == OFPRAW_NXT_FLOW_MOD) {
/* Nicira extended flow_mod. */
fm->importance = 0;
fm->buffer_id = ntohl(nfm->buffer_id);
fm->out_port = u16_to_ofp(ntohs(nfm->out_port));
- fm->out_group = OFPG11_ANY;
+ fm->out_group = OFPG_ANY;
raw_flags = nfm->flags;
} else {
OVS_NOT_REACHED();
{
struct ofpbuf *msg = ofpbuf_from_list(list_back(replies));
size_t start_ofs = msg->size;
- struct ofp13_meter_config *reply = ofpbuf_put_uninit(msg, sizeof *reply);
- reply->flags = htons(mc->flags);
- reply->meter_id = htonl(mc->meter_id);
+ struct ofp13_meter_config *reply;
+ ofpbuf_put_uninit(msg, sizeof *reply);
ofputil_put_bands(mc->n_bands, mc->bands, msg);
+ reply = ofpbuf_at_assert(msg, start_ofs, sizeof *reply);
+ reply->flags = htons(mc->flags);
+ reply->meter_id = htonl(mc->meter_id);
reply->length = htons(msg->size - start_ofs);
ofpmp_postappend(replies, start_ofs);
fsr->aggregate = aggregate;
ofputil_match_from_ofp10_match(&ofsr->match, &fsr->match);
fsr->out_port = u16_to_ofp(ntohs(ofsr->out_port));
- fsr->out_group = OFPG11_ANY;
+ fsr->out_group = OFPG_ANY;
fsr->table_id = ofsr->table_id;
fsr->cookie = fsr->cookie_mask = htonll(0);
fsr->aggregate = aggregate;
fsr->out_port = u16_to_ofp(ntohs(nfsr->out_port));
- fsr->out_group = OFPG11_ANY;
+ fsr->out_group = OFPG_ANY;
fsr->table_id = nfsr->table_id;
return 0;
case OFPRAW_OFPT10_QUEUE_GET_CONFIG_REQUEST:
qgcr10 = b.data;
*port = u16_to_ofp(ntohs(qgcr10->port));
- return 0;
+ break;
case OFPRAW_OFPT11_QUEUE_GET_CONFIG_REQUEST:
qgcr11 = b.data;
- return ofputil_port_from_ofp11(qgcr11->port, port);
+ enum ofperr error = ofputil_port_from_ofp11(qgcr11->port, port);
+ if (error || *port == OFPP_ANY) {
+ return error;
+ }
+ break;
+
+ default:
+ OVS_NOT_REACHED();
}
- OVS_NOT_REACHED();
+ return (ofp_to_u16(*port) < ofp_to_u16(OFPP_MAX)
+ ? 0
+ : OFPERR_OFPQOFC_BAD_PORT);
}
/* Constructs and returns the beginning of a reply to
}
static void
-put_queue_rate(struct ofpbuf *reply, enum ofp_queue_properties property,
- uint16_t rate)
+put_ofp10_queue_rate(struct ofpbuf *reply,
+ enum ofp10_queue_properties property, uint16_t rate)
{
if (rate != UINT16_MAX) {
- struct ofp_queue_prop_rate *oqpr;
+ struct ofp10_queue_prop_rate *oqpr;
oqpr = ofpbuf_put_zeros(reply, sizeof *oqpr);
oqpr->prop_header.property = htons(property);
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->msg;
- port = qgcr11->port;
opq12 = ofpbuf_put_zeros(reply, sizeof *opq12);
- opq12->port = port;
+ opq12->port = ofputil_port_to_ofp11(oqc->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);
+ put_ofp10_queue_rate(reply, OFPQT10_MIN_RATE, oqc->min_rate);
+ put_ofp10_queue_rate(reply, OFPQT11_MAX_RATE, oqc->max_rate);
len = ofpbuf_at(reply, len_ofs, sizeof *len);
*len = htons(reply->size - start_ofs);
}
static enum ofperr
-parse_queue_rate(const struct ofp_queue_prop_header *hdr, uint16_t *rate)
+parse_ofp10_queue_rate(const struct ofp10_queue_prop_header *hdr,
+ uint16_t *rate)
{
- const struct ofp_queue_prop_rate *oqpr;
+ const struct ofp10_queue_prop_rate *oqpr;
if (hdr->len == htons(sizeof *oqpr)) {
- oqpr = (const struct ofp_queue_prop_rate *) hdr;
+ oqpr = (const struct ofp10_queue_prop_rate *) hdr;
*rate = ntohs(oqpr->rate);
return 0;
} else {
len -= opq_len;
while (len > 0) {
- const struct ofp_queue_prop_header *hdr;
+ const struct ofp10_queue_prop_header *hdr;
unsigned int property;
unsigned int prop_len;
enum ofperr error = 0;
property = ntohs(hdr->property);
switch (property) {
- case OFPQT_MIN_RATE:
- error = parse_queue_rate(hdr, &queue->min_rate);
+ case OFPQT10_MIN_RATE:
+ error = parse_ofp10_queue_rate(hdr, &queue->min_rate);
break;
- case OFPQT_MAX_RATE:
- error = parse_queue_rate(hdr, &queue->max_rate);
+ case OFPQT11_MAX_RATE:
+ error = parse_ofp10_queue_rate(hdr, &queue->max_rate);
break;
default:
ofpbuf_use_const(&b, oh, ntohs(oh->length));
raw = ofpraw_pull_assert(&b);
+ ofpbuf_clear(ofpacts);
if (raw == OFPRAW_OFPT11_PACKET_OUT) {
enum ofperr error;
const struct ofp11_packet_out *opo = ofpbuf_pull(&b, sizeof *opo);
const struct ofp10_phy_port *opp)
{
pp->port_no = u16_to_ofp(ntohs(opp->port_no));
- memcpy(pp->hw_addr, opp->hw_addr, OFP_ETH_ALEN);
+ pp->hw_addr = opp->hw_addr;
ovs_strlcpy(pp->name, opp->name, OFP_MAX_PORT_NAME_LEN);
pp->config = ntohl(opp->config) & OFPPC10_ALL;
if (error) {
return error;
}
- memcpy(pp->hw_addr, op->hw_addr, OFP_ETH_ALEN);
+ pp->hw_addr = op->hw_addr;
ovs_strlcpy(pp->name, op->name, OFP_MAX_PORT_NAME_LEN);
pp->config = ntohl(op->config) & OFPPC11_ALL;
if (error) {
return error;
}
- memcpy(pp->hw_addr, op->hw_addr, OFP_ETH_ALEN);
+ pp->hw_addr = op->hw_addr;
ovs_strlcpy(pp->name, op->name, OFP_MAX_PORT_NAME_LEN);
pp->config = ntohl(op->config) & OFPPC11_ALL;
while (properties.size > 0) {
struct ofpbuf payload;
enum ofperr error;
- uint16_t type;
+ uint64_t type;
- error = ofputil_pull_property(&properties, &payload, &type);
+ error = ofpprop_pull(&properties, &payload, &type);
if (error) {
return error;
}
break;
default:
- log_property(true, "unknown port property %"PRIu16, type);
- error = 0;
+ error = OFPPROP_UNKNOWN(true, "port", type);
break;
}
memset(opp, 0, sizeof *opp);
opp->port_no = htons(ofp_to_u16(pp->port_no));
- memcpy(opp->hw_addr, pp->hw_addr, ETH_ADDR_LEN);
+ opp->hw_addr = pp->hw_addr;
ovs_strlcpy(opp->name, pp->name, OFP_MAX_PORT_NAME_LEN);
opp->config = htonl(pp->config & OFPPC10_ALL);
memset(op, 0, sizeof *op);
op->port_no = ofputil_port_to_ofp11(pp->port_no);
- memcpy(op->hw_addr, pp->hw_addr, ETH_ADDR_LEN);
+ op->hw_addr = pp->hw_addr;
ovs_strlcpy(op->name, pp->name, OFP_MAX_PORT_NAME_LEN);
op->config = htonl(pp->config & OFPPC11_ALL);
op = ofpbuf_put_zeros(b, sizeof *op);
op->port_no = ofputil_port_to_ofp11(pp->port_no);
op->length = htons(sizeof *op + sizeof *eth);
- memcpy(op->hw_addr, pp->hw_addr, ETH_ADDR_LEN);
+ op->hw_addr = pp->hw_addr;
ovs_strlcpy(op->name, pp->name, sizeof op->name);
op->config = htonl(pp->config & OFPPC11_ALL);
op->state = htonl(pp->state & OFPPS11_ALL);
ofp_port_t port)
{
struct ofpbuf *request;
- ovs_be32 ofp11_port;
switch (ofp_version) {
case OFP10_VERSION:
request = ofpraw_alloc(OFPRAW_OFPST10_PORT_DESC_REQUEST,
ofp_version, 0);
break;
-
- case OFP15_VERSION:
+ case OFP15_VERSION:{
+ struct ofp15_port_desc_request *req;
request = ofpraw_alloc(OFPRAW_OFPST15_PORT_DESC_REQUEST,
ofp_version, 0);
- ofp11_port = ofputil_port_to_ofp11(port);
- ofpbuf_put(request, &ofp11_port, sizeof ofp11_port);
+ req = ofpbuf_put_zeros(request, sizeof *req);
+ req->port_no = ofputil_port_to_ofp11(port);
break;
-
+ }
default:
OVS_NOT_REACHED();
}
ofpmp_postappend(replies, start_ofs);
}
\f
+/* ofputil_switch_config */
+
+/* Decodes 'oh', which must be an OFPT_GET_CONFIG_REPLY or OFPT_SET_CONFIG
+ * message, into 'config'. Returns false if 'oh' contained any flags that
+ * aren't specified in its version of OpenFlow, true otherwise. */
+static bool
+ofputil_decode_switch_config(const struct ofp_header *oh,
+ struct ofputil_switch_config *config)
+{
+ const struct ofp_switch_config *osc;
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ ofpraw_pull_assert(&b);
+ osc = ofpbuf_pull(&b, sizeof *osc);
+
+ config->frag = ntohs(osc->flags) & OFPC_FRAG_MASK;
+ config->miss_send_len = ntohs(osc->miss_send_len);
+
+ ovs_be16 valid_mask = htons(OFPC_FRAG_MASK);
+ if (oh->version < OFP13_VERSION) {
+ const ovs_be16 ttl_bit = htons(OFPC_INVALID_TTL_TO_CONTROLLER);
+ valid_mask |= ttl_bit;
+ config->invalid_ttl_to_controller = (osc->flags & ttl_bit) != 0;
+ } else {
+ config->invalid_ttl_to_controller = -1;
+ }
+
+ return !(osc->flags & ~valid_mask);
+}
+
+void
+ofputil_decode_get_config_reply(const struct ofp_header *oh,
+ struct ofputil_switch_config *config)
+{
+ ofputil_decode_switch_config(oh, config);
+}
+
+enum ofperr
+ofputil_decode_set_config(const struct ofp_header *oh,
+ struct ofputil_switch_config *config)
+{
+ return (ofputil_decode_switch_config(oh, config)
+ ? 0
+ : OFPERR_OFPSCFC_BAD_FLAGS);
+}
+
+static struct ofpbuf *
+ofputil_put_switch_config(const struct ofputil_switch_config *config,
+ struct ofpbuf *b)
+{
+ const struct ofp_header *oh = b->data;
+ struct ofp_switch_config *osc = ofpbuf_put_zeros(b, sizeof *osc);
+ osc->flags = htons(config->frag);
+ if (config->invalid_ttl_to_controller > 0 && oh->version < OFP13_VERSION) {
+ osc->flags |= htons(OFPC_INVALID_TTL_TO_CONTROLLER);
+ }
+ osc->miss_send_len = htons(config->miss_send_len);
+ return b;
+}
+
+struct ofpbuf *
+ofputil_encode_get_config_reply(const struct ofp_header *request,
+ const struct ofputil_switch_config *config)
+{
+ struct ofpbuf *b = ofpraw_alloc_reply(OFPRAW_OFPT_GET_CONFIG_REPLY,
+ request, 0);
+ return ofputil_put_switch_config(config, b);
+}
+
+struct ofpbuf *
+ofputil_encode_set_config(const struct ofputil_switch_config *config,
+ enum ofp_version version)
+{
+ struct ofpbuf *b = ofpraw_alloc(OFPRAW_OFPT_SET_CONFIG, version, 0);
+ return ofputil_put_switch_config(config, b);
+}
+\f
/* ofputil_switch_features */
#define OFPC_COMMON (OFPC_FLOW_STATS | OFPC_TABLE_STATS | OFPC_PORT_STATS | \
parse_port_mod_ethernet_property(struct ofpbuf *property,
struct ofputil_port_mod *pm)
{
- struct ofp14_port_mod_prop_ethernet *eth = property->data;
+ ovs_be32 advertise;
+ enum ofperr error;
- if (property->size != sizeof *eth) {
- return OFPERR_OFPBRC_BAD_LEN;
+ error = ofpprop_parse_be32(property, &advertise);
+ if (!error) {
+ pm->advertise = netdev_port_features_from_ofp11(advertise);
}
-
- pm->advertise = netdev_port_features_from_ofp11(eth->advertise);
- return 0;
+ return error;
}
/* Decodes the OpenFlow "port mod" message in '*oh' into an abstract form in
const struct ofp10_port_mod *opm = b.data;
pm->port_no = u16_to_ofp(ntohs(opm->port_no));
- memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
+ pm->hw_addr = opm->hw_addr;
pm->config = ntohl(opm->config) & OFPPC10_ALL;
pm->mask = ntohl(opm->mask) & OFPPC10_ALL;
pm->advertise = netdev_port_features_from_ofp10(opm->advertise);
return error;
}
- memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
+ pm->hw_addr = opm->hw_addr;
pm->config = ntohl(opm->config) & OFPPC11_ALL;
pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
pm->advertise = netdev_port_features_from_ofp11(opm->advertise);
return error;
}
- memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
+ pm->hw_addr = opm->hw_addr;
pm->config = ntohl(opm->config) & OFPPC11_ALL;
pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
while (b.size > 0) {
struct ofpbuf property;
enum ofperr error;
- uint16_t type;
+ uint64_t type;
- error = ofputil_pull_property(&b, &property, &type);
+ error = ofpprop_pull(&b, &property, &type);
if (error) {
return error;
}
break;
default:
- log_property(loose, "unknown port_mod property %"PRIu16, type);
- if (loose) {
- error = 0;
- } else if (type == OFPPMPT14_EXPERIMENTER) {
- error = OFPERR_OFPBPC_BAD_EXPERIMENTER;
- } else {
- error = OFPERR_OFPBRC_BAD_TYPE;
- }
+ error = OFPPROP_UNKNOWN(loose, "port_mod", type);
break;
}
b = ofpraw_alloc(OFPRAW_OFPT10_PORT_MOD, ofp_version, 0);
opm = ofpbuf_put_zeros(b, sizeof *opm);
opm->port_no = htons(ofp_to_u16(pm->port_no));
- memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
+ opm->hw_addr = pm->hw_addr;
opm->config = htonl(pm->config & OFPPC10_ALL);
opm->mask = htonl(pm->mask & OFPPC10_ALL);
opm->advertise = netdev_port_features_to_ofp10(pm->advertise);
b = ofpraw_alloc(OFPRAW_OFPT11_PORT_MOD, ofp_version, 0);
opm = ofpbuf_put_zeros(b, sizeof *opm);
opm->port_no = ofputil_port_to_ofp11(pm->port_no);
- memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
+ opm->hw_addr = pm->hw_addr;
opm->config = htonl(pm->config & OFPPC11_ALL);
opm->mask = htonl(pm->mask & OFPPC11_ALL);
opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
}
case OFP14_VERSION:
case OFP15_VERSION: {
- struct ofp14_port_mod_prop_ethernet *eth;
struct ofp14_port_mod *opm;
- b = ofpraw_alloc(OFPRAW_OFPT14_PORT_MOD, ofp_version, sizeof *eth);
+ b = ofpraw_alloc(OFPRAW_OFPT14_PORT_MOD, ofp_version, 0);
opm = ofpbuf_put_zeros(b, sizeof *opm);
opm->port_no = ofputil_port_to_ofp11(pm->port_no);
- memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
+ opm->hw_addr = pm->hw_addr;
opm->config = htonl(pm->config & OFPPC11_ALL);
opm->mask = htonl(pm->mask & OFPPC11_ALL);
if (pm->advertise) {
- eth = ofpbuf_put_zeros(b, sizeof *eth);
- eth->type = htons(OFPPMPT14_ETHERNET);
- eth->length = htons(sizeof *eth);
- eth->advertise = netdev_port_features_to_ofp11(pm->advertise);
+ ofpprop_put_be32(b, OFPPMPT14_ETHERNET,
+ netdev_port_features_to_ofp11(pm->advertise));
}
break;
}
static enum ofperr
pull_table_feature_property(struct ofpbuf *msg, struct ofpbuf *payload,
- uint16_t *typep)
+ uint64_t *typep)
{
enum ofperr error;
- error = ofputil_pull_property(msg, payload, typep);
+ error = ofpprop_pull(msg, payload, typep);
if (payload && !error) {
- ofpbuf_pull(payload, sizeof(struct ofp_prop_header));
+ ofpbuf_pull(payload, (char *)payload->msg - (char *)payload->header);
}
return error;
}
uint32_t types = 0;
while (payload->size > 0) {
- uint16_t type;
enum ofperr error;
+ uint64_t type;
- error = ofputil_pull_property__(payload, NULL, 1, &type);
+ error = ofpprop_pull__(payload, NULL, 1, 0x10000, &type);
if (error) {
return error;
}
while (payload->size > 0) {
enum ovs_instruction_type inst;
enum ofperr error;
- uint16_t ofpit;
+ uint64_t ofpit;
/* OF1.3 and OF1.4 aren't clear about padding in the instruction IDs.
* It seems clear that they aren't padded to 8 bytes, though, because
*
* Anyway, we just assume they're all glommed together on byte
* boundaries. */
- error = ofputil_pull_property__(payload, NULL, 1, &ofpit);
+ error = ofpprop_pull__(payload, NULL, 1, 0x10000, &ofpit);
if (error) {
return error;
}
while (properties.size > 0) {
struct ofpbuf payload;
enum ofperr error;
- uint16_t type;
+ uint64_t type;
error = pull_table_feature_property(&properties, &payload, &type);
if (error) {
case OFPTFPT13_EXPERIMENTER:
case OFPTFPT13_EXPERIMENTER_MISS:
default:
- log_property(loose, "unknown table features property %"PRIu16,
- type);
- error = loose ? 0 : OFPERR_OFPBPC_BAD_TYPE;
+ error = OFPPROP_UNKNOWN(loose, "table features", type);
break;
}
if (error) {
size_t start_ofs;
int field;
- start_ofs = start_property(reply, property);
+ start_ofs = ofpprop_start(reply, property);
BITMAP_FOR_EACH_1 (field, MFF_N_IDS, fields->bm) {
nx_put_header(reply, field, version,
masks && bitmap_is_set(masks->bm, field));
}
- end_property(reply, start_ofs);
+ ofpprop_end(reply, start_ofs);
}
static void
enum ofp13_table_feature_prop_type set_fields_type,
int miss_offset, enum ofp_version version)
{
- size_t start_ofs;
-
- start_ofs = start_property(reply, actions_type + miss_offset);
- put_bitmap_properties(reply,
- ntohl(ofpact_bitmap_to_openflow(taf->ofpacts,
- version)));
- end_property(reply, start_ofs);
-
+ ofpprop_put_bitmap(reply, actions_type + miss_offset,
+ ntohl(ofpact_bitmap_to_openflow(taf->ofpacts,
+ version)));
put_fields_property(reply, &taf->set_fields, NULL,
set_fields_type + miss_offset, version);
}
size_t start_ofs;
uint8_t table_id;
- start_ofs = start_property(reply, OFPTFPT13_INSTRUCTIONS + miss_offset);
- put_bitmap_properties(reply,
- ntohl(ovsinst_bitmap_to_openflow(tif->instructions,
- version)));
- end_property(reply, start_ofs);
+ ofpprop_put_bitmap(reply, OFPTFPT13_INSTRUCTIONS + miss_offset,
+ ntohl(ovsinst_bitmap_to_openflow(tif->instructions,
+ version)));
- start_ofs = start_property(reply, OFPTFPT13_NEXT_TABLES + miss_offset);
+ start_ofs = ofpprop_start(reply, OFPTFPT13_NEXT_TABLES + miss_offset);
BITMAP_FOR_EACH_1 (table_id, 255, tif->next) {
ofpbuf_put(reply, &table_id, 1);
}
- end_property(reply, start_ofs);
+ ofpprop_end(reply, start_ofs);
put_table_action_features(reply, &tif->write,
OFPTFPT13_WRITE_ACTIONS,
}
static enum ofperr
-parse_table_desc_eviction_property(struct ofpbuf *property,
- struct ofputil_table_desc *td)
+parse_table_desc_vacancy_property(struct ofpbuf *property,
+ struct ofputil_table_desc *td)
{
- struct ofp14_table_mod_prop_eviction *ote = property->data;
+ struct ofp14_table_mod_prop_vacancy *otv = property->data;
- if (property->size != sizeof *ote) {
+ if (property->size != sizeof *otv) {
return OFPERR_OFPBPC_BAD_LEN;
}
- td->eviction_flags = ntohl(ote->flags);
+ td->table_vacancy.vacancy_down = otv->vacancy_down;
+ td->table_vacancy.vacancy_up = otv->vacancy_up;
+ td->table_vacancy.vacancy = otv->vacancy;
return 0;
}
ofpbuf_use_const(&properties, ofpbuf_pull(msg, length), length);
td->eviction = ofputil_decode_table_eviction(otd->config, version);
+ td->vacancy = ofputil_decode_table_vacancy(otd->config, version);
td->eviction_flags = UINT32_MAX;
while (properties.size > 0) {
struct ofpbuf payload;
enum ofperr error;
- uint16_t type;
+ uint64_t type;
- error = ofputil_pull_property(&properties, &payload, &type);
+ error = ofpprop_pull(&properties, &payload, &type);
if (error) {
return error;
}
switch (type) {
case OFPTMPT14_EVICTION:
- error = parse_table_desc_eviction_property(&payload, td);
+ error = ofpprop_parse_u32(&payload, &td->eviction_flags);
+ break;
+
+ case OFPTMPT14_VACANCY:
+ error = parse_table_desc_vacancy_property(&payload, td);
break;
default:
- log_property(true, "unknown table_desc property %"PRIu16, type);
- error = 0;
+ error = OFPPROP_UNKNOWN(true, "table_desc", type);
break;
}
start_otd = reply->size;
ofpbuf_put_zeros(reply, sizeof *otd);
if (td->eviction_flags != UINT32_MAX) {
- struct ofp14_table_mod_prop_eviction *ote;
+ ofpprop_put_u32(reply, OFPTMPT14_EVICTION, td->eviction_flags);
+ }
+ if (td->vacancy == OFPUTIL_TABLE_VACANCY_ON) {
+ struct ofp14_table_mod_prop_vacancy *otv;
- ote = ofpbuf_put_zeros(reply, sizeof *ote);
- ote->type = htons(OFPTMPT14_EVICTION);
- ote->length = htons(sizeof *ote);
- ote->flags = htonl(td->eviction_flags);
+ otv = ofpbuf_put_zeros(reply, sizeof *otv);
+ otv->type = htons(OFPTMPT14_VACANCY);
+ otv->length = htons(sizeof *otv);
+ otv->vacancy_down = td->table_vacancy.vacancy_down;
+ otv->vacancy_up = td->table_vacancy.vacancy_up;
+ otv->vacancy = td->table_vacancy.vacancy;
}
otd = ofpbuf_at_assert(reply, start_otd, sizeof *otd);
otd->length = htons(reply->size - start_otd);
otd->table_id = td->table_id;
otd->config = ofputil_encode_table_config(OFPUTIL_TABLE_MISS_DEFAULT,
- td->eviction, version);
+ td->eviction, td->vacancy,
+ version);
ofpmp_postappend(replies, start_otd);
}
+/* This function parses Vacancy property, and decodes the
+ * ofp14_table_mod_prop_vacancy in ofputil_table_mod.
+ * Returns OFPERR_OFPBPC_BAD_VALUE error code when vacancy_down is
+ * greater than vacancy_up and also when current vacancy has non-zero
+ * value. Returns 0 on success. */
static enum ofperr
-parse_table_mod_eviction_property(struct ofpbuf *property,
- struct ofputil_table_mod *tm)
+parse_table_mod_vacancy_property(struct ofpbuf *property,
+ struct ofputil_table_mod *tm)
{
- struct ofp14_table_mod_prop_eviction *ote = property->data;
+ struct ofp14_table_mod_prop_vacancy *otv = property->data;
- if (property->size != sizeof *ote) {
+ if (property->size != sizeof *otv) {
return OFPERR_OFPBPC_BAD_LEN;
}
-
- tm->eviction_flags = ntohl(ote->flags);
+ tm->table_vacancy.vacancy_down = otv->vacancy_down;
+ tm->table_vacancy.vacancy_up = otv->vacancy_up;
+ if (tm->table_vacancy.vacancy_down > tm->table_vacancy.vacancy_up) {
+ OFPPROP_LOG(&bad_ofmsg_rl, false,
+ "Value of vacancy_down is greater than vacancy_up");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+ if (tm->table_vacancy.vacancy_down > 100 ||
+ tm->table_vacancy.vacancy_up > 100) {
+ OFPPROP_LOG(&bad_ofmsg_rl, false, "Vacancy threshold percentage "
+ "should not be greater than 100");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+ tm->table_vacancy.vacancy = otv->vacancy;
+ if (tm->table_vacancy.vacancy) {
+ OFPPROP_LOG(&bad_ofmsg_rl, false,
+ "Vacancy value should be zero for table-mod messages");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
return 0;
}
+/* Given 'config', taken from an OpenFlow 'version' message that specifies
+ * table configuration (a table mod, table stats, or table features message),
+ * returns the table vacancy configuration that it specifies.
+ *
+ * Only OpenFlow 1.4 and later specify table vacancy configuration this way,
+ * so for other 'version' this function always returns
+ * OFPUTIL_TABLE_VACANCY_DEFAULT. */
+static enum ofputil_table_vacancy
+ofputil_decode_table_vacancy(ovs_be32 config, enum ofp_version version)
+{
+ return (version < OFP14_VERSION ? OFPUTIL_TABLE_VACANCY_DEFAULT
+ : config & htonl(OFPTC14_VACANCY_EVENTS) ? OFPUTIL_TABLE_VACANCY_ON
+ : OFPUTIL_TABLE_VACANCY_OFF);
+}
+
/* Given 'config', taken from an OpenFlow 'version' message that specifies
* table configuration (a table mod, table stats, or table features message),
* returns the table eviction configuration that it specifies.
static ovs_be32
ofputil_encode_table_config(enum ofputil_table_miss miss,
enum ofputil_table_eviction eviction,
+ enum ofputil_table_vacancy vacancy,
enum ofp_version version)
{
+ uint32_t config = 0;
/* See the section "OFPTC_* Table Configuration" in DESIGN.md for more
* information on the crazy evolution of this field. */
switch (version) {
case OFP14_VERSION:
case OFP15_VERSION:
- /* OpenFlow 1.4 introduced OFPTC14_EVICTION and OFPTC14_VACANCY_EVENTS
- * and we don't support the latter yet. */
- return htonl(eviction == OFPUTIL_TABLE_EVICTION_ON
- ? OFPTC14_EVICTION : 0);
+ /* OpenFlow 1.4 introduced OFPTC14_EVICTION and
+ * OFPTC14_VACANCY_EVENTS. */
+ if (eviction == OFPUTIL_TABLE_EVICTION_ON) {
+ config |= OFPTC14_EVICTION;
+ }
+ if (vacancy == OFPUTIL_TABLE_VACANCY_ON) {
+ config |= OFPTC14_VACANCY_EVENTS;
+ }
+ return htonl(config);
}
OVS_NOT_REACHED();
pm->miss = OFPUTIL_TABLE_MISS_DEFAULT;
pm->eviction = OFPUTIL_TABLE_EVICTION_DEFAULT;
pm->eviction_flags = UINT32_MAX;
+ pm->vacancy = OFPUTIL_TABLE_VACANCY_DEFAULT;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
raw = ofpraw_pull_assert(&b);
pm->table_id = otm->table_id;
pm->miss = ofputil_decode_table_miss(otm->config, oh->version);
pm->eviction = ofputil_decode_table_eviction(otm->config, oh->version);
+ pm->vacancy = ofputil_decode_table_vacancy(otm->config, oh->version);
while (b.size > 0) {
struct ofpbuf property;
enum ofperr error;
- uint16_t type;
+ uint64_t type;
- error = ofputil_pull_property(&b, &property, &type);
+ error = ofpprop_pull(&b, &property, &type);
if (error) {
return error;
}
switch (type) {
case OFPTMPT14_EVICTION:
- error = parse_table_mod_eviction_property(&property, pm);
+ error = ofpprop_parse_u32(&property, &pm->eviction);
+ break;
+
+ case OFPTMPT14_VACANCY:
+ error = parse_table_mod_vacancy_property(&property, pm);
break;
default:
otm = ofpbuf_put_zeros(b, sizeof *otm);
otm->table_id = tm->table_id;
otm->config = ofputil_encode_table_config(tm->miss, tm->eviction,
- ofp_version);
+ tm->vacancy, ofp_version);
break;
}
case OFP14_VERSION:
case OFP15_VERSION: {
struct ofp14_table_mod *otm;
- struct ofp14_table_mod_prop_eviction *ote;
+ struct ofp14_table_mod_prop_vacancy *otv;
b = ofpraw_alloc(OFPRAW_OFPT14_TABLE_MOD, ofp_version, 0);
otm = ofpbuf_put_zeros(b, sizeof *otm);
otm->table_id = tm->table_id;
otm->config = ofputil_encode_table_config(tm->miss, tm->eviction,
- ofp_version);
+ tm->vacancy, ofp_version);
if (tm->eviction_flags != UINT32_MAX) {
- ote = ofpbuf_put_zeros(b, sizeof *ote);
- ote->type = htons(OFPTMPT14_EVICTION);
- ote->length = htons(sizeof *ote);
- ote->flags = htonl(tm->eviction_flags);
+ ofpprop_put_u32(b, OFPTMPT14_EVICTION, tm->eviction_flags);
+ }
+ if (tm->vacancy == OFPUTIL_TABLE_VACANCY_ON) {
+ otv = ofpbuf_put_zeros(b, sizeof *otv);
+ otv->type = htons(OFPTMPT14_VACANCY);
+ otv->length = htons(sizeof *otv);
+ otv->vacancy_down = tm->table_vacancy.vacancy_down;
+ otv->vacancy_up = tm->table_vacancy.vacancy_up;
}
break;
}
return 0;
}
+/* Encodes 'rf' according to 'protocol', and returns the encoded message.
+ * 'protocol' must be for OpenFlow 1.4 or later. */
+struct ofpbuf *
+ofputil_encode_requestforward(const struct ofputil_requestforward *rf,
+ enum ofputil_protocol protocol)
+{
+ enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
+ struct ofpbuf *inner;
+
+ switch (rf->reason) {
+ case OFPRFR_GROUP_MOD:
+ inner = ofputil_encode_group_mod(ofp_version, rf->group_mod);
+ break;
+
+ case OFPRFR_METER_MOD:
+ inner = ofputil_encode_meter_mod(ofp_version, rf->meter_mod);
+ break;
+
+ case OFPRFR_N_REASONS:
+ default:
+ OVS_NOT_REACHED();
+ }
+
+ struct ofp_header *inner_oh = inner->data;
+ inner_oh->xid = rf->xid;
+ inner_oh->length = htons(inner->size);
+
+ struct ofpbuf *outer = ofpraw_alloc_xid(OFPRAW_OFPT14_REQUESTFORWARD,
+ ofp_version, htonl(0),
+ inner->size);
+ ofpbuf_put(outer, inner->data, inner->size);
+ ofpbuf_delete(inner);
+
+ return outer;
+}
+
+/* Decodes OFPT_REQUESTFORWARD message 'outer'. On success, puts the decoded
+ * form into '*rf' and returns 0, and the caller is later responsible for
+ * freeing the content of 'rf', with ofputil_destroy_requestforward(rf). On
+ * failure, returns an ofperr and '*rf' is indeterminate. */
+enum ofperr
+ofputil_decode_requestforward(const struct ofp_header *outer,
+ struct ofputil_requestforward *rf)
+{
+ struct ofpbuf b;
+ enum ofperr error;
+
+ ofpbuf_use_const(&b, outer, ntohs(outer->length));
+
+ /* Skip past outer message. */
+ enum ofpraw outer_raw = ofpraw_pull_assert(&b);
+ ovs_assert(outer_raw == OFPRAW_OFPT14_REQUESTFORWARD);
+
+ /* Validate inner message. */
+ if (b.size < sizeof(struct ofp_header)) {
+ return OFPERR_OFPBFC_MSG_BAD_LEN;
+ }
+ const struct ofp_header *inner = b.data;
+ unsigned int inner_len = ntohs(inner->length);
+ if (inner_len < sizeof(struct ofp_header) || inner_len > b.size) {
+ return OFPERR_OFPBFC_MSG_BAD_LEN;
+ }
+ if (inner->version != outer->version) {
+ return OFPERR_OFPBRC_BAD_VERSION;
+ }
+
+ /* Parse inner message. */
+ enum ofptype type;
+ error = ofptype_decode(&type, inner);
+ if (error) {
+ return error;
+ }
+
+ rf->xid = inner->xid;
+ if (type == OFPTYPE_GROUP_MOD) {
+ rf->reason = OFPRFR_GROUP_MOD;
+ rf->group_mod = xmalloc(sizeof *rf->group_mod);
+ error = ofputil_decode_group_mod(inner, rf->group_mod);
+ if (error) {
+ free(rf->group_mod);
+ return error;
+ }
+ } else if (type == OFPTYPE_METER_MOD) {
+ rf->reason = OFPRFR_METER_MOD;
+ rf->meter_mod = xmalloc(sizeof *rf->meter_mod);
+ ofpbuf_init(&rf->bands, 64);
+ error = ofputil_decode_meter_mod(inner, rf->meter_mod, &rf->bands);
+ if (error) {
+ free(rf->meter_mod);
+ ofpbuf_uninit(&rf->bands);
+ return error;
+ }
+ } else {
+ return OFPERR_OFPBFC_MSG_UNSUP;
+ }
+
+ return 0;
+}
+
+/* Frees the content of 'rf', which should have been initialized through a
+ * successful call to ofputil_decode_requestforward(). */
+void
+ofputil_destroy_requestforward(struct ofputil_requestforward *rf)
+{
+ if (!rf) {
+ return;
+ }
+
+ switch (rf->reason) {
+ case OFPRFR_GROUP_MOD:
+ ofputil_uninit_group_mod(rf->group_mod);
+ free(rf->group_mod);
+ break;
+
+ case OFPRFR_METER_MOD:
+ ofpbuf_uninit(&rf->bands);
+ free(rf->meter_mod);
+ break;
+
+ case OFPRFR_N_REASONS:
+ OVS_NOT_REACHED();
+ }
+}
+
/* Table stats. */
/* OpenFlow 1.0 and 1.1 don't distinguish between a field that cannot be
features->nonmiss.instructions, OFP12_VERSION);
out->config = ofputil_encode_table_config(features->miss_config,
OFPUTIL_TABLE_EVICTION_DEFAULT,
+ OFPUTIL_TABLE_VACANCY_DEFAULT,
OFP12_VERSION);
out->max_entries = htonl(features->max_entries);
out->active_count = htonl(stats->active_count);
ofpraw_pull_assert(msg);
}
+ ofpbuf_clear(ofpacts);
if (!msg->size) {
return EOF;
}
}
const char *
-ofputil_frag_handling_to_string(enum ofp_config_flags flags)
+ofputil_frag_handling_to_string(enum ofputil_frag_handling frag)
{
- switch (flags & OFPC_FRAG_MASK) {
- case OFPC_FRAG_NORMAL: return "normal";
- case OFPC_FRAG_DROP: return "drop";
- case OFPC_FRAG_REASM: return "reassemble";
- case OFPC_FRAG_NX_MATCH: return "nx-match";
+ switch (frag) {
+ case OFPUTIL_FRAG_NORMAL: return "normal";
+ case OFPUTIL_FRAG_DROP: return "drop";
+ case OFPUTIL_FRAG_REASM: return "reassemble";
+ case OFPUTIL_FRAG_NX_MATCH: return "nx-match";
}
OVS_NOT_REACHED();
}
bool
-ofputil_frag_handling_from_string(const char *s, enum ofp_config_flags *flags)
+ofputil_frag_handling_from_string(const char *s,
+ enum ofputil_frag_handling *frag)
{
if (!strcasecmp(s, "normal")) {
- *flags = OFPC_FRAG_NORMAL;
+ *frag = OFPUTIL_FRAG_NORMAL;
} else if (!strcasecmp(s, "drop")) {
- *flags = OFPC_FRAG_DROP;
+ *frag = OFPUTIL_FRAG_DROP;
} else if (!strcasecmp(s, "reassemble")) {
- *flags = OFPC_FRAG_REASM;
+ *frag = OFPUTIL_FRAG_REASM;
} else if (!strcasecmp(s, "nx-match")) {
- *flags = OFPC_FRAG_NX_MATCH;
+ *frag = OFPUTIL_FRAG_NX_MATCH;
} else {
return false;
}
ofputil_group_from_string(const char *s, uint32_t *group_idp)
{
if (!strcasecmp(s, "any")) {
- *group_idp = OFPG11_ANY;
+ *group_idp = OFPG_ANY;
} else if (!strcasecmp(s, "all")) {
- *group_idp = OFPG11_ALL;
+ *group_idp = OFPG_ALL;
} else if (!str_to_uint(s, 10, group_idp)) {
VLOG_WARN("%s is not a valid group ID. (Valid group IDs are "
"32-bit nonnegative integers or the keywords ANY or "
/* Appends to 's' a string representation of the OpenFlow group ID 'group_id'.
* Most groups' string representation is just the number, but for special
- * groups, e.g. OFPG11_ALL, it is the name, e.g. "ALL". */
+ * groups, e.g. OFPG_ALL, it is the name, e.g. "ALL". */
void
ofputil_format_group(uint32_t group_id, struct ds *s)
{
/* Puts in the 'bufsize' byte in 'namebuf' a null-terminated string
* representation of OpenFlow group ID 'group_id'. Most group are represented
- * as just their number, but special groups, e.g. OFPG11_ALL, are represented
+ * as just their number, but special groups, e.g. OFPG_ALL, are represented
* by name, e.g. "ALL". */
void
ofputil_group_to_string(uint32_t group_id,
char namebuf[MAX_GROUP_NAME_LEN + 1], size_t bufsize)
{
switch (group_id) {
- case OFPG11_ALL:
+ case OFPG_ALL:
ovs_strlcpy(namebuf, "ALL", bufsize);
break;
- case OFPG11_ANY:
+ case OFPG_ANY:
ovs_strlcpy(namebuf, "ANY", bufsize);
break;
wc.masks.nw_ttl = 0;
}
if (!(may_match & MAY_ARP_SHA)) {
- memset(wc.masks.arp_sha, 0, ETH_ADDR_LEN);
+ WC_UNMASK_FIELD(&wc, arp_sha);
}
if (!(may_match & MAY_ARP_THA)) {
- memset(wc.masks.arp_tha, 0, ETH_ADDR_LEN);
+ WC_UNMASK_FIELD(&wc, arp_tha);
}
if (!(may_match & MAY_IPV6)) {
wc.masks.ipv6_src = wc.masks.ipv6_dst = in6addr_any;
while (properties.size > 0) {
struct ofpbuf payload;
enum ofperr error;
- uint16_t type;
+ uint64_t type;
- error = ofputil_pull_property(&properties, &payload, &type);
+ error = ofpprop_pull(&properties, &payload, &type);
if (error) {
return error;
}
break;
default:
- log_property(true, "unknown port stats property %"PRIu16, type);
- error = 0;
+ error = OFPPROP_UNKNOWN(true, "port stats", type);
break;
}
uint32_t group_id)
{
struct ofpbuf *request;
- ovs_be32 gid;
switch (ofp_version) {
case OFP10_VERSION:
request = ofpraw_alloc(OFPRAW_OFPST11_GROUP_DESC_REQUEST,
ofp_version, 0);
break;
- case OFP15_VERSION:
+ case OFP15_VERSION:{
+ struct ofp15_group_desc_request *req;
request = ofpraw_alloc(OFPRAW_OFPST15_GROUP_DESC_REQUEST,
ofp_version, 0);
- gid = htonl(group_id);
- ofpbuf_put(request, &gid, sizeof gid);
+ req = ofpbuf_put_zeros(request, sizeof *req);
+ req->group_id = htonl(group_id);
break;
+ }
default:
OVS_NOT_REACHED();
}
ob->watch_group = htonl(bucket->watch_group);
}
-static void
-ofputil_put_ofp15_group_bucket_prop_weight(ovs_be16 weight,
- struct ofpbuf *openflow)
-{
- size_t start_ofs;
- struct ofp15_group_bucket_prop_weight *prop;
-
- start_ofs = start_property(openflow, OFPGBPT15_WEIGHT);
- ofpbuf_put_zeros(openflow, sizeof *prop - sizeof(struct ofp_prop_header));
- prop = ofpbuf_at_assert(openflow, start_ofs, sizeof *prop);
- prop->weight = weight;
- end_property(openflow, start_ofs);
-}
-
-static void
-ofputil_put_ofp15_group_bucket_prop_watch(ovs_be32 watch, uint16_t type,
- struct ofpbuf *openflow)
-{
- size_t start_ofs;
- struct ofp15_group_bucket_prop_watch *prop;
-
- start_ofs = start_property(openflow, type);
- ofpbuf_put_zeros(openflow, sizeof *prop - sizeof(struct ofp_prop_header));
- prop = ofpbuf_at_assert(openflow, start_ofs, sizeof *prop);
- prop->watch = watch;
- end_property(openflow, start_ofs);
-}
-
static void
ofputil_put_ofp15_bucket(const struct ofputil_bucket *bucket,
uint32_t bucket_id, enum ofp11_group_type group_type,
actions_len = openflow->size - actions_start;
if (group_type == OFPGT11_SELECT) {
- ofputil_put_ofp15_group_bucket_prop_weight(htons(bucket->weight),
- openflow);
+ ofpprop_put_u16(openflow, OFPGBPT15_WEIGHT, bucket->weight);
}
if (bucket->watch_port != OFPP_ANY) {
- ovs_be32 port = ofputil_port_to_ofp11(bucket->watch_port);
- ofputil_put_ofp15_group_bucket_prop_watch(port,
- OFPGBPT15_WATCH_PORT,
- openflow);
+ ofpprop_put_be32(openflow, OFPGBPT15_WATCH_PORT,
+ ofputil_port_to_ofp11(bucket->watch_port));
}
if (bucket->watch_group != OFPG_ANY) {
- ovs_be32 group = htonl(bucket->watch_group);
- ofputil_put_ofp15_group_bucket_prop_watch(group,
- OFPGBPT15_WATCH_GROUP,
- openflow);
+ ofpprop_put_u32(openflow, OFPGBPT15_WATCH_GROUP, bucket->watch_group);
}
ob = ofpbuf_at_assert(openflow, start, sizeof *ob);
prop->exp_type = htonl(NTRT_SELECTION_METHOD);
strcpy(prop->selection_method, gp->selection_method);
prop->selection_method_param = htonll(gp->selection_method_param);
- end_property(openflow, start);
+ ofpprop_end(openflow, start);
}
static void
gds->type, reply, version);
}
ogds = ofpbuf_at_assert(reply, start_ogds, sizeof *ogds);
- ogds->length = htons(reply->size - start_ogds);
ogds->type = gds->type;
ogds->group_id = htonl(gds->group_id);
ogds->bucket_list_len = htons(reply->size - start_buckets);
ofputil_put_group_prop_ntr_selection_method(version, &gds->props,
reply);
}
+ ogds->length = htons(reply->size - start_ogds);
ofpmp_postappend(replies, start_ogds);
}
return 0;
}
-static enum ofperr
-parse_ofp15_group_bucket_prop_weight(const struct ofpbuf *payload,
- ovs_be16 *weight)
-{
- struct ofp15_group_bucket_prop_weight *prop = payload->data;
-
- if (payload->size != sizeof *prop) {
- log_property(false, "OpenFlow bucket weight property length "
- "%u is not valid", payload->size);
- return OFPERR_OFPBPC_BAD_LEN;
- }
-
- *weight = prop->weight;
-
- return 0;
-}
-
-static enum ofperr
-parse_ofp15_group_bucket_prop_watch(const struct ofpbuf *payload,
- ovs_be32 *watch)
-{
- struct ofp15_group_bucket_prop_watch *prop = payload->data;
-
- if (payload->size != sizeof *prop) {
- log_property(false, "OpenFlow bucket watch port or group "
- "property length %u is not valid", payload->size);
- return OFPERR_OFPBPC_BAD_LEN;
- }
-
- *watch = prop->watch;
-
- return 0;
-}
-
static enum ofperr
ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length,
enum ofp_version version, uint8_t group_type,
while (properties.size > 0) {
struct ofpbuf payload;
- uint16_t type;
+ uint64_t type;
- err = ofputil_pull_property(&properties, &payload, &type);
+ err = ofpprop_pull(&properties, &payload, &type);
if (err) {
goto err;
}
switch (type) {
case OFPGBPT15_WEIGHT:
- err = parse_ofp15_group_bucket_prop_weight(&payload, &weight);
+ err = ofpprop_parse_be16(&payload, &weight);
break;
case OFPGBPT15_WATCH_PORT:
- err = parse_ofp15_group_bucket_prop_watch(&payload,
- &watch_port);
+ err = ofpprop_parse_be32(&payload, &watch_port);
break;
case OFPGBPT15_WATCH_GROUP:
- err = parse_ofp15_group_bucket_prop_watch(&payload,
- &watch_group);
+ err = ofpprop_parse_be32(&payload, &watch_group);
break;
default:
- log_property(false, "unknown group bucket property %"PRIu16,
- type);
- err = OFPERR_OFPBPC_BAD_TYPE;
+ err = OFPPROP_UNKNOWN(false, "group bucket", type);
break;
}
case OFPGT11_ALL:
case OFPGT11_INDIRECT:
case OFPGT11_FF:
- log_property(false, "ntr selection method property is only allowed "
- "for select groups");
+ OFPPROP_LOG(&bad_ofmsg_rl, false, "ntr selection method property is "
+ "only allowed for select groups");
return OFPERR_OFPBPC_BAD_VALUE;
default:
OVS_NOT_REACHED();
case OFPGC15_DELETE:
case OFPGC15_INSERT_BUCKET:
case OFPGC15_REMOVE_BUCKET:
- log_property(false, "ntr selection method property is only allowed "
- "for add and delete group modifications");
+ OFPPROP_LOG(&bad_ofmsg_rl, false, "ntr selection method property is "
+ "only allowed for add and delete group modifications");
return OFPERR_OFPBPC_BAD_VALUE;
default:
OVS_NOT_REACHED();
}
if (payload->size < sizeof *prop) {
- log_property(false, "ntr selection method property length "
- "%u is not valid", payload->size);
+ OFPPROP_LOG(&bad_ofmsg_rl, false, "ntr selection method property "
+ "length %u is not valid", payload->size);
return OFPERR_OFPBPC_BAD_LEN;
}
method_len = strnlen(prop->selection_method, NTR_MAX_SELECTION_METHOD_LEN);
if (method_len == NTR_MAX_SELECTION_METHOD_LEN) {
- log_property(false, "ntr selection method is not null terminated");
+ OFPPROP_LOG(&bad_ofmsg_rl, false,
+ "ntr selection method is not null terminated");
return OFPERR_OFPBPC_BAD_VALUE;
}
if (strcmp("hash", prop->selection_method)) {
- log_property(false, "ntr selection method '%s' is not supported",
- prop->selection_method);
+ OFPPROP_LOG(&bad_ofmsg_rl, false,
+ "ntr selection method '%s' is not supported",
+ prop->selection_method);
return OFPERR_OFPBPC_BAD_VALUE;
}
gp->selection_method_param = ntohll(prop->selection_method_param);
if (!method_len && gp->selection_method_param) {
- log_property(false, "ntr selection method parameter is non-zero but "
- "selection method is empty");
+ OFPPROP_LOG(&bad_ofmsg_rl, false, "ntr selection method parameter is "
+ "non-zero but selection method is empty");
return OFPERR_OFPBPC_BAD_VALUE;
}
fields_len = ntohs(prop->length) - sizeof *prop;
if (!method_len && fields_len) {
- log_property(false, "ntr selection method parameter is zero "
- "but fields are provided");
+ OFPPROP_LOG(&bad_ofmsg_rl, false, "ntr selection method parameter is "
+ "zero but fields are provided");
return OFPERR_OFPBPC_BAD_VALUE;
}
error = oxm_pull_field_array(payload->data, fields_len,
&gp->fields);
if (error) {
- log_property(false, "ntr selection method fields are invalid");
+ OFPPROP_LOG(&bad_ofmsg_rl, false,
+ "ntr selection method fields are invalid");
return error;
}
return 0;
}
-static enum ofperr
-parse_group_prop_ntr(struct ofpbuf *payload, uint32_t exp_type,
- enum ofp11_group_type group_type,
- enum ofp15_group_mod_command group_cmd,
- struct ofputil_group_props *gp)
-{
- enum ofperr error;
-
- switch (exp_type) {
- case NTRT_SELECTION_METHOD:
- error = parse_group_prop_ntr_selection_method(payload, group_type,
- group_cmd, gp);
- break;
-
- default:
- log_property(false, "unknown group property ntr experimenter type "
- "%"PRIu32, exp_type);
- error = OFPERR_OFPBPC_BAD_TYPE;
- break;
- }
-
- return error;
-}
-
-static enum ofperr
-parse_ofp15_group_prop_exp(struct ofpbuf *payload,
- enum ofp11_group_type group_type,
- enum ofp15_group_mod_command group_cmd,
- struct ofputil_group_props *gp)
-{
- struct ofp_prop_experimenter *prop = payload->data;
- uint16_t experimenter;
- uint32_t exp_type;
- enum ofperr error;
-
- if (payload->size < sizeof *prop) {
- return OFPERR_OFPBPC_BAD_LEN;
- }
-
- experimenter = ntohl(prop->experimenter);
- exp_type = ntohl(prop->exp_type);
-
- switch (experimenter) {
- case NTR_VENDOR_ID:
- error = parse_group_prop_ntr(payload, exp_type, group_type,
- group_cmd, gp);
- break;
-
- default:
- log_property(false, "unknown group property experimenter %"PRIu16,
- experimenter);
- error = OFPERR_OFPBPC_BAD_EXPERIMENTER;
- break;
- }
-
- return error;
-}
-
static enum ofperr
parse_ofp15_group_properties(struct ofpbuf *msg,
enum ofp11_group_type group_type,
while (properties.size > 0) {
struct ofpbuf payload;
enum ofperr error;
- uint16_t type;
+ uint64_t type;
- error = ofputil_pull_property(&properties, &payload, &type);
+ error = ofpprop_pull(&properties, &payload, &type);
if (error) {
return error;
}
switch (type) {
- case OFPGPT15_EXPERIMENTER:
- error = parse_ofp15_group_prop_exp(&payload, group_type,
- group_cmd, gp);
+ case OFPPROP_EXP(NTR_VENDOR_ID, NTRT_SELECTION_METHOD):
+ case OFPPROP_EXP(NTR_COMPAT_VENDOR_ID, NTRT_SELECTION_METHOD):
+ error = parse_group_prop_ntr_selection_method(&payload, group_type,
+ group_cmd, gp);
break;
default:
- log_property(false, "unknown group property %"PRIu16, type);
- error = OFPERR_OFPBPC_BAD_TYPE;
+ error = OFPPROP_UNKNOWN(false, "group", type);
break;
}
* claim that the group mod command is OFPGC15_ADD to
* satisfy the check in parse_group_prop_ntr_selection_method() */
return parse_ofp15_group_properties(msg, gd->type, OFPGC15_ADD, &gd->props,
- msg->size);
+ length - sizeof *ogds - bucket_list_len);
}
/* Converts a group description reply in 'msg' into an abstract
switch (gm->type) {
case OFPGT11_INDIRECT:
if (!list_is_singleton(&gm->buckets)) {
- return OFPERR_OFPGMFC_OUT_OF_BUCKETS;
+ return OFPERR_OFPGMFC_INVALID_GROUP;
}
break;
case OFPGT11_ALL:
case OFPGT11_FF:
break;
default:
- OVS_NOT_REACHED();
+ return OFPERR_OFPGMFC_BAD_TYPE;
}
switch (gm->command) {
}
break;
default:
- OVS_NOT_REACHED();
+ return OFPERR_OFPGMFC_BAD_COMMAND;
}
LIST_FOR_EACH (bucket, list_node, &gm->buckets) {
}
break;
default:
- OVS_NOT_REACHED();
+ /* Returning BAD TYPE to be consistent
+ * though gm->type has been checked already. */
+ return OFPERR_OFPGMFC_BAD_TYPE;
}
}
case OFPTYPE_TABLE_MOD:
case OFPTYPE_METER_MOD:
case OFPTYPE_PACKET_OUT:
- case OFPTYPE_NXT_GENEVE_TABLE_MOD:
+ case OFPTYPE_NXT_TLV_TABLE_MOD:
/* Not to be bundlable. */
case OFPTYPE_ECHO_REQUEST:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
case OFPTYPE_TABLE_DESC_REPLY:
case OFPTYPE_ROLE_STATUS:
- case OFPTYPE_NXT_GENEVE_TABLE_REQUEST:
- case OFPTYPE_NXT_GENEVE_TABLE_REPLY:
+ case OFPTYPE_REQUESTFORWARD:
+ case OFPTYPE_NXT_TLV_TABLE_REQUEST:
+ case OFPTYPE_NXT_TLV_TABLE_REPLY:
break;
}
}
static void
-encode_geneve_table_mappings(struct ofpbuf *b, struct ovs_list *mappings)
+encode_tlv_table_mappings(struct ofpbuf *b, struct ovs_list *mappings)
{
- struct ofputil_geneve_map *map;
+ struct ofputil_tlv_map *map;
LIST_FOR_EACH (map, list_node, mappings) {
- struct nx_geneve_map *nx_map;
+ struct nx_tlv_map *nx_map;
nx_map = ofpbuf_put_zeros(b, sizeof *nx_map);
nx_map->option_class = htons(map->option_class);
}
struct ofpbuf *
-ofputil_encode_geneve_table_mod(enum ofp_version ofp_version,
- struct ofputil_geneve_table_mod *gtm)
+ofputil_encode_tlv_table_mod(enum ofp_version ofp_version,
+ struct ofputil_tlv_table_mod *ttm)
{
struct ofpbuf *b;
- struct nx_geneve_table_mod *nx_gtm;
+ struct nx_tlv_table_mod *nx_ttm;
- b = ofpraw_alloc(OFPRAW_NXT_GENEVE_TABLE_MOD, ofp_version, 0);
- nx_gtm = ofpbuf_put_zeros(b, sizeof *nx_gtm);
- nx_gtm->command = htons(gtm->command);
- encode_geneve_table_mappings(b, >m->mappings);
+ b = ofpraw_alloc(OFPRAW_NXT_TLV_TABLE_MOD, ofp_version, 0);
+ nx_ttm = ofpbuf_put_zeros(b, sizeof *nx_ttm);
+ nx_ttm->command = htons(ttm->command);
+ encode_tlv_table_mappings(b, &ttm->mappings);
return b;
}
static enum ofperr
-decode_geneve_table_mappings(struct ofpbuf *msg, unsigned int max_fields,
+decode_tlv_table_mappings(struct ofpbuf *msg, unsigned int max_fields,
struct ovs_list *mappings)
{
list_init(mappings);
while (msg->size) {
- struct nx_geneve_map *nx_map;
- struct ofputil_geneve_map *map;
+ struct nx_tlv_map *nx_map;
+ struct ofputil_tlv_map *map;
nx_map = ofpbuf_pull(msg, sizeof *nx_map);
map = xmalloc(sizeof *map);
map->option_type = nx_map->option_type;
map->option_len = nx_map->option_len;
- if (map->option_len == 0 || map->option_len % 4 ||
- map->option_len > GENEVE_MAX_OPT_SIZE) {
+ if (map->option_len % 4 || map->option_len > TLV_MAX_OPT_SIZE) {
VLOG_WARN_RL(&bad_ofmsg_rl,
- "geneve table option length (%u) is not a valid option size",
+ "tlv table option length (%u) is not a valid option size",
map->option_len);
- ofputil_uninit_geneve_table(mappings);
- return OFPERR_NXGTMFC_BAD_OPT_LEN;
+ ofputil_uninit_tlv_table(mappings);
+ return OFPERR_NXTTMFC_BAD_OPT_LEN;
}
map->index = ntohs(nx_map->index);
if (map->index >= max_fields) {
VLOG_WARN_RL(&bad_ofmsg_rl,
- "geneve table field index (%u) is too large (max %u)",
+ "tlv table field index (%u) is too large (max %u)",
map->index, max_fields - 1);
- ofputil_uninit_geneve_table(mappings);
- return OFPERR_NXGTMFC_BAD_FIELD_IDX;
+ ofputil_uninit_tlv_table(mappings);
+ return OFPERR_NXTTMFC_BAD_FIELD_IDX;
}
}
}
enum ofperr
-ofputil_decode_geneve_table_mod(const struct ofp_header *oh,
- struct ofputil_geneve_table_mod *gtm)
+ofputil_decode_tlv_table_mod(const struct ofp_header *oh,
+ struct ofputil_tlv_table_mod *ttm)
{
struct ofpbuf msg;
- struct nx_geneve_table_mod *nx_gtm;
+ struct nx_tlv_table_mod *nx_ttm;
ofpbuf_use_const(&msg, oh, ntohs(oh->length));
ofpraw_pull_assert(&msg);
- nx_gtm = ofpbuf_pull(&msg, sizeof *nx_gtm);
- gtm->command = ntohs(nx_gtm->command);
- if (gtm->command > NXGTMC_CLEAR) {
+ nx_ttm = ofpbuf_pull(&msg, sizeof *nx_ttm);
+ ttm->command = ntohs(nx_ttm->command);
+ if (ttm->command > NXTTMC_CLEAR) {
VLOG_WARN_RL(&bad_ofmsg_rl,
- "geneve table mod command (%u) is out of range",
- gtm->command);
- return OFPERR_NXGTMFC_BAD_COMMAND;
+ "tlv table mod command (%u) is out of range",
+ ttm->command);
+ return OFPERR_NXTTMFC_BAD_COMMAND;
}
- return decode_geneve_table_mappings(&msg, TUN_METADATA_NUM_OPTS,
- >m->mappings);
+ return decode_tlv_table_mappings(&msg, TUN_METADATA_NUM_OPTS,
+ &ttm->mappings);
}
struct ofpbuf *
-ofputil_encode_geneve_table_reply(const struct ofp_header *oh,
- struct ofputil_geneve_table_reply *gtr)
+ofputil_encode_tlv_table_reply(const struct ofp_header *oh,
+ struct ofputil_tlv_table_reply *ttr)
{
struct ofpbuf *b;
- struct nx_geneve_table_reply *nx_gtr;
+ struct nx_tlv_table_reply *nx_ttr;
- b = ofpraw_alloc_reply(OFPRAW_NXT_GENEVE_TABLE_REPLY, oh, 0);
- nx_gtr = ofpbuf_put_zeros(b, sizeof *nx_gtr);
- nx_gtr->max_option_space = htonl(gtr->max_option_space);
- nx_gtr->max_fields = htons(gtr->max_fields);
+ b = ofpraw_alloc_reply(OFPRAW_NXT_TLV_TABLE_REPLY, oh, 0);
+ nx_ttr = ofpbuf_put_zeros(b, sizeof *nx_ttr);
+ nx_ttr->max_option_space = htonl(ttr->max_option_space);
+ nx_ttr->max_fields = htons(ttr->max_fields);
- encode_geneve_table_mappings(b, >r->mappings);
+ encode_tlv_table_mappings(b, &ttr->mappings);
return b;
}
-/* Decodes the NXT_GENEVE_TABLE_REPLY message in 'oh' into '*gtr'. Returns 0
+/* Decodes the NXT_TLV_TABLE_REPLY message in 'oh' into '*ttr'. Returns 0
* if successful, otherwise an ofperr.
*
- * The decoder verifies that the indexes in 'gtr->mappings' are less than
- * 'gtr->max_fields', but the caller must ensure, if necessary, that they are
+ * The decoder verifies that the indexes in 'ttr->mappings' are less than
+ * 'ttr->max_fields', but the caller must ensure, if necessary, that they are
* less than TUN_METADATA_NUM_OPTS. */
enum ofperr
-ofputil_decode_geneve_table_reply(const struct ofp_header *oh,
- struct ofputil_geneve_table_reply *gtr)
+ofputil_decode_tlv_table_reply(const struct ofp_header *oh,
+ struct ofputil_tlv_table_reply *ttr)
{
struct ofpbuf msg;
- struct nx_geneve_table_reply *nx_gtr;
+ struct nx_tlv_table_reply *nx_ttr;
ofpbuf_use_const(&msg, oh, ntohs(oh->length));
ofpraw_pull_assert(&msg);
- nx_gtr = ofpbuf_pull(&msg, sizeof *nx_gtr);
- gtr->max_option_space = ntohl(nx_gtr->max_option_space);
- gtr->max_fields = ntohs(nx_gtr->max_fields);
+ nx_ttr = ofpbuf_pull(&msg, sizeof *nx_ttr);
+ ttr->max_option_space = ntohl(nx_ttr->max_option_space);
+ ttr->max_fields = ntohs(nx_ttr->max_fields);
- return decode_geneve_table_mappings(&msg, gtr->max_fields, >r->mappings);
+ return decode_tlv_table_mappings(&msg, ttr->max_fields, &ttr->mappings);
}
void
-ofputil_uninit_geneve_table(struct ovs_list *mappings)
+ofputil_uninit_tlv_table(struct ovs_list *mappings)
{
- struct ofputil_geneve_map *map;
+ struct ofputil_tlv_map *map;
LIST_FOR_EACH_POP (map, list_node, mappings) {
free(map);
* treats unknown properties and values as an error, as a switch would want to
* do when interpreting a configuration request made by a controller.
*
- * Returns 0 if successful, otherwise an OFPERR_* value. */
+ * Returns 0 if successful, otherwise an OFPERR_* value.
+ *
+ * Returns error code OFPERR_OFPACFC_INVALID if the value of mask is not in
+ * the valid range of mask.
+ *
+ * Returns error code OFPERR_OFPACFC_UNSUPPORTED if the configuration is not
+ * supported.*/
enum ofperr
ofputil_decode_set_async_config(const struct ofp_header *oh,
uint32_t master[OAM_N_TYPES],
raw == OFPRAW_OFPT14_GET_ASYNC_REPLY) {
while (b.size > 0) {
- struct ofp14_async_config_prop_reasons *msg;
struct ofpbuf property;
enum ofperr error;
- uint16_t type;
+ uint64_t type;
+ uint32_t mask;
- error = ofputil_pull_property(&b, &property, &type);
+ error = ofpprop_pull__(&b, &property, 8, 0xfffe, &type);
if (error) {
return error;
}
- msg = property.data;
-
- if (property.size != sizeof *msg) {
- return OFPERR_OFPBRC_BAD_LEN;
+ error = ofpprop_parse_u32(&property, &mask);
+ if (error) {
+ return error;
}
+ if (!loose) {
+ error = ofputil_check_mask(type, mask);
+ if (error) {
+ return error;
+ }
+ }
+
switch (type) {
case OFPACPT_PACKET_IN_SLAVE:
- slave[OAM_PACKET_IN] = ntohl(msg->mask);
+ slave[OAM_PACKET_IN] = mask;
break;
case OFPACPT_PACKET_IN_MASTER:
- master[OAM_PACKET_IN] = ntohl(msg->mask);
+ master[OAM_PACKET_IN] = mask;
break;
case OFPACPT_PORT_STATUS_SLAVE:
- slave[OAM_PORT_STATUS] = ntohl(msg->mask);
+ slave[OAM_PORT_STATUS] = mask;
break;
case OFPACPT_PORT_STATUS_MASTER:
- master[OAM_PORT_STATUS] = ntohl(msg->mask);
+ master[OAM_PORT_STATUS] = mask;
break;
case OFPACPT_FLOW_REMOVED_SLAVE:
- slave[OAM_FLOW_REMOVED] = ntohl(msg->mask);
+ slave[OAM_FLOW_REMOVED] = mask;
break;
case OFPACPT_FLOW_REMOVED_MASTER:
- master[OAM_FLOW_REMOVED] = ntohl(msg->mask);
+ master[OAM_FLOW_REMOVED] = mask;
break;
case OFPACPT_ROLE_STATUS_SLAVE:
- slave[OAM_ROLE_STATUS] = ntohl(msg->mask);
+ slave[OAM_ROLE_STATUS] = mask;
break;
case OFPACPT_ROLE_STATUS_MASTER:
- master[OAM_ROLE_STATUS] = ntohl(msg->mask);
+ master[OAM_ROLE_STATUS] = mask;
break;
case OFPACPT_TABLE_STATUS_SLAVE:
- slave[OAM_TABLE_STATUS] = ntohl(msg->mask);
+ slave[OAM_TABLE_STATUS] = mask;
break;
case OFPACPT_TABLE_STATUS_MASTER:
- master[OAM_TABLE_STATUS] = ntohl(msg->mask);
+ master[OAM_TABLE_STATUS] = mask;
break;
case OFPACPT_REQUESTFORWARD_SLAVE:
- slave[OAM_REQUESTFORWARD] = ntohl(msg->mask);
+ slave[OAM_REQUESTFORWARD] = mask;
break;
case OFPACPT_REQUESTFORWARD_MASTER:
- master[OAM_REQUESTFORWARD] = ntohl(msg->mask);
+ master[OAM_REQUESTFORWARD] = mask;
break;
default:
- error = loose ? 0 : OFPERR_OFPBPC_BAD_TYPE;
- break;
- }
- if (error) {
+ error = loose ? 0 : OFPERR_OFPACFC_UNSUPPORTED;
return error;
}
}
int role;
for (role = 0; role < 2; role++) {
- struct ofp14_async_config_prop_reasons *msg;
-
- msg = ofpbuf_put_zeros(buf, sizeof *msg);
+ enum ofp14_async_config_prop_type prop_type;
switch (type) {
case OAM_PACKET_IN:
- msg->type = (role ? htons(OFPACPT_PACKET_IN_SLAVE)
- : htons(OFPACPT_PACKET_IN_MASTER));
+ prop_type = (role ? OFPACPT_PACKET_IN_SLAVE
+ : OFPACPT_PACKET_IN_MASTER);
break;
case OAM_PORT_STATUS:
- msg->type = (role ? htons(OFPACPT_PORT_STATUS_SLAVE)
- : htons(OFPACPT_PORT_STATUS_MASTER));
+ prop_type = (role ? OFPACPT_PORT_STATUS_SLAVE
+ : OFPACPT_PORT_STATUS_MASTER);
break;
case OAM_FLOW_REMOVED:
- msg->type = (role ? htons(OFPACPT_FLOW_REMOVED_SLAVE)
- : htons(OFPACPT_FLOW_REMOVED_MASTER));
+ prop_type = (role ? OFPACPT_FLOW_REMOVED_SLAVE
+ : OFPACPT_FLOW_REMOVED_MASTER);
break;
case OAM_ROLE_STATUS:
- msg->type = (role ? htons(OFPACPT_ROLE_STATUS_SLAVE)
- : htons(OFPACPT_ROLE_STATUS_MASTER));
+ prop_type = (role ? OFPACPT_ROLE_STATUS_SLAVE
+ : OFPACPT_ROLE_STATUS_MASTER);
break;
case OAM_TABLE_STATUS:
- msg->type = (role ? htons(OFPACPT_TABLE_STATUS_SLAVE)
- : htons(OFPACPT_TABLE_STATUS_MASTER));
+ prop_type = (role ? OFPACPT_TABLE_STATUS_SLAVE
+ : OFPACPT_TABLE_STATUS_MASTER);
break;
case OAM_REQUESTFORWARD:
- msg->type = (role ? htons(OFPACPT_REQUESTFORWARD_SLAVE)
- : htons(OFPACPT_REQUESTFORWARD_MASTER));
+ prop_type = (role ? OFPACPT_REQUESTFORWARD_SLAVE
+ : OFPACPT_REQUESTFORWARD_MASTER);
break;
default:
return OFPERR_OFPBRC_BAD_TYPE;
}
- msg->length = htons(sizeof *msg);
- msg->mask = (role ? htonl(slave_mask) : htonl(master_mask));
+ ofpprop_put_u32(buf, prop_type, role ? slave_mask : master_mask);
}
return 0;