/*
- * 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.
}
}
+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)
{
{
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);
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
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;
}
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 | \
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();
}
}
}
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;
}
}
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_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;
}
}