summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
d012fea)
This cleans up the handling of modifying existing flows. There now exists
OFPFC_MODIFY and OFPFC_MODIFY_STRICT commands, which have the same matching
characteristics to their OFPFC_DELETE* counterparts. When adding a flow that
already exists, the counters and timers are now reset (ie, its treated as a
new flow). This commit also adds the "--strict" option to dpctl to allow
strict matching for "mod-flows" and "del-flows".
21 files changed:
-/* 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,
*
* 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;
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];
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);
-/* 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
*
* 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 *,
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 *);
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
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. */
* 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);
}
{
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)
{
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_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);
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;
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.
/* To prevent loops, make sure there's no action to send to the
* OFP_TABLE virtual port.
}
flow_extract_match(&key, &ofm->match);
}
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 (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);
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;
return mod_flow(chain, ofm);
} else if (command == OFPFC_DELETE) {
struct sw_flow_key key;
}
static int table_dummy_modify(struct sw_table *swt,
}
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;
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) {
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++;
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) {
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);
}
&& (!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)) {
} 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;
rcu_assign_pointer(*bucket, flow);
flow_deferred_free(old_flow);
retval = 1;
}
static int table_hash_modify(struct sw_table *swt,
}
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;
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 (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;
}
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;
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++;
}
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;
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);
}
}
count += do_delete(bucket, flow);
}
}
}
static int table_hash2_modify(struct sw_table *swt,
}
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;
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,
}
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)) {
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);
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,
}
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;
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) {
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++;
}
flow_replace_acts(flow, actions, n_actions);
count++;
}
unsigned int count = 0;
list_for_each_entry (flow, &tl->flows, node) {
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);
}
&& (!strict || (flow->priority == priority)))
count += do_delete(swt, flow);
}
* retained by the caller. */
int (*insert)(struct sw_table *table, struct sw_flow *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,
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
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. */
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. */
};
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:
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;
case OFPFC_DELETE:
ds_put_cstr(string, " DEL: ");
break;
-/* 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,
*
* 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;
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];
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);
-/* 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
*
* 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 *,
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 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;
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
/* To prevent loops, make sure there's no action to send to the
}
flow_extract_match(&key, &ofm->match);
}
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 (ntohl(ofm->buffer_id) != UINT32_MAX) {
struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id));
if (command == OFPFC_ADD) {
return add_flow(dp, ofm);
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;
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
}
/* 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
* 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;
{
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_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 *);
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)) {
} 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;
*bucket = flow;
flow_free(old_flow);
retval = 1;
}
static int table_hash_modify(struct sw_table *swt,
}
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;
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 (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;
}
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;
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++;
}
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;
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++;
}
do_delete(bucket);
count++;
}
}
static int table_hash2_modify(struct sw_table *swt,
}
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;
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,
}
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)) {
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);
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,
}
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;
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) {
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++;
}
flow_replace_acts(flow, actions, n_actions);
count++;
}
unsigned int count = 0;
LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) {
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++;
&& (!strict || (flow->priority == priority))) {
do_delete(flow);
count++;
* retained by the caller. */
int (*insert)(struct sw_table *table, struct sw_flow *flow);
* 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,
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
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
.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
.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
.TP
\fBmonitor \fIswitch\fR
\fB255\fR, statistics are gathered about flows from all tables.
.SH OPTIONS
\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
.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"
#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;
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 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[])
{
int main(int argc, char *argv[])
{
struct command *p;
set_program_name(argv[0]);
time_init();
vlog_init();
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;
signal(SIGPIPE, SIG_IGN);
argc -= optind;
ofp_fatal(0, "'%s' command takes at most %d arguments",
p->name, p->max_args);
else {
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);
-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'},
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
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
VCONN_SSL_LONG_OPTIONS
};
char *short_options = long_options_to_short_options(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;
for (;;) {
unsigned long int timeout;
int c;
vlog_set_verbosity(optarg);
break;
vlog_set_verbosity(optarg);
break;
+ case OPT_STRICT:
+ s->strict = true;
+ break;
+
VCONN_SSL_OPTION_HANDLERS
case '?':
VCONN_SSL_OPTION_HANDLERS
case '?':
program_name, program_name);
vconn_usage(true, false, false);
printf("\nOptions:\n"
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"
" -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");
}
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);
{
struct dpif dp;
open_nl_vconn(argv[1], false, &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);
{
struct dpif dp;
open_nl_vconn(argv[1], false, &dp);
return retval ? retval : dpif_add_port(dpif, netdev);
}
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");
}
{
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");
}
{
add_del_ports(argc, argv, dpif_del_port, "remove", "from");
}
-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
{
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;
{
struct nicira_header *request, *reply;
struct vconn *vconn;
-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
{
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);
}
{
dump_trivial_stats_transaction(argv[1], OFPST_TABLE);
}
match->wildcards = htonl(wildcards);
}
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;
{
struct ofp_flow_stats_request *req;
struct ofpbuf *request;
dump_stats_transaction(argv[1], 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;
{
struct ofp_aggregate_stats_request *req;
struct ofpbuf *request;
dump_stats_transaction(argv[1], 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;
{
struct vconn *vconn;
struct ofpbuf *buffer;
-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;
{
struct vconn *vconn;
FILE *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;
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,
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->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? */
ofm->reserved = htonl(0);
/* xxx Should we use the buffer library? */
-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;
{
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 = 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);
ofm->idle_timeout = htons(0);
ofm->hard_timeout = htons(0);
ofm->buffer_id = htonl(UINT32_MAX);
-do_monitor(int argc UNUSED, char *argv[])
+do_monitor(const struct settings *s, int argc UNUSED, char *argv[])
{
struct vconn *vconn;
const char *name;
{
struct vconn *vconn;
const char *name;
-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
{
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;
{
struct ofpbuf *request;
struct vconn *vconn;
-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;
{
struct ofpbuf *request, *reply;
struct ofp_switch_features *osf;
-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;
{
size_t max_payload = 65535 - sizeof(struct ofp_header);
unsigned int payload;
-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;
{
size_t max_payload = 65535 - sizeof(struct ofp_header);
struct timeval start, end;
count * message_size / (duration / 1000.0));
}
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)