Skip to content

Commit

Permalink
openflow: Table maintenance commands for Geneve options.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Ben Pfaff <[email protected]>
  • Loading branch information
jessegross committed Jun 25, 2015
1 parent 00fe22f commit 6159c53
Show file tree
Hide file tree
Showing 17 changed files with 574 additions and 0 deletions.
70 changes: 70 additions & 0 deletions include/openflow/nicira-ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -900,4 +900,74 @@ struct nx_flow_monitor_cancel {
};
OFP_ASSERT(sizeof(struct nx_flow_monitor_cancel) == 4);

/* Geneve option table maintainance commands.
*
* 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.
*
* 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. */

/* Geneve table commands */
enum nx_geneve_table_mod_command {
NXGTMC_ADD, /* New mappings (fails if an option is already
mapped). */
NXGTMC_DELETE, /* Delete mappings, identified by index
* (unmapped options are ignored). */
NXGTMC_CLEAR, /* Clear all mappings. Additional information
in this command is ignored. */
};

/* Map between a Geneve option and an NXM field. */
struct nx_geneve_map {
ovs_be16 option_class; /* Geneve option class. */
uint8_t option_type; /* Geneve option type. */
uint8_t option_len; /* Geneve option length (multiple of 4). */
ovs_be16 index; /* NXM_NX_TUN_METADATA<n> index */
uint8_t pad[2];
};
OFP_ASSERT(sizeof(struct nx_geneve_map) == 8);

/* NXT_GENEVE_TABLE_MOD.
*
* Use to configure a mapping between Geneve options (class, type, length)
* and NXM fields (NXM_NX_TUN_METADATA<n> where 'index' is <n>).
*
* This command is atomic: all operations on different options will
* either succeed or fail. */
struct nx_geneve_table_mod {
ovs_be16 command; /* One of NTGTMC_* */
uint8_t pad[6];
/* struct nx_geneve_map[0]; Array of maps between indicies and Geneve
options. The number of elements is
inferred from the length field in the
header. */
};
OFP_ASSERT(sizeof(struct nx_geneve_table_mod) == 8);

/* NXT_GENEVE_TABLE_REPLY.
*
* Issued in reponse to an NXT_GENEVE_TABLE_REQUEST to give information
* about the current status of the Geneve table in the switch. Provides
* both static information about the switch's capabilities as well as
* the configured Geneve option table. */
struct nx_geneve_table_reply {
ovs_be32 max_option_space; /* Maximum total of option sizes supported. */
ovs_be16 max_fields; /* Maximum number of match fields supported. */
uint8_t pad[2];
/* struct nx_geneve_map[0]; Array of maps between indicies and Geneve
options. The number of elements is
inferred from the length field in the
header. */
};
OFP_ASSERT(sizeof(struct nx_geneve_table_reply) == 8);

