When \fBdl_type\fR and \fBnw_proto\fR take other values, the values of
these settings are ignored (see \fBFlow Syntax\fR above).
.
+.IP \fBtable=\fInumber\fR
+If specified, limits the flow manipulation and flow dump commands to
+only apply to the table with the given \fInumber\fR.
+\fInumber\fR is a number between 0 and 31, inclusive.
+.
+If this field is not specified, for \fBadd-flow\fR, \fBadd-flows\fR,
+\fBmod-flows\fR and \fBdel-flows\fR commands, the switch will choose
+the table for these commands to operate on; for \fBdump-flows\fR and
+\fBdump-aggregate\fR commands, statistics are gathered about flows
+from all tables.
+.IP
+When this field is specified in \fBadd-flow\fR, \fBadd-flows\fR,
+\fBmod-flows\fR and \fBdel-flows\fR commands, it will activate a
+Nicira extension to OpenFlow, which as of this writing is only
+known to be implemented by Open vSwitch.
+.
.PP
The following shorthand notations are also available:
.
\fBout_port=\fIport\fR
If set, a matching flow must include an output action to \fIport\fR.
.
-.PP
-The \fBdump\-flows\fR and \fBdump\-aggregate\fR commands support an
-additional optional field:
-.
-.IP \fBtable=\fInumber\fR
-If specified, limits the flows about which statistics are gathered to
-those in the table with the given \fInumber\fR. Tables are numbered
-as shown by the \fBdump\-tables\fR command.
-.
-If this field is not specified, or if \fInumber\fR is given as
-\fB255\fR, statistics are gathered about flows from all tables.
.
.SS "Table Entry Output"
.
if (table_idx && !strcmp(name, "table")) {
*table_idx = atoi(value);
+ if (*table_idx < 0 || *table_idx > 31) {
+ ovs_fatal(0, "table %s is invalid, must be between 0 and 31", value);
+ }
} else if (out_port && !strcmp(name, "out_port")) {
*out_port = atoi(value);
} else if (priority && !strcmp(name, "priority")) {
dump_stats_transaction(argv[1], request);
}
+static void
+enable_flow_mod_table_id_ext(struct vconn *vconn, uint8_t enable)
+{
+ struct nxt_flow_mod_table_id *flow_mod_table_id;
+ struct ofpbuf *buffer;
+
+ flow_mod_table_id = make_openflow(sizeof *flow_mod_table_id, OFPT_VENDOR, &buffer);
+
+ flow_mod_table_id->vendor = htonl(NX_VENDOR_ID);
+ flow_mod_table_id->subtype = htonl(NXT_FLOW_MOD_TABLE_ID);
+ flow_mod_table_id->set = enable;
+
+ send_openflow_buffer(vconn, buffer);
+}
+
static void
do_add_flow(int argc OVS_UNUSED, char *argv[])
{
uint16_t priority, idle_timeout, hard_timeout;
uint64_t cookie;
struct ofp_match match;
+ uint8_t table_idx;
/* Parse and send. str_to_flow() will expand and reallocate the data in
* 'buffer', so we can't keep pointers to across the str_to_flow() call. */
make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(argv[2], &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout,
+ &table_idx, NULL, &priority, &idle_timeout, &hard_timeout,
&cookie);
ofm = buffer->data;
ofm->match = match;
ofm->priority = htons(priority);
open_vconn(argv[1], &vconn);
+ if (table_idx != 0xff) {
+ enable_flow_mod_table_id_ext(vconn, 1);
+ ofm->command = htons(ntohs(ofm->command) | (table_idx << 8));
+ }
send_openflow_buffer(vconn, buffer);
vconn_close(vconn);
}
struct vconn *vconn;
FILE *file;
char line[1024];
+ uint8_t table_idx;
+ int table_id_enabled = 0;
file = fopen(argv[2], "r");
if (file == NULL) {
* call. */
make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(line, &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout,
+ &table_idx, NULL, &priority, &idle_timeout, &hard_timeout,
&cookie);
ofm = buffer->data;
ofm->match = match;
ofm->buffer_id = htonl(UINT32_MAX);
ofm->priority = htons(priority);
+ if (table_idx != 0xff) {
+ if (!table_id_enabled) {
+ enable_flow_mod_table_id_ext(vconn, 1);
+ table_id_enabled = 1;
+ }
+ ofm->command = htons(ntohs(ofm->command) | (table_idx << 8));
+ } else {
+ if (table_id_enabled) {
+ enable_flow_mod_table_id_ext(vconn, 0);
+ table_id_enabled = 0;
+ }
+ }
send_openflow_buffer(vconn, buffer);
}
vconn_close(vconn);
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
struct ofp_match match;
+ uint8_t table_idx;
/* Parse and send. str_to_flow() will expand and reallocate the data in
* 'buffer', so we can't keep pointers to across the str_to_flow() call. */
make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(argv[2], &match, buffer,
- NULL, NULL, &priority, &idle_timeout, &hard_timeout,
+ &table_idx, NULL, &priority, &idle_timeout, &hard_timeout,
&cookie);
ofm = buffer->data;
ofm->match = match;
ofm->priority = htons(priority);
open_vconn(argv[1], &vconn);
+ if (table_idx != 0xff) {
+ enable_flow_mod_table_id_ext(vconn, 1);
+ ofm->command = htons(ntohs(ofm->command) | (table_idx << 8));
+ }
send_openflow_buffer(vconn, buffer);
vconn_close(vconn);
}
uint16_t out_port;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
+ uint8_t table_idx;
/* Parse and send. */
ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
ofm->priority = htons(priority);
open_vconn(argv[1], &vconn);
+ if (table_idx != 0xff) {
+ enable_flow_mod_table_id_ext(vconn, 1);
+ ofm->command = htons(ntohs(ofm->command) | (table_idx << 8));
+ }
send_openflow_buffer(vconn, buffer);
vconn_close(vconn);
}