diff options
-rw-r--r-- | include/openflow/openflow-1.3.h | 24 | ||||
-rw-r--r-- | include/openvswitch/ofp-table.h | 14 | ||||
-rw-r--r-- | lib/ofp-table.c | 83 |
3 files changed, 118 insertions, 3 deletions
diff --git a/include/openflow/openflow-1.3.h b/include/openflow/openflow-1.3.h index a521995da..c48a8ea7f 100644 --- a/include/openflow/openflow-1.3.h +++ b/include/openflow/openflow-1.3.h @@ -215,13 +215,24 @@ struct ofp13_table_stats { }; OFP_ASSERT(sizeof(struct ofp13_table_stats) == 24); +enum ofp15_table_features_command { + OFPTFC15_REPLACE = 0, /* Replace full pipeline. */ + OFPTFC15_MODIFY = 1, /* Modify flow tables capabilities. */ + OFPTFC15_ENABLE = 2, /* Enable flow tables in the pipeline. */ + OFPTFC15_DISABLE = 3, /* Disable flow tables in pipeline. */ +}; + /* Body for ofp_multipart_request of type OFPMP_TABLE_FEATURES./ * Body of reply to OFPMP_TABLE_FEATURES request. */ struct ofp13_table_features { ovs_be16 length; /* Length is padded to 64 bits. */ uint8_t table_id; /* Identifier of table. Lower numbered tables are consulted first. */ - uint8_t pad[5]; /* Align to 64-bits. */ + + /* Added in OF1.5. Earlier versions acted like OFPTFC15_REPLACE. */ + uint8_t command; /* One of OFPTFC15_*. */ + + uint8_t pad[4]; /* Align to 64-bits. */ char name[OFP_MAX_TABLE_NAME_LEN]; ovs_be64 metadata_match; /* Bits of metadata table can match. */ ovs_be64 metadata_write; /* Bits of metadata table can write. */ @@ -260,6 +271,17 @@ enum ofp13_table_feature_prop_type { OFPTFPT13_APPLY_SETFIELD_MISS = 15, /* Apply Set-Field for table-miss. */ OFPTFPT13_EXPERIMENTER = 0xFFFE, /* Experimenter property. */ OFPTFPT13_EXPERIMENTER_MISS = 0xFFFF, /* Experimenter for table-miss. */ + + /* OpenFlow says that each of these properties must occur exactly once. */ +#define OFPTFPT13_REQUIRED ((1u << OFPTFPT13_INSTRUCTIONS) | \ + (1u << OFPTFPT13_NEXT_TABLES) | \ + (1u << OFPTFPT13_WRITE_ACTIONS) | \ + (1u << OFPTFPT13_APPLY_ACTIONS) | \ + (1u << OFPTFPT13_MATCH) | \ + (1u << OFPTFPT13_WILDCARDS) | \ + (1u << OFPTFPT13_WRITE_SETFIELD) | \ + (1u << OFPTFPT13_APPLY_SETFIELD)) + }; /* Body of reply to OFPMP13_PORT request. If a counter is unsupported, set diff --git a/include/openvswitch/ofp-table.h b/include/openvswitch/ofp-table.h index 713ce26d0..370ec85ae 100644 --- a/include/openvswitch/ofp-table.h +++ b/include/openvswitch/ofp-table.h @@ -187,13 +187,23 @@ void ofputil_table_desc_format(struct ds *, * include support for a subset of ofp_table_features through OFPST_TABLE (aka * OFPMP_TABLE). */ struct ofputil_table_features { - uint8_t table_id; /* Identifier of table. Lower numbered tables - are consulted first. */ + /* Only for OFPT_TABLE_FEATURES requests and only the first table_features + * in such a request. */ + enum ofp15_table_features_command command; + + /* The following are always present in table features requests and + * replies. */ + uint8_t table_id; char name[OFP_MAX_TABLE_NAME_LEN]; ovs_be64 metadata_match; /* Bits of metadata table can match. */ ovs_be64 metadata_write; /* Bits of metadata table can write. */ uint32_t max_entries; /* Max number of entries supported. */ + /* True if the message included any properties. This is important for + * OFPT_TABLE_FEATURES requests, which change table properties only if any + * are included. */ + bool any_properties; + /* Flags. * * 'miss_config' is relevant for OpenFlow 1.1 and 1.2 only, because those diff --git a/lib/ofp-table.c b/lib/ofp-table.c index 8a070af3f..126b5060a 100644 --- a/lib/ofp-table.c +++ b/lib/ofp-table.c @@ -74,6 +74,33 @@ ofputil_table_vacancy_to_string(enum ofputil_table_vacancy vacancy) default: return "***error***"; } } + +static bool +ofp15_table_features_command_is_valid(enum ofp15_table_features_command cmd) +{ + switch (cmd) { + case OFPTFC15_REPLACE: + case OFPTFC15_MODIFY: + case OFPTFC15_ENABLE: + case OFPTFC15_DISABLE: + return true; + + default: + return false; + } +} + +static const char * +ofp15_table_features_command_to_string(enum ofp15_table_features_command cmd) +{ + switch (cmd) { + case OFPTFC15_REPLACE: return "replace"; + case OFPTFC15_MODIFY: return "modify"; + case OFPTFC15_ENABLE: return "enable"; + case OFPTFC15_DISABLE: return "disable"; + default: return "***bad command***"; + } +} /* ofputil_table_map. */ @@ -361,6 +388,15 @@ ofputil_decode_table_features(struct ofpbuf *msg, return OFPERR_OFPBPC_BAD_LEN; } + if (oh->version >= OFP15_VERSION) { + if (!ofp15_table_features_command_is_valid(otf->command)) { + return OFPERR_OFPTFFC_BAD_COMMAND; + } + tf->command = otf->command; + } else { + tf->command = OFPTFC15_REPLACE; + } + tf->table_id = otf->table_id; if (tf->table_id == OFPTT_ALL) { return OFPERR_OFPTFFC_BAD_TABLE; @@ -382,7 +418,9 @@ ofputil_decode_table_features(struct ofpbuf *msg, struct ofpbuf properties = ofpbuf_const_initializer(ofpbuf_pull(msg, len), len); + tf->any_properties = properties.size > 0; ofpbuf_pull(&properties, sizeof *otf); + uint32_t seen = 0; while (properties.size > 0) { struct ofpbuf payload; enum ofperr error; @@ -393,6 +431,14 @@ ofputil_decode_table_features(struct ofpbuf *msg, return error; } + if (type < 32) { + uint32_t bit = 1u << type; + if (seen & bit) { + return OFPERR_OFPTFFC_BAD_FEATURES; + } + seen |= bit; + } + switch ((enum ofp13_table_feature_prop_type) type) { case OFPTFPT13_INSTRUCTIONS: error = parse_instruction_ids(&payload, loose, @@ -464,6 +510,36 @@ ofputil_decode_table_features(struct ofpbuf *msg, } } + /* OpenFlow 1.3 and 1.4 always require all of the required properties. + * OpenFlow 1.5 requires all of them if any property is present. */ + if ((seen & OFPTFPT13_REQUIRED) != OFPTFPT13_REQUIRED + && (tf->any_properties || oh->version < OFP15_VERSION)) { + VLOG_WARN_RL(&rl, "table features message missing required property"); + return OFPERR_OFPTFFC_BAD_FEATURES; + } + + /* Copy nonmiss to miss when appropriate. */ + if (tf->any_properties) { + if (!(seen & (1u << OFPTFPT13_INSTRUCTIONS_MISS))) { + tf->miss.instructions = tf->nonmiss.instructions; + } + if (!(seen & (1u << OFPTFPT13_NEXT_TABLES_MISS))) { + memcpy(tf->miss.next, tf->nonmiss.next, sizeof tf->miss.next); + } + if (!(seen & (1u << OFPTFPT13_WRITE_ACTIONS_MISS))) { + tf->miss.write.ofpacts = tf->nonmiss.write.ofpacts; + } + if (!(seen & (1u << OFPTFPT13_APPLY_ACTIONS_MISS))) { + tf->miss.apply.ofpacts = tf->nonmiss.apply.ofpacts; + } + if (!(seen & (1u << OFPTFPT13_WRITE_SETFIELD_MISS))) { + tf->miss.write.set_fields = tf->nonmiss.write.set_fields; + } + if (!(seen & (1u << OFPTFPT13_APPLY_SETFIELD_MISS))) { + tf->miss.apply.set_fields = tf->nonmiss.apply.set_fields; + } + } + /* Fix inconsistencies: * * - Turn on 'match' bits that are set in 'mask', because maskable @@ -577,6 +653,7 @@ ofputil_append_table_features_reply(const struct ofputil_table_features *tf, otf = ofpbuf_put_zeros(reply, sizeof *otf); otf->table_id = tf->table_id; + otf->command = version >= OFP15_VERSION ? tf->command : 0; ovs_strlcpy_arrays(otf->name, tf->name); otf->metadata_match = tf->metadata_match; otf->metadata_write = tf->metadata_write; @@ -1434,6 +1511,12 @@ ofputil_table_features_format( const struct ofputil_table_stats *prev_stats, int *first_ditto, int *last_ditto) { + if (!prev_features && features->command != OFPTFC15_REPLACE) { + ds_put_format(s, "\n command: %s", + ofp15_table_features_command_to_string( + features->command)); + } + int table = features->table_id; int prev_table = prev_features ? prev_features->table_id : 0; |