* 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 {
}
}
+static enum ofperr
+ofputil_check_mask(uint16_t type, uint32_t mask)
+{
+ switch (type) {
+ case OFPACPT_PACKET_IN_SLAVE:
+ case OFPACPT_PACKET_IN_MASTER:
+ if (mask > MAXIMUM_MASK_PACKET_IN) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ break;
+
+ case OFPACPT_FLOW_REMOVED_SLAVE:
+ case OFPACPT_FLOW_REMOVED_MASTER:
+ if (mask > MAXIMUM_MASK_FLOW_REMOVED) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ break;
+
+ case OFPACPT_PORT_STATUS_SLAVE:
+ case OFPACPT_PORT_STATUS_MASTER:
+ if (mask > MAXIMUM_MASK_PORT_STATUS) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ break;
+
+ case OFPACPT_ROLE_STATUS_SLAVE:
+ case OFPACPT_ROLE_STATUS_MASTER:
+ if (mask > MAXIMUM_MASK_ROLE_STATUS) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ break;
+
+ 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;
+
+ case OFPACPT_REQUESTFORWARD_SLAVE:
+ case OFPACPT_REQUESTFORWARD_MASTER:
+ if (mask > MAXIMUM_MASK_REQUESTFORWARD) {
+ return OFPERR_OFPACFC_INVALID;
+ }
+ break;
+ }
+ return 0;
+}
+
static size_t
start_property(struct ofpbuf *msg, uint16_t type)
{
void
ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 34);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35);
/* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
return 0;
}
+static enum ofperr
+parse_table_desc_vacancy_property(struct ofpbuf *property,
+ struct ofputil_table_desc *td)
+{
+ struct ofp14_table_mod_prop_vacancy *otv = property->data;
+
+ if (property->size != sizeof *otv) {
+ return OFPERR_OFPBPC_BAD_LEN;
+ }
+
+ td->table_vacancy.vacancy_down = otv->vacancy_down;
+ td->table_vacancy.vacancy_up = otv->vacancy_up;
+ td->table_vacancy.vacancy = otv->vacancy;
+ return 0;
+}
+
/* Decodes the next OpenFlow "table desc" message (of possibly several) from
* 'msg' into an abstract form in '*td'. Returns 0 if successful, EOF if the
* last "table desc" in 'msg' was already decoded, otherwise an OFPERR_*
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) {
error = parse_table_desc_eviction_property(&payload, td);
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;
ote->length = htons(sizeof *ote);
ote->flags = htonl(td->eviction_flags);
}
+ if (td->vacancy == OFPUTIL_TABLE_VACANCY_ON) {
+ struct ofp14_table_mod_prop_vacancy *otv;
+
+ 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_vacancy_property(struct ofpbuf *property,
+ struct ofputil_table_mod *tm)
+{
+ struct ofp14_table_mod_prop_vacancy *otv = property->data;
+
+ if (property->size != sizeof *otv) {
+ return OFPERR_OFPBPC_BAD_LEN;
+ }
+ 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) {
+ log_property(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) {
+ log_property(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) {
+ log_property(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);
+}
+
static enum ofperr
parse_table_mod_eviction_property(struct ofpbuf *property,
struct ofputil_table_mod *tm)
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;
error = parse_table_mod_eviction_property(&property, pm);
break;
+ case OFPTMPT14_VACANCY:
+ error = parse_table_mod_vacancy_property(&property, pm);
+ break;
+
default:
error = OFPERR_OFPBRC_BAD_TYPE;
break;
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->length = htons(sizeof *ote);
ote->flags = htonl(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;
}
default:
inner = ofputil_encode_meter_mod(ofp_version, rf->meter_mod);
break;
+ case OFPRFR_N_REASONS:
default:
OVS_NOT_REACHED();
}
case OFPRFR_METER_MOD:
ofpbuf_uninit(&rf->bands);
free(rf->meter_mod);
+ break;
+
+ case OFPRFR_N_REASONS:
+ OVS_NOT_REACHED();
}
}
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);
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_DESC_REPLY:
case OFPTYPE_ROLE_STATUS:
case OFPTYPE_REQUESTFORWARD:
- case OFPTYPE_NXT_GENEVE_TABLE_REQUEST:
- case OFPTYPE_NXT_GENEVE_TABLE_REPLY:
+ 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 % 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],
return OFPERR_OFPBRC_BAD_LEN;
}
+ if (!loose) {
+ error = ofputil_check_mask(type, ntohl(msg->mask));
+ if (error) {
+ return error;
+ }
+ }
+
switch (type) {
case OFPACPT_PACKET_IN_SLAVE:
slave[OAM_PACKET_IN] = ntohl(msg->mask);
break;
default:
- error = loose ? 0 : OFPERR_OFPBPC_BAD_TYPE;
- break;
- }
- if (error) {
+ error = loose ? 0 : OFPERR_OFPACFC_UNSUPPORTED;
return error;
}
}