return -ENOBUFS;
}
-/* Modifies actions in 'chain' that match 'key'. Returns the number of
- * flows that were modified.
+/* Modifies actions in 'chain' that match 'key'. If 'strict' set, wildcards
+ * and priority must match. Returns the number of flows that were modified.
*
* Expensive in the general case as currently implemented, since it requires
* iterating through the entire contents of each table for keys that contain
* wildcards. Relatively cheap for fully specified keys. */
int
chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
+ uint16_t priority, int strict,
const struct ofp_action *actions, int n_actions)
{
int count = 0;
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
- count += t->modify(t, key, actions, n_actions);
+ count += t->modify(t, key, priority, strict, actions, n_actions);
}
return count;
}
-/* Deletes from 'chain' any and all flows that match 'key'. Returns the number
- * of flows that were deleted.
+/* Deletes from 'chain' any and all flows that match 'key'. If 'strict' set,
+ * wildcards and priority must match. Returns the number of flows that were
+ * deleted.
*
* Expensive in the general case as currently implemented, since it requires
* iterating through the entire contents of each table for keys that contain
struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *);
int chain_insert(struct sw_chain *, struct sw_flow *);
int chain_modify(struct sw_chain *, const struct sw_flow_key *,
- const struct ofp_action *, int);
+ uint16_t, int, const struct ofp_action *, int);
int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, int);
int chain_timeout(struct sw_chain *);
void chain_destroy(struct sw_chain *);
EXPORT_SYMBOL(flow_matches_2wild);
/* Returns nonzero if 't' (the table entry's key) and 'd' (the key
- * describing the deletion) match, that is, if their fields are
+ * describing the match) match, that is, if their fields are
* equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the
* wildcards must match in both 't_key' and 'd_key'. Note that the
* table's wildcards are ignored unless 'strict' is set. */
-int flow_del_matches(const struct sw_flow_key *t, const struct sw_flow_key *d, int strict)
+int flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d,
+ int strict)
{
if (strict && d->wildcards != t->wildcards)
return 0;
return flow_matches_1wild(t, d);
}
-EXPORT_SYMBOL(flow_del_matches);
+EXPORT_SYMBOL(flow_matches_desc);
static uint32_t make_nw_mask(int n_wild_bits)
{
int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *);
int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *);
-int flow_del_matches(const struct sw_flow_key *, const struct sw_flow_key *,
+int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *,
int);
struct sw_flow *flow_alloc(int n_actions, gfp_t flags);
void flow_free(struct sw_flow *);
int i;
int n_actions;
struct sw_flow_key key;
+ uint16_t priority;
+ int strict;
/* To prevent loops, make sure there's no action to send to the
* OFP_TABLE virtual port.
}
flow_extract_match(&key, &ofm->match);
- chain_modify(chain, &key, ofm->actions, n_actions);
+ priority = key.wildcards ? ntohs(ofm->priority) : -1;
+ strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0;
+ chain_modify(chain, &key, priority, strict, ofm->actions, n_actions);
if (ntohl(ofm->buffer_id) != (uint32_t) -1) {
struct sk_buff *skb = retrieve_skb(ntohl(ofm->buffer_id));
if (command == OFPFC_ADD) {
return add_flow(chain, ofm);
- } else if (command == OFPFC_MODIFY) {
+ } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) {
return mod_flow(chain, ofm);
} else if (command == OFPFC_DELETE) {
struct sw_flow_key key;
}
static int table_dummy_modify(struct sw_table *swt,
- const struct sw_flow_key *key,
+ const struct sw_flow_key *key, uint16_t priority, int strict,
const struct ofp_action *actions, int n_actions)
{
struct sw_table_dummy *td = (struct sw_table_dummy *) swt;
unsigned int count = 0;
list_for_each_entry (flow, &td->flows, node) {
- if (flow_matches_1wild(&flow->key, key)) {
+ if (flow_matches_desc(&flow->key, key, strict)
+ && (!strict || (flow->priority == priority))) {
flow_replace_acts(flow, actions, n_actions);
/* xxx Do whatever is necessary to modify the entry in hardware */
count++;
unsigned int count = 0;
list_for_each_entry (flow, &td->flows, node) {
- if (flow_del_matches(&flow->key, key, strict)
+ if (flow_matches_desc(&flow->key, key, strict)
&& (!strict || (flow->priority == priority)))
count += do_delete(swt, flow);
}
} else {
struct sw_flow *old_flow = *bucket;
if (flow_keys_equal(&old_flow->key, &flow->key)) {
- /* Keep stats from the original flow */
- flow->init_time = old_flow->init_time;
- flow->packet_count = old_flow->packet_count;
- flow->byte_count = old_flow->byte_count;
-
rcu_assign_pointer(*bucket, flow);
flow_deferred_free(old_flow);
retval = 1;
}
static int table_hash_modify(struct sw_table *swt,
- const struct sw_flow_key *key,
+ const struct sw_flow_key *key, uint16_t priority, int strict,
const struct ofp_action *actions, int n_actions)
{
struct sw_table_hash *th = (struct sw_table_hash *) swt;
if (key->wildcards == 0) {
struct sw_flow **bucket = find_bucket(swt, key);
struct sw_flow *flow = *bucket;
- if (flow && flow_matches_1wild(&flow->key, key)) {
+ if (flow && flow_matches_desc(&flow->key, key, strict)
+ && (!strict || (flow->priority == priority))) {
flow_replace_acts(flow, actions, n_actions);
count = 1;
}
for (i = 0; i <= th->bucket_mask; i++) {
struct sw_flow **bucket = &th->buckets[i];
struct sw_flow *flow = *bucket;
- if (flow && flow_matches_1wild(&flow->key, key)) {
+ if (flow && flow_matches_desc(&flow->key, key, strict)
+ && (!strict || (flow->priority == priority))) {
flow_replace_acts(flow, actions, n_actions);
count++;
}
for (i = 0; i <= th->bucket_mask; i++) {
struct sw_flow **bucket = &th->buckets[i];
struct sw_flow *flow = *bucket;
- if (flow && flow_del_matches(&flow->key, key, strict))
+ if (flow && flow_matches_desc(&flow->key, key, strict))
count += do_delete(bucket, flow);
}
}
}
static int table_hash2_modify(struct sw_table *swt,
- const struct sw_flow_key *key,
+ const struct sw_flow_key *key, uint16_t priority, int strict,
const struct ofp_action *actions, int n_actions)
{
struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
- return (table_hash_modify(t2->subtable[0], key, actions, n_actions)
- + table_hash_modify(t2->subtable[1], key, actions, n_actions));
+ return (table_hash_modify(t2->subtable[0], key, priority, strict,
+ actions, n_actions)
+ + table_hash_modify(t2->subtable[1], key, priority, strict,
+ actions, n_actions));
}
static int table_hash2_delete(struct sw_table *swt,
if (f->priority == flow->priority
&& f->key.wildcards == flow->key.wildcards
&& flow_matches_2wild(&f->key, &flow->key)) {
- /* Keep stats from the original flow */
- flow->init_time = f->init_time;
- flow->packet_count = f->packet_count;
- flow->byte_count = f->byte_count;
-
flow->serial = f->serial;
list_replace_rcu(&f->node, &flow->node);
list_replace_rcu(&f->iter_node, &flow->iter_node);
}
static int table_linear_modify(struct sw_table *swt,
- const struct sw_flow_key *key,
+ const struct sw_flow_key *key, uint16_t priority, int strict,
const struct ofp_action *actions, int n_actions)
{
struct sw_table_linear *tl = (struct sw_table_linear *) swt;
unsigned int count = 0;
list_for_each_entry (flow, &tl->flows, node) {
- if (flow_matches_1wild(&flow->key, key)) {
+ if (flow_matches_desc(&flow->key, key, strict)
+ && (!strict || (flow->priority == priority))) {
flow_replace_acts(flow, actions, n_actions);
count++;
}
unsigned int count = 0;
list_for_each_entry (flow, &tl->flows, node) {
- if (flow_del_matches(&flow->key, key, strict)
+ if (flow_matches_desc(&flow->key, key, strict)
&& (!strict || (flow->priority == priority)))
count += do_delete(swt, flow);
}
* retained by the caller. */
int (*insert)(struct sw_table *table, struct sw_flow *flow);
- /* Modifies the actions in 'table' that match 'key'. Returns the
- * number of flows that were modified. */
+ /* Modifies the actions in 'table' that match 'key'. If 'strict'
+ * set, wildcards and priority must match. Returns the number of flows
+ * that were modified. */
int (*modify)(struct sw_table *table, const struct sw_flow_key *key,
+ uint16_t priority, int strict,
const struct ofp_action *actions, int n_actions);
/* Deletes from 'table' any and all flows that match 'key' from
enum ofp_flow_mod_command {
OFPFC_ADD, /* New flow. */
OFPFC_MODIFY, /* Modify all matching flows. */
+ OFPFC_MODIFY_STRICT, /* Modify entry strictly matching wildcards */
OFPFC_DELETE, /* Delete all matching flows. */
OFPFC_DELETE_STRICT /* Strictly match wildcards and priority. */
};
case OFPFC_MODIFY:
ds_put_cstr(string, " MOD: ");
break;
+ case OFPFC_MODIFY_STRICT:
+ ds_put_cstr(string, " MOD_STRICT: ");
+ break;
case OFPFC_DELETE:
ds_put_cstr(string, " DEL: ");
break;
return -ENOBUFS;
}
-/* Modifies actions in 'chain' that match 'key'. Returns the number of
- * flows that were modified.
+/* Modifies actions in 'chain' that match 'key'. If 'strict' set, wildcards
+ * and priority must match. Returns the number of flows that were modified.
*
* Expensive in the general case as currently implemented, since it requires
* iterating through the entire contents of each table for keys that contain
* wildcards. Relatively cheap for fully specified keys. */
int
chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
+ uint16_t priority, int strict,
const struct ofp_action *actions, int n_actions)
{
int count = 0;
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
- count += t->modify(t, key, actions, n_actions);
+ count += t->modify(t, key, priority, strict, actions, n_actions);
}
return count;
}
-/* Deletes from 'chain' any and all flows that match 'key'. Returns the number
- * of flows that were deleted.
+/* Deletes from 'chain' any and all flows that match 'key'. If 'strict' set,
+ * wildcards and priority must match. Returns the number of flows that were
+ * deleted.
*
* Expensive in the general case as currently implemented, since it requires
* iterating through the entire contents of each table for keys that contain
struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *);
int chain_insert(struct sw_chain *, struct sw_flow *);
int chain_modify(struct sw_chain *, const struct sw_flow_key *,
- const struct ofp_action *, int);
+ uint16_t, int, const struct ofp_action *, int);
int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, int);
void chain_timeout(struct sw_chain *, struct list *deleted);
void chain_destroy(struct sw_chain *);
int n_actions;
int i;
struct sw_flow_key key;
+ uint16_t priority;
+ int strict;
/* To prevent loops, make sure there's no action to send to the
}
flow_extract_match(&key, &ofm->match);
- chain_modify(dp->chain, &key, ofm->actions, n_actions);
+ priority = key.wildcards ? ntohs(ofm->priority) : -1;
+ strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0;
+ chain_modify(dp->chain, &key, priority, strict, ofm->actions, n_actions);
if (ntohl(ofm->buffer_id) != UINT32_MAX) {
struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id));
if (command == OFPFC_ADD) {
return add_flow(dp, ofm);
- } else if (command == OFPFC_MODIFY) {
+ } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) {
return mod_flow(dp, ofm);
} else if (command == OFPFC_DELETE) {
struct sw_flow_key key;
}
/* Returns nonzero if 't' (the table entry's key) and 'd' (the key
- * describing the deletion) match, that is, if their fields are
+ * describing the match) match, that is, if their fields are
* equal modulo wildcards, zero otherwise. If 'strict' is nonzero, the
* wildcards must match in both 't_key' and 'd_key'. Note that the
* table's wildcards are ignored unless 'strict' is set. */
int
-flow_del_matches(const struct sw_flow_key *t, const struct sw_flow_key *d, int strict)
+flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d,
+ int strict)
{
if (strict && d->wildcards != t->wildcards) {
return 0;
int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *);
int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *);
-int flow_del_matches(const struct sw_flow_key *, const struct sw_flow_key *,
+int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *,
int);
struct sw_flow *flow_alloc(int n_actions);
void flow_free(struct sw_flow *);
} else {
struct sw_flow *old_flow = *bucket;
if (!flow_compare(&old_flow->key.flow, &flow->key.flow)) {
- /* Keep stats from the original flow */
- flow->used = old_flow->used;
- flow->created = old_flow->created;
- flow->packet_count = old_flow->packet_count;
- flow->byte_count = old_flow->byte_count;
-
*bucket = flow;
flow_free(old_flow);
retval = 1;
}
static int table_hash_modify(struct sw_table *swt,
- const struct sw_flow_key *key,
+ const struct sw_flow_key *key, uint16_t priority, int strict,
const struct ofp_action *actions, int n_actions)
{
struct sw_table_hash *th = (struct sw_table_hash *) swt;
if (key->wildcards == 0) {
struct sw_flow **bucket = find_bucket(swt, key);
struct sw_flow *flow = *bucket;
- if (flow && flow_matches_1wild(&flow->key, key)) {
+ if (flow && flow_matches_desc(&flow->key, key, strict)
+ && (!strict || (flow->priority == priority))) {
flow_replace_acts(flow, actions, n_actions);
count = 1;
}
for (i = 0; i <= th->bucket_mask; i++) {
struct sw_flow **bucket = &th->buckets[i];
struct sw_flow *flow = *bucket;
- if (flow && flow_matches_1wild(&flow->key, key)) {
+ if (flow && flow_matches_desc(&flow->key, key, strict)
+ && (!strict || (flow->priority == priority))) {
flow_replace_acts(flow, actions, n_actions);
count++;
}
for (i = 0; i <= th->bucket_mask; i++) {
struct sw_flow **bucket = &th->buckets[i];
struct sw_flow *flow = *bucket;
- if (flow && flow_del_matches(&flow->key, key, strict)) {
+ if (flow && flow_matches_desc(&flow->key, key, strict)) {
do_delete(bucket);
count++;
}
}
static int table_hash2_modify(struct sw_table *swt,
- const struct sw_flow_key *key,
+ const struct sw_flow_key *key, uint16_t priority, int strict,
const struct ofp_action *actions, int n_actions)
{
struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
- return (table_hash_modify(t2->subtable[0], key, actions, n_actions)
- + table_hash_modify(t2->subtable[1], key, actions, n_actions));
+ return (table_hash_modify(t2->subtable[0], key, priority, strict,
+ actions, n_actions)
+ + table_hash_modify(t2->subtable[1], key, priority, strict,
+ actions, n_actions));
}
static int table_hash2_delete(struct sw_table *swt,
if (f->priority == flow->priority
&& f->key.wildcards == flow->key.wildcards
&& flow_matches_2wild(&f->key, &flow->key)) {
- /* Keep stats from the original flow */
- flow->used = f->used;
- flow->created = f->created;
- flow->packet_count = f->packet_count;
- flow->byte_count = f->byte_count;
-
flow->serial = f->serial;
list_replace(&flow->node, &f->node);
list_replace(&flow->iter_node, &f->iter_node);
}
static int table_linear_modify(struct sw_table *swt,
- const struct sw_flow_key *key,
+ const struct sw_flow_key *key, uint16_t priority, int strict,
const struct ofp_action *actions, int n_actions)
{
struct sw_table_linear *tl = (struct sw_table_linear *) swt;
unsigned int count = 0;
LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) {
- if (flow_matches_1wild(&flow->key, key)) {
+ if (flow_matches_desc(&flow->key, key, strict)
+ && (!strict || (flow->priority == priority))) {
flow_replace_acts(flow, actions, n_actions);
count++;
}
unsigned int count = 0;
LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) {
- if (flow_del_matches(&flow->key, key, strict)
+ if (flow_matches_desc(&flow->key, key, strict)
&& (!strict || (flow->priority == priority))) {
do_delete(flow);
count++;
* retained by the caller. */
int (*insert)(struct sw_table *table, struct sw_flow *flow);
- /* Modifies entries in 'table' that match 'key'. Returns the
- * number of flows that were modified. */
+ /* Modifies the actions in 'table' that match 'key'. If 'strict'
+ * set, wildcards and priority must match. Returns the number of flows
+ * that were modified. */
int (*modify)(struct sw_table *table, const struct sw_flow_key *key,
+ uint16_t priority, int strict,
const struct ofp_action *actions, int n_actions);
/* Deletes from 'table' any and all flows that match 'key' from
.TP
\fBmod-flows \fIswitch flow\fR
Modify the actions in entries from the datapath \fIswitch\fR's tables
-that match \fIflow\fR. See \fBFLOW SYNTAX\fR, below, for the syntax
-of \fIflows\fR.
+that match \fIflow\fR. When invoked with the \fB--strict\fR option,
+wildcards are not treated as active for matching purposes. See
+\fBFLOW SYNTAX\fR, below, for the syntax of \fIflows\fR.
.TP
\fBdel-flows \fIswitch \fR[\fIflow\fR]
Deletes entries from the datapath \fIswitch\fR's tables that match
-\fIflow\fR. If \fIflow\fR is omitted, all flows in the datapath's
-tables are removed. See \fBFLOW SYNTAX\fR, below, for the syntax of
-\fIflows\fR.
+\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
\fB255\fR, statistics are gathered about flows from all tables.
.SH OPTIONS
+.TP
+\fB--strict\fR
+Uses strict matching when running flow modification commands.
+
.TP
\fB-t\fR, \fB--timeout=\fIsecs\fR
Limits \fBdpctl\fR runtime to approximately \fIsecs\fR seconds. If
#define MOD_PORT_CMD_FLOOD "flood"
#define MOD_PORT_CMD_NOFLOOD "noflood"
+
+/* Settings that may be configured by the user. */
+struct settings {
+ bool strict; /* Use strict matching for flow mod commands */
+};
+
struct command {
const char *name;
int min_args;
int max_args;
- void (*handler)(int argc, char *argv[]);
+ void (*handler)(const struct settings *, int argc, char *argv[]);
};
static struct command all_commands[];
static void usage(void) NO_RETURN;
-static void parse_options(int argc, char *argv[]);
+static void parse_options(int argc, char *argv[], struct settings *);
int main(int argc, char *argv[])
{
+ struct settings s;
struct command *p;
set_program_name(argv[0]);
time_init();
vlog_init();
- parse_options(argc, argv);
+ parse_options(argc, argv, &s);
signal(SIGPIPE, SIG_IGN);
argc -= optind;
ofp_fatal(0, "'%s' command takes at most %d arguments",
p->name, p->max_args);
else {
- p->handler(argc, argv);
+ p->handler(&s, argc, argv);
exit(0);
}
}
}
static void
-parse_options(int argc, char *argv[])
+parse_options(int argc, char *argv[], struct settings *s)
{
+ enum {
+ OPT_STRICT = UCHAR_MAX + 1
+ };
static struct option long_options[] = {
{"timeout", required_argument, 0, 't'},
{"verbose", optional_argument, 0, 'v'},
+ {"strict", no_argument, 0, OPT_STRICT},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
VCONN_SSL_LONG_OPTIONS
};
char *short_options = long_options_to_short_options(long_options);
+ /* Set defaults that we can figure out before parsing options. */
+ s->strict = false;
+
for (;;) {
unsigned long int timeout;
int c;
vlog_set_verbosity(optarg);
break;
+ case OPT_STRICT:
+ s->strict = true;
+ break;
+
VCONN_SSL_OPTION_HANDLERS
case '?':
program_name, program_name);
vconn_usage(true, false, false);
printf("\nOptions:\n"
+ " --strict use strict match for flow commands\n"
" -t, --timeout=SECS give up after SECS seconds\n"
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
" -v, --verbose set maximum verbosity level\n"
run(dpif_open(atoi(name + 3), subscribe, dpif), "opening datapath");
}
-static void do_add_dp(int argc UNUSED, char *argv[])
+static void do_add_dp(const struct settings *s, int argc UNUSED, char *argv[])
{
struct dpif dp;
open_nl_vconn(argv[1], false, &dp);
dpif_close(&dp);
}
-static void do_del_dp(int argc UNUSED, char *argv[])
+static void do_del_dp(const struct settings *s, int argc UNUSED, char *argv[])
{
struct dpif dp;
open_nl_vconn(argv[1], false, &dp);
return retval ? retval : dpif_add_port(dpif, netdev);
}
-static void do_add_port(int argc UNUSED, char *argv[])
+static void do_add_port(const struct settings *s, int argc UNUSED,
+ char *argv[])
{
add_del_ports(argc, argv, ifup_and_add_port, "add", "to");
}
-static void do_del_port(int argc UNUSED, char *argv[])
+static void do_del_port(const struct settings *s, int argc UNUSED,
+ char *argv[])
{
add_del_ports(argc, argv, dpif_del_port, "remove", "from");
}
}
static void
-do_show(int argc UNUSED, char *argv[])
+do_show(const struct settings *s, int argc UNUSED, char *argv[])
{
dump_trivial_transaction(argv[1], OFPT_FEATURES_REQUEST);
dump_trivial_transaction(argv[1], OFPT_GET_CONFIG_REQUEST);
}
static void
-do_status(int argc, char *argv[])
+do_status(const struct settings *s, int argc, char *argv[])
{
struct nicira_header *request, *reply;
struct vconn *vconn;
}
static void
-do_dump_desc(int argc, char *argv[])
+do_dump_desc(const struct settings *s, int argc, char *argv[])
{
dump_trivial_stats_transaction(argv[1], OFPST_DESC);
}
static void
-do_dump_tables(int argc, char *argv[])
+do_dump_tables(const struct settings *s, int argc, char *argv[])
{
dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
}
match->wildcards = htonl(wildcards);
}
-static void do_dump_flows(int argc, char *argv[])
+static void do_dump_flows(const struct settings *s, int argc, char *argv[])
{
struct ofp_flow_stats_request *req;
struct ofpbuf *request;
dump_stats_transaction(argv[1], request);
}
-static void do_dump_aggregate(int argc, char *argv[])
+static void do_dump_aggregate(const struct settings *s, int argc,
+ char *argv[])
{
struct ofp_aggregate_stats_request *req;
struct ofpbuf *request;
dump_stats_transaction(argv[1], request);
}
-static void do_add_flow(int argc, char *argv[])
+static void do_add_flow(const struct settings *s, int argc, char *argv[])
{
struct vconn *vconn;
struct ofpbuf *buffer;
vconn_close(vconn);
}
-static void do_add_flows(int argc, char *argv[])
+static void do_add_flows(const struct settings *s, int argc, char *argv[])
{
struct vconn *vconn;
FILE *file;
fclose(file);
}
-static void do_mod_flows(int argc, char *argv[])
+static void do_mod_flows(const struct settings *s, int argc, char *argv[])
{
- uint16_t idle_timeout, hard_timeout;
+ uint16_t priority, idle_timeout, hard_timeout;
struct vconn *vconn;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
size = sizeof *ofm + (sizeof ofm->actions[0] * MAX_ADD_ACTS);
ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
str_to_flow(argv[2], &ofm->match, &ofm->actions[0], &n_actions,
- NULL, NULL, &idle_timeout, &hard_timeout);
- ofm->command = htons(OFPFC_MODIFY);
+ 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->buffer_id = htonl(UINT32_MAX);
- ofm->priority = htons(0);
+ ofm->priority = htons(priority);
ofm->reserved = htonl(0);
/* xxx Should we use the buffer library? */
vconn_close(vconn);
}
-static void do_del_flows(int argc, char *argv[])
+static void do_del_flows(const struct settings *s, int argc, char *argv[])
{
struct vconn *vconn;
uint16_t priority;
ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, 0, NULL,
&priority, NULL, NULL);
- ofm->command = htons(OFPFC_DELETE);
+ 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);
}
static void
-do_monitor(int argc UNUSED, char *argv[])
+do_monitor(const struct settings *s, int argc UNUSED, char *argv[])
{
struct vconn *vconn;
const char *name;
}
static void
-do_dump_ports(int argc, char *argv[])
+do_dump_ports(const struct settings *s, int argc, char *argv[])
{
dump_trivial_stats_transaction(argv[1], OFPST_PORT);
}
static void
-do_probe(int argc, char *argv[])
+do_probe(const struct settings *s, int argc, char *argv[])
{
struct ofpbuf *request;
struct vconn *vconn;
}
static void
-do_mod_port(int argc, char *argv[])
+do_mod_port(const struct settings *s, int argc, char *argv[])
{
struct ofpbuf *request, *reply;
struct ofp_switch_features *osf;
}
static void
-do_ping(int argc, char *argv[])
+do_ping(const struct settings *s, int argc, char *argv[])
{
size_t max_payload = 65535 - sizeof(struct ofp_header);
unsigned int payload;
}
static void
-do_benchmark(int argc, char *argv[])
+do_benchmark(const struct settings *s, int argc, char *argv[])
{
size_t max_payload = 65535 - sizeof(struct ofp_header);
struct timeval start, end;
count * message_size / (duration / 1000.0));
}
-static void do_help(int argc UNUSED, char *argv[] UNUSED)
+static void do_help(const struct settings *s, int argc UNUSED,
+ char *argv[] UNUSED)
{
usage();
}