- datapath/linux-2.6/openflow_mod.ko
- - datapath/linux-2.6/hwtable_<table>_mod.ko for each <table>
- specified on --enable-hw-tables (if any).
-
3. Run "make install" to install the executables and manpages into the
running system, by default under /usr/local.
% insmod datapath/linux-2.6/openflow_mod.ko
- After you load the openflow module, you may load one hardware switch
- table module (if any were built) to enable support for that hardware
- switching table.
-
The insmod program must be run as root. You may need to specify a
full path to insmod, e.g. /sbin/insmod. To verify that the modules
have been loaded, run "/sbin/lsmod" and check that openflow_mod is
% ./configure --with-l24=/path/to/linux-2.6 KARCH=mips
-If you have hardware that supports accelerated OpenFlow switching, and
-you have obtained a hardware table module for your hardware and
-extracted it into the OpenFlow reference distribution source tree,
-then you may also enable building support for the hardware switching
-table with --enable-hw-tables. For example, if your hardware
-switching table is in a directory named datapath/hwtable-foomatic, you
-could compile support for it with the running Linux 2.6 kernel like
-so:
-
- % ./configure --with-l26=/lib/modules/`uname -r`/build \
- --enable-hw-tables=foomatic
-
-For more information about hardware table modules, please read
-README.hwtables at the root of the OpenFlow distribution tree.
Building Debian Packages
========================
bridged to the physical switch ports by the secchan, for use in
in-band control.
- If you built a support module for hardware accelerated OpenFlow
- switching and you want to use it, you must load it before creating
- the datapath with "dpctl adddp".
-
2. Use dpctl to attach the datapath to physical interfaces on the
machine. Say, for example, you want to create a trivial 2-port
switch using interfaces eth1 and eth2, you would issue the following
+++ /dev/null
-Hardware Table Support -*- text -*-
-----------------------
-
-The OpenFlow reference implementation in this distribution provides a
-mechanism to support hardware that can accelerate OpenFlow switching.
-The mechanism consists of the ability to add a "hardware acceleration"
-switching table ahead of the software switching tables implemented by
-the reference implementation. The hardware switching table is
-expected to handle any incoming packets that it can on its own. Any
-packets that it cannot handle itself it may pass up to the software
-table implementations.
-
-Hardware table implementation are built as separate kernel modules
-that may be loaded after the openflow module. At most one hardware
-table module may be loaded at a time. Only datapaths created after a
-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,
-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
-distribution includes a "dummy" hardware module that demonstrates how
-this works.
-
-Even though only one may be loaded at a given time, any number of
-hardware table modules may be built along with the OpenFlow kernel
-modules. Specify each NAME that identifies a module to be built on
-the OpenFlow configure script command as the argument to
---enable-hw-tables, e.g.:
- ./configure --enable-hw-tables=NAME
-
-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
-distribute it for builders to extract into their distribution
-directory.
+++ /dev/null
-/* Copyright (c) 2008, 2009 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 <linux/module.h>
-#include <linux/rcupdate.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/rculist.h>
-#include <linux/delay.h>
-#include <linux/if_arp.h>
-
-#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
-
-
-/* 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;
-
- unsigned int max_flows;
- unsigned int n_flows;
- struct list_head flows;
- struct list_head iter_flows;
- unsigned long int next_serial;
-};
-
-
-static struct sw_flow *table_dummy_lookup(struct sw_table *swt,
- const struct odp_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_1wild(key, &flow->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 (and you should update n_flows in struct
- * xxx sw_table_dummy, too).
- */
- kfree(flow->private);
- return 0;
-}
-
-static int table_dummy_modify(struct sw_table *swt,
- const struct odp_flow_key *key, uint16_t priority, int strict,
- const struct ofp_action_header *actions, size_t actions_len)
-{
- struct sw_table_dummy *td = (struct sw_table_dummy *) swt;
- struct sw_flow *flow;
- unsigned int count = 0;
-
- list_for_each_entry (flow, &td->flows, node) {
- if (flow_matches_desc(&flow->key, key, strict)
- && (!strict || (flow->priority == priority))) {
- flow_replace_acts(flow, actions, actions_len);
- /* xxx Do whatever is necessary to modify the entry in hardware */
- count++;
- }
- }
- return count;
-}
-
-
-static int do_delete(struct sw_table *swt, struct sw_flow *flow)
-{
- /* 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);
- flow_deferred_free(flow);
- return 1;
-}
-
-static int table_dummy_delete(struct sw_table *swt,
- const struct odp_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 (flow, &td->flows, node) {
- if (flow_matches_desc(&flow->key, key, strict)
- && (!strict || (flow->priority == priority)))
- count += do_delete(swt, flow);
- }
- td->n_flows -= count;
- 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;
- int del_count = 0;
- uint64_t packet_count = 0;
- uint64_t byte_count = 0;
- int reason;
-
- 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->packet_count = packet_count;
- flow->byte_count = byte_count;
- flow->used = jiffies;
- }
-
- 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, reason);
- }
- del_count += do_delete(swt, flow);
- }
- }
- mutex_unlock(&dp_mutex);
-
- td->n_flows -= del_count;
- 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 odp_flow_key *key,
- struct sw_table_position *position,
- int (*callback)(struct sw_flow *, void *),
- void *private)
-{
- struct sw_table_dummy *td = (struct sw_table_dummy *) swt;
- struct sw_flow *flow;
- unsigned long start;
-
- start = ~position->private[0];
- list_for_each_entry (flow, &td->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;
- 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->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;
-}
-
-
-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->modify = table_dummy_modify;
- 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;
- td->n_flows = 0;
- INIT_LIST_HEAD(&td->flows);
- INIT_LIST_HEAD(&td->iter_flows);
- td->next_serial = 0;
-
- 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");