#endif /* openflow/nicira-ext.h */
1 change: 1 addition & 0 deletions lib/automake.mk
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ lib_libopenvswitch_la_SOURCES = \
lib/tnl-ports.c \
lib/tnl-ports.h \
lib/token-bucket.c \
lib/tun-metadata.h \
lib/type-props.h \
lib/unaligned.h \
lib/unicode.c \
Expand Down
3 changes: 3 additions & 0 deletions lib/learning-switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,9 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg)
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
case OFPTYPE_BUNDLE_CONTROL:
case OFPTYPE_BUNDLE_ADD_MESSAGE:
case OFPTYPE_NXT_GENEVE_TABLE_MOD:
case OFPTYPE_NXT_GENEVE_TABLE_REQUEST:
case OFPTYPE_NXT_GENEVE_TABLE_REPLY:
default:
if (VLOG_IS_DBG_ENABLED()) {
char *s = ofp_to_string(msg->data, msg->size, 2);
Expand Down
28 changes: 28 additions & 0 deletions lib/ofp-errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,34 @@ enum ofperr {
/* OF1.4+(16,7). Error in output port/group. */
OFPERR_OFPMOFC_BAD_OUT,

/* ## ----------------------------- ## */
/* ## OFPET_GENEVE_TABLE_MOD_FAILED ## */
/* ## ----------------------------- ## */

/* NX1.0-1.1(1,527), NX1.2+(16). The Geneve table mod command is not
* recognized as a valid operation. */
OFPERR_NXGTMFC_BAD_COMMAND,

/* NX1.0-1.1(1,528), NX1.2+(17). The option length is not a valid
* option size for Geneve. */
OFPERR_NXGTMFC_BAD_OPT_LEN,

/* NX1.0-1.1(1,529), NX1.2+(18). The field index is out of range for
* the supported NX_TUN_METADATA<n> match. */
OFPERR_NXGTMFC_BAD_FIELD_IDX,

/* NX1.0-1.1(1,530), NX1.2+(19). The total set of configured options
* exceeds the maximum supported by the switch. */
OFPERR_NXGTMFC_TABLE_FULL,

/* NX1.0-1.1(1,531), NX1.2+(20). The controller issued an NXGTMC_ADD
* command for a field index that is already mapped. */
OFPERR_NXGTMFC_ALREADY_MAPPED,

/* NX1.0-1.1(1,532), NX1.2+(21). The Geneve option that is attempting
* to be mapped is the same as one assigned to a different field. */
OFPERR_NXGTMFC_DUP_ENTRY,

/* ## ------------------ ## */
/* ## OFPET_EXPERIMENTER ## */
/* ## ------------------ ## */
Expand Down
12 changes: 12 additions & 0 deletions lib/ofp-msgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,15 @@ enum ofpraw {

/* NXT 1.0+ (23): void. */
OFPRAW_NXT_FLOW_MONITOR_RESUMED,

/* NXT 1.0+ (24): struct nx_geneve_table_mod, struct nx_geneve_map[]. */
OFPRAW_NXT_GENEVE_TABLE_MOD,

/* NXT 1.0+ (25): void. */
OFPRAW_NXT_GENEVE_TABLE_REQUEST,

/* NXT 1.0+ (26): struct nx_geneve_table_reply, struct nx_geneve_map[]. */
OFPRAW_NXT_GENEVE_TABLE_REPLY,
};

/* Decoding messages into OFPRAW_* values. */
Expand Down Expand Up @@ -620,6 +629,9 @@ enum ofptype {
OFPTYPE_SET_PACKET_IN_FORMAT, /* OFPRAW_NXT_SET_PACKET_IN_FORMAT. */
OFPTYPE_FLOW_AGE, /* OFPRAW_NXT_FLOW_AGE. */
OFPTYPE_SET_CONTROLLER_ID, /* OFPRAW_NXT_SET_CONTROLLER_ID. */
OFPTYPE_NXT_GENEVE_TABLE_MOD, /* OFPRAW_NXT_GENEVE_TABLE_MOD. */
OFPTYPE_NXT_GENEVE_TABLE_REQUEST, /* OFPRAW_NXT_GENEVE_TABLE_REQUEST. */
OFPTYPE_NXT_GENEVE_TABLE_REPLY, /* OFPRAW_NXT_GENEVE_TABLE_REPLY. */

/* Flow monitor extension. */
OFPTYPE_FLOW_MONITOR_CANCEL, /* OFPRAW_NXT_FLOW_MONITOR_CANCEL. */
Expand Down
33 changes: 33 additions & 0 deletions lib/ofp-parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -1584,3 +1584,36 @@ parse_ofp_group_mod_file(const char *file_name, uint16_t command,
}
return NULL;
}

char * OVS_WARN_UNUSED_RESULT
parse_ofp_geneve_table_mod_str(struct ofputil_geneve_table_mod *gtm,
uint16_t command, const char *s,
enum ofputil_protocol *usable_protocols)
{
*usable_protocols = OFPUTIL_P_NXM_OXM_ANY;

gtm->command = command;
list_init(&gtm->mappings);

while (*s) {
struct ofputil_geneve_map *map = xmalloc(sizeof *map);
int n;

if (*s == ',') {
s++;
}

list_push_back(&gtm->mappings, &map->list_node);

if (!ovs_scan(s, "{class=%"SCNi16",type=%"SCNi8",len=%"SCNi8"}->tun_metadata%"SCNi16"%n",
&map->option_class, &map->option_type, &map->option_len,
&map->index, &n)) {
ofputil_uninit_geneve_table(&gtm->mappings);
return xstrdup("invalid geneve mapping");
}

s += n;
}

return NULL;
}
6 changes: 6 additions & 0 deletions lib/ofp-parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct ofputil_flow_stats_request;
struct ofputil_group_mod;
struct ofputil_meter_mod;
struct ofputil_table_mod;
struct ofputil_geneve_table_mod;
struct simap;
enum ofputil_protocol;

Expand Down Expand Up @@ -84,6 +85,11 @@ char *parse_ofp_group_mod_str(struct ofputil_group_mod *, uint16_t command,
enum ofputil_protocol *usable_protocols)
OVS_WARN_UNUSED_RESULT;

char *parse_ofp_geneve_table_mod_str(struct ofputil_geneve_table_mod *,
uint16_t command, const char *string,
enum ofputil_protocol *usable_protocols)
OVS_WARN_UNUSED_RESULT;

char *str_to_u8(const char *str, const char *name, uint8_t *valuep)
OVS_WARN_UNUSED_RESULT;
char *str_to_u16(const char *str, const char *name, uint16_t *valuep)
Expand Down
91 changes: 91 additions & 0 deletions lib/ofp-print.c
Original file line number Diff line number Diff line change
Expand Up @@ -2641,6 +2641,85 @@ ofp_print_bundle_add(struct ds *s, const struct ofp_header *oh, int verbosity)
}
}

