Flow mod behavior: Add a new flag to flow mods and flow conflict

detection handler for table maintanance

Add a CHECK_OVERLAP flag to flow mods which requires the switch to do
the (potentially more costly) check that there doesn't already exist a
conflicting flow with the same priority. If there is one, the mod
fails and an error code is returned.

Flow expiry: Record OFPFF_SEND_FLOW_EXP flag in user data path
This commit is contained in:
Yiannis Yiakoumis authored and Mikio Hara committed 2009-06-29 10:00:55 -07:00
1 parent c42075a48f
commit a47208dc76
21 files changed
+412 -111

No files matched your search

+21 -1
View File
@@ -167,6 +167,27 @@ chain_modify(struct sw_chain *chain, const struct sw_flow_key *key,
return count;
}
/* Checks whether the chain has an entry with the same priority which conflicts
* with 'key'. If 'strict' set, wildcards should also match. If 'strict' is not
* set, comparison is done 'module wildcards'.
*
* Returns 'true' if such an entry exists, 'false' otherwise. */
int
chain_has_conflict(struct sw_chain *chain, const struct sw_flow_key *key,
uint16_t priority, int strict)
{
int i;
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
if (t->has_conflict(t, key, priority, strict)) {
return true;
}
}
return false;
}
/* 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
@@ -193,7 +214,6 @@ chain_delete(struct sw_chain *chain, const struct sw_flow_key *key,
}
return count;
}
/* Deletes timed-out flow entries from all the tables in 'chain' and appends
+2
View File
@@ -64,6 +64,8 @@ struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *, int)
int chain_insert(struct sw_chain *, struct sw_flow *, int);
int chain_modify(struct sw_chain *, const struct sw_flow_key *,
uint16_t, int, const struct ofp_action_header *, size_t, int);
int chain_has_conflict(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);
void chain_timeout(struct sw_chain *, struct list *deleted);
+90 -55
View File
@@ -548,8 +548,8 @@ dp_output_port(struct datapath *dp, struct ofpbuf *buffer,
case OFPP_TABLE: {
struct sw_port *p = lookup_port(dp, in_port);
if (run_flow_through_tables(dp, buffer, p)) {
ofpbuf_delete(buffer);
if (run_flow_through_tables(dp, buffer, p)) {
ofpbuf_delete(buffer);
}
break;
}
@@ -833,13 +833,13 @@ int run_flow_through_tables(struct datapath *dp, struct ofpbuf *buffer,
ofpbuf_delete(buffer);
return 0;
}
if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP)
if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP)
&& p->config & (!eth_addr_equals(key.flow.dl_dst, stp_eth_addr)
? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) {
ofpbuf_delete(buffer);
return 0;
}
ofpbuf_delete(buffer);
return 0;
}
flow = chain_lookup(dp->chain, &key, 0);
if (flow != NULL) {
@@ -931,7 +931,7 @@ recv_packet_out(struct datapath *dp, const struct sender *sender,
return -ESRCH;
}
}
flow_extract(buffer, ntohs(opo->in_port), &key.flow);
v_code = validate_actions(dp, &key, opo->actions, actions_len);
@@ -969,6 +969,7 @@ add_flow(struct datapath *dp, const struct sender *sender,
uint16_t v_code;
struct sw_flow *flow;
size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm;
int overlap;
/* Allocate memory. */
flow = flow_alloc(actions_len);
@@ -984,11 +985,23 @@ add_flow(struct datapath *dp, const struct sender *sender,
goto error_free_flow;
}
/* Fill out flow. */
flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1;
if (ntohs(ofm->flags) & OFPFF_CHECK_OVERLAP) {
/* check whether there is any conflict */
overlap = chain_has_conflict(dp->chain, &flow->key, flow->priority,
false);
if (overlap){
dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED,
OFPFMFC_OVERLAP, ofm, ntohs(ofm->header.length));
goto error_free_flow;
}
}
/* Fill out flow. */
flow->idle_timeout = ntohs(ofm->idle_timeout);
flow->hard_timeout = ntohs(ofm->hard_timeout);
flow->send_flow_exp = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_EXP) ? 1 : 0;
flow_setup_actions(flow, ofm->actions, actions_len);
/* Act. */
@@ -1032,30 +1045,52 @@ mod_flow(struct datapath *dp, const struct sender *sender,
{
int error = -ENOMEM;
uint16_t v_code;
size_t actions_len;
struct sw_flow_key key;
uint16_t priority;
size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm;
struct sw_flow *flow;
int strict;
flow_extract_match(&key, &ofm->match);
actions_len = ntohs(ofm->header.length) - sizeof *ofm;
v_code = validate_actions(dp, &key, ofm->actions, actions_len);
/* Allocate memory. */
flow = flow_alloc(actions_len);
if (flow == NULL)
goto error;
flow_extract_match(&flow->key, &ofm->match);
v_code = validate_actions(dp, &flow->key, ofm->actions, actions_len);
if (v_code != ACT_VALIDATION_OK) {
dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code,
ofm, ntohs(ofm->header.length));
ofm, ntohs(ofm->header.length));
goto error;
}
priority = key.wildcards ? ntohs(ofm->priority) : -1;
flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1;
strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0;
chain_modify(dp->chain, &key, priority, strict, ofm->actions, actions_len,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0);
/* First try to modify existing flows if any */
/* if there is no matching flow, add it */
if (!chain_modify(dp->chain, &flow->key, flow->priority,
strict, ofm->actions, actions_len,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0)) {
/* Fill out flow. */
flow->idle_timeout = ntohs(ofm->idle_timeout);
flow->hard_timeout = ntohs(ofm->hard_timeout);
flow->send_flow_exp = (ntohs(ofm->flags) & OFPFF_SEND_FLOW_EXP) ? 1 : 0;
flow_setup_actions(flow, ofm->actions, actions_len);
error = chain_insert(dp->chain, flow,
(ntohs(ofm->flags) & OFPFF_EMERG) ? 1 : 0);
if (error == -ENOBUFS) {
dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED,
OFPFMFC_ALL_TABLES_FULL, ofm,
ntohs(ofm->header.length));
goto error;
} else if (error) {
goto error;
}
}
if (ntohl(ofm->buffer_id) != UINT32_MAX) {
struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id));
if (buffer) {
struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id));
if (buffer) {
struct sw_flow_key skb_key;
uint16_t in_port = ntohs(ofm->match.in_port);
flow_extract(buffer, in_port, &skb_key.flow);
@@ -1355,47 +1390,47 @@ static void port_stats_done(void *state)
*/
static int
vendor_stats_init(const void *body, int body_len,
void **state)
void **state)
{
/* min_body was checked, this should be safe */
const uint32_t vendor = ntohl(*((uint32_t *)body));
int err;
/* min_body was checked, this should be safe */
const uint32_t vendor = ntohl(*((uint32_t *)body));
int err;
switch (vendor) {
default:
err = -EINVAL;
}
switch (vendor) {
default:
err = -EINVAL;
}
return err;
return err;
}
static int
vendor_stats_dump(struct datapath *dp, void *state, struct ofpbuf *buffer)
{
const uint32_t vendor = *((uint32_t *)state);
int err;
const uint32_t vendor = *((uint32_t *)state);
int err;
switch (vendor) {
default:
/* Should never happen */
err = 0;
}
switch (vendor) {
default:
/* Should never happen */
err = 0;
}
return err;
return err;
}
static void
vendor_stats_done(void *state)
{
const uint32_t vendor = *((uint32_t *) state);
const uint32_t vendor = *((uint32_t *) state);
switch (vendor) {
default:
/* Should never happen */
free(state);
}
switch (vendor) {
default:
/* Should never happen */
free(state);
}
return;
return;
}
struct stats_type {
@@ -1466,12 +1501,12 @@ static const struct stats_type stats[] = {
port_stats_done
},
{
OFPST_VENDOR,
8, /* vendor + subtype */
32, /* whatever */
vendor_stats_init,
vendor_stats_dump,
vendor_stats_done
OFPST_VENDOR,
8, /* vendor + subtype */
32, /* whatever */
vendor_stats_init,
vendor_stats_dump,
vendor_stats_done
},
};
@@ -1718,7 +1753,7 @@ uint32_t save_buffer(struct ofpbuf *buffer)
/* Don't buffer packet if existing entry is less than
* OVERWRITE_SECS old. */
if (time_now() < p->timeout) { /* FIXME */
return (uint32_t)-1;
return (uint32_t)-1;
} else {
ofpbuf_delete(p->buffer);
}
+2
View File
@@ -78,9 +78,11 @@ protection_callback(struct sw_flow *flow, void *private_)
memset(&match, 0, sizeof(match));
flow_fill_match(&match, &flow->key.flow, flow->key.wildcards);
flow_extract_match(&tgtflow->key, &match);
/* Fill out flow. */
tgtflow->priority = flow->priority;
tgtflow->idle_timeout = 0;
tgtflow->hard_timeout = 0;
tgtflow->send_flow_exp = flow->send_flow_exp;
flow_setup_actions(tgtflow, actions->actions, actions->actions_len);
error = chain_insert(private->dp->chain, tgtflow, 0);
+39
View File
@@ -124,6 +124,34 @@ static int table_hash_modify(struct sw_table *swt,
return count;
}
static int table_hash_has_conflict(struct sw_table *swt,
const struct sw_flow_key *key,
uint16_t priority, int strict)
{
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_desc(&flow->key, key,strict)
&& (flow->priority == priority)) {
return true;
}
} else {
unsigned int i;
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)
&& (flow->priority == priority)) {
return true;
}
}
}
return false;
}
/* Caller must update n_flows. */
static void
do_delete(struct sw_flow **bucket)
@@ -272,6 +300,7 @@ struct sw_table *table_hash_create(unsigned int polynomial,
swt->lookup = table_hash_lookup;
swt->insert = table_hash_insert;
swt->modify = table_hash_modify;
swt->has_conflict = table_hash_has_conflict;
swt->delete = table_hash_delete;
swt->timeout = table_hash_timeout;
swt->destroy = table_hash_destroy;
@@ -324,6 +353,15 @@ static int table_hash2_modify(struct sw_table *swt,
actions, actions_len));
}
static int table_hash2_has_conflict(struct sw_table *swt,
const struct sw_flow_key *key,
uint16_t priority, int strict)
{
struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
return (table_hash_has_conflict(t2->subtable[0], key, priority, strict) ||
table_hash_has_conflict(t2->subtable[1], key, priority, strict));
}
static int table_hash2_delete(struct datapath *dp, struct sw_table *swt,
const struct sw_flow_key *key,
uint16_t out_port,
@@ -414,6 +452,7 @@ struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0,
swt->lookup = table_hash2_lookup;
swt->insert = table_hash2_insert;
swt->modify = table_hash2_modify;
swt->has_conflict = table_hash2_has_conflict;
swt->delete = table_hash2_delete;
swt->timeout = table_hash2_timeout;
swt->destroy = table_hash2_destroy;
+17
View File
@@ -119,6 +119,22 @@ static int table_linear_modify(struct sw_table *swt,
return count;
}
static int table_linear_has_conflict(struct sw_table *swt,
const struct sw_flow_key *key,
uint16_t priority, int strict)
{
struct sw_table_linear *tl = (struct sw_table_linear *) swt;
struct sw_flow *flow;
LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) {
if (flow_matches_desc(&flow->key, key, strict)
&& (flow->priority == priority)) {
return true;
}
}
return false;
}
static void
do_delete(struct sw_flow *flow)
{
@@ -229,6 +245,7 @@ struct sw_table *table_linear_create(unsigned int max_flows)
swt->lookup = table_linear_lookup;
swt->insert = table_linear_insert;
swt->modify = table_linear_modify;
swt->has_conflict = table_linear_has_conflict;
swt->delete = table_linear_delete;
swt->timeout = table_linear_timeout;
swt->destroy = table_linear_destroy;
+7 -1
View File
@@ -89,12 +89,18 @@ struct sw_table {
int (*insert)(struct sw_table *table, struct sw_flow *flow);
/* Modifies the actions in 'table' that match 'key'. If 'strict'
* set, wildcards and priority must match. Returns the number of flows
* 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_header *actions, size_t actions_len);
/* Checks whether 'table' has an equal priotiry entry of thethat conflicts
* with 'key'. If 'strict' is set, wildcards must match.
* Returns the number of flows that were modified. */
int (*has_conflict)(struct sw_table *table, const struct sw_flow_key *key,
uint16_t priority, int strict);
/* Deletes from 'table' any and all flows that match 'key' from
* 'table'. If 'out_port' is not OFPP_NONE, then matching entries
* must have that port as an argument for an output action. If