From: Ben Pfaff Date: Thu, 26 Jun 2008 23:21:18 +0000 (-0700) Subject: Modified the naming scheme for hardware tables. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=89d08b1a1760ca31b4f1ce22945ba31ed16f7484;p=openvswitch Modified the naming scheme for hardware tables. Because of historical string munging during the kernel build process if you named your hardware table hwtable-something, when it was built the filename would look appropriate, but the actual module info would change the internal name to be hwtable_something, thus after an insmod with the filename you could not perform an rmmod with the same filename. As a result the naming scheme has been changed to hwtable_NAME, NAME being the hardware the table supports. Further, include files in the hardware table should be prefixed with the folder name, e.g. #include "hwtable_NAME/my_header.h". Based on commits from David Erickson . --- diff --git a/README.hwtables b/README.hwtables index e0b2a038..2b005539 100644 --- a/README.hwtables +++ b/README.hwtables @@ -17,7 +17,7 @@ hardware table module is loaded (and before it is unloaded) will take advantage of hardware switching features. Creating a hardware table module is straightforward. Create a -directory in the openflow source tree named datapath/hwtable-NAME, +directory in the openflow source tree named datapath/hwtable_NAME, where NAME identifies the hardware that the module supports. Populate that directory with the C source files that comprise the module, plus a file named Modules.mk that specifies how to build the module. This @@ -33,6 +33,6 @@ the OpenFlow configure script command as the argument to Each hardware table module's code is encapsulated in a directory, so it is easy to separate a hardware table implementation from OpenFlow. -Simply package up the contents of the hwtable-NAME directory and +Simply package up the contents of the hwtable_NAME directory and distribute it for builders to extract into their distribution directory. diff --git a/configure.ac b/configure.ac index 2be62d59..5fea45f8 100644 --- a/configure.ac +++ b/configure.ac @@ -45,7 +45,7 @@ case "${enable_hw_tables}" in # ( ;; esac for d in $hw_tables; do - mk=datapath/hwtable-$d/Modules.mk + mk=datapath/hwtable_$d/Modules.mk if test ! -e $srcdir/$mk; then AC_MSG_ERROR([--enable-hw-tables=$d specified but $mk is missing]) fi diff --git a/datapath/hwtable-dummy/Modules.mk b/datapath/hwtable-dummy/Modules.mk deleted file mode 100644 index 97484a0f..00000000 --- a/datapath/hwtable-dummy/Modules.mk +++ /dev/null @@ -1,6 +0,0 @@ -# Specify the module to build. -all_modules += hwtable-dummy - -# Specify the source files that comprise the module. -hwtable-dummy_sources = \ - hwtable-dummy/hwtable-dummy.c diff --git a/datapath/hwtable-dummy/hwtable-dummy.c b/datapath/hwtable-dummy/hwtable-dummy.c deleted file mode 100644 index d84dde0c..00000000 --- a/datapath/hwtable-dummy/hwtable-dummy.c +++ /dev/null @@ -1,308 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include - -#include "chain.h" -#include "table.h" -#include "flow.h" -#include "datapath.h" - - -/* Max number of flow entries supported by the hardware */ -#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; - - /* xxx If per-entry data is needed, define it here. */ -}; - -struct sw_table_dummy { - struct sw_table swt; - - spinlock_t lock; - unsigned int max_flows; - atomic_t 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)) { - return flow; - } - } - return NULL; -} - -static int table_dummy_insert(struct sw_table *swt, struct sw_flow *flow) -{ - /* xxx Use a data cache? */ - flow->private = kzalloc(sizeof(struct sw_flow_dummy), GFP_ATOMIC); - if (flow->private == NULL) - return 0; - - /* 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. - */ - 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; -} - -static int table_dummy_delete(struct sw_table *swt, - const struct sw_flow_key *key, uint16_t priority, int strict) -{ - struct sw_table_dummy *td = (struct sw_table_dummy *) swt; - struct sw_flow *flow; - unsigned int count = 0; - - list_for_each_entry_rcu (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); - return count; -} - - -static int table_dummy_timeout(struct datapath *dp, struct sw_table *swt) -{ - 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; - - 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". - */ - - if ((packet_count > flow->packet_count) - && (flow->max_idle != OFP_FLOW_PERMANENT)) { - flow->packet_count = packet_count; - flow->timeout = jiffies + HZ * flow->max_idle; - } - - if (flow_timeout(flow)) { - if (dp->flags & OFPC_SEND_FLOW_EXP) { - /* xxx Get byte count */ - flow->byte_count = 0; - dp_send_flow_expired(dp, flow); - } - del_count += do_delete(swt, flow); - } - if ((i % 50) == 0) { - msleep_interruptible(1); - } - i++; - } - - /* 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); - return del_count; -} - - -static void table_dummy_destroy(struct sw_table *swt) -{ - struct sw_table_dummy *td = (struct sw_table_dummy *)swt; - - - /* xxx This table is being destroyed, so free any data that you - * xxx don't want to leak. - */ - - - if (td) { - while (!list_empty(&td->flows)) { - struct sw_flow *flow = list_entry(td->flows.next, - struct sw_flow, node); - list_del(&flow->node); - flow_free(flow); - } - kfree(td); - } -} - -static int table_dummy_iterate(struct sw_table *swt, - const struct sw_flow_key *key, - struct sw_table_position *position, - int (*callback)(struct sw_flow *, void *), - void *private) -{ - struct sw_table_dummy *tl = (struct sw_table_dummy *) swt; - struct sw_flow *flow; - 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)) { - int error = callback(flow, private); - if (error) { - position->private[0] = ~flow->serial; - return error; - } - } - } - return 0; -} - -static void table_dummy_stats(struct sw_table *swt, - struct sw_table_stats *stats) -{ - struct sw_table_dummy *td = (struct sw_table_dummy *) swt; - stats->name = "dummy"; - stats->n_flows = atomic_read(&td->n_flows); - stats->max_flows = td->max_flows; -} - - -static struct sw_table *table_dummy_create(void) -{ - struct sw_table_dummy *td; - struct sw_table *swt; - - td = kzalloc(sizeof *td, GFP_KERNEL); - if (td == NULL) - return NULL; - - swt = &td->swt; - swt->lookup = table_dummy_lookup; - swt->insert = table_dummy_insert; - swt->delete = table_dummy_delete; - swt->timeout = table_dummy_timeout; - swt->destroy = table_dummy_destroy; - swt->iterate = table_dummy_iterate; - swt->stats = table_dummy_stats; - - td->max_flows = DUMMY_MAX_FLOW; - atomic_set(&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; -} - -static int __init dummy_init(void) -{ - return chain_set_hw_hook(table_dummy_create, THIS_MODULE); -} -module_init(dummy_init); - -static void dummy_cleanup(void) -{ - chain_clear_hw_hook(); -} -module_exit(dummy_cleanup); - -MODULE_DESCRIPTION("Dummy hardware table driver"); -MODULE_AUTHOR("Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University"); -MODULE_LICENSE("Stanford License"); diff --git a/datapath/hwtable_dummy/Modules.mk b/datapath/hwtable_dummy/Modules.mk new file mode 100644 index 00000000..2a3014d9 --- /dev/null +++ b/datapath/hwtable_dummy/Modules.mk @@ -0,0 +1,7 @@ +# Specify the module to build. +all_modules += hwtable_dummy + +# Specify the source files that comprise the module. +hwtable_dummy_sources = \ + hwtable_dummy/hwtable_dummy.c + diff --git a/datapath/hwtable_dummy/hwtable_dummy.c b/datapath/hwtable_dummy/hwtable_dummy.c new file mode 100644 index 00000000..d84dde0c --- /dev/null +++ b/datapath/hwtable_dummy/hwtable_dummy.c @@ -0,0 +1,308 @@ +/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford + * Junior University + * + * We are making the OpenFlow specification and associated documentation + * (Software) available for public use and benefit with the expectation + * that others will use, modify and enhance the Software and contribute + * those enhancements back to the community. However, since we would + * like to make the Software available for broadest use, with as few + * restrictions as possible permission is hereby granted, free of + * charge, to any person obtaining a copy of this Software to deal in + * the Software under the copyrights without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * The name and trademarks of copyright holder(s) may NOT be used in + * advertising or publicity pertaining to the Software or any + * derivatives without specific, written prior permission. + */ + +#include +#include +#include +#include +#include +#include + +#include "chain.h" +#include "table.h" +#include "flow.h" +#include "datapath.h" + + +/* Max number of flow entries supported by the hardware */ +#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; + + /* xxx If per-entry data is needed, define it here. */ +}; + +struct sw_table_dummy { + struct sw_table swt; + + spinlock_t lock; + unsigned int max_flows; + atomic_t 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)) { + return flow; + } + } + return NULL; +} + +static int table_dummy_insert(struct sw_table *swt, struct sw_flow *flow) +{ + /* xxx Use a data cache? */ + flow->private = kzalloc(sizeof(struct sw_flow_dummy), GFP_ATOMIC); + if (flow->private == NULL) + return 0; + + /* 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. + */ + 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; +} + +static int table_dummy_delete(struct sw_table *swt, + const struct sw_flow_key *key, uint16_t priority, int strict) +{ + struct sw_table_dummy *td = (struct sw_table_dummy *) swt; + struct sw_flow *flow; + unsigned int count = 0; + + list_for_each_entry_rcu (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); + return count; +} + + +static int table_dummy_timeout(struct datapath *dp, struct sw_table *swt) +{ + 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; + + 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". + */ + + if ((packet_count > flow->packet_count) + && (flow->max_idle != OFP_FLOW_PERMANENT)) { + flow->packet_count = packet_count; + flow->timeout = jiffies + HZ * flow->max_idle; + } + + if (flow_timeout(flow)) { + if (dp->flags & OFPC_SEND_FLOW_EXP) { + /* xxx Get byte count */ + flow->byte_count = 0; + dp_send_flow_expired(dp, flow); + } + del_count += do_delete(swt, flow); + } + if ((i % 50) == 0) { + msleep_interruptible(1); + } + i++; + } + + /* 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); + return del_count; +} + + +static void table_dummy_destroy(struct sw_table *swt) +{ + struct sw_table_dummy *td = (struct sw_table_dummy *)swt; + + + /* xxx This table is being destroyed, so free any data that you + * xxx don't want to leak. + */ + + + if (td) { + while (!list_empty(&td->flows)) { + struct sw_flow *flow = list_entry(td->flows.next, + struct sw_flow, node); + list_del(&flow->node); + flow_free(flow); + } + kfree(td); + } +} + +static int table_dummy_iterate(struct sw_table *swt, + const struct sw_flow_key *key, + struct sw_table_position *position, + int (*callback)(struct sw_flow *, void *), + void *private) +{ + struct sw_table_dummy *tl = (struct sw_table_dummy *) swt; + struct sw_flow *flow; + 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)) { + int error = callback(flow, private); + if (error) { + position->private[0] = ~flow->serial; + return error; + } + } + } + return 0; +} + +static void table_dummy_stats(struct sw_table *swt, + struct sw_table_stats *stats) +{ + struct sw_table_dummy *td = (struct sw_table_dummy *) swt; + stats->name = "dummy"; + stats->n_flows = atomic_read(&td->n_flows); + stats->max_flows = td->max_flows; +} + + +static struct sw_table *table_dummy_create(void) +{ + struct sw_table_dummy *td; + struct sw_table *swt; + + td = kzalloc(sizeof *td, GFP_KERNEL); + if (td == NULL) + return NULL; + + swt = &td->swt; + swt->lookup = table_dummy_lookup; + swt->insert = table_dummy_insert; + swt->delete = table_dummy_delete; + swt->timeout = table_dummy_timeout; + swt->destroy = table_dummy_destroy; + swt->iterate = table_dummy_iterate; + swt->stats = table_dummy_stats; + + td->max_flows = DUMMY_MAX_FLOW; + atomic_set(&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; +} + +static int __init dummy_init(void) +{ + return chain_set_hw_hook(table_dummy_create, THIS_MODULE); +} +module_init(dummy_init); + +static void dummy_cleanup(void) +{ + chain_clear_hw_hook(); +} +module_exit(dummy_cleanup); + +MODULE_DESCRIPTION("Dummy hardware table driver"); +MODULE_AUTHOR("Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University"); +MODULE_LICENSE("Stanford License");