*
* 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.
- *
- * The caller need not hold any locks. */
+ * wildcards. Relatively cheap for fully specified keys. */
int
chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, int strict)
{
}
-/* Performs timeout processing on all the tables in 'chain'. Returns the
- * number of flow entries deleted through expiration.
+/* Deletes timed-out flow entries from all the tables in 'chain' and appends
+ * the deleted flows to 'deleted'.
*
* Expensive as currently implemented, since it iterates through the entire
- * contents of each table.
- *
- * The caller need not hold any locks. */
-int
-chain_timeout(struct sw_chain *chain, struct datapath *dp)
+ * contents of each table. */
+void
+chain_timeout(struct sw_chain *chain, struct list *deleted)
{
- int count = 0;
int i;
for (i = 0; i < chain->n_tables; i++) {
struct sw_table *t = chain->tables[i];
- count += t->timeout(dp, t);
+ t->timeout(t, deleted);
}
- return count;
}
/* Destroys 'chain', which must not have any users. */
struct sw_flow;
struct sw_flow_key;
-struct datapath;
+struct list;
#define TABLE_LINEAR_MAX_FLOWS 100
#define TABLE_HASH_MAX_FLOWS 65536
struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *);
int chain_insert(struct sw_chain *, struct sw_flow *);
int chain_delete(struct sw_chain *, const struct sw_flow_key *, int);
-int chain_timeout(struct sw_chain *, struct datapath *);
+void chain_timeout(struct sw_chain *, struct list *deleted);
void chain_destroy(struct sw_chain *);
void chain_print_stats(struct sw_chain *);
void dp_update_port_flags(struct datapath *dp, const struct ofp_phy_port *opp);
void dp_output_control(struct datapath *, struct buffer *, int in_port,
size_t max_len, int reason);
+static void send_flow_expired(struct datapath *, struct sw_flow *);
static void send_port_status(struct sw_port *p, uint8_t status);
static void del_switch_port(struct sw_port *p);
static void execute_actions(struct datapath *, struct buffer *,
int i;
if (now != dp->last_timeout) {
- chain_timeout(dp->chain, dp);
+ struct list deleted = LIST_INITIALIZER(&deleted);
+ struct sw_flow *f, *n;
+
+ chain_timeout(dp->chain, &deleted);
+ LIST_FOR_EACH_SAFE (f, n, struct sw_flow, node, &deleted) {
+ send_flow_expired(dp, f);
+ list_remove(&f->node);
+ flow_free(f);
+ }
dp->last_timeout = now;
}
poll_timer_wait(1000);
}
void
-dp_send_flow_expired(struct datapath *dp, struct sw_flow *flow)
+send_flow_expired(struct datapath *dp, struct sw_flow *flow)
{
struct buffer *buffer;
struct ofp_flow_expired *ofe;
void dp_run(struct datapath *);
void dp_wait(struct datapath *);
-void dp_send_flow_expired(struct datapath *, struct sw_flow *);
-
#endif /* datapath.h */
return count;
}
-static int table_hash_timeout(struct datapath *dp, struct sw_table *swt)
+static void table_hash_timeout(struct sw_table *swt, struct list *deleted)
{
struct sw_table_hash *th = (struct sw_table_hash *) swt;
unsigned int i;
- int count = 0;
for (i = 0; i <= th->bucket_mask; i++) {
struct sw_flow **bucket = &th->buckets[i];
struct sw_flow *flow = *bucket;
if (flow && flow_timeout(flow)) {
- dp_send_flow_expired(dp, flow);
- do_delete(bucket);
- count++;
+ list_push_back(deleted, &flow->node);
+ *bucket = NULL;
+ th->n_flows--;
}
}
- th->n_flows -= count;
- return count;
}
static void table_hash_destroy(struct sw_table *swt)
+ table_hash_delete(t2->subtable[1], key, strict));
}
-static int table_hash2_timeout(struct datapath *dp, struct sw_table *swt)
+static void table_hash2_timeout(struct sw_table *swt, struct list *deleted)
{
struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
- return (table_hash_timeout(dp, t2->subtable[0])
- + table_hash_timeout(dp, t2->subtable[1]));
+ table_hash_timeout(t2->subtable[0], deleted);
+ table_hash_timeout(t2->subtable[1], deleted);
}
static void table_hash2_destroy(struct sw_table *swt)
return count;
}
-static int table_linear_timeout(struct datapath *dp, struct sw_table *swt)
+static void table_linear_timeout(struct sw_table *swt, struct list *deleted)
{
struct sw_table_linear *tl = (struct sw_table_linear *) swt;
struct sw_flow *flow, *n;
- int count = 0;
LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) {
if (flow_timeout(flow)) {
- dp_send_flow_expired(dp, flow);
- do_delete(flow);
- count++;
+ list_remove(&flow->node);
+ list_push_back(deleted, &flow->node);
+ tl->n_flows--;
}
}
- tl->n_flows -= count;
- return count;
}
static void table_linear_destroy(struct sw_table *swt)
}
}
-static int table_mac_timeout(struct datapath *dp, struct sw_table *swt)
+static void table_mac_timeout(struct sw_table *swt, struct list *deleted)
{
struct sw_table_mac *tm = (struct sw_table_mac *) swt;
unsigned int i;
- int count = 0;
for (i = 0; i <= tm->bucket_mask; i++) {
struct list *bucket = &tm->buckets[i];
struct sw_flow *flow, *next;
LIST_FOR_EACH_SAFE (flow, next, struct sw_flow, node, bucket) {
if (flow_timeout(flow)) {
- dp_send_flow_expired(dp, flow);
- do_delete(flow);
- count++;
+ list_remove(&flow->node);
+ list_push_back(deleted, &flow->node);
+ tm->n_flows--;
}
}
}
- tm->n_flows -= count;
- return count;
}
static void table_mac_destroy(struct sw_table *swt)
struct sw_flow;
struct sw_flow_key;
-struct datapath;
+struct list;
/* Iterator through the flows stored in a table. */
struct swt_iterator {
int strict);
/* Performs timeout processing on all the flow entries in 'table'.
- * Returns the number of flow entries deleted through expiration. */
- int (*timeout)(struct datapath *dp, struct sw_table *table);
+ * Appends all the flow entries removed from 'table' to 'deleted' for the
+ * caller to free. */
+ void (*timeout)(struct sw_table *table, struct list *deleted);
/* Destroys 'table', which must not have any users. */
void (*destroy)(struct sw_table *table);