2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-01 06:45:17 +00:00

openflow-1.1+: OFPT_TABLE_MOD (part 1)

Added infrastructure to support Openflow OFPT_TABLE_MOD message. This patch
does not include the flexible table miss handling code that is necessary to
support the semantics specified in OFPT_TABLE_MOD messages.

Current flow miss behavior continues to conform to Openflow 1.0.  Future
commits to add more flexible table miss support are needed to fully support
OPFT_TABLE_MOD for Openflow-1.1+.

Signed-off-by: Andy Zhou <azhou@nicira.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Andy Zhou
2013-09-07 03:02:32 -07:00
committed by Ben Pfaff
parent 451564513e
commit 918f2b8270
13 changed files with 287 additions and 3 deletions

View File

@@ -447,11 +447,11 @@ OFP_ASSERT(sizeof(struct ofp11_table_mod) == 8);
These flags are used in ofp_table_stats messages to describe the current
configuration and in ofp_table_mod messages to configure table behavior. */
enum ofp11_table_config {
OFPTC11_TABLE_MISS_CONTROLLER = 0, /* Send to controller. */
OFPTC11_TABLE_MISS_CONTROLLER = 0 << 0, /* Send to controller. */
OFPTC11_TABLE_MISS_CONTINUE = 1 << 0, /* Continue to the next table in the
pipeline (OpenFlow 1.0
behavior). */
OFPTC11_TABLE_MISS_DROP = 1 << 1, /* Drop the packet. */
OFPTC11_TABLE_MISS_DROP = 2 << 0, /* Drop the packet. */
OFPTC11_TABLE_MISS_MASK = 3
};

View File

@@ -348,6 +348,7 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg)
case OFPTYPE_FLOW_MOD:
case OFPTYPE_GROUP_MOD:
case OFPTYPE_PORT_MOD:
case OFPTYPE_TABLE_MOD:
case OFPTYPE_BARRIER_REQUEST:
case OFPTYPE_BARRIER_REPLY:
case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:

View File

@@ -185,6 +185,9 @@ enum ofpraw {
/* OFPT 1.1+ (16): struct ofp11_port_mod. */
OFPRAW_OFPT11_PORT_MOD,
/* OFPT 1.1+ (17): struct ofp11_table_mod. */
OFPRAW_OFPT11_TABLE_MOD,
/* OFPT 1.0 (18): void. */
OFPRAW_OFPT10_BARRIER_REQUEST,
/* OFPT 1.1+ (20): void. */
@@ -466,6 +469,7 @@ enum ofptype {
OFPTYPE_GROUP_MOD, /* OFPRAW_OFPT11_GROUP_MOD. */
OFPTYPE_PORT_MOD, /* OFPRAW_OFPT10_PORT_MOD.
* OFPRAW_OFPT11_PORT_MOD. */
OFPTYPE_TABLE_MOD, /* OFPRAW_OFPT11_TABLE_MOD. */
/* Barrier messages. */
OFPTYPE_BARRIER_REQUEST, /* OFPRAW_OFPT10_BARRIER_REQUEST.

View File

@@ -1706,6 +1706,47 @@ parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string,
return error;
}
/* Convert 'table_id' and 'flow_miss_handling' (as described for the
* "mod-table" command in the ovs-ofctl man page) into 'tm' for sending the
* specified table_mod 'command' to a switch.
*
* Returns NULL if successful, otherwise a malloc()'d string describing the
* error. The caller is responsible for freeing the returned string. */
char * WARN_UNUSED_RESULT
parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id,
const char *flow_miss_handling,
enum ofputil_protocol *usable_protocols)
{
/* Table mod requires at least OF 1.1. */
*usable_protocols = OFPUTIL_P_OF11_UP;
if (!strcasecmp(table_id, "all")) {
tm->table_id = 255;
} else {
char *error = str_to_u8(table_id, "table_id", &tm->table_id);
if (error) {
return error;
}
}
if (strcmp(flow_miss_handling, "controller") == 0) {
tm->config = OFPTC11_TABLE_MISS_CONTROLLER;
} else if (strcmp(flow_miss_handling, "continue") == 0) {
tm->config = OFPTC11_TABLE_MISS_CONTINUE;
} else if (strcmp(flow_miss_handling, "drop") == 0) {
tm->config = OFPTC11_TABLE_MISS_DROP;
} else {
return xasprintf("invalid flow_miss_handling %s", flow_miss_handling);
}
if (tm->table_id == 0xfe && tm->config == OFPTC11_TABLE_MISS_CONTINUE) {
return xstrdup("last table's flow miss handling can not be continue");
}
return NULL;
}
/* Opens file 'file_name' and reads each line as a flow_mod of the specified
* type (one of OFPFC_*). Stores each flow_mod in '*fm', an array allocated
* on the caller's behalf, and the number of flow_mods in '*n_fms'.

View File

@@ -31,6 +31,7 @@ struct ofputil_flow_monitor_request;
struct ofputil_flow_stats_request;
struct ofputil_group_mod;
struct ofputil_meter_mod;
struct ofputil_table_mod;
enum ofputil_protocol;
char *parse_ofp_str(struct ofputil_flow_mod *, int command, const char *str_,
@@ -41,6 +42,12 @@ char *parse_ofp_flow_mod_str(struct ofputil_flow_mod *, const char *string,
uint16_t command,
enum ofputil_protocol *usable_protocols)
WARN_UNUSED_RESULT;
char *parse_ofp_table_mod(struct ofputil_table_mod *,
const char *table_id, const char *flow_miss_handling,
enum ofputil_protocol *usable_protocols)
WARN_UNUSED_RESULT;
char *parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
struct ofputil_flow_mod **fms, size_t *n_fms,
enum ofputil_protocol *usable_protocols)

View File

@@ -964,6 +964,49 @@ ofp_print_port_mod(struct ds *string, const struct ofp_header *oh)
}
}
static void
ofp_print_table_miss_config(struct ds *string, const uint32_t config)
{
uint32_t table_miss_config = config & OFPTC11_TABLE_MISS_MASK;
switch (table_miss_config) {
case OFPTC11_TABLE_MISS_CONTROLLER:
ds_put_cstr(string, "controller\n");
break;
case OFPTC11_TABLE_MISS_CONTINUE:
ds_put_cstr(string, "continue\n");
break;
case OFPTC11_TABLE_MISS_DROP:
ds_put_cstr(string, "drop\n");
break;
default:
ds_put_cstr(string, "Unknown\n");
break;
}
}
static void
ofp_print_table_mod(struct ds *string, const struct ofp_header *oh)
{
struct ofputil_table_mod pm;
enum ofperr error;
error = ofputil_decode_table_mod(oh, &pm);
if (error) {
ofp_print_error(string, error);
return;
}
if (pm.table_id == 0xff) {
ds_put_cstr(string, " table_id: ALL_TABLES");
} else {
ds_put_format(string, " table_id=%"PRIu8, pm.table_id);
}
ds_put_cstr(string, ", flow_miss_config=");
ofp_print_table_miss_config(string, pm.config);
}
static void
ofp_print_meter_flags(struct ds *s, uint16_t flags)
{
@@ -2431,6 +2474,10 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
ofp_print_port_mod(string, oh);
break;
case OFPTYPE_TABLE_MOD:
ofp_print_table_mod(string, oh);
break;
case OFPTYPE_METER_MOD:
ofp_print_meter_mod(string, oh);
break;

View File

@@ -3660,7 +3660,7 @@ ofputil_encode_port_status(const struct ofputil_port_status *ps,
ofpmsg_update_length(b);
return b;
}
/* ofputil_port_mod */
/* Decodes the OpenFlow "port mod" message in '*oh' into an abstract form in
@@ -3742,7 +3742,66 @@ ofputil_encode_port_mod(const struct ofputil_port_mod *pm,
opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
break;
}
default:
NOT_REACHED();
}
return b;
}
/* ofputil_table_mod */
/* Decodes the OpenFlow "table mod" message in '*oh' into an abstract form in
* '*pm'. Returns 0 if successful, otherwise an OFPERR_* value. */
enum ofperr
ofputil_decode_table_mod(const struct ofp_header *oh,
struct ofputil_table_mod *pm)
{
enum ofpraw raw;
struct ofpbuf b;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
raw = ofpraw_pull_assert(&b);
if (raw == OFPRAW_OFPT11_TABLE_MOD) {
const struct ofp11_table_mod *otm = b.data;
pm->table_id = otm->table_id;
pm->config = ntohl(otm->config);
} else {
return OFPERR_OFPBRC_BAD_TYPE;
}
return 0;
}
/* Converts the abstract form of a "table mod" message in '*pm' into an OpenFlow
* message suitable for 'protocol', and returns that encoded form in a buffer
* owned by the caller. */
struct ofpbuf *
ofputil_encode_table_mod(const struct ofputil_table_mod *pm,
enum ofputil_protocol protocol)
{
enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
struct ofpbuf *b;
switch (ofp_version) {
case OFP10_VERSION: {
ovs_fatal(0, "table mod needs OpenFlow 1.1 or later "
"(\'-O OpenFlow11\')");
break;
}
case OFP11_VERSION:
case OFP12_VERSION:
case OFP13_VERSION: {
struct ofp11_table_mod *otm;
b = ofpraw_alloc(OFPRAW_OFPT11_TABLE_MOD, ofp_version, 0);
otm = ofpbuf_put_zeros(b, sizeof *otm);
otm->table_id = pm->table_id;
otm->config = htonl(pm->config);
break;
}
default:
NOT_REACHED();
}

View File

@@ -565,6 +565,17 @@ enum ofperr ofputil_decode_port_mod(const struct ofp_header *,
struct ofpbuf *ofputil_encode_port_mod(const struct ofputil_port_mod *,
enum ofputil_protocol);
/* Abstract ofp_table_mod. */
struct ofputil_table_mod {
uint8_t table_id; /* ID of the table, 0xff indicates all tables. */
uint32_t config;
};
enum ofperr ofputil_decode_table_mod(const struct ofp_header *,
struct ofputil_table_mod *);
struct ofpbuf *ofputil_encode_table_mod(const struct ofputil_table_mod *,
enum ofputil_protocol);
/* Meter band configuration for all supported band types. */
struct ofputil_meter_band {
uint16_t type;

View File

@@ -1156,6 +1156,7 @@ is_admitted_msg(const struct ofpbuf *b)
case OFPTYPE_FLOW_MOD:
case OFPTYPE_GROUP_MOD:
case OFPTYPE_PORT_MOD:
case OFPTYPE_TABLE_MOD:
case OFPTYPE_METER_MOD:
case OFPTYPE_BARRIER_REQUEST:
case OFPTYPE_BARRIER_REPLY:

View File

@@ -5144,6 +5144,26 @@ handle_group_mod(struct ofconn *ofconn, const struct ofp_header *oh)
}
}
static enum ofperr
handle_table_mod(struct ofconn *ofconn, const struct ofp_header *oh)
{
struct ofputil_table_mod tm;
enum ofperr error;
error = reject_slave_controller(ofconn);
if (error) {
return error;
}
error = ofputil_decode_table_mod(oh, &tm);
if (error) {
return error;
}
/* XXX Actual table mod support is not implemented yet. */
return 0;
}
static enum ofperr
handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
{
@@ -5182,6 +5202,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
case OFPTYPE_GROUP_MOD:
return handle_group_mod(ofconn, oh);
case OFPTYPE_TABLE_MOD:
return handle_table_mod(ofconn, oh);
case OFPTYPE_METER_MOD:
return handle_meter_mod(ofconn, oh);

View File

@@ -978,6 +978,33 @@ OFPT_PORT_MOD (OF1.3) (xid=0x3):port: 3: addr:50:54:00:00:00:01
])
AT_CLEANUP
AT_SETUP([OFPT_TABLE_MOD - OF1.1])
AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print "\
02 11 00 10 00 00 00 02 02 00 00 00 00 00 00 02 \
" 3], [0], [dnl
OFPT_TABLE_MOD (OF1.1) (xid=0x2): table_id=2, flow_miss_config=drop
])
AT_CLEANUP
AT_SETUP([OFPT_TABLE_MOD - OF1.2])
AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print "\
03 11 00 10 00 00 00 02 02 00 00 00 00 00 00 01 \
" 3], [0], [dnl
OFPT_TABLE_MOD (OF1.2) (xid=0x2): table_id=2, flow_miss_config=continue
])
AT_CLEANUP
AT_SETUP([OFPT_TABLE_MOD - OF1.3])
AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print "\
04 11 00 10 00 00 00 02 02 00 00 00 00 00 00 00 \
" 3], [0], [dnl
OFPT_TABLE_MOD (OF1.3) (xid=0x2): table_id=2, flow_miss_config=controller
])
AT_CLEANUP
AT_SETUP([OFPST_DESC request])
AT_KEYWORDS([ofp-print OFPT_STATS_REQUEST])
AT_CHECK([ovs-ofctl ofp-print "0110000c0000000100000000"], [0], [dnl

View File

@@ -213,6 +213,31 @@ Prints to the console statistics for the specified \fIgroups in the
groups are printed. See \fBGroup Syntax\fR, below, for the syntax of
\fIgroups\fR.
.
.IP "\fBmod\-table \fIswitch\fR \fItable_id\fR \fIflow_miss_handling\fR"
An OpenFlow 1.0 switch looks up each packet that arrives at the switch
in table 0, then in table 1 if there is no match in table 0, then in
table 2, and so on until the packet finds a match in some table.
Finally, if no match was found, the switch sends the packet to the
controller
.IP
OpenFlow 1.1 and later offer more flexibility. This command
configures the flow table miss handling configuration for table
\fItable_id\fR in \fIswitch\fR. \fItable_id\fR may be an OpenFlow
table number between 0 and 254, inclusive, or the keyword \fBALL\fR to
modify all tables. \fIflow_miss_handling\fR may be any one of the
following:
.RS
.IP \fBdrop\fR
Drop the packet.
.IP \fBcontinue\fR
Continue to the next table in the pipeline. (This is how an OpenFlow
1.0 switch always handles packets that do not match any flow, in
tables other than the last one.)
.IP \fBcontroller\fR
Send to controller. (This is how an OpenFlow 1.0 switch always
handles packets that do not match any flow in the last table.)
.RE
.
.SS "OpenFlow Switch Flow Table Commands"
.
These commands manage the flow table in an OpenFlow switch. In each

View File

@@ -281,6 +281,7 @@ usage(void)
" dump-desc SWITCH print switch description\n"
" dump-tables SWITCH print table stats\n"
" mod-port SWITCH IFACE ACT modify port behavior\n"
" mod-table SWITCH MOD modify flow table behavior\n"
" get-frags SWITCH print fragment handling behavior\n"
" set-frags SWITCH FRAG_MODE set fragment handling behavior\n"
" dump-ports SWITCH [PORT] print port statistics\n"
@@ -1663,6 +1664,42 @@ found:
vconn_close(vconn);
}
static void
ofctl_mod_table(int argc OVS_UNUSED, char *argv[])
{
enum ofputil_protocol protocol, usable_protocols;
struct ofputil_table_mod tm;
struct vconn *vconn;
char *error;
int i;
error = parse_ofp_table_mod(&tm, argv[2], argv[3], &usable_protocols);
if (error) {
ovs_fatal(0, "%s", error);
}
protocol = open_vconn(argv[1], &vconn);
if (!(protocol & usable_protocols)) {
for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
enum ofputil_protocol f = 1 << i;
if (f != protocol
&& f & usable_protocols
&& try_set_protocol(vconn, f, &protocol)) {
protocol = f;
break;
}
}
}
if (!(protocol & usable_protocols)) {
char *usable_s = ofputil_protocols_to_string(usable_protocols);
ovs_fatal(0, "Switch does not support table mod message(%s)", usable_s);
}
transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol));
vconn_close(vconn);
}
static void
ofctl_get_frags(int argc OVS_UNUSED, char *argv[])
{
@@ -3152,6 +3189,7 @@ static const struct command all_commands[] = {
{ "dump-ports", 1, 2, ofctl_dump_ports },
{ "dump-ports-desc", 1, 1, ofctl_dump_ports_desc },
{ "mod-port", 3, 3, ofctl_mod_port },
{ "mod-table", 3, 3, ofctl_mod_table },
{ "get-frags", 1, 1, ofctl_get_frags },
{ "set-frags", 2, 2, ofctl_set_frags },
{ "ofp-parse", 1, 1, ofctl_ofp_parse },