Emergency flow cache: Suppress flow removed notification for flows in

emergency flow table, add logic to emergency flow to reject entries
with timer
This commit is contained in:
Mikio Hara committed 2009-07-11 21:02:04 -07:00
1 parent 46c78aa8aa
commit 36a60a74fc
16 files changed
+139 -141

No files matched your search

+5 -2
View File
@@ -1095,7 +1095,10 @@ dp_send_flow_end(struct datapath *dp, struct sw_flow *flow,
struct sk_buff *skb;
struct nx_flow_end *nfe;
if (!dp->send_flow_end && !flow->send_flow_exp)
if (!dp->send_flow_end && !flow->send_flow_rem)
return 0;
if (flow->emerg_flow)
return 0;
nfe = alloc_openflow_skb(dp, sizeof *nfe, OFPT_VENDOR, 0, &skb);
@@ -1113,7 +1116,7 @@ dp_send_flow_end(struct datapath *dp, struct sw_flow *flow,
nfe->tcp_flags = flow->tcp_flags;
nfe->ip_tos = flow->ip_tos;
nfe->send_flow_exp = flow->send_flow_exp;
nfe->send_flow_exp = flow->send_flow_rem;
nfe->idle_timeout = htons(flow->idle_timeout);
+2 -1
View File
@@ -94,7 +94,8 @@ struct sw_flow {
uint16_t idle_timeout; /* Idle time before discarding (seconds). */
uint16_t hard_timeout; /* Hard expiration time (seconds) */
uint64_t used; /* Last used time (in jiffies). */
uint8_t send_flow_exp; /* Send a flow expiry to the controller */
uint8_t send_flow_rem; /* Send a flow removed to the controller */
uint8_t emerg_flow; /* Emergency flow indicator */
struct sw_flow_actions *sf_acts;
+16 -2
View File
@@ -233,6 +233,7 @@ add_flow(struct sw_chain *chain, const struct sender *sender,
}
flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1;
if (ntohs(ofm->flags) & OFPFF_CHECK_OVERLAP) {
/* check whether there is any conflict */
overlap = chain_has_conflict(chain, &flow->key, flow->priority,
@@ -246,10 +247,22 @@ add_flow(struct sw_chain *chain, const struct sender *sender,
}
}
if (ntohs(ofm->flags) & OFPFF_EMERG) {
if (ntohs(ofm->idle_timeout) != 0
|| ntohs(ofm->hard_timeout) != 0) {
dp_send_error_msg(chain->dp, sender,
OFPET_FLOW_MOD_FAILED,
OFPFMFC_EMERG,
ofm, ntohs(ofm->header.length));
goto error_free_flow;
}
}
/* Fill out flow. */
flow->idle_timeout = ntohs(ofm->idle_timeout);
flow->hard_timeout = ntohs(ofm->hard_timeout);
flow->send_flow_exp = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0;
flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0;
flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0;
flow_setup_actions(flow, ofm->actions, actions_len);
/* Act. */
@@ -320,8 +333,9 @@ mod_flow(struct sw_chain *chain, const struct sender *sender,
/* Fill out flow. */
flow->idle_timeout = ntohs(ofm->idle_timeout);
flow->hard_timeout = ntohs(ofm->hard_timeout);
flow->send_flow_exp = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM)
flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM)
? 1 : 0;
flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0;
flow_setup_actions(flow, ofm->actions, actions_len);
error = chain_insert(chain, flow,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0);
+2 -1
View File
@@ -79,7 +79,8 @@ protection_callback(struct sw_flow *flow, void *private_)
tgtflow->priority = flow->priority;
tgtflow->idle_timeout = 0;
tgtflow->hard_timeout = 0;
tgtflow->send_flow_exp = flow->send_flow_exp;
tgtflow->send_flow_rem = flow->send_flow_rem;
tgtflow->emerg_flow = 0;
flow_setup_actions(tgtflow, actions->actions, actions->actions_len);
error = chain_insert(private->chain, tgtflow, 0);
+3 -1
View File
@@ -635,7 +635,9 @@ enum ofp_flow_mod_failed_code {
OFPFMFC_ALL_TABLES_FULL, /* Flow not added because of full tables. */
OFPFMFC_OVERLAP, /* Attempted to add overlapping flow with
* CHECK_OVERLAP flag set. */
OFPFMFC_EPERM /* Permissions error. */
OFPFMFC_EPERM, /* Permissions error. */
OFPFMFC_EMERG /* Flow not added because of non-zero idle/hard
* timeout. */
};
/* OFPT_ERROR: Error message (datapath -> controller). */
+10 -2
View File
@@ -875,12 +875,15 @@ static const struct error_type error_types[] = {
#define ERROR_CODE(TYPE, CODE) {TYPE, CODE, #CODE}
ERROR_TYPE(OFPET_HELLO_FAILED),
ERROR_CODE(OFPET_HELLO_FAILED, OFPHFC_INCOMPATIBLE),
ERROR_CODE(OFPET_HELLO_FAILED, OFPHFC_EPERM),
ERROR_TYPE(OFPET_BAD_REQUEST),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VERSION),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_STAT),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VERSION),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE),
ERROR_CODE(OFPET_BAD_REQUEST, OFPBRC_EPERM),
ERROR_TYPE(OFPET_BAD_ACTION),
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_TYPE),
@@ -888,9 +891,14 @@ static const struct error_type error_types[] = {
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR),
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE),
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_OUT_PORT),
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT),
ERROR_CODE(OFPET_BAD_ACTION, OFPBAC_EPERM),
ERROR_TYPE(OFPET_FLOW_MOD_FAILED),
ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL)
ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL),
ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_OVERLAP),
ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_EPERM),
ERROR_CODE(OFPET_FLOW_MOD_FAILED, OFPFMFC_EMERG)
};
#define N_ERROR_TYPES ARRAY_SIZE(error_types)
+3
View File
@@ -198,6 +198,9 @@ inc_error_notification(struct ofpstat *ifps, struct ofp_header *hdr)
case OFPFMFC_EPERM:
INC_IFP_STAT(ifps, ofps_error_code.fmf_eperm);
break;
case OFPFMFC_EMERG:
INC_IFP_STAT(ifps, ofps_error_code.fmf_emerg);
break;
default:
INC_IFP_STAT(ifps, ofps_error_code.unknown);
break;
+3
View File
@@ -33,6 +33,8 @@
#ifndef OFPSTAT_H_
#define OFPSTAT_H_
struct ofp_header;
struct ofpstat {
uint64_t ofps_total;
uint64_t ofps_unknown;
@@ -64,6 +66,7 @@ struct ofpstat {
uint64_t fmf_all_tables_full;
uint64_t fmf_overlap;
uint64_t fmf_eperm;
uint64_t fmf_emerg;
uint64_t unknown;
} ofps_error_code;
uint64_t ofps_echo_request;
@@ -37,7 +37,7 @@ sub test_emergency_cache_first {
my $emergency_wildcards = $enums{'OFPFW_ALL'}; # wildcard match all to the all ports
my $emergency_flags = $enums{'OFPFF_EMERG'};
my $flow_mod_emergency_pkt =
create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $enums{'OFPP_ALL'}, $max_idle, $emergency_flags, $emergency_wildcards );
create_flow_mod_from_udp( $ofp, $test_pkt, $in_port, $enums{'OFPP_ALL'}, $max_idle_no_expire, $emergency_flags, $emergency_wildcards );
#print HexDump($flow_mod_normal_pkt);
#print HexDump($flow_mod_emergency_pkt);
+23 -8
View File
@@ -537,7 +537,7 @@ output_packet(struct datapath *dp, struct ofpbuf *buffer, uint16_t out_port)
*/
void
dp_output_port(struct datapath *dp, struct ofpbuf *buffer,
int in_port, int out_port, bool ignore_no_fwd)
int in_port, int out_port, bool ignore_no_fwd UNUSED)
{
assert(buffer);
@@ -735,7 +735,11 @@ dp_send_flow_end(struct datapath *dp, struct sw_flow *flow,
struct ofpbuf *buffer;
struct nx_flow_end *nfe;
if (!dp->send_flow_end && !flow->send_flow_exp) {
if (!dp->send_flow_end && !flow->send_flow_rem) {
return;
}
if (flow->emerg_flow) {
return;
}
@@ -754,7 +758,7 @@ dp_send_flow_end(struct datapath *dp, struct sw_flow *flow,
nfe->tcp_flags = flow->tcp_flags;
nfe->ip_tos = flow->ip_tos;
nfe->send_flow_exp = flow->send_flow_exp;
nfe->send_flow_exp = flow->send_flow_rem;
nfe->idle_timeout = htons(flow->idle_timeout);
@@ -1016,10 +1020,19 @@ add_flow(struct datapath *dp, const struct sender *sender,
}
}
if (ntohs(ofm->flags) & OFPFF_EMERG) {
if (ntohs(ofm->idle_timeout) != 0 || ntohs(ofm->hard_timeout) != 0) {
dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED,
OFPFMFC_EMERG, ofm, ntohs(ofm->header.length));
goto error_free_flow;
}
}
/* Fill out flow. */
flow->idle_timeout = ntohs(ofm->idle_timeout);
flow->hard_timeout = ntohs(ofm->hard_timeout);
flow->send_flow_exp = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0;
flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0;
flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0;
flow_setup_actions(flow, ofm->actions, actions_len);
/* Act. */
@@ -1092,7 +1105,8 @@ mod_flow(struct datapath *dp, const struct sender *sender,
/* Fill out flow. */
flow->idle_timeout = ntohs(ofm->idle_timeout);
flow->hard_timeout = ntohs(ofm->hard_timeout);
flow->send_flow_exp = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0;
flow->send_flow_rem = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_REM) ? 1 : 0;
flow->emerg_flow = (ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0;
flow_setup_actions(flow, ofm->actions, actions_len);
error = chain_insert(dp->chain, flow,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0);
@@ -1407,8 +1421,8 @@ static void port_stats_done(void *state)
* };
*/
static int
vendor_stats_init(const void *body, int body_len,
void **state)
vendor_stats_init(const void *body, int body_len UNUSED,
void **state UNUSED)
{
/* min_body was checked, this should be safe */
const uint32_t vendor = ntohl(*((uint32_t *)body));
@@ -1423,7 +1437,8 @@ vendor_stats_init(const void *body, int body_len,
}
static int
vendor_stats_dump(struct datapath *dp, void *state, struct ofpbuf *buffer)
vendor_stats_dump(struct datapath *dp UNUSED, void *state,
struct ofpbuf *buffer UNUSED)
{
const uint32_t vendor = *((uint32_t *)state);
int err;
+6 -5
View File
@@ -78,11 +78,12 @@ protection_callback(struct sw_flow *flow, void *private_)
memset(&match, 0, sizeof(match));
flow_fill_match(&match, &flow->key.flow, flow->key.wildcards);
flow_extract_match(&tgtflow->key, &match);
/* Fill out flow. */
/* Fill out flow. */
tgtflow->priority = flow->priority;
tgtflow->idle_timeout = 0;
tgtflow->hard_timeout = 0;
tgtflow->send_flow_exp = flow->send_flow_exp;
tgtflow->send_flow_rem = flow->send_flow_rem;
tgtflow->emerg_flow = 0;
flow_setup_actions(tgtflow, actions->actions, actions->actions_len);
error = chain_insert(private->dp->chain, tgtflow, 0);
@@ -112,11 +113,11 @@ do_protection(struct datapath *dp)
}
int
private_recv_msg(struct datapath *dp, const struct sender *sender,
private_recv_msg(struct datapath *dp, const struct sender *sender UNUSED,
const void *ofph)
{
struct private_vxhdr *vxhdr = ofph;
struct private_vxopt *vxopt = (vxhdr + 1);
struct private_vxhdr *vxhdr = (struct private_vxhdr *)ofph;
struct private_vxopt *vxopt = (struct private_vxopt *)(vxhdr + 1);
int error = 0;
switch (ntohs(vxopt->pvo_type)) {
+1 -1
View File
@@ -185,7 +185,7 @@ flow_setup_actions(struct sw_flow * flow,
if (actions_len > flow->sf_acts->actions_len)
ofp_fatal(0,
"flow_setup_actions: actions_len is too big (%d > %lu)",
actions_len, flow->sf_acts->actions_len);
actions_len, (unsigned long)flow->sf_acts->actions_len);
flow->used = flow->created = time_msec();
flow->sf_acts->actions_len = actions_len;
+3 -2
View File
@@ -64,8 +64,9 @@ struct sw_flow {
uint64_t created; /* When the flow was created. */
uint64_t packet_count; /* Number of packets seen. */
uint64_t byte_count; /* Number of bytes seen. */
uint8_t reason; /* Reason flow expired (one of NXFER_*). */
uint8_t send_flow_exp; /* Send a flow expiry to the controller */
uint8_t reason; /* Reason flow removed (one of NXFER_*). */
uint8_t send_flow_rem; /* Send a flow removed to the controller */
uint8_t emerg_flow; /* Emergency flow indicator */
uint8_t tcp_flags; /* Union of seen TCP flags. */
uint8_t ip_tos; /* IP TOS value. */
+18 -28
View File
@@ -164,8 +164,8 @@ spanning tree protocol is not in use.
\fBdump-flows \fIswitch \fR[\fIflows\fR]
Prints to the console all flow entries in datapath \fIswitch\fR's
tables that match \fIflows\fR. If \fIflows\fR is omitted, all flows
in the datapath are retrieved. See \fBFLOW SYNTAX\fR, below, for the
syntax of \fIflows\fR.
except emergency flows in the datapath flows are retrieved.
See \fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR.
.TP
\fBdump-aggregate \fIswitch \fR[\fIflows\fR]
@@ -186,12 +186,6 @@ Add flow entries as described in \fIfile\fR to the datapath \fIswitch\fR's
tables. Each line in \fIfile\fR is a flow entry in the format
described in \fBFLOW SYNTAX\fR, below.
.TP
\fBadd-emerg-flow \fIswitch flow\fR
Add the emergency flow entry as described by \fIflow\fR to the datapath
\fIswitch\fR's tables. The flow entry is in the format described in
\fBFLOW SYNTAX\fR, below.
.TP
\fBmod-flows \fIswitch flow\fR
Modify the actions in entries from the datapath \fIswitch\fR's tables
@@ -208,15 +202,6 @@ omitted and the \fB--strict\fR option is not used, all flows in the
datapath's tables are removed. See \fBFLOW SYNTAX\fR, below, for the
syntax of \fIflows\fR.
.TP
\fBdel-emerg-flows \fIswitch \fR[\fIflow\fR]
Deletes emergency entries from the datapath \fIswitch\fR's tables that match
\fIflow\fR. When invoked with the \fB--strict\fR option, wildcards are
not treated as active for matching purposes. If \fIflow\fR is
omitted and the \fB--strict\fR option is not used, all flows in the
datapath's tables are removed. See \fBFLOW SYNTAX\fR, below, for the
syntax of \fIflows\fR.
.TP
\fBmonitor \fIswitch\fR
Connects to \fIswitch\fR and prints to the console all OpenFlow
@@ -354,8 +339,7 @@ Same as \fBdl_type=0x0800,nw_proto=17\fR.
Same as \fBdl_type=0x0806\fR.
.PP
The \fBadd-flow\fR, \fBadd-flows\fR and \fBadd-emerg-flow\fR commands
require an additional field:
The \fBadd-flow\fR and \fBadd-flows\fR commands require an additional field:
.IP \fIactions\fB=\fItarget\fR[\fB,\fItarget\fR...]\fR
Specifies a comma-separated list of actions to take on a packet when the
@@ -422,7 +406,7 @@ Strips the VLAN tag from a packet if it is present.
not yet expose to the user.)
.PP
The \fBadd-flow\fR, \fBadd-flows\fR, \fBadd-emerg-flow\fR, \fBdel-flows\fR,
The \fBadd-flow\fR, \fBadd-flows\fR, \fBdel-flows\fR,
and \fBdel-emerg-flows\fR commands support an additional optional field:
.IP \fBpriority=\fIvalue\fR
@@ -431,7 +415,7 @@ which should be a number between 0 and 65535, inclusive. If this
field is not specified, it defaults to 32768.
.PP
The \fBadd-flow\fR, \fBadd-flows\fR and \fBadd-emerg-flow\fR commands support
The \fBadd-flow\fR and \fBadd-flows\fR commands support
additional optional fields:
.TP
@@ -446,24 +430,30 @@ regardless of activity. A value of 0 (the default) gives the flow no
hard expiration deadline.
.PP
The \fBdump-flows\fR, \fBdump-aggregate\fR, \fBdel-flows\fR
and \fBdel-emerg-flows\fR commands support the additional optional field:
The \fBdump-flows\fR, \fBdump-aggregate\fR and \fBdel-flows\fR
commands support the additional optional field:
.TP
\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:
\fBadd-flow\fR, \fBadd-flows\fR, \fBdel-flows\fR, \fBdump-flows\fR,
and \fBdump-aggregate\fR commands support the 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.
those in the table with the given \fInumber\fR. Normal (non emergency)
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.
\fB255\fR, statistics are gathered about flows from all normal (non
emergency) tables and flow manipulations are applied to notmal tables.
If this field is given as \fB254\fR, statistics are gathered about
flows from emergency table and flow manipulations are applied to
emergency table.
.SH OPTIONS
.TP
+33 -82
View File
@@ -237,10 +237,8 @@ usage(void)
" dump-aggregate SWITCH FLOW print aggregate stats for FLOWs\n"
" add-flow SWITCH FLOW add flow described by FLOW\n"
" add-flows SWITCH FILE add flows from FILE\n"
" add-emerg-flow SWITCH FLOW add emergency flow described by FLOW\n"
" mod-flows SWITCH FLOW modify actions of matching FLOWs\n"
" del-flows SWITCH [FLOW] delete matching FLOWs\n"
" del-emerg-flows SWITCH [FLOW] delete matching emergency FLOWs\n"
" monitor SWITCH print packets received from SWITCH\n"
" execute SWITCH CMD [ARG...] execute CMD with ARGS on SWITCH\n"
"\nFor local datapaths, remote switches, and controllers:\n"
@@ -640,11 +638,12 @@ print_protocol_stat(struct ofpstat *ofps_rcvd, struct ofpstat *ofps_sent)
fprintf(stdout,
PREFIX_STR
"%"PRIu64" flow mod fail: %"PRIu64" all tables full, "
"%"PRIu64" overlap, %"PRIu64" eperm\n",
"%"PRIu64" overlap, %"PRIu64" eperm, %"PRIu64" emerg\n",
ntohll(ifps->ofps_error_type.flow_mod_fail),
ntohll(ifps->ofps_error_code.fmf_all_tables_full),
ntohll(ifps->ofps_error_code.fmf_overlap),
ntohll(ifps->ofps_error_code.fmf_eperm));
ntohll(ifps->ofps_error_code.fmf_eperm),
ntohll(ifps->ofps_error_code.fmf_emerg));
fprintf(stdout,
PREFIX_STR
"%"PRIu64" unknown type, %"PRIu64" unknown code\n",
@@ -939,7 +938,7 @@ parse_field(const char *name, const struct field **f_out)
static void
str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
uint8_t *table_idx, uint16_t *out_port, uint16_t *priority,
uint8_t *table_idx, uint16_t *out_port, uint16_t *priority,
uint16_t *idle_timeout, uint16_t *hard_timeout)
{
char *save_ptr = NULL;
@@ -962,7 +961,7 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
*hard_timeout = OFP_FLOW_PERMANENT;
}
if (actions) {
char *act_str = strstr(string, "action");
char *act_str = strstr(string, "actions");
if (!act_str) {
ofp_fatal(0, "must specify an action");
}
@@ -998,7 +997,7 @@ str_to_flow(char *string, struct ofp_match *match, struct ofpbuf *actions,
if (!value) {
ofp_fatal(0, "field %s missing value", name);
}
if (table_idx && !strcmp(name, "table")) {
*table_idx = atoi(value);
} else if (out_port && !strcmp(name, "out_port")) {
@@ -1067,6 +1066,8 @@ do_dump_aggregate(const struct settings *s UNUSED, int argc, char *argv[])
dump_stats_transaction(argv[1], request);
}
#define EMERG_TABLE_ID 0xfe
static void
do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
{
@@ -1074,50 +1075,24 @@ do_add_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
uint16_t priority, idle_timeout, hard_timeout;
uint8_t table_id;
struct ofp_match match;
/* 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_id, NULL, &priority, &idle_timeout, &hard_timeout);
ofm = buffer->data;
ofm->match = match;
ofm->command = htons(OFPFC_ADD);
ofm->idle_timeout = htons(idle_timeout);
ofm->hard_timeout = htons(hard_timeout);
ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout);
ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout);
ofm->buffer_id = htonl(UINT32_MAX);
ofm->priority = htons(priority);
ofm->reserved = htonl(0);
open_vconn(argv[1], &vconn);
send_openflow_buffer(vconn, buffer);
vconn_close(vconn);
}
static void
do_add_emerg_flow(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
{
struct vconn *vconn;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
uint16_t priority, idle_timeout, hard_timeout, flags;
struct ofp_match match;
/* 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);
ofm = buffer->data;
ofm->match = match;
ofm->command = htons(OFPFC_ADD);
ofm->idle_timeout = htons(idle_timeout);
ofm->hard_timeout = htons(hard_timeout);
ofm->buffer_id = htonl(UINT32_MAX);
ofm->priority = htons(priority);
flags = OFPFF_EMERG;
ofm->flags = htons(flags);
ofm->flags = htons(OFPFF_SEND_FLOW_REM);
if (table_id == EMERG_TABLE_ID)
ofm->flags |= htons(OFPFF_EMERG);
ofm->reserved = htonl(0);
open_vconn(argv[1], &vconn);
@@ -1142,6 +1117,7 @@ do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
uint16_t priority, idle_timeout, hard_timeout;
uint8_t table_id;
struct ofp_match match;
char *comment;
@@ -1162,14 +1138,17 @@ do_add_flows(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
* call. */
ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(line, &match, buffer,
NULL, NULL, &priority, &idle_timeout, &hard_timeout);
&table_id, NULL, &priority, &idle_timeout, &hard_timeout);
ofm = buffer->data;
ofm->match = match;
ofm->command = htons(OFPFC_ADD);
ofm->idle_timeout = htons(idle_timeout);
ofm->hard_timeout = htons(hard_timeout);
ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout);
ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout);
ofm->buffer_id = htonl(UINT32_MAX);
ofm->priority = htons(priority);
ofm->flags = htons(OFPFF_SEND_FLOW_REM);
if (table_id == EMERG_TABLE_ID)
ofm->flags |= htons(OFPFF_EMERG);
ofm->reserved = htonl(0);
send_openflow_buffer(vconn, buffer);
@@ -1182,6 +1161,7 @@ static void
do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
{
uint16_t priority, idle_timeout, hard_timeout;
uint8_t table_id;
struct vconn *vconn;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
@@ -1189,15 +1169,17 @@ do_mod_flows(const struct settings *s, int argc UNUSED, char *argv[])
/* Parse and send. */
ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(argv[2], &ofm->match, buffer,
NULL, NULL, &priority, &idle_timeout, &hard_timeout);
&table_id, NULL, &priority, &idle_timeout, &hard_timeout);
if (s->strict) {
ofm->command = htons(OFPFC_MODIFY_STRICT);
} else {
ofm->command = htons(OFPFC_MODIFY);
}
ofm->idle_timeout = htons(idle_timeout);
ofm->hard_timeout = htons(hard_timeout);
ofm->idle_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(idle_timeout);
ofm->hard_timeout = table_id == EMERG_TABLE_ID ? 0 : htons(hard_timeout);
ofm->buffer_id = htonl(UINT32_MAX);
if (table_id == EMERG_TABLE_ID)
ofm->flags = htons(OFPFF_EMERG);
ofm->priority = htons(priority);
ofm->reserved = htonl(0);
@@ -1211,13 +1193,14 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[])
struct vconn *vconn;
uint16_t priority;
uint16_t out_port;
uint8_t table_id;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
/* Parse and send. */
ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL,
&out_port, &priority, NULL, NULL);
str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL,
&table_id, &out_port, &priority, NULL, NULL);
if (s->strict) {
ofm->command = htons(OFPFC_DELETE_STRICT);
} else {
@@ -1226,6 +1209,8 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[])
ofm->idle_timeout = htons(0);
ofm->hard_timeout = htons(0);
ofm->buffer_id = htonl(UINT32_MAX);
if (table_id == EMERG_TABLE_ID)
ofm->flags = htons(OFPFF_EMERG);
ofm->out_port = htons(out_port);
ofm->priority = htons(priority);
ofm->reserved = htonl(0);
@@ -1235,38 +1220,6 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[])
vconn_close(vconn);
}
static void do_del_emerg_flows(const struct settings *s, int argc, char *argv[])
{
struct vconn *vconn;
uint16_t priority;
uint16_t out_port;
uint16_t flags;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
/* Parse and send. */
ofm = make_openflow(sizeof *ofm, OFPT_FLOW_MOD, &buffer);
str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, NULL,
&out_port, &priority, NULL, NULL);
if (s->strict) {
ofm->command = htons(OFPFC_DELETE_STRICT);
} else {
ofm->command = htons(OFPFC_DELETE);
}
ofm->idle_timeout = htons(0);
ofm->hard_timeout = htons(0);
ofm->buffer_id = htonl(UINT32_MAX);
ofm->out_port = htons(out_port);
ofm->priority = htons(priority);
flags = OFPFF_EMERG;
ofm->flags = htons(flags);
ofm->reserved = htonl(0);
open_vconn(argv[1], &vconn);
send_openflow_buffer(vconn, buffer);
vconn_close(vconn);
}
static void
do_monitor(const struct settings *s UNUSED, int argc UNUSED, char *argv[])
{
@@ -1576,10 +1529,8 @@ static struct command all_commands[] = {
{ "dump-aggregate", 1, 2, do_dump_aggregate },
{ "add-flow", 2, 2, do_add_flow },
{ "add-flows", 2, 2, do_add_flows },
{ "add-emerg-flow", 2, 2, do_add_emerg_flow },
{ "mod-flows", 2, 2, do_mod_flows },
{ "del-flows", 1, 2, do_del_flows },
{ "del-emerg-flows", 1, 2, do_del_emerg_flows },
{ "dump-ports", 1, 1, do_dump_ports },
{ "mod-port", 3, 3, do_mod_port },
{ "probe", 1, 1, do_probe },
@@ -252,7 +252,8 @@ static const value_string sc_frag_choices[] = {
/* Error strings for the various error types */
static const gchar *hello_failed_err_str[] = {"No compatible version"};
static const gchar *hello_failed_err_str[] = {"No compatible version",
"Permissions error"};
#define N_HELLOFAILED (sizeof hello_failed_err_str / sizeof hello_failed_err_str[0])
@@ -260,7 +261,8 @@ static const gchar *bad_request_err_str[] = {"ofp_header.version not supported",
"ofp_header.type not supported",
"ofp_stats_request.type not supported",
"Vendor not supported (in ofp_vendor or ofp_stats_request or ofp_stats_reply)",
"Vendor subtype not supported"};
"Vendor subtype not supported",
"Permissions error"};
#define N_BADREQUEST (sizeof bad_request_err_str / sizeof bad_request_err_str[0])
@@ -269,12 +271,15 @@ static const gchar *bad_action_err_str[] = {"Unknown action type",
"Unknown vendor id specified",
"Unknown action type for vendor id",
"Problem validating output action",
"Bad action argument"};
"Bad action argument",
"Permissions error"};
#define N_BADACTION (sizeof bad_action_err_str / sizeof bad_action_err_str[0])
static const gchar *flow_mod_failed_err_str[] = {"Flow not added because of full tables",
"Flow not added because of conflicting entry in tables"};
"Flow not added because of conflicting entry in tables",
"Permissions error",
"Flow not added because of non-zero idle/hard timeout"};
#define N_FLOWMODFAILED (sizeof flow_mod_failed_err_str / sizeof flow_mod_failed_err_str[0])
@@ -1283,7 +1288,7 @@ void proto_register_openflow()
{ "Out Port (delete* only)", "of.fm_out_port", FT_STRING, BASE_NONE, NO_STRINGS, NO_MASK, "Out Port (delete* only)", HFILL } },
{ &ofp_flow_mod_flags[0],
{ "Send flow expirations", "of.fm_flags", FT_UINT16, BASE_DEC, VALS(names_choice), OFPFF_SEND_FLOW_REM, "Send flow expirations", HFILL }},
{ "Send flow removed", "of.fm_flags", FT_UINT16, BASE_DEC, VALS(names_choice), OFPFF_SEND_FLOW_REM, "Send flow removed", HFILL }},
{ &ofp_flow_mod_flags[1],
{ "Check for overlap before adding flow", "of.fm_flags", FT_UINT16, BASE_DEC, VALS(names_choice), OFPFF_CHECK_OVERLAP, "Check for overlap before adding flow", HFILL } },