static void
print_geneve_table(struct ds *s, struct ovs_list *mappings)
{
struct ofputil_geneve_map *map;

ds_put_cstr(s, " mapping table:\n");
ds_put_cstr(s, " class\ttype\tlength\tmatch field\n");
ds_put_cstr(s, " -----\t----\t------\t-----------");

LIST_FOR_EACH (map, list_node, mappings) {
ds_put_char(s, '\n');
ds_put_format(s, " 0x%"PRIx16"\t0x%"PRIx8"\t%"PRIu8"\ttun_metadata%"PRIu16,
map->option_class, map->option_type, map->option_len,
map->index);
}
}

static void
ofp_print_geneve_table_mod(struct ds *s, const struct ofp_header *oh)
{
int error;
struct ofputil_geneve_table_mod gtm;

error = ofputil_decode_geneve_table_mod(oh, &gtm);
if (error) {
ofp_print_error(s, error);
return;
}

ds_put_cstr(s, "\n ");

switch (gtm.command) {
case NXGTMC_ADD:
ds_put_cstr(s, "ADD");
break;
case NXGTMC_DELETE:
ds_put_cstr(s, "DEL");
break;
case NXGTMC_CLEAR:
ds_put_cstr(s, "CLEAR");
break;
}

if (gtm.command != NXGTMC_CLEAR) {
print_geneve_table(s, &gtm.mappings);
}

ofputil_uninit_geneve_table(&gtm.mappings);
}

static void
ofp_print_geneve_table_reply(struct ds *s, const struct ofp_header *oh)
{
int error;
struct ofputil_geneve_table_reply gtr;
struct ofputil_geneve_map *map;
int allocated_space = 0;

error = ofputil_decode_geneve_table_reply(oh, &gtr);
if (error) {
ofp_print_error(s, error);
return;
}

ds_put_char(s, '\n');

LIST_FOR_EACH (map, list_node, &gtr.mappings) {
allocated_space += map->option_len;
}

ds_put_format(s, " max option space=%"PRIu32" max fields=%"PRIu16"\n",
gtr.max_option_space, gtr.max_fields);
ds_put_format(s, " allocated option space=%d\n", allocated_space);
ds_put_char(s, '\n');
print_geneve_table(s, &gtr.mappings);

ofputil_uninit_geneve_table(&gtr.mappings);
}

static void
ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
struct ds *string, int verbosity)
Expand Down Expand Up @@ -2899,6 +2978,18 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
case OFPTYPE_BUNDLE_ADD_MESSAGE:
ofp_print_bundle_add(string, msg, verbosity);
break;

case OFPTYPE_NXT_GENEVE_TABLE_MOD:
ofp_print_geneve_table_mod(string, msg);
break;

case OFPTYPE_NXT_GENEVE_TABLE_REQUEST:
break;

case OFPTYPE_NXT_GENEVE_TABLE_REPLY:
ofp_print_geneve_table_reply(string, msg);
break;

}
}

Expand Down
Loading

0 comments on commit 6159c53

Please sign in to comment.