2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-04 00:05:15 +00:00

ovs-ofctl: Accept only valid flow_mod and flow_stats_request fields.

OpenFlow commands have several idiosyncratic fields that are used in some
cases and ignored in others.  Until now, ovs-ofctl has been lax about
allowing some of them in places where they are ignored.  This commit
tightens the checks to exactly what is allowed.

Bug #5979.
Reported-by: Reid Price <reid@nicira.com>
This commit is contained in:
Ben Pfaff
2011-06-22 10:37:18 -07:00
parent b053c7c1a0
commit c821124b25
4 changed files with 68 additions and 29 deletions

View File

@@ -790,28 +790,71 @@ parse_reg_value(struct cls_rule *rule, int reg_idx, const char *value)
} }
} }
/* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl /* Convert 'str_' (as described in the Flow Syntax section of the ovs-ofctl man
* man page) into 'fm'. If 'actions' is specified, an action must be in * page) into 'fm' for sending the specified flow_mod 'command' to a switch.
* 'string' and may be expanded or reallocated. */ * If 'actions' is specified, an action must be in 'string' and may be expanded
* or reallocated.
*
* To parse syntax for an OFPT_FLOW_MOD (or NXT_FLOW_MOD), use an OFPFC_*
* constant for 'command'. To parse syntax for an OFPST_FLOW or
* OFPST_AGGREGATE (or NXST_FLOW or NXST_AGGREGATE), use -1 for 'command'. */
void void
parse_ofp_str(struct flow_mod *fm, struct ofpbuf *actions, const char *str_, parse_ofp_str(struct flow_mod *fm, int command, const char *str_, bool verbose)
bool verbose)
{ {
enum {
F_OUT_PORT = 1 << 0,
F_ACTIONS = 1 << 1,
F_COOKIE = 1 << 2,
F_TIMEOUT = 1 << 3,
F_PRIORITY = 1 << 4
} fields;
char *string = xstrdup(str_); char *string = xstrdup(str_);
char *save_ptr = NULL; char *save_ptr = NULL;
char *name; char *name;
switch (command) {
case -1:
fields = F_OUT_PORT;
break;
case OFPFC_ADD:
fields = F_ACTIONS | F_COOKIE | F_TIMEOUT | F_PRIORITY;
break;
case OFPFC_DELETE:
fields = F_OUT_PORT;
break;
case OFPFC_DELETE_STRICT:
fields = F_OUT_PORT | F_PRIORITY;
break;
case OFPFC_MODIFY:
fields = F_ACTIONS | F_COOKIE;
break;
case OFPFC_MODIFY_STRICT:
fields = F_ACTIONS | F_COOKIE | F_PRIORITY;
break;
default:
NOT_REACHED();
}
cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY); cls_rule_init_catchall(&fm->cr, OFP_DEFAULT_PRIORITY);
fm->cookie = htonll(0); fm->cookie = htonll(0);
fm->table_id = 0xff; fm->table_id = 0xff;
fm->command = UINT16_MAX; fm->command = command;
fm->idle_timeout = OFP_FLOW_PERMANENT; fm->idle_timeout = OFP_FLOW_PERMANENT;
fm->hard_timeout = OFP_FLOW_PERMANENT; fm->hard_timeout = OFP_FLOW_PERMANENT;
fm->buffer_id = UINT32_MAX; fm->buffer_id = UINT32_MAX;
fm->out_port = OFPP_NONE; fm->out_port = OFPP_NONE;
fm->flags = 0; fm->flags = 0;
if (actions) { if (fields & F_ACTIONS) {
char *act_str = strstr(string, "action"); struct ofpbuf actions;
char *act_str;
act_str = strstr(string, "action");
if (!act_str) { if (!act_str) {
ofp_fatal(str_, verbose, "must specify an action"); ofp_fatal(str_, verbose, "must specify an action");
} }
@@ -824,9 +867,10 @@ parse_ofp_str(struct flow_mod *fm, struct ofpbuf *actions, const char *str_,
act_str++; act_str++;
str_to_action(act_str, actions); ofpbuf_init(&actions, sizeof(union ofp_action));
fm->actions = actions->data; str_to_action(act_str, &actions);
fm->n_actions = actions->size / sizeof(union ofp_action); fm->actions = ofpbuf_steal_data(&actions);
fm->n_actions = actions.size / sizeof(union ofp_action);
} else { } else {
fm->actions = NULL; fm->actions = NULL;
fm->n_actions = 0; fm->n_actions = 0;
@@ -853,13 +897,13 @@ parse_ofp_str(struct flow_mod *fm, struct ofpbuf *actions, const char *str_,
fm->table_id = atoi(value); fm->table_id = atoi(value);
} else if (!strcmp(name, "out_port")) { } else if (!strcmp(name, "out_port")) {
fm->out_port = atoi(value); fm->out_port = atoi(value);
} else if (!strcmp(name, "priority")) { } else if (fields & F_PRIORITY && !strcmp(name, "priority")) {
fm->cr.priority = atoi(value); fm->cr.priority = atoi(value);
} else if (!strcmp(name, "idle_timeout")) { } else if (fields & F_TIMEOUT && !strcmp(name, "idle_timeout")) {
fm->idle_timeout = atoi(value); fm->idle_timeout = atoi(value);
} else if (!strcmp(name, "hard_timeout")) { } else if (fields & F_TIMEOUT && !strcmp(name, "hard_timeout")) {
fm->hard_timeout = atoi(value); fm->hard_timeout = atoi(value);
} else if (!strcmp(name, "cookie")) { } else if (fields & F_COOKIE && !strcmp(name, "cookie")) {
fm->cookie = htonll(str_to_u64(value)); fm->cookie = htonll(str_to_u64(value));
} else if (parse_field_name(name, &f)) { } else if (parse_field_name(name, &f)) {
if (!strcmp(value, "*") || !strcmp(value, "ANY")) { if (!strcmp(value, "*") || !strcmp(value, "ANY")) {
@@ -922,7 +966,6 @@ parse_ofp_flow_mod_str(struct list *packets, enum nx_flow_format *cur_format,
bool *flow_mod_table_id, char *string, uint16_t command, bool *flow_mod_table_id, char *string, uint16_t command,
bool verbose) bool verbose)
{ {
bool is_del = command == OFPFC_DELETE || command == OFPFC_DELETE_STRICT;
enum nx_flow_format min_format, next_format; enum nx_flow_format min_format, next_format;
struct cls_rule rule_copy; struct cls_rule rule_copy;
struct ofpbuf actions; struct ofpbuf actions;
@@ -930,8 +973,7 @@ parse_ofp_flow_mod_str(struct list *packets, enum nx_flow_format *cur_format,
struct flow_mod fm; struct flow_mod fm;
ofpbuf_init(&actions, 64); ofpbuf_init(&actions, 64);
parse_ofp_str(&fm, is_del ? NULL : &actions, string, verbose); parse_ofp_str(&fm, command, string, verbose);
fm.command = command;
min_format = ofputil_min_flow_format(&fm.cr); min_format = ofputil_min_flow_format(&fm.cr);
next_format = MAX(*cur_format, min_format); next_format = MAX(*cur_format, min_format);
@@ -987,7 +1029,7 @@ parse_ofp_flow_stats_request_str(struct flow_stats_request *fsr,
{ {
struct flow_mod fm; struct flow_mod fm;
parse_ofp_str(&fm, NULL, string, false); parse_ofp_str(&fm, -1, string, false);
fsr->aggregate = aggregate; fsr->aggregate = aggregate;
fsr->match = fm.cr; fsr->match = fm.cr;
fsr->out_port = fm.out_port; fsr->out_port = fm.out_port;

View File

@@ -29,7 +29,7 @@ struct flow_stats_request;
struct list; struct list;
struct ofpbuf; struct ofpbuf;
void parse_ofp_str(struct flow_mod *, struct ofpbuf *actions, const char *str_, void parse_ofp_str(struct flow_mod *, int command, const char *str_,
bool verbose); bool verbose);
void parse_ofp_flow_mod_str(struct list *packets, void parse_ofp_flow_mod_str(struct list *packets,

View File

@@ -553,8 +553,8 @@ Finally, field assignments to \fBduration\fR, \fBn_packets\fR, or
command to be used as input for other commands that parse flows. command to be used as input for other commands that parse flows.
. .
.PP .PP
The \fBadd\-flow\fR and \fBadd\-flows\fR commands require an additional The \fBadd\-flow\fR, \fBadd\-flows\fR, and \fBmod\-flows\fR commands
field, which must be the final field specified: require an additional field, which must be the final field specified:
. .
.IP \fBactions=\fR[\fItarget\fR][\fB,\fItarget\fR...]\fR .IP \fBactions=\fR[\fItarget\fR][\fB,\fItarget\fR...]\fR
Specifies a comma-separated list of actions to take on a packet when the Specifies a comma-separated list of actions to take on a packet when the
@@ -738,14 +738,15 @@ support an additional optional field:
. .
A cookie is an opaque identifier that can be associated with the flow. A cookie is an opaque identifier that can be associated with the flow.
\fIvalue\fR can be any 64-bit number and need not be unique among \fIvalue\fR can be any 64-bit number and need not be unique among
flows. flows. If this field is omitted, these commands set a default cookie
value of 0.
. .
.PP .PP
The following additional field sets the priority for flows added by The following additional field sets the priority for flows added by
the \fBadd\-flow\fR and \fBadd\-flows\fR commands. For the \fBadd\-flow\fR and \fBadd\-flows\fR commands. For
\fBmod\-flows\fR and \fBdel\-flows\fR when \fB\-\-strict\fR is \fBmod\-flows\fR and \fBdel\-flows\fR when \fB\-\-strict\fR is
specified, priority must match along with the rest of the flow specified, priority must match along with the rest of the flow
specification. Other commands ignore the priority value. specification. Other commands do not allow priority to be specified.
. .
.IP \fBpriority=\fIvalue\fR .IP \fBpriority=\fIvalue\fR
The priority at which a wildcarded entry will match in comparison to The priority at which a wildcarded entry will match in comparison to
@@ -778,10 +779,6 @@ and \fBdel\-flows\fR commands support one additional optional field:
\fBout_port=\fIport\fR \fBout_port=\fIport\fR
If set, a matching flow must include an output action to \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:
.
.SS "Table Entry Output" .SS "Table Entry Output"
. .
The \fBdump\-tables\fR and \fBdump\-aggregate\fR commands print information The \fBdump\-tables\fR and \fBdump\-aggregate\fR commands print information

View File

@@ -1035,7 +1035,7 @@ read_flows_from_file(const char *filename, struct classifier *cls, int index)
struct flow_mod fm; struct flow_mod fm;
ofpbuf_init(&actions, 64); ofpbuf_init(&actions, 64);
parse_ofp_str(&fm, &actions, ds_cstr(&s), true); parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), true);
version = xmalloc(sizeof *version); version = xmalloc(sizeof *version);
version->cookie = fm.cookie; version->cookie = fm.cookie;