Free sk_buffs with kfree_skb() instead of just kfree().
[sliver-openvswitch.git] / datapath / chain.c
index 2b1178b..cd3b6e5 100644 (file)
@@ -62,8 +62,7 @@ error:
 /* Searches 'chain' for a flow matching 'key', which must not have any wildcard
  * fields.  Returns the flow if successful, otherwise a null pointer.
  *
- * Caller must hold rcu_read_lock, and not release it until it is done with the
- * returned flow. */
+ * Caller must hold rcu_read_lock or dp_mutex. */
 struct sw_flow *chain_lookup(struct sw_chain *chain,
                         const struct sw_flow_key *key)
 {
@@ -73,8 +72,11 @@ struct sw_flow *chain_lookup(struct sw_chain *chain,
        for (i = 0; i < chain->n_tables; i++) {
                struct sw_table *t = chain->tables[i];
                struct sw_flow *flow = t->lookup(t, key);
-               if (flow)
+               t->n_lookup++;
+               if (flow) {
+                       t->n_matched++;
                        return flow;
+               }
        }
        return NULL;
 }
@@ -85,12 +87,12 @@ struct sw_flow *chain_lookup(struct sw_chain *chain,
  * If successful, 'flow' becomes owned by the chain, otherwise it is retained
  * by the caller.
  *
- * Caller must hold rcu_read_lock.  If insertion is successful, it must not
- * release rcu_read_lock until it is done with the inserted flow. */
+ * Caller must hold dp_mutex. */
 int chain_insert(struct sw_chain *chain, struct sw_flow *flow)
 {
        int i;
 
+       might_sleep();
        for (i = 0; i < chain->n_tables; i++) {
                struct sw_table *t = chain->tables[i];
                if (t->insert(t, flow))
@@ -100,25 +102,47 @@ int chain_insert(struct sw_chain *chain, struct sw_flow *flow)
        return -ENOBUFS;
 }
 
-/* Deletes from 'chain' any and all flows that match 'key'.  Returns the number
- * of flows that were deleted.
+/* 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, 
+               uint16_t priority, int strict,
+               const struct ofp_action_header *actions, size_t actions_len)
+{
+       int count = 0;
+       int i;
+
+       for (i = 0; i < chain->n_tables; i++) {
+               struct sw_table *t = chain->tables[i];
+               count += t->modify(t, key, priority, strict, actions, actions_len);
+       }
+
+       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.
  *
  * 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. */
+ * Caller must hold dp_mutex. */
 int chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, 
                uint16_t priority, int strict)
 {
        int count = 0;
        int i;
 
+       might_sleep();
        for (i = 0; i < chain->n_tables; i++) {
                struct sw_table *t = chain->tables[i];
-               rcu_read_lock();
                count += t->delete(t, key, priority, strict);
-               rcu_read_unlock();
        }
 
        return count;
@@ -130,17 +154,17 @@ int chain_delete(struct sw_chain *chain, const struct sw_flow_key *key,
  * Expensive as currently implemented, since it iterates through the entire
  * contents of each table.
  *
- * The caller need not hold any locks. */
+ * Caller must not hold dp_mutex, because individual tables take and release it
+ * as necessary. */
 int chain_timeout(struct sw_chain *chain)
 {
        int count = 0;
        int i;
 
+       might_sleep();
        for (i = 0; i < chain->n_tables; i++) {
                struct sw_table *t = chain->tables[i];
-               rcu_read_lock();
                count += t->timeout(chain->dp, t);
-               rcu_read_unlock();
        }
        return count;
 }
@@ -153,28 +177,13 @@ void chain_destroy(struct sw_chain *chain)
        synchronize_rcu();
        for (i = 0; i < chain->n_tables; i++) {
                struct sw_table *t = chain->tables[i];
-               t->destroy(t);
+               if (t->destroy)
+                       t->destroy(t);
        }
        module_put(chain->owner);
        kfree(chain);
 }
 
-/* Prints statistics for each of the tables in 'chain'. */
-void chain_print_stats(struct sw_chain *chain)
-{
-       int i;
-
-       printk("\n");
-       for (i = 0; i < chain->n_tables; i++) {
-               struct sw_table *t = chain->tables[i];
-               struct sw_table_stats stats;
-               t->stats(t, &stats);
-               printk("%s: %lu/%lu flows\n",
-                                       stats.name, stats.n_flows, stats.max_flows);
-       }
-}
-
-
 int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void),
                      struct module *owner)
 {