Add support for listing and deleting entries based on an output port.

To support this, an "out_port" field has been added to the "ofp_flow_mod",
"ofp_flow_stats_request", and "ofp_aggregate_stats_request" messages.  If an
"out_port" contains a value other than "OFPP_NONE", it introduces a constraint
when matching.  This constraint is that the rule must contain an output action
directed at that port.  Other constraints such as ofp_match structs and
priorities are still used; this is purely an *additional* constraint.  Note
that to get previous behavior, though, "out_port" must be set to "OFPP_NONE",
since "0" is a valid port id.  This only applies to the delete and
delete_strict flow mod commands; the field is ignored by add, modify, and
modify_strict.
This commit is contained in:
Justin Pettit authored and Brandon Heller committed 2008-12-02 00:48:28 -08:00
1 parent bf35d7b0b9
commit 75f7b917bc
20 files changed
+205 -76

No files matched your search

+6 -5
View File
@@ -124,9 +124,10 @@ chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
return count;
}
/* 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.
/* Deletes from 'chain' any and all flows that match 'key'. If 'out_port'
* is not OFPP_NONE, then matching entries must have that port as an
* argument for an output action. If 'strict" is set, then 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
@@ -134,7 +135,7 @@ chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
*
* Caller must hold dp_mutex. */
int chain_delete(struct sw_chain *chain, const struct sw_flow_key *key,
uint16_t priority, int strict)
uint16_t out_port, uint16_t priority, int strict)
{
int count = 0;
int i;
@@ -142,7 +143,7 @@ int chain_delete(struct sw_chain *chain, const struct sw_flow_key *key,
might_sleep();
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
count += t->delete(t, key, priority, strict);
count += t->delete(t, key, out_port, priority, strict);
}
return count;
+2 -1
View File
@@ -27,7 +27,8 @@ 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 *,
uint16_t, int, const struct ofp_action_header *, size_t);
int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, int);
int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t,
uint16_t, int);
int chain_timeout(struct sw_chain *);
void chain_destroy(struct sw_chain *);
+3 -3
View File
@@ -1382,8 +1382,8 @@ static int flow_stats_dump(struct datapath *dp, void *state,
{
struct sw_table *table = dp->chain->tables[s->table_idx];
error = table->iterate(table, &match_key, &s->position,
flow_stats_dump_callback, s);
error = table->iterate(table, &match_key, s->rq->out_port,
&s->position, flow_stats_dump_callback, s);
if (error)
break;
@@ -1447,7 +1447,7 @@ static int aggregate_stats_dump(struct datapath *dp, void *state,
struct sw_table *table = dp->chain->tables[table_idx];
int error;
error = table->iterate(table, &match_key, &position,
error = table->iterate(table, &match_key, rq->out_port, &position,
aggregate_stats_dump_callback, rpy);
if (error)
return error;
+34
View File
@@ -167,6 +167,40 @@ int flow_timeout(struct sw_flow *flow)
}
EXPORT_SYMBOL(flow_timeout);
/* Returns nonzero if 'flow' contains an output action to 'out_port' or
* has the value OFPP_NONE. 'out_port' is in network-byte order. */
int flow_has_out_port(struct sw_flow *flow, uint16_t out_port)
{
struct sw_flow_actions *sf_acts;
size_t actions_len;
uint8_t *p;
if (out_port == htons(OFPP_NONE))
return 1;
sf_acts = rcu_dereference(flow->sf_acts);
actions_len = sf_acts->actions_len;
p = (uint8_t *)sf_acts->actions;
while (actions_len > 0) {
struct ofp_action_header *ah = (struct ofp_action_header *)p;
size_t len = ntohs(ah->len);
if (ah->type == htons(OFPAT_OUTPUT)) {
struct ofp_action_output *oa = (struct ofp_action_output *)p;
if (oa->port == out_port)
return 1;
}
p += len;
actions_len -= len;
}
return 0;
}
EXPORT_SYMBOL(flow_has_out_port);
/* Allocates and returns a new flow with room for 'actions_len' actions,
* using allocation flags 'flags'. Returns the new flow or a null pointer
* on failure. */
+1
View File
@@ -106,6 +106,7 @@ 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_desc(const struct sw_flow_key *, const struct sw_flow_key *,
int);
int flow_has_out_port(struct sw_flow *, uint16_t);
struct sw_flow *flow_alloc(size_t actions_len, gfp_t flags);
void flow_free(struct sw_flow *);
void flow_deferred_free(struct sw_flow *);
+3 -2
View File
@@ -322,13 +322,14 @@ recv_flow(struct sw_chain *chain, const struct sender *sender, const void *msg)
} else if (command == OFPFC_DELETE) {
struct sw_flow_key key;
flow_extract_match(&key, &ofm->match);
return chain_delete(chain, &key, 0, 0) ? 0 : -ESRCH;
return chain_delete(chain, &key, ofm->out_port, 0, 0) ? 0 : -ESRCH;
} else if (command == OFPFC_DELETE_STRICT) {
struct sw_flow_key key;
uint16_t priority;
flow_extract_match(&key, &ofm->match);
priority = key.wildcards ? ntohs(ofm->priority) : -1;
return chain_delete(chain, &key, priority, 1) ? 0 : -ESRCH;
return chain_delete(chain, &key, ofm->out_port,
priority, 1) ? 0 : -ESRCH;
} else {
return -ENOTSUPP;
}
+17 -12
View File
@@ -113,8 +113,8 @@ static int do_delete(struct sw_flow **bucket, struct sw_flow *flow)
* argument, since all exact-match entries are the same (highest)
* priority. */
static int table_hash_delete(struct sw_table *swt,
const struct sw_flow_key *key,
uint16_t priority, int strict)
const struct sw_flow_key *key, uint16_t out_port,
uint16_t priority, int strict)
{
struct sw_table_hash *th = (struct sw_table_hash *) swt;
unsigned int count = 0;
@@ -122,7 +122,8 @@ static int table_hash_delete(struct sw_table *swt,
if (key->wildcards == 0) {
struct sw_flow **bucket = find_bucket(swt, key);
struct sw_flow *flow = *bucket;
if (flow && flow_keys_equal(&flow->key, key))
if (flow && flow_keys_equal(&flow->key, key)
&& flow_has_out_port(flow, out_port))
count = do_delete(bucket, flow);
} else {
unsigned int i;
@@ -130,7 +131,8 @@ static int table_hash_delete(struct sw_table *swt,
for (i = 0; i <= th->bucket_mask; i++) {
struct sw_flow **bucket = &th->buckets[i];
struct sw_flow *flow = *bucket;
if (flow && flow_matches_desc(&flow->key, key, strict))
if (flow && flow_matches_desc(&flow->key, key, strict)
&& flow_has_out_port(flow, out_port))
count += do_delete(bucket, flow);
}
}
@@ -174,7 +176,7 @@ static void table_hash_destroy(struct sw_table *swt)
}
static int table_hash_iterate(struct sw_table *swt,
const struct sw_flow_key *key,
const struct sw_flow_key *key, uint16_t out_port,
struct sw_table_position *position,
int (*callback)(struct sw_flow *, void *private),
void *private)
@@ -189,7 +191,7 @@ static int table_hash_iterate(struct sw_table *swt,
int error;
flow = table_hash_lookup(swt, key);
if (!flow)
if (!flow || !flow_has_out_port(flow, out_port))
return 0;
error = callback(flow, private);
@@ -201,7 +203,8 @@ static int table_hash_iterate(struct sw_table *swt,
for (i = position->private[0]; i <= th->bucket_mask; i++) {
struct sw_flow *flow = th->buckets[i];
if (flow && flow_matches_1wild(&flow->key, key)) {
if (flow && flow_matches_1wild(&flow->key, key)
&& flow_has_out_port(flow, out_port)) {
int error = callback(flow, private);
if (error) {
position->private[0] = i;
@@ -301,11 +304,13 @@ static int table_hash2_modify(struct sw_table *swt,
static int table_hash2_delete(struct sw_table *swt,
const struct sw_flow_key *key,
uint16_t out_port,
uint16_t priority, int strict)
{
struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
return (table_hash_delete(t2->subtable[0], key, priority, strict)
+ table_hash_delete(t2->subtable[1], key, priority, strict));
return (table_hash_delete(t2->subtable[0], key, out_port, priority, strict)
+ table_hash_delete(t2->subtable[1], key, out_port,
priority, strict));
}
static int table_hash2_timeout(struct datapath *dp, struct sw_table *swt)
@@ -324,7 +329,7 @@ static void table_hash2_destroy(struct sw_table *swt)
}
static int table_hash2_iterate(struct sw_table *swt,
const struct sw_flow_key *key,
const struct sw_flow_key *key, uint16_t out_port,
struct sw_table_position *position,
int (*callback)(struct sw_flow *, void *),
void *private)
@@ -333,8 +338,8 @@ static int table_hash2_iterate(struct sw_table *swt,
int i;
for (i = position->private[1]; i < 2; i++) {
int error = table_hash_iterate(t2->subtable[i], key, position,
callback, private);
int error = table_hash_iterate(t2->subtable[i], key, out_port,
position, callback, private);
if (error) {
return error;
}
+6 -3
View File
@@ -99,7 +99,8 @@ static int do_delete(struct sw_table *swt, struct sw_flow *flow)
}
static int table_linear_delete(struct sw_table *swt,
const struct sw_flow_key *key, uint16_t priority, int strict)
const struct sw_flow_key *key, uint16_t out_port,
uint16_t priority, int strict)
{
struct sw_table_linear *tl = (struct sw_table_linear *) swt;
struct sw_flow *flow;
@@ -107,6 +108,7 @@ static int table_linear_delete(struct sw_table *swt,
list_for_each_entry (flow, &tl->flows, node) {
if (flow_matches_desc(&flow->key, key, strict)
&& flow_has_out_port(flow, out_port)
&& (!strict || (flow->priority == priority)))
count += do_delete(swt, flow);
}
@@ -147,7 +149,7 @@ static void table_linear_destroy(struct sw_table *swt)
}
static int table_linear_iterate(struct sw_table *swt,
const struct sw_flow_key *key,
const struct sw_flow_key *key, uint16_t out_port,
struct sw_table_position *position,
int (*callback)(struct sw_flow *, void *),
void *private)
@@ -159,7 +161,8 @@ static int table_linear_iterate(struct sw_table *swt,
start = position->private[0];
list_for_each_entry (flow, &tl->iter_flows, iter_node) {
if (flow->serial >= start
&& flow_matches_2wild(key, &flow->key)) {
&& flow_matches_2wild(key, &flow->key)
&& flow_has_out_port(flow, out_port)) {
int error = callback(flow, private);
if (error) {
position->private[0] = flow->serial;
+11 -8
View File
@@ -65,10 +65,12 @@ struct sw_table {
const struct ofp_action_header *actions, size_t actions_len);
/* Deletes from 'table' any and all flows that match 'key' from
* 'table'. If 'strict' set, wildcards and priority must match.
* Returns the number of flows that were deleted. */
* 'table'. If 'out_port' is not OFPP_NONE, then matching entries
* must have that port as an argument for an output action. If
* 'strict' is set, wildcards and priority must match. Returns the
* number of flows that were deleted. */
int (*delete)(struct sw_table *table, const struct sw_flow_key *key,
uint16_t priority, int strict);
uint16_t out_port, uint16_t priority, int strict);
/* Performs timeout processing on all the flow entries in 'table'.
* Returns the number of flow entries deleted through expiration. */
@@ -78,10 +80,11 @@ struct sw_table {
void (*destroy)(struct sw_table *table);
/* Iterates through the flow entries in 'table', passing each one
* matches 'key' to 'callback'. The callback function should return 0
* to continue iteration or a nonzero error code to stop. The iterator
* function returns either 0 if the table iteration completed or the
* value returned by the callback function otherwise.
* matches 'key' and output port 'out_port' to 'callback'. The
* callback function should return 0 to continue iteration or a
* nonzero error code to stop. The iterator function returns either
* 0 if the table iteration completed or the value returned by the
* callback function otherwise.
*
* The iteration starts at 'position', which may be initialized to
* all-zero-bits to iterate from the beginning of the table. If the
@@ -91,7 +94,7 @@ struct sw_table {
* that caused the error (assuming that that flow entry has not been
* deleted in the meantime). */
int (*iterate)(struct sw_table *table,
const struct sw_flow_key *key,
const struct sw_flow_key *key, uint16_t out_port,
struct sw_table_position *position,
int (*callback)(struct sw_flow *flow, void *private),
void *private);
+15 -4
View File
@@ -63,7 +63,7 @@
/* The most significant bit being set in the version field indicates an
* experimental OpenFlow version.
*/
#define OFP_VERSION 0x96
#define OFP_VERSION 0x97
#define OFP_MAX_TABLE_NAME_LEN 32
#define OFP_MAX_PORT_NAME_LEN 16
@@ -532,12 +532,17 @@ struct ofp_flow_mod {
uint16_t priority; /* Priority level of flow entry. */
uint32_t buffer_id; /* Buffered packet to apply to (or -1).
Not meaningful for OFPFC_DELETE*. */
uint16_t out_port; /* For OFPFC_DELETE* commands, require
matching entries to include this as an
output port. A value of OFPP_NONE
indicates no restriction. */
uint8_t pad[2]; /* Align to 32-bits. */
uint32_t reserved; /* Reserved for future use. */
struct ofp_action_header actions[0]; /* The action length is inferred
from the length field in the
header. */
};
OFP_ASSERT(sizeof(struct ofp_flow_mod) == 60);
OFP_ASSERT(sizeof(struct ofp_flow_mod) == 64);
/* Why did this flow expire? */
enum ofp_flow_expired_reason {
@@ -686,7 +691,10 @@ struct ofp_flow_stats_request {
struct ofp_match match; /* Fields to match */
uint8_t table_id; /* ID of table to read (from ofp_table_stats)
or 0xff for all tables. */
uint8_t pad[3]; /* Align to 32 bits. */
uint8_t pad; /* Align to 32 bits. */
uint16_t out_port; /* Require matching entries to include this
as an output port. A value of OFPP_NONE
indicates no restriction. */
};
OFP_ASSERT(sizeof(struct ofp_flow_stats_request) == 40);
@@ -713,7 +721,10 @@ struct ofp_aggregate_stats_request {
struct ofp_match match; /* Fields to match */
uint8_t table_id; /* ID of table to read (from ofp_table_stats)
or 0xff for all tables. */
uint8_t pad[3]; /* Align to 32 bits. */
uint8_t pad; /* Align to 32 bits. */
uint16_t out_port; /* Require matching entries to include this
as an output port. A value of OFPP_NONE
indicates no restriction. */
};
OFP_ASSERT(sizeof(struct ofp_aggregate_stats_request) == 40);
+6 -5
View File
@@ -137,23 +137,24 @@ chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
return count;
}
/* 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.
/* Deletes from 'chain' any and all flows that match 'key'. If 'out_port'
* is not OFPP_NONE, then matching entries must have that port as an
* argument for an output action. If 'strict" is set, then 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
* wildcards. Relatively cheap for fully specified keys. */
int
chain_delete(struct sw_chain *chain, const struct sw_flow_key *key,
uint16_t priority, int strict)
uint16_t out_port, uint16_t priority, int strict)
{
int count = 0;
int i;
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
count += t->delete(t, key, priority, strict);
count += t->delete(t, key, out_port, priority, strict);
}
return count;
+2 -1
View File
@@ -59,7 +59,8 @@ 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 *,
uint16_t, int, const struct ofp_action_header *, size_t);
int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, int);
int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t,
uint16_t, int);
void chain_timeout(struct sw_chain *, struct list *deleted);
void chain_destroy(struct sw_chain *);
+6 -5
View File
@@ -1098,13 +1098,14 @@ recv_flow(struct datapath *dp, const struct sender *sender,
} else if (command == OFPFC_DELETE) {
struct sw_flow_key key;
flow_extract_match(&key, &ofm->match);
return chain_delete(dp->chain, &key, 0, 0) ? 0 : -ESRCH;
return chain_delete(dp->chain, &key, ofm->out_port, 0, 0) ? 0 : -ESRCH;
} else if (command == OFPFC_DELETE_STRICT) {
struct sw_flow_key key;
uint16_t priority;
flow_extract_match(&key, &ofm->match);
priority = key.wildcards ? ntohs(ofm->priority) : -1;
return chain_delete(dp->chain, &key, priority, 1) ? 0 : -ESRCH;
return chain_delete(dp->chain, &key, ofm->out_port,
priority, 1) ? 0 : -ESRCH;
} else {
return -ENODEV;
}
@@ -1167,8 +1168,8 @@ static int flow_stats_dump(struct datapath *dp, void *state,
{
struct sw_table *table = dp->chain->tables[s->table_idx];
if (table->iterate(table, &match_key, &s->position,
flow_stats_dump_callback, s))
if (table->iterate(table, &match_key, s->rq.out_port,
&s->position, flow_stats_dump_callback, s))
break;
s->table_idx++;
@@ -1227,7 +1228,7 @@ static int aggregate_stats_dump(struct datapath *dp, void *state,
struct sw_table *table = dp->chain->tables[table_idx];
int error;
error = table->iterate(table, &match_key, &position,
error = table->iterate(table, &match_key, rq->out_port, &position,
aggregate_stats_dump_callback, rpy);
if (error)
return error;
+28
View File
@@ -262,6 +262,34 @@ bool flow_timeout(struct sw_flow *flow)
}
}
/* Returns nonzero if 'flow' contains an output action to 'out_port' or
* has the value OFPP_NONE. 'out_port' is in network-byte order. */
int flow_has_out_port(struct sw_flow *flow, uint16_t out_port)
{
struct sw_flow_actions *sf_acts = flow->sf_acts;
size_t actions_len = sf_acts->actions_len;
uint8_t *p = (uint8_t *)sf_acts->actions;
if (out_port == htons(OFPP_NONE))
return 1;
while (actions_len > 0) {
struct ofp_action_header *ah = (struct ofp_action_header *)p;
size_t len = ntohs(ah->len);
if (ah->type == htons(OFPAT_OUTPUT)) {
struct ofp_action_output *oa = (struct ofp_action_output *)p;
if (oa->port == out_port) {
return 1;
}
}
p += len;
actions_len -= len;
}
return 0;
}
void flow_used(struct sw_flow *flow, struct ofpbuf *buffer)
{
flow->used = time_now();
+1
View File
@@ -78,6 +78,7 @@ 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_desc(const struct sw_flow_key *, const struct sw_flow_key *,
int);
int flow_has_out_port(struct sw_flow *flow, uint16_t out_port);
struct sw_flow *flow_alloc(size_t);
void flow_free(struct sw_flow *);
void flow_deferred_free(struct sw_flow *);
+20 -10
View File
@@ -136,6 +136,7 @@ do_delete(struct sw_flow **bucket)
* priority. */
static int table_hash_delete(struct sw_table *swt,
const struct sw_flow_key *key,
uint16_t out_port,
uint16_t priority, int strict)
{
struct sw_table_hash *th = (struct sw_table_hash *) swt;
@@ -144,7 +145,8 @@ static int table_hash_delete(struct sw_table *swt,
if (key->wildcards == 0) {
struct sw_flow **bucket = find_bucket(swt, key);
struct sw_flow *flow = *bucket;
if (flow && !flow_compare(&flow->key.flow, &key->flow)) {
if (flow && !flow_compare(&flow->key.flow, &key->flow)
&& flow_has_out_port(flow, out_port)) {
do_delete(bucket);
count = 1;
}
@@ -154,7 +156,8 @@ static int table_hash_delete(struct sw_table *swt,
for (i = 0; i <= th->bucket_mask; i++) {
struct sw_flow **bucket = &th->buckets[i];
struct sw_flow *flow = *bucket;
if (flow && flow_matches_desc(&flow->key, key, strict)) {
if (flow && flow_matches_desc(&flow->key, key, strict)
&& flow_has_out_port(flow, out_port)) {
do_delete(bucket);
count++;
}
@@ -194,7 +197,7 @@ static void table_hash_destroy(struct sw_table *swt)
}
static int table_hash_iterate(struct sw_table *swt,
const struct sw_flow_key *key,
const struct sw_flow_key *key, uint16_t out_port,
struct sw_table_position *position,
int (*callback)(struct sw_flow *, void *private),
void *private)
@@ -207,13 +210,17 @@ static int table_hash_iterate(struct sw_table *swt,
if (key->wildcards == 0) {
struct sw_flow *flow = table_hash_lookup(swt, key);
position->private[0] = -1;
return flow ? callback(flow, private) : 0;
if (!flow || !flow_has_out_port(flow, out_port)) {
return 0;
}
return callback(flow, private);
} else {
int i;
for (i = position->private[0]; i <= th->bucket_mask; i++) {
struct sw_flow *flow = th->buckets[i];
if (flow && flow_matches_1wild(&flow->key, key)) {
if (flow && flow_matches_1wild(&flow->key, key)
&& flow_has_out_port(flow, out_port)) {
int error = callback(flow, private);
if (error) {
position->private[0] = i + 1;
@@ -316,11 +323,13 @@ static int table_hash2_modify(struct sw_table *swt,
static int table_hash2_delete(struct sw_table *swt,
const struct sw_flow_key *key,
uint16_t out_port,
uint16_t priority, int strict)
{
struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
return (table_hash_delete(t2->subtable[0], key, priority, strict)
+ table_hash_delete(t2->subtable[1], key, priority, strict));
return (table_hash_delete(t2->subtable[0], key, out_port, priority, strict)
+ table_hash_delete(t2->subtable[1], key, out_port, priority,
strict));
}
static void table_hash2_timeout(struct sw_table *swt, struct list *deleted)
@@ -339,7 +348,8 @@ static void table_hash2_destroy(struct sw_table *swt)
}
static int table_hash2_iterate(struct sw_table *swt,
const struct sw_flow_key *key,
const struct sw_flow_key *key,
uint16_t out_port,
struct sw_table_position *position,
int (*callback)(struct sw_flow *, void *),
void *private)
@@ -348,8 +358,8 @@ static int table_hash2_iterate(struct sw_table *swt,
int i;
for (i = position->private[1]; i < 2; i++) {
int error = table_hash_iterate(t2->subtable[i], key, position,
callback, private);
int error = table_hash_iterate(t2->subtable[i], key, out_port,
position, callback, private);
if (error) {
return error;
}
+6 -1
View File
@@ -128,6 +128,7 @@ do_delete(struct sw_flow *flow)
static int table_linear_delete(struct sw_table *swt,
const struct sw_flow_key *key,
uint16_t out_port,
uint16_t priority, int strict)
{
struct sw_table_linear *tl = (struct sw_table_linear *) swt;
@@ -136,6 +137,7 @@ static int table_linear_delete(struct sw_table *swt,
LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) {
if (flow_matches_desc(&flow->key, key, strict)
&& flow_has_out_port(flow, out_port)
&& (!strict || (flow->priority == priority))) {
do_delete(flow);
count++;
@@ -175,6 +177,7 @@ static void table_linear_destroy(struct sw_table *swt)
static int table_linear_iterate(struct sw_table *swt,
const struct sw_flow_key *key,
uint16_t out_port,
struct sw_table_position *position,
int (*callback)(struct sw_flow *, void *),
void *private)
@@ -185,7 +188,9 @@ static int table_linear_iterate(struct sw_table *swt,
start = ~position->private[0];
LIST_FOR_EACH (flow, struct sw_flow, iter_node, &tl->iter_flows) {
if (flow->serial <= start && flow_matches_2wild(key, &flow->key)) {
if (flow->serial <= start
&& flow_matches_2wild(key, &flow->key)
&& flow_has_out_port(flow, out_port)) {
int error = callback(flow, private);
if (error) {
position->private[0] = ~(flow->serial - 1);
+10 -7
View File
@@ -95,10 +95,12 @@ struct sw_table {
const struct ofp_action_header *actions, size_t actions_len);
/* Deletes from 'table' any and all flows that match 'key' from
* 'table'. If 'strict' set, wildcards must match. Returns the
* 'table'. If 'out_port' is not OFPP_NONE, then matching entries
* must have that port as an argument for an output action. If
* 'strict' is set, wildcards and priority must match. Returns the
* number of flows that were deleted. */
int (*delete)(struct sw_table *table, const struct sw_flow_key *key,
uint16_t priority, int strict);
uint16_t out_port, uint16_t priority, int strict);
/* Performs timeout processing on all the flow entries in 'table'.
* Appends all the flow entries removed from 'table' to 'deleted' for the
@@ -109,10 +111,11 @@ struct sw_table {
void (*destroy)(struct sw_table *table);
/* Iterates through the flow entries in 'table', passing each one
* matches 'key' to 'callback'. The callback function should return 0
* to continue iteration or a nonzero error code to stop. The iterator
* function returns either 0 if the table iteration completed or the
* value returned by the callback function otherwise.
* matches 'key' and output port 'out_port' to 'callback'. The
* callback function should return 0 to continue iteration or a
* nonzero error code to stop. The iterator function returns either
* 0 if the table iteration completed or the value returned by the
* callback function otherwise.
*
* The iteration starts at 'position', which may be initialized to
* all-zero-bits to iterate from the beginning of the table. If the
@@ -121,7 +124,7 @@ struct sw_table {
* iterator function to resume iteration later with the following
* flow. */
int (*iterate)(struct sw_table *table,
const struct sw_flow_key *key,
const struct sw_flow_key *key, uint16_t out_port,
struct sw_table_position *position,
int (*callback)(struct sw_flow *flow, void *private),
void *private);
+8
View File
@@ -403,6 +403,14 @@ Causes the flow to expire after the given number of seconds,
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-flow\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:
+20 -9
View File
@@ -762,7 +762,7 @@ parse_field(const char *name, const struct field **f_out)
static void
str_to_flow(char *string, struct ofp_match *match,
struct ofp_action_header *actions, size_t *actions_len,
uint8_t *table_idx, uint16_t *priority,
uint8_t *table_idx, uint16_t *out_port, uint16_t *priority,
uint16_t *idle_timeout, uint16_t *hard_timeout)
{
@@ -772,6 +772,9 @@ str_to_flow(char *string, struct ofp_match *match,
if (table_idx) {
*table_idx = 0xff;
}
if (out_port) {
*out_port = OFPP_NONE;
}
if (priority) {
*priority = OFP_DEFAULT_PRIORITY;
}
@@ -821,6 +824,8 @@ str_to_flow(char *string, struct ofp_match *match,
if (table_idx && !strcmp(name, "table")) {
*table_idx = atoi(value);
} else if (out_port && !strcmp(name, "out_port")) {
*out_port = atoi(value);
} else if (priority && !strcmp(name, "priority")) {
*priority = atoi(value);
} else if (idle_timeout && !strcmp(name, "idle_timeout")) {
@@ -856,12 +861,14 @@ str_to_flow(char *string, struct ofp_match *match,
static void do_dump_flows(const struct settings *s, int argc, char *argv[])
{
struct ofp_flow_stats_request *req;
uint16_t out_port;
struct ofpbuf *request;
req = alloc_stats_request(sizeof *req, OFPST_FLOW, &request);
str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, 0,
&req->table_id, NULL, NULL, NULL);
memset(req->pad, 0, sizeof req->pad);
&req->table_id, &out_port, NULL, NULL, NULL);
memset(&req->pad, 0, sizeof req->pad);
req->out_port = htons(out_port);
dump_stats_transaction(argv[1], request);
}
@@ -871,11 +878,13 @@ static void do_dump_aggregate(const struct settings *s, int argc,
{
struct ofp_aggregate_stats_request *req;
struct ofpbuf *request;
uint16_t out_port;
req = alloc_stats_request(sizeof *req, OFPST_AGGREGATE, &request);
str_to_flow(argc > 2 ? argv[2] : "", &req->match, NULL, 0,
&req->table_id, NULL, NULL, NULL);
memset(req->pad, 0, sizeof req->pad);
&req->table_id, &out_port, NULL, NULL, NULL);
memset(&req->pad, 0, sizeof req->pad);
req->out_port = htons(out_port);
dump_stats_transaction(argv[1], request);
}
@@ -945,7 +954,7 @@ static void do_add_flow(const struct settings *s, int argc, char *argv[])
size = sizeof *ofm + actions_len;
ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
str_to_flow(argv[2], &ofm->match, &ofm->actions[0], &actions_len,
NULL, &priority, &idle_timeout, &hard_timeout);
NULL, NULL, &priority, &idle_timeout, &hard_timeout);
ofm->command = htons(OFPFC_ADD);
ofm->idle_timeout = htons(idle_timeout);
ofm->hard_timeout = htons(hard_timeout);
@@ -997,7 +1006,7 @@ static void do_add_flows(const struct settings *s, int argc, char *argv[])
size = sizeof *ofm + actions_len;
ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
str_to_flow(line, &ofm->match, &ofm->actions[0], &actions_len,
NULL, &priority, &idle_timeout, &hard_timeout);
NULL, NULL, &priority, &idle_timeout, &hard_timeout);
ofm->command = htons(OFPFC_ADD);
ofm->idle_timeout = htons(idle_timeout);
ofm->hard_timeout = htons(hard_timeout);
@@ -1027,7 +1036,7 @@ static void do_mod_flows(const struct settings *s, int argc, char *argv[])
size = sizeof *ofm + actions_len;
ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
str_to_flow(argv[2], &ofm->match, &ofm->actions[0], &actions_len,
NULL, &priority, &idle_timeout, &hard_timeout);
NULL, NULL, &priority, &idle_timeout, &hard_timeout);
if (s->strict) {
ofm->command = htons(OFPFC_MODIFY_STRICT);
} else {
@@ -1051,6 +1060,7 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[])
{
struct vconn *vconn;
uint16_t priority;
uint16_t out_port;
struct ofpbuf *buffer;
struct ofp_flow_mod *ofm;
size_t size;
@@ -1059,7 +1069,7 @@ static void do_del_flows(const struct settings *s, int argc, char *argv[])
size = sizeof *ofm;
ofm = make_openflow(size, OFPT_FLOW_MOD, &buffer);
str_to_flow(argc > 2 ? argv[2] : "", &ofm->match, NULL, 0, NULL,
&priority, NULL, NULL);
&out_port, &priority, NULL, NULL);
if (s->strict) {
ofm->command = htons(OFPFC_DELETE_STRICT);
} else {
@@ -1068,6 +1078,7 @@ 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);
ofm->out_port = htons(out_port);
ofm->priority = htons(priority);
ofm->reserved = htonl(0);