#include "chain.h"
#include "flow.h"
#include "table.h"
+#include <linux/module.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+static struct sw_table *(*create_hw_table_hook)(void);
+static struct module *hw_table_owner;
+static DEFINE_SPINLOCK(hook_lock);
/* Attempts to append 'table' to the set of tables in 'chain'. Returns 0 or
* negative error. If 'table' is null it is assumed that table creation failed
{
struct sw_chain *chain = kzalloc(sizeof *chain, GFP_KERNEL);
if (chain == NULL)
- return NULL;
+ goto error;
chain->dp = dp;
+ chain->owner = try_module_get(hw_table_owner) ? hw_table_owner : NULL;
+ if (chain->owner && create_hw_table_hook) {
+ struct sw_table *hwtable = create_hw_table_hook();
+ if (!hwtable || add_table(chain, hwtable))
+ goto error;
+ }
if (add_table(chain, table_hash2_create(0x1EDC6F41, TABLE_HASH_MAX_FLOWS,
0x741B8CD7, TABLE_HASH_MAX_FLOWS))
- || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS))) {
- chain_destroy(chain);
- return NULL;
- }
-
+ || add_table(chain, table_linear_create(TABLE_LINEAR_MAX_FLOWS)))
+ goto error;
return chain;
+
+error:
+ if (chain)
+ chain_destroy(chain);
+ return NULL;
}
/* Searches 'chain' for a flow matching 'key', which must not have any wildcard
struct sw_table *t = chain->tables[i];
t->destroy(t);
}
+ module_put(chain->owner);
kfree(chain);
}
stats.name, stats.n_flows, stats.max_flows);
}
}
+
+
+int chain_set_hw_hook(struct sw_table *(*create_hw_table)(void),
+ struct module *owner)
+{
+ int retval = -EBUSY;
+
+ spin_lock(&hook_lock);
+ if (!create_hw_table_hook) {
+ create_hw_table_hook = create_hw_table;
+ hw_table_owner = owner;
+ retval = 0;
+ }
+ spin_unlock(&hook_lock);
+
+ return retval;
+}
+EXPORT_SYMBOL(chain_set_hw_hook);
+
+void chain_clear_hw_hook(void)
+{
+ create_hw_table_hook = NULL;
+ hw_table_owner = NULL;
+}
+EXPORT_SYMBOL(chain_clear_hw_hook);