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:
1 parent
46c78aa8aa
commit
36a60a74fc
16 files changed
+136
-138
No files matched your search
+5
-2
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -82,7 +82,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->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)) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
+31
-80
@@ -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",
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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 } },
|
||||
|
||||
Reference in new issue
Block a user