mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 14:25:26 +00:00
openflow: Table maintenance commands for Geneve options.
In order to work with Geneve options, we need to maintain a mapping table between an option (defined by <class, type, length>) and an NXM field that can be operated on for the purposes of matches, actions, etc. This mapping must be explicitly specified by the user. Conceptually, this table could be communicated using either OpenFlow or OVSDB. Using OVSDB requires less code and definition of extensions than OpenFlow but introduces the possibility that mapping table updates and flow modifications are desynchronized from each other. This is dangerous because the mapping table signifcantly impacts the way that flows using Geneve options are installed and processed by OVS. Therefore, the mapping table is maintained using OpenFlow commands instead, which opens the possibility of using synchronization between table changes and flow modifications through barriers, bundles, etc. There are two primary groups of OpenFlow messages that are introduced as Nicira extensions: modification commands (add, delete, clear mappings) and table status request/reply to dump the current table along with switch information. Note that mappings should not be changed while they are in active use by a flow. The result of doing so is undefined. This only adds the OpenFlow infrastructure but doesn't actually do anything with the information yet after the messages have been decoded. Signed-off-by: Jesse Gross <jesse@nicira.com> Acked-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
140
lib/ofp-util.c
140
lib/ofp-util.c
@@ -41,6 +41,7 @@
|
||||
#include "openflow/netronome-ext.h"
|
||||
#include "packets.h"
|
||||
#include "random.h"
|
||||
#include "tun-metadata.h"
|
||||
#include "unaligned.h"
|
||||
#include "type-props.h"
|
||||
#include "openvswitch/vlog.h"
|
||||
@@ -8759,6 +8760,7 @@ ofputil_is_bundlable(enum ofptype type)
|
||||
case OFPTYPE_TABLE_MOD:
|
||||
case OFPTYPE_METER_MOD:
|
||||
case OFPTYPE_PACKET_OUT:
|
||||
case OFPTYPE_NXT_GENEVE_TABLE_MOD:
|
||||
|
||||
/* Not to be bundlable. */
|
||||
case OFPTYPE_ECHO_REQUEST:
|
||||
@@ -8822,6 +8824,8 @@ ofputil_is_bundlable(enum ofptype type)
|
||||
case OFPTYPE_METER_FEATURES_STATS_REPLY:
|
||||
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
|
||||
case OFPTYPE_ROLE_STATUS:
|
||||
case OFPTYPE_NXT_GENEVE_TABLE_REQUEST:
|
||||
case OFPTYPE_NXT_GENEVE_TABLE_REPLY:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -8893,3 +8897,139 @@ ofputil_encode_bundle_add(enum ofp_version ofp_version,
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
static void
|
||||
encode_geneve_table_mappings(struct ofpbuf *b, struct ovs_list *mappings)
|
||||
{
|
||||
struct ofputil_geneve_map *map;
|
||||
|
||||
LIST_FOR_EACH (map, list_node, mappings) {
|
||||
struct nx_geneve_map *nx_map;
|
||||
|
||||
nx_map = ofpbuf_put_zeros(b, sizeof *nx_map);
|
||||
nx_map->option_class = htons(map->option_class);
|
||||
nx_map->option_type = map->option_type;
|
||||
nx_map->option_len = map->option_len;
|
||||
nx_map->index = htons(map->index);
|
||||
}
|
||||
}
|
||||
|
||||
struct ofpbuf *
|
||||
ofputil_encode_geneve_table_mod(enum ofp_version ofp_version,
|
||||
struct ofputil_geneve_table_mod *gtm)
|
||||
{
|
||||
struct ofpbuf *b;
|
||||
struct nx_geneve_table_mod *nx_gtm;
|
||||
|
||||
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);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static enum ofperr
|
||||
decode_geneve_table_mappings(struct ofpbuf *msg, struct ovs_list *mappings)
|
||||
{
|
||||
list_init(mappings);
|
||||
|
||||
while (msg->size) {
|
||||
struct nx_geneve_map *nx_map;
|
||||
struct ofputil_geneve_map *map;
|
||||
|
||||
nx_map = ofpbuf_pull(msg, sizeof *nx_map);
|
||||
map = xmalloc(sizeof *map);
|
||||
list_push_back(mappings, &map->list_node);
|
||||
|
||||
map->option_class = ntohs(nx_map->option_class);
|
||||
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) {
|
||||
VLOG_WARN_RL(&bad_ofmsg_rl,
|
||||
"geneve table option length (%u) is not a valid option size",
|
||||
map->option_len);
|
||||
ofputil_uninit_geneve_table(mappings);
|
||||
return OFPERR_NXGTMFC_BAD_OPT_LEN;
|
||||
}
|
||||
|
||||
map->index = ntohs(nx_map->index);
|
||||
if (map->index >= TUN_METADATA_NUM_OPTS) {
|
||||
VLOG_WARN_RL(&bad_ofmsg_rl,
|
||||
"geneve table field index (%u) is too large (max %u)",
|
||||
map->index, TUN_METADATA_NUM_OPTS - 1);
|
||||
ofputil_uninit_geneve_table(mappings);
|
||||
return OFPERR_NXGTMFC_BAD_FIELD_IDX;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum ofperr
|
||||
ofputil_decode_geneve_table_mod(const struct ofp_header *oh,
|
||||
struct ofputil_geneve_table_mod *gtm)
|
||||
{
|
||||
struct ofpbuf msg;
|
||||
struct nx_geneve_table_mod *nx_gtm;
|
||||
|
||||
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) {
|
||||
VLOG_WARN_RL(&bad_ofmsg_rl,
|
||||
"geneve table mod command (%u) is out of range",
|
||||
gtm->command);
|
||||
return OFPERR_NXGTMFC_BAD_COMMAND;
|
||||
}
|
||||
|
||||
return decode_geneve_table_mappings(&msg, >m->mappings);
|
||||
}
|
||||
|
||||
struct ofpbuf *
|
||||
ofputil_encode_geneve_table_reply(const struct ofp_header *oh,
|
||||
struct ofputil_geneve_table_reply *gtr)
|
||||
{
|
||||
struct ofpbuf *b;
|
||||
struct nx_geneve_table_reply *nx_gtr;
|
||||
|
||||
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);
|
||||
|
||||
encode_geneve_table_mappings(b, >r->mappings);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
enum ofperr
|
||||
ofputil_decode_geneve_table_reply(const struct ofp_header *oh,
|
||||
struct ofputil_geneve_table_reply *gtr)
|
||||
{
|
||||
struct ofpbuf msg;
|
||||
struct nx_geneve_table_reply *nx_gtr;
|
||||
|
||||
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);
|
||||
|
||||
return decode_geneve_table_mappings(&msg, >r->mappings);
|
||||
}
|
||||
|
||||
void
|
||||
ofputil_uninit_geneve_table(struct ovs_list *mappings)
|
||||
{
|
||||
struct ofputil_geneve_map *map;
|
||||
|
||||
LIST_FOR_EACH_POP (map, list_node, mappings) {
|
||||
free(map);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user