#define DUMMY_MAX_FLOW 8192
-/* xxx Explain need for this separate list because of RCU */
-static spinlock_t pending_free_lock;
-static struct list_head pending_free_list;
-
/* sw_flow private data for dummy table entries. */
struct sw_flow_dummy {
struct list_head node;
struct sw_table_dummy {
struct sw_table swt;
- spinlock_t lock;
unsigned int max_flows;
- atomic_t n_flows;
+ unsigned int n_flows;
struct list_head flows;
struct list_head iter_flows;
unsigned long int next_serial;
};
-static void table_dummy_sfw_destroy(struct sw_flow_dummy *sfw)
-{
- /* xxx Remove the entry from hardware. If you need to do any other
- * xxx clean-up associated with the entry, do it here.
- */
-
- kfree(sfw);
-}
-
-static void table_dummy_rcu_callback(struct rcu_head *rcu)
-{
- struct sw_flow *flow = container_of(rcu, struct sw_flow, rcu);
-
- spin_lock(&pending_free_lock);
- if (flow->private) {
- struct sw_flow_dummy *sfw = flow->private;
- list_add(&sfw->node, &pending_free_list);
- flow->private = NULL;
- }
- spin_unlock(&pending_free_lock);
- flow_free(flow);
-}
-
-static void table_dummy_flow_deferred_free(struct sw_flow *flow)
-{
- call_rcu(&flow->rcu, table_dummy_rcu_callback);
-}
-
static struct sw_flow *table_dummy_lookup(struct sw_table *swt,
const struct sw_flow_key *key)
{
struct sw_table_dummy *td = (struct sw_table_dummy *) swt;
struct sw_flow *flow;
list_for_each_entry (flow, &td->flows, node) {
- if (flow_matches(&flow->key, key)) {
+ if (flow_matches_1wild(key, &flow->key)) {
return flow;
}
}
/* xxx Do whatever needs to be done to insert an entry in hardware.
* xxx If the entry can't be inserted, return 0. This stub code
* xxx doesn't do anything yet, so we're going to return 0...you
- * xxx shouldn't.
+ * xxx shouldn't (and you should update n_flows in struct
+ * xxx sw_table_dummy, too).
*/
kfree(flow->private);
return 0;
static int do_delete(struct sw_table *swt, struct sw_flow *flow)
{
- if (flow_del(flow)) {
- list_del_rcu(&flow->node);
- list_del_rcu(&flow->iter_node);
- table_dummy_flow_deferred_free(flow);
- return 1;
- }
- return 0;
+ /* xxx Remove the entry from hardware. If you need to do any other
+ * xxx clean-up associated with the entry, do it here.
+ */
+ list_del_rcu(&flow->node);
+ list_del_rcu(&flow->iter_node);
+ return 1;
}
static int table_dummy_delete(struct sw_table *swt,
struct sw_flow *flow;
unsigned int count = 0;
- list_for_each_entry_rcu (flow, &td->flows, node) {
+ list_for_each_entry (flow, &td->flows, node) {
if (flow_del_matches(&flow->key, key, strict)
&& (!strict || (flow->priority == priority)))
count += do_delete(swt, flow);
}
- if (count)
- atomic_sub(count, &td->n_flows);
+ td->n_flows -= count;
return count;
}
{
struct sw_table_dummy *td = (struct sw_table_dummy *) swt;
struct sw_flow *flow;
- struct sw_flow_dummy *sfw, *n;
int del_count = 0;
uint64_t packet_count = 0;
- int i = 0;
+ uint64_t byte_count = 0;
+ int reason;
- list_for_each_entry_rcu (flow, &td->flows, node) {
- /* xxx Retrieve the packet count associated with this entry
- * xxx and store it in "packet_count".
+ mutex_lock(&dp_mutex);
+ list_for_each_entry (flow, &td->flows, node) {
+ /* xxx Retrieve the packet and byte counts associated with this
+ * entry xxx and store them in "packet_count" and "byte_count".
*/
- if ((packet_count > flow->packet_count)
- && (flow->max_idle != OFP_FLOW_PERMANENT)) {
+ if (packet_count != flow->packet_count) {
flow->packet_count = packet_count;
- flow->timeout = jiffies + HZ * flow->max_idle;
+ flow->byte_count = byte_count;
+ flow->used = jiffies;
}
- if (flow_timeout(flow)) {
+ reason = flow_timeout(flow);
+ if (reason >= 0) {
if (dp->flags & OFPC_SEND_FLOW_EXP) {
/* xxx Get byte count */
flow->byte_count = 0;
- dp_send_flow_expired(dp, flow);
+ dp_send_flow_expired(dp, flow, reason);
}
del_count += do_delete(swt, flow);
}
- if ((i % 50) == 0) {
- msleep_interruptible(1);
- }
- i++;
}
+ mutex_unlock(&dp_mutex);
- /* Remove any entries queued for removal */
- spin_lock_bh(&pending_free_lock);
- list_for_each_entry_safe (sfw, n, &pending_free_list, node) {
- list_del(&sfw->node);
- table_dummy_sfw_destroy(sfw);
- }
- spin_unlock_bh(&pending_free_lock);
-
- if (del_count)
- atomic_sub(del_count, &td->n_flows);
+ td->n_flows -= del_count;
return del_count;
}
unsigned long start;
start = ~position->private[0];
- list_for_each_entry_rcu (flow, &tl->iter_flows, iter_node) {
- if (flow->serial <= start && flow_matches(key, &flow->key)) {
+ list_for_each_entry (flow, &tl->iter_flows, iter_node) {
+ if (flow->serial <= start && flow_matches_2wild(key,
+ &flow->key)) {
int error = callback(flow, private);
if (error) {
position->private[0] = ~flow->serial;
{
struct sw_table_dummy *td = (struct sw_table_dummy *) swt;
stats->name = "dummy";
- stats->n_flows = atomic_read(&td->n_flows);
+ stats->wildcards = OFPFW_ALL; /* xxx Set this appropriately */
+ stats->n_flows = td->n_flows;
stats->max_flows = td->max_flows;
+ stats->n_matched = swt->n_matched;
}
swt->stats = table_dummy_stats;
td->max_flows = DUMMY_MAX_FLOW;
- atomic_set(&td->n_flows, 0);
+ td->n_flows = 0;
INIT_LIST_HEAD(&td->flows);
INIT_LIST_HEAD(&td->iter_flows);
- spin_lock_init(&td->lock);
td->next_serial = 0;
- INIT_LIST_HEAD(&pending_free_list);
- spin_lock_init(&pending_free_lock);
-
return swt;
}