Remove userspace switch in favor of the superior userspace datapath.
authorBen Pfaff <blp@nicira.com>
Tue, 6 Jan 2009 22:01:20 +0000 (14:01 -0800)
committerBen Pfaff <blp@nicira.com>
Tue, 6 Jan 2009 22:07:00 +0000 (14:07 -0800)
31 files changed:
INSTALL
Makefile.am
README
controller/controller.8.in
debian/openflow-switch.README.Debian
debian/openflow-switch.install
debian/openflow-switch.manpages
secchan/secchan.8.in
switch/.gitignore [deleted file]
switch/TODO [deleted file]
switch/automake.mk [deleted file]
switch/chain.c [deleted file]
switch/chain.h [deleted file]
switch/crc32.c [deleted file]
switch/crc32.h [deleted file]
switch/datapath.c [deleted file]
switch/datapath.h [deleted file]
switch/dp_act.c [deleted file]
switch/dp_act.h [deleted file]
switch/nx_act.c [deleted file]
switch/nx_act.h [deleted file]
switch/switch-flow.c [deleted file]
switch/switch-flow.h [deleted file]
switch/switch.8.in [deleted file]
switch/switch.c [deleted file]
switch/table-hash.c [deleted file]
switch/table-linear.c [deleted file]
switch/table.h [deleted file]
udatapath/udatapath.8.in
utilities/dpctl.8.in
utilities/ofp-pki.8.in

diff --git a/INSTALL b/INSTALL
index 8f558b4..fc7d3f7 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -8,8 +8,8 @@ reference implementation of OpenFlow.  Please send any comments to:
 Contents
 ========
 
 Contents
 ========
 
-The OpenFlow reference implementation includes three separate
-OpenFlow switch implementations:
+The OpenFlow reference implementation includes two OpenFlow switch
+implementations:
 
         - The "kernel-based switch": This divides the switch into a
           "datapath" Linux kernel module (openflow_mod.o for Linux 2.4
 
         - The "kernel-based switch": This divides the switch into a
           "datapath" Linux kernel module (openflow_mod.o for Linux 2.4
@@ -26,15 +26,6 @@ OpenFlow switch implementations:
           datapath-based switch does not require building a kernel
           module, but it is not as fast as the kernel-based switch.
 
           datapath-based switch does not require building a kernel
           module, but it is not as fast as the kernel-based switch.
 
-        - The "userspace switch": This implements an OpenFlow switch
-          as a single user program (built as switch/switch).  The
-          userspace switch is the easiest to build and use but it is
-          much less featureful than the other switch implementations.
-
-          The userspace switch is deprecated in favor of the userspace
-          datapath-based switch.  It will likely be removed in a
-          future OpenFlow release.
-
 The reference implementation also contains a simple OpenFlow
 controller (built as controller/controller) and a number of related
 utilities.
 The reference implementation also contains a simple OpenFlow
 controller (built as controller/controller) and a number of related
 utilities.
@@ -184,8 +175,6 @@ distribution in the ordinary way using "configure" and "make".
 
       - Tests: various binaries in tests/.
 
 
       - Tests: various binaries in tests/.
 
-      - Switch executable: switch/switch.
-
    If your distribution includes the OpenFlow extensions, the
    following additional binaries will be built:
 
    If your distribution includes the OpenFlow extensions, the
    following additional binaries will be built:
 
@@ -333,8 +322,8 @@ Follow these instructions to build Debian packages for OpenFlow.
       - Completely by hand, as described under the Testing section
         below.
 
       - Completely by hand, as described under the Testing section
         below.
 
-        For the userspace switch, this is the only supported form of
-        configuration.
+        For the userspace datapath-based switch, this is the only
+        supported form of configuration.
 
       - By editing /etc/default/openflow-switch.  You must at least
         configure some network devices, by uncommenting NETDEVS and
 
       - By editing /etc/default/openflow-switch.  You must at least
         configure some network devices, by uncommenting NETDEVS and
@@ -347,7 +336,7 @@ Follow these instructions to build Debian packages for OpenFlow.
            % /etc/init.d/openflow-switch restart
 
         This form of configuration is not supported for the userspace
            % /etc/init.d/openflow-switch restart
 
         This form of configuration is not supported for the userspace
-        switch.
+        datapath-based switch.
 
       - By running the ofp-switch-setup program.  This interactive
         program will walk you through all the steps of configuring an
 
       - By running the ofp-switch-setup program.  This interactive
         program will walk you through all the steps of configuring an
@@ -357,7 +346,7 @@ Follow these instructions to build Debian packages for OpenFlow.
            % ofp-switch-setup
 
         This form of configuration is not supported for the userspace
            % ofp-switch-setup
 
         This form of configuration is not supported for the userspace
-        switch.
+        datapath-based switch.
 
 Testing
 =======
 
 Testing
 =======
@@ -403,42 +392,6 @@ These instructions use the OpenFlow userspace datapath ("udatapath").
    now be able to send packets to each other, as if they were plugged
    into ports on a conventional Ethernet switch.
 
    now be able to send packets to each other, as if they were plugged
    into ports on a conventional Ethernet switch.
 
-Userspace Switch
-----------------
-
-These instructions use the OpenFlow userspace switch that runs as an
-integrated userspace program.  Keep in mind that the userspace switch
-is deprecated: you should use the userspace datapath instead.
-
-1. Start the OpenFlow controller running in the background, by running
-   the "controller" program with a command like the following:
-
-      # controller ptcp: &
-
-   This command causes the controller to bind to port 6633 (the
-   default) awaiting connections from OpenFlow switches.  See
-   controller(8) for details.
-
-   The "controller" program does not require any special privilege, so
-   you do not need to run it as root.
-   
-2. The "switch" program must run as root, so log in as root, or use a
-   program such as "su" to become root temporarily.
-
-3. On the same machine, use the "switch" program to start an OpenFlow
-   switch, specifying network devices to use as switch ports on the -i
-   option as a comma-separated list, like so:
-
-      # switch tcp:127.0.0.1 -i eth1,eth2
-   
-   The network devices that you specify should not have configured IP
-   addresses.
-
-4. The controller causes each switch that connects to it to act like a
-   learning Ethernet switch.  Thus, devices plugged into the specified
-   network ports should now be able to send packets to each other, as
-   if they were plugged into ports on a conventional Ethernet switch.
-
 Installation
 ============
 
 Installation
 ============
 
@@ -459,9 +412,6 @@ each switch to reach the controller over the network:
         please refer to secchan(8) for instructions on setting up
         controller discovery.  
 
         please refer to secchan(8) for instructions on setting up
         controller discovery.  
 
-        The (deprecated) userspace switch does not support in-band
-        control.
-
 Controller Setup
 ----------------
 
 Controller Setup
 ----------------
 
@@ -643,36 +593,6 @@ The OpenFlow kernel module must be loaded, as described under
    use, because the switch must then also obtain its own IP address
    and the controller's location via DHCP.
 
    use, because the switch must then also obtain its own IP address
    and the controller's location via DHCP.
 
-Userspace Switch-Based Setup
-----------------------------
-
-To set up an OpenFlow switch using the (deprecated) userspace switch,
-follow this procedure.  The userspace switch must be connected to the
-controller over a "control network" that is physically separate from
-the one that the switch and controller are controlling.  (The other
-switch implementations do not have this limitation.)
-
-0. The commands below must run as root, so log in as root, or use a
-   program such as "su" to become root temporarily.
-
-1. Use the "switch" program to start an OpenFlow switch, specifying
-   the IP address of the controller as the first argument to the
-   switch program, and the network devices to include in the switch as
-   arguments to the -i option.  For example, if the controller is
-   running on host 192.168.1.2 port 6633 (the default port), and eth1
-   and eth2 are to be the switch ports, the switch invocation would
-   look like this:
-
-      # switch tcp:127.0.0.1 -i eth1,eth2
-   
-   The network devices that you specify should not have configured IP
-   addresses.
-
-2. The controller causes each switch that connects to it to act like a
-   learning Ethernet switch.  Thus, devices plugged into the specified
-   network ports should now be able to send packets to each other, as
-   if they were plugged into ports on a conventional Ethernet switch.
-
 Configuration
 =============
 
 Configuration
 =============
 
@@ -744,9 +664,8 @@ controllerca subdirectory contains controller certificate authority
 related files, including the following:
 
     - cacert.pem: Root certificate for the controller certificate
 related files, including the following:
 
     - cacert.pem: Root certificate for the controller certificate
-      authority.  This file must be provided to the switch or secchan
-      program with the --ca-cert option to enable it to authenticate
-      valid controllers.
+      authority.  This file must be provided to secchan with the
+      --ca-cert option to enable it to authenticate valid controllers.
 
     - private/cakey.pem: Private signing key for the controller
       certificate authority.  This file must be kept secret.  There is
 
     - private/cakey.pem: Private signing key for the controller
       certificate authority.  This file must be kept secret.  There is
@@ -780,7 +699,7 @@ named sc-privkey.pem and sc-cert.pem, for example, you could run:
 sc-privkey.pem and sc-cert.pem would need to be copied to the switch
 for its use at runtime (they could then be deleted from their original
 locations).  The --private-key and --certificate options,
 sc-privkey.pem and sc-cert.pem would need to be copied to the switch
 for its use at runtime (they could then be deleted from their original
 locations).  The --private-key and --certificate options,
-respectively, of switch and secchan would point to these files.
+respectively, of secchan would point to these files.
 
 Bug Reporting
 -------------
 
 Bug Reporting
 -------------
index dadf848..84fb6e7 100644 (file)
@@ -64,7 +64,6 @@ include lib/automake.mk
 include secchan/automake.mk
 include controller/automake.mk
 include utilities/automake.mk
 include secchan/automake.mk
 include controller/automake.mk
 include utilities/automake.mk
-include switch/automake.mk
 include udatapath/automake.mk
 include tests/automake.mk
 include include/automake.mk
 include udatapath/automake.mk
 include tests/automake.mk
 include include/automake.mk
diff --git a/README b/README
index 28cfab9..8b9b7bd 100644 (file)
--- a/README
+++ b/README
@@ -30,10 +30,10 @@ Specification [2].
 What's here?
 ------------
 
 What's here?
 ------------
 
-This distribution includes three different reference implementations
-of an OpenFlow switch.  The first implementation, which is closely
-tied to Linux because it is partially implemented in the Linux kernel,
-has the following components:
+This distribution includes two reference implementations of an
+OpenFlow switch.  The first implementation, which is closely tied to
+Linux because it is partially implemented in the Linux kernel, has the
+following components:
 
        - A Linux kernel module that implements the flow table and
           OpenFlow protocol, in the datapath directory.
 
        - A Linux kernel module that implements the flow table and
           OpenFlow protocol, in the datapath directory.
@@ -52,11 +52,6 @@ The second implementation has the following components:
           component of the reference switch (the same program used in
           the kernel-based implementation).
 
           component of the reference switch (the same program used in
           the kernel-based implementation).
 
-The third implementation is a single userspace program, named
-"switch", that integrates all three parts of an OpenFlow switch.  This
-implementation is deprecated.  It lacks features present in the other
-two implementations.
-
 This distribution includes some additional software as well:
 
        - controller, a simple program that connects to any number of
 This distribution includes some additional software as well:
 
        - controller, a simple program that connects to any number of
index b608c93..a266252 100644 (file)
@@ -171,6 +171,6 @@ To bind locally to port 6633 (the default) and wait for incoming connections fro
 .SH "SEE ALSO"
 
 .BR dpctl (8),
 .SH "SEE ALSO"
 
 .BR dpctl (8),
-.BR switch (8),
 .BR secchan (8),
 .BR secchan (8),
+.BR udatapath (8),
 .BR vlogconf (8)
 .BR vlogconf (8)
index d4b1cb3..d9a931c 100644 (file)
@@ -12,5 +12,7 @@ README.Debian for openflow-switch
   the openflow-datapath-source package, then follow the instructions
   given in /usr/share/doc/openflow-datapath-source/README.Debian
 
   the openflow-datapath-source package, then follow the instructions
   given in /usr/share/doc/openflow-datapath-source/README.Debian
 
-* This package does not yet support the userspace switch
-  implementation.
+* This package does not yet support the userspace datapath-based
+  switch implementation.
+
+ -- Ben Pfaff <blp@nicira.com>, Tue,  6 Jan 2009 13:52:33 -0800
index 53dc04d..5a864ba 100644 (file)
@@ -1,4 +1,3 @@
-_debian/switch/switch usr/sbin
 _debian/secchan/secchan usr/sbin
 _debian/utilities/dpctl usr/sbin
 _debian/utilities/ofp-discover usr/sbin
 _debian/secchan/secchan usr/sbin
 _debian/utilities/dpctl usr/sbin
 _debian/utilities/ofp-discover usr/sbin
index e50d997..b79db3d 100644 (file)
@@ -1,6 +1,5 @@
 debian/ofp-switch-setup.8
 _debian/secchan/secchan.8
 debian/ofp-switch-setup.8
 _debian/secchan/secchan.8
-_debian/switch/switch.8
 _debian/utilities/ofp-discover.8
 _debian/utilities/ofp-kill.8
 _debian/utilities/dpctl.8
 _debian/utilities/ofp-discover.8
 _debian/utilities/ofp-kill.8
 _debian/utilities/dpctl.8
index 79380d0..66bed8f 100644 (file)
@@ -467,5 +467,5 @@ Prints version information to the console.
 .BR ofp-discover (8),
 .BR controller (8),
 .BR ofp-pki (8),
 .BR ofp-discover (8),
 .BR controller (8),
 .BR ofp-pki (8),
-.BR vlogconf (8),
-.BR switch (8)
+.BR udatapath (8),
+.BR vlogconf (8)
diff --git a/switch/.gitignore b/switch/.gitignore
deleted file mode 100644 (file)
index c55f1fa..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-/Makefile
-/Makefile.in
-/switch
-/switch.8
diff --git a/switch/TODO b/switch/TODO
deleted file mode 100644 (file)
index c437733..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-* Give it a more specific name (ofswitch? ofp-switch?)
-
-* Test memory leaks.
-
-* Test packet header modifications.
-
-* Clean up file organization.
-
-* Update comments.
-
-* Reduce steady-state use of malloc.
-
-* Address FIXMEs.
-
-* Add real FSM support.
-
-* Make vlog modules dynamic.
-
-* Use controller-connection in secchan.
-
-* Implement dpctl support for switch.
diff --git a/switch/automake.mk b/switch/automake.mk
deleted file mode 100644 (file)
index d9826f4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-bin_PROGRAMS += switch/switch
-man_MANS += switch/switch.8
-
-switch_switch_SOURCES = \
-       switch/chain.c \
-       switch/chain.h \
-       switch/crc32.c \
-       switch/crc32.h \
-       switch/datapath.c \
-       switch/datapath.h \
-       switch/dp_act.c \
-       switch/dp_act.h \
-       switch/nx_act.c \
-       switch/nx_act.h \
-       switch/switch.c \
-       switch/switch-flow.c \
-       switch/switch-flow.h \
-       switch/table.h \
-       switch/table-hash.c \
-       switch/table-linear.c
-
-switch_switch_LDADD = lib/libopenflow.a $(FAULT_LIBS) $(SSL_LIBS)
-
-EXTRA_DIST += switch/switch.8.in
-DISTCLEANFILES += switch/switch.8
diff --git a/switch/chain.c b/switch/chain.c
deleted file mode 100644 (file)
index 8f09c00..0000000
+++ /dev/null
@@ -1,191 +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 <config.h>
-#include "chain.h"
-#include <assert.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "switch-flow.h"
-#include "table.h"
-
-#define THIS_MODULE VLM_chain
-#include "vlog.h"
-
-/* 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
- * due to out-of-memory. */
-static int add_table(struct sw_chain *chain, struct sw_table *table)
-{
-    if (table == NULL)
-        return -ENOMEM;
-    if (chain->n_tables >= CHAIN_MAX_TABLES) {
-        VLOG_ERR("too many tables in chain\n");
-        table->destroy(table);
-        return -ENOBUFS;
-    }
-    chain->tables[chain->n_tables++] = table;
-    return 0;
-}
-
-/* Creates and returns a new chain.  Returns NULL if the chain cannot be
- * created. */
-struct sw_chain *chain_create(void)
-{
-    struct sw_chain *chain = calloc(1, sizeof *chain);
-    if (chain == NULL)
-        return NULL;
-
-    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;
-    }
-
-    return chain;
-}
-
-/* Searches 'chain' for a flow matching 'key', which must not have any wildcard
- * fields.  Returns the flow if successful, otherwise a null pointer. */
-struct sw_flow *
-chain_lookup(struct sw_chain *chain, const struct sw_flow_key *key)
-{
-    int i;
-
-    assert(!key->wildcards);
-    for (i = 0; i < chain->n_tables; i++) {
-        struct sw_table *t = chain->tables[i];
-        struct sw_flow *flow = t->lookup(t, key);
-        t->n_lookup++;
-        if (flow) {
-            t->n_matched++;
-            return flow;
-        }
-    }
-    return NULL;
-}
-
-/* Inserts 'flow' into 'chain', replacing any duplicate flow.  Returns 0 if
- * successful or a negative error.
- *
- * If successful, 'flow' becomes owned by the chain, otherwise it is retained
- * by the caller. */
-int
-chain_insert(struct sw_chain *chain, struct sw_flow *flow)
-{
-    int i;
-
-    for (i = 0; i < chain->n_tables; i++) {
-        struct sw_table *t = chain->tables[i];
-        if (t->insert(t, flow))
-            return 0;
-    }
-
-    return -ENOBUFS;
-}
-
-/* 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 'out_port' 
- * is not OFPP_NONE, then matching entries must have that port as an 
- * argument for an output action.  If 'strict" is set, then 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. */
-int
-chain_delete(struct sw_chain *chain, const struct sw_flow_key *key, 
-             uint16_t out_port, uint16_t priority, int strict)
-{
-    int count = 0;
-    int i;
-
-    for (i = 0; i < chain->n_tables; i++) {
-        struct sw_table *t = chain->tables[i];
-        count += t->delete(t, key, out_port, priority, strict);
-    }
-
-    return count;
-
-}
-
-/* Deletes timed-out flow entries from all the tables in 'chain' and appends
- * the deleted flows to 'deleted'.
- *
- * Expensive as currently implemented, since it iterates through the entire
- * contents of each table. */
-void
-chain_timeout(struct sw_chain *chain, struct list *deleted)
-{
-    int i;
-
-    for (i = 0; i < chain->n_tables; i++) {
-        struct sw_table *t = chain->tables[i];
-        t->timeout(t, deleted);
-    }
-}
-
-/* Destroys 'chain', which must not have any users. */
-void
-chain_destroy(struct sw_chain *chain)
-{
-    int i;
-
-    for (i = 0; i < chain->n_tables; i++) {
-        struct sw_table *t = chain->tables[i];
-        t->destroy(t);
-    }
-    free(chain);
-}
diff --git a/switch/chain.h b/switch/chain.h
deleted file mode 100644 (file)
index 9ffe072..0000000
+++ /dev/null
@@ -1,67 +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.
- */
-
-#ifndef CHAIN_H
-#define CHAIN_H 1
-
-#include <stddef.h>
-#include <stdint.h>
-
-struct sw_flow;
-struct sw_flow_key;
-struct ofp_action_header;
-struct list;
-
-#define TABLE_LINEAR_MAX_FLOWS  100
-#define TABLE_HASH_MAX_FLOWS    65536
-#define TABLE_MAC_MAX_FLOWS      1024
-#define TABLE_MAC_NUM_BUCKETS   1024
-
-/* Set of tables chained together in sequence from cheap to expensive. */
-#define CHAIN_MAX_TABLES 4
-struct sw_chain {
-    int n_tables;
-    struct sw_table *tables[CHAIN_MAX_TABLES];
-};
-
-struct sw_chain *chain_create(void);
-struct sw_flow *chain_lookup(struct sw_chain *, const struct sw_flow_key *);
-int chain_insert(struct sw_chain *, struct sw_flow *);
-int chain_modify(struct sw_chain *, const struct sw_flow_key *, 
-        uint16_t, int, const struct ofp_action_header *, size_t);
-int chain_delete(struct sw_chain *, const struct sw_flow_key *, uint16_t, 
-        uint16_t, int);
-void chain_timeout(struct sw_chain *, struct list *deleted);
-void chain_destroy(struct sw_chain *);
-
-#endif /* chain.h */
diff --git a/switch/crc32.c b/switch/crc32.c
deleted file mode 100644 (file)
index f6c2c0b..0000000
+++ /dev/null
@@ -1,68 +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 <config.h>
-#include "crc32.h"
-
-void
-crc32_init(struct crc32 *crc, unsigned int polynomial)
-{
-    int i;
-
-    for (i = 0; i < CRC32_TABLE_SIZE; ++i) {
-        unsigned int reg = i << 24;
-        int j;
-        for (j = 0; j < CRC32_TABLE_BITS; j++) {
-            int topBit = (reg & 0x80000000) != 0;
-            reg <<= 1;
-            if (topBit)
-                reg ^= polynomial;
-        }
-        crc->table[i] = reg;
-    }
-}
-
-unsigned int
-crc32_calculate(const struct crc32 *crc, const void *data_, size_t n_bytes)
-{
-    const uint8_t *data = data_;
-    unsigned int result = 0;
-    size_t i;
-
-    for (i = 0; i < n_bytes; i++) {
-        unsigned int top = result >> 24;
-        top ^= data[i];
-        result = (result << 8) ^ crc->table[top];
-    }
-    return result;
-}
diff --git a/switch/crc32.h b/switch/crc32.h
deleted file mode 100644 (file)
index 355aefd..0000000
+++ /dev/null
@@ -1,50 +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.
- */
-
-#ifndef CRC32_H
-#define CRC32_H 1
-
-#include <stdint.h>
-#include <stddef.h>
-
-#define CRC32_TABLE_BITS 8
-#define CRC32_TABLE_SIZE (1u << CRC32_TABLE_BITS)
-
-struct crc32 {
-    unsigned int table[CRC32_TABLE_SIZE];
-};
-
-void crc32_init(struct crc32 *, unsigned int polynomial);
-unsigned int crc32_calculate(const struct crc32 *, const void *, size_t);
-
-#endif /* crc32.h */
diff --git a/switch/datapath.c b/switch/datapath.c
deleted file mode 100644 (file)
index 452d471..0000000
+++ /dev/null
@@ -1,1649 +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 "datapath.h"
-#include <arpa/inet.h>
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include "chain.h"
-#include "csum.h"
-#include "flow.h"
-#include "list.h"
-#include "netdev.h"
-#include "ofpbuf.h"
-#include "openflow/openflow.h"
-#include "packets.h"
-#include "poll-loop.h"
-#include "rconn.h"
-#include "stp.h"
-#include "switch-flow.h"
-#include "table.h"
-#include "timeval.h"
-#include "vconn.h"
-#include "xtoxll.h"
-#include "dp_act.h"
-
-#define THIS_MODULE VLM_datapath
-#include "vlog.h"
-
-extern char mfr_desc;
-extern char hw_desc;
-extern char sw_desc;
-extern char serial_num;
-
-/* Capabilities supported by this implementation. */
-#define OFP_SUPPORTED_CAPABILITIES ( OFPC_FLOW_STATS \
-        | OFPC_TABLE_STATS \
-        | OFPC_PORT_STATS \
-        | OFPC_MULTI_PHY_TX )
-
-/* Actions supported by this implementation. */
-#define OFP_SUPPORTED_ACTIONS ( (1 << OFPAT_OUTPUT)         \
-                                | (1 << OFPAT_SET_VLAN_VID) \
-                                | (1 << OFPAT_SET_VLAN_PCP) \
-                                | (1 << OFPAT_STRIP_VLAN)   \
-                                | (1 << OFPAT_SET_DL_SRC)   \
-                                | (1 << OFPAT_SET_DL_DST)   \
-                                | (1 << OFPAT_SET_NW_SRC)   \
-                                | (1 << OFPAT_SET_NW_DST)   \
-                                | (1 << OFPAT_SET_TP_SRC)   \
-                                | (1 << OFPAT_SET_TP_DST) )
-
-struct sw_port {
-    uint32_t config;            /* Some subset of OFPPC_* flags. */
-    uint32_t state;             /* Some subset of OFPPS_* flags. */
-    struct datapath *dp;
-    struct netdev *netdev;
-    struct list node; /* Element in datapath.ports. */
-    unsigned long long int rx_packets, tx_packets;
-    unsigned long long int rx_bytes, tx_bytes;
-    unsigned long long int tx_dropped;
-};
-
-/* The origin of a received OpenFlow message, to enable sending a reply. */
-struct sender {
-    struct remote *remote;      /* The device that sent the message. */
-    uint32_t xid;               /* The OpenFlow transaction ID. */
-};
-
-/* A connection to a controller or a management device. */
-struct remote {
-    struct list node;
-    struct rconn *rconn;
-#define TXQ_LIMIT 128           /* Max number of packets to queue for tx. */
-    int n_txq;                  /* Number of packets queued for tx on rconn. */
-
-    /* Support for reliable, multi-message replies to requests.
-     *
-     * If an incoming request needs to have a reliable reply that might
-     * require multiple messages, it can use remote_start_dump() to set up
-     * a callback that will be called as buffer space for replies. */
-    int (*cb_dump)(struct datapath *, void *aux);
-    void (*cb_done)(void *aux);
-    void *cb_aux;
-};
-
-#define DP_MAX_PORTS 255
-BUILD_ASSERT_DECL(DP_MAX_PORTS <= OFPP_MAX);
-
-struct datapath {
-    /* Remote connections. */
-    struct remote *controller;  /* Connection to controller. */
-    struct list remotes;        /* All connections (including controller). */
-    struct pvconn *listen_pvconn;
-
-    time_t last_timeout;
-
-    /* Unique identifier for this datapath */
-    uint64_t  id;
-
-    struct sw_chain *chain;  /* Forwarding rules. */
-
-    /* Configuration set from controller. */
-    uint16_t flags;
-    uint16_t miss_send_len;
-
-    /* Switch ports. */
-    struct sw_port ports[DP_MAX_PORTS];
-    struct list port_list; /* List of ports, for flooding. */
-};
-
-static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
-
-static struct remote *remote_create(struct datapath *, struct rconn *);
-static void remote_run(struct datapath *, struct remote *);
-static void remote_wait(struct remote *);
-static void remote_destroy(struct remote *);
-
-void dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm);
-static void send_flow_expired(struct datapath *, struct sw_flow *,
-                              enum ofp_flow_expired_reason);
-static int update_port_status(struct sw_port *p);
-static void send_port_status(struct sw_port *p, uint8_t status);
-static void del_switch_port(struct sw_port *p);
-
-/* Buffers are identified to userspace by a 31-bit opaque ID.  We divide the ID
- * into a buffer number (low bits) and a cookie (high bits).  The buffer number
- * is an index into an array of buffers.  The cookie distinguishes between
- * different packets that have occupied a single buffer.  Thus, the more
- * buffers we have, the lower-quality the cookie... */
-#define PKT_BUFFER_BITS 8
-#define N_PKT_BUFFERS (1 << PKT_BUFFER_BITS)
-#define PKT_BUFFER_MASK (N_PKT_BUFFERS - 1)
-
-#define PKT_COOKIE_BITS (32 - PKT_BUFFER_BITS)
-
-int run_flow_through_tables(struct datapath *, struct ofpbuf *,
-                            struct sw_port *);
-void fwd_port_input(struct datapath *, struct ofpbuf *, struct sw_port *);
-int fwd_control_input(struct datapath *, const struct sender *,
-                      const void *, size_t);
-
-uint32_t save_buffer(struct ofpbuf *);
-static struct ofpbuf *retrieve_buffer(uint32_t id);
-static void discard_buffer(uint32_t id);
-
-static int port_no(struct datapath *dp, struct sw_port *p) 
-{
-    assert(p >= dp->ports && p < &dp->ports[ARRAY_SIZE(dp->ports)]);
-    return p - dp->ports;
-}
-
-/* Generates and returns a random datapath id. */
-static uint64_t
-gen_datapath_id(void)
-{
-    uint8_t ea[ETH_ADDR_LEN];
-    eth_addr_random(ea);
-    return eth_addr_to_uint64(ea);
-}
-
-int
-dp_new(struct datapath **dp_, uint64_t dpid, struct rconn *rconn)
-{
-    struct datapath *dp;
-
-    dp = calloc(1, sizeof *dp);
-    if (!dp) {
-        return ENOMEM;
-    }
-
-    dp->last_timeout = time_now();
-    list_init(&dp->remotes);
-    dp->controller = remote_create(dp, rconn);
-    dp->listen_pvconn = NULL;
-    dp->id = dpid <= UINT64_C(0xffffffffffff) ? dpid : gen_datapath_id();
-    dp->chain = chain_create();
-    if (!dp->chain) {
-        VLOG_ERR("could not create chain");
-        free(dp);
-        return ENOMEM;
-    }
-
-    list_init(&dp->port_list);
-    dp->flags = 0;
-    dp->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN;
-    *dp_ = dp;
-    return 0;
-}
-
-int
-dp_add_port(struct datapath *dp, const char *name)
-{
-    struct netdev *netdev;
-    struct in6_addr in6;
-    struct in_addr in4;
-    struct sw_port *p;
-    int error;
-
-    error = netdev_open(name, NETDEV_ETH_TYPE_ANY, &netdev);
-    if (error) {
-        return error;
-    }
-    error = netdev_set_flags(netdev, NETDEV_UP | NETDEV_PROMISC, false);
-    if (error) {
-        VLOG_ERR("couldn't set promiscuous mode on %s device", name);
-        netdev_close(netdev);
-        return error;
-    }
-    if (netdev_get_in4(netdev, &in4)) {
-        VLOG_ERR("%s device has assigned IP address %s", name, inet_ntoa(in4));
-    }
-    if (netdev_get_in6(netdev, &in6)) {
-        char in6_name[INET6_ADDRSTRLEN + 1];
-        inet_ntop(AF_INET6, &in6, in6_name, sizeof in6_name);
-        VLOG_ERR("%s device has assigned IPv6 address %s", name, in6_name);
-    }
-
-    for (p = dp->ports; ; p++) {
-        if (p >= &dp->ports[ARRAY_SIZE(dp->ports)]) {
-            return EXFULL;
-        } else if (!p->netdev) {
-            break;
-        }
-    }
-
-    memset(p, '\0', sizeof *p);
-
-    p->dp = dp;
-    p->netdev = netdev;
-    list_push_back(&dp->port_list, &p->node);
-
-    /* Notify the ctlpath that this port has been added */
-    send_port_status(p, OFPPR_ADD);
-
-    return 0;
-}
-
-void
-dp_add_listen_pvconn(struct datapath *dp, struct pvconn *listen_pvconn)
-{
-    assert(!dp->listen_pvconn);
-    dp->listen_pvconn = listen_pvconn;
-}
-
-void
-dp_run(struct datapath *dp)
-{
-    time_t now = time_now();
-    struct sw_port *p, *pn;
-    struct remote *r, *rn;
-    struct ofpbuf *buffer = NULL;
-
-    if (now != dp->last_timeout) {
-        struct list deleted = LIST_INITIALIZER(&deleted);
-        struct sw_flow *f, *n;
-
-        LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) {
-            if (update_port_status(p)) {
-                send_port_status(p, OFPPR_MODIFY);
-            }
-        }
-
-        chain_timeout(dp->chain, &deleted);
-        LIST_FOR_EACH_SAFE (f, n, struct sw_flow, node, &deleted) {
-            send_flow_expired(dp, f, f->reason);
-            list_remove(&f->node);
-            flow_free(f);
-        }
-        dp->last_timeout = now;
-    }
-    poll_timer_wait(1000);
-    
-    LIST_FOR_EACH_SAFE (p, pn, struct sw_port, node, &dp->port_list) {
-        int error;
-
-        if (!buffer) {
-            /* Allocate buffer with some headroom to add headers in forwarding
-             * to the controller or adding a vlan tag, plus an extra 2 bytes to
-             * allow IP headers to be aligned on a 4-byte boundary.  */
-            const int headroom = 128 + 2;
-            const int hard_header = VLAN_ETH_HEADER_LEN;
-            const int mtu = netdev_get_mtu(p->netdev);
-            buffer = ofpbuf_new(headroom + hard_header + mtu);
-            buffer->data = (char*)buffer->data + headroom;
-        }
-        error = netdev_recv(p->netdev, buffer);
-        if (!error) {
-            p->rx_packets++;
-            p->rx_bytes += buffer->size;
-            fwd_port_input(dp, buffer, p);
-            buffer = NULL;
-        } else if (error != EAGAIN) {
-            VLOG_ERR_RL(&rl, "error receiving data from %s: %s",
-                        netdev_get_name(p->netdev), strerror(error));
-        }
-    }
-    ofpbuf_delete(buffer);
-
-    /* Talk to remotes. */
-    LIST_FOR_EACH_SAFE (r, rn, struct remote, node, &dp->remotes) {
-        remote_run(dp, r);
-    }
-    if (dp->listen_pvconn) {
-        for (;;) {
-            struct vconn *new_vconn;
-            int retval;
-
-            retval = pvconn_accept(dp->listen_pvconn, OFP_VERSION, &new_vconn);
-            if (retval) {
-                if (retval != EAGAIN) {
-                    VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval));
-                }
-                break;
-            }
-            remote_create(dp, rconn_new_from_vconn("passive", new_vconn));
-        }
-    }
-}
-
-static void
-remote_run(struct datapath *dp, struct remote *r)
-{
-    int i;
-
-    rconn_run(r->rconn);
-
-    /* Do some remote processing, but cap it at a reasonable amount so that
-     * other processing doesn't starve. */
-    for (i = 0; i < 50; i++) {
-        if (!r->cb_dump) {
-            struct ofpbuf *buffer;
-            struct ofp_header *oh;
-
-            buffer = rconn_recv(r->rconn);
-            if (!buffer) {
-                break;
-            }
-
-            if (buffer->size >= sizeof *oh) {
-                struct sender sender;
-
-                oh = buffer->data;
-                sender.remote = r;
-                sender.xid = oh->xid;
-                fwd_control_input(dp, &sender, buffer->data, buffer->size);
-            } else {
-                VLOG_WARN_RL(&rl, "received too-short OpenFlow message");
-            }
-            ofpbuf_delete(buffer); 
-        } else {
-            if (r->n_txq < TXQ_LIMIT) {
-                int error = r->cb_dump(dp, r->cb_aux);
-                if (error <= 0) {
-                    if (error) {
-                        VLOG_WARN_RL(&rl, "dump callback error: %s",
-                                     strerror(-error));
-                    }
-                    r->cb_done(r->cb_aux);
-                    r->cb_dump = NULL;
-                }
-            } else {
-                break;
-            }
-        }
-    }
-
-    if (!rconn_is_alive(r->rconn)) {
-        remote_destroy(r);
-    }
-}
-
-static void
-remote_wait(struct remote *r) 
-{
-    rconn_run_wait(r->rconn);
-    rconn_recv_wait(r->rconn);
-}
-
-static void
-remote_destroy(struct remote *r)
-{
-    if (r) {
-        if (r->cb_dump && r->cb_done) {
-            r->cb_done(r->cb_aux);
-        }
-        list_remove(&r->node);
-        rconn_destroy(r->rconn);
-        free(r);
-    }
-}
-
-static struct remote *
-remote_create(struct datapath *dp, struct rconn *rconn) 
-{
-    struct remote *remote = xmalloc(sizeof *remote);
-    list_push_back(&dp->remotes, &remote->node);
-    remote->rconn = rconn;
-    remote->cb_dump = NULL;
-    remote->n_txq = 0;
-    return remote;
-}
-
-/* Starts a callback-based, reliable, possibly multi-message reply to a
- * request made by 'remote'.
- *
- * 'dump' designates a function that will be called when the 'remote' send
- * queue has an empty slot.  It should compose a message and send it on
- * 'remote'.  On success, it should return 1 if it should be called again when
- * another send queue slot opens up, 0 if its transmissions are complete, or a
- * negative errno value on failure.
- *
- * 'done' designates a function to clean up any resources allocated for the
- * dump.  It must handle being called before the dump is complete (which will
- * happen if 'remote' is closed unexpectedly).
- *
- * 'aux' is passed to 'dump' and 'done'. */
-static void
-remote_start_dump(struct remote *remote,
-                  int (*dump)(struct datapath *, void *),
-                  void (*done)(void *),
-                  void *aux) 
-{
-    assert(!remote->cb_dump);
-    remote->cb_dump = dump;
-    remote->cb_done = done;
-    remote->cb_aux = aux;
-}
-
-void
-dp_wait(struct datapath *dp) 
-{
-    struct sw_port *p;
-    struct remote *r;
-
-    LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) {
-        netdev_recv_wait(p->netdev);
-    }
-    LIST_FOR_EACH (r, struct remote, node, &dp->remotes) {
-        remote_wait(r);
-    }
-    if (dp->listen_pvconn) {
-        pvconn_wait(dp->listen_pvconn);
-    }
-}
-
-/* Delete 'p' from switch. */
-static void
-del_switch_port(struct sw_port *p)
-{
-    send_port_status(p, OFPPR_DELETE);
-    netdev_close(p->netdev);
-    p->netdev = NULL;
-    list_remove(&p->node);
-}
-
-void
-dp_destroy(struct datapath *dp)
-{
-    struct sw_port *p, *n;
-
-    if (!dp) {
-        return;
-    }
-
-    LIST_FOR_EACH_SAFE (p, n, struct sw_port, node, &dp->port_list) {
-        del_switch_port(p); 
-    }
-    chain_destroy(dp->chain);
-    free(dp);
-}
-
-/* Send packets out all the ports except the originating one.  If the
- * "flood" argument is set, don't send out ports with flooding disabled.
- */
-static int
-output_all(struct datapath *dp, struct ofpbuf *buffer, int in_port, int flood)
-{
-    struct sw_port *p;
-    int prev_port;
-
-    prev_port = -1;
-    LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) {
-        if (port_no(dp, p) == in_port) {
-            continue;
-        }
-        if (flood && p->config & OFPPC_NO_FLOOD) {
-            continue;
-        }
-        if (prev_port != -1) {
-            dp_output_port(dp, ofpbuf_clone(buffer), in_port, prev_port,
-                           false);
-        }
-        prev_port = port_no(dp, p);
-    }
-    if (prev_port != -1)
-        dp_output_port(dp, buffer, in_port, prev_port, false);
-    else
-        ofpbuf_delete(buffer);
-
-    return 0;
-}
-
-void
-output_packet(struct datapath *dp, struct ofpbuf *buffer, int out_port) 
-{
-    if (out_port >= 0 && out_port < DP_MAX_PORTS) { 
-        struct sw_port *p = &dp->ports[out_port];
-        if (p->netdev != NULL && !(p->config & OFPPC_PORT_DOWN)) {
-            if (!netdev_send(p->netdev, buffer)) {
-                p->tx_packets++;
-                p->tx_bytes += buffer->size;
-            } else {
-                p->tx_dropped++;
-            }
-            return;
-        }
-    }
-
-    ofpbuf_delete(buffer);
-    VLOG_DBG_RL(&rl, "can't forward to bad port %d\n", out_port);
-}
-
-/* Takes ownership of 'buffer' and transmits it to 'out_port' on 'dp'.
- */
-void
-dp_output_port(struct datapath *dp, struct ofpbuf *buffer,
-               int in_port, int out_port, bool ignore_no_fwd)
-{
-
-    assert(buffer);
-    if (out_port == OFPP_FLOOD) {
-        output_all(dp, buffer, in_port, 1); 
-    } else if (out_port == OFPP_ALL) {
-        output_all(dp, buffer, in_port, 0); 
-    } else if (out_port == OFPP_CONTROLLER) {
-        dp_output_control(dp, buffer, in_port, 0, OFPR_ACTION); 
-    } else if (out_port == OFPP_IN_PORT) {
-        output_packet(dp, buffer, in_port);
-    } else if (out_port == OFPP_TABLE) {
-        struct sw_port *p = in_port < DP_MAX_PORTS ? &dp->ports[in_port] : 0;
-               if (run_flow_through_tables(dp, buffer, p)) {
-                       ofpbuf_delete(buffer);
-        }
-    } else {
-        if (in_port == out_port) {
-            VLOG_DBG_RL(&rl, "can't directly forward to input port");
-            return;
-        }
-        output_packet(dp, buffer, out_port);
-    }
-}
-
-static void *
-make_openflow_reply(size_t openflow_len, uint8_t type,
-                    const struct sender *sender, struct ofpbuf **bufferp)
-{
-    return make_openflow_xid(openflow_len, type, sender ? sender->xid : 0,
-                             bufferp);
-}
-
-static int
-send_openflow_buffer(struct datapath *dp, struct ofpbuf *buffer,
-                     const struct sender *sender)
-{
-    struct remote *remote = sender ? sender->remote : dp->controller;
-    struct rconn *rconn = remote->rconn;
-    int retval;
-
-    update_openflow_length(buffer);
-    retval = rconn_send_with_limit(rconn, buffer, &remote->n_txq, TXQ_LIMIT);
-    if (retval) {
-        VLOG_WARN_RL(&rl, "send to %s failed: %s",
-                     rconn_get_name(rconn), strerror(retval));
-    }
-    return retval;
-}
-
-/* Takes ownership of 'buffer' and transmits it to 'dp''s controller.  If the
- * packet can be saved in a buffer, then only the first max_len bytes of
- * 'buffer' are sent; otherwise, all of 'buffer' is sent.  'reason' indicates
- * why 'buffer' is being sent. 'max_len' sets the maximum number of bytes that
- * the caller wants to be sent; a value of 0 indicates the entire packet should
- * be sent. */
-void
-dp_output_control(struct datapath *dp, struct ofpbuf *buffer, int in_port,
-                  size_t max_len, int reason)
-{
-    struct ofp_packet_in *opi;
-    size_t total_len;
-    uint32_t buffer_id;
-
-    buffer_id = save_buffer(buffer);
-    total_len = buffer->size;
-    if (buffer_id != UINT32_MAX && max_len && buffer->size > max_len) {
-        buffer->size = max_len;
-    }
-
-    opi = ofpbuf_push_uninit(buffer, offsetof(struct ofp_packet_in, data));
-    opi->header.version = OFP_VERSION;
-    opi->header.type    = OFPT_PACKET_IN;
-    opi->header.length  = htons(buffer->size);
-    opi->header.xid     = htonl(0);
-    opi->buffer_id      = htonl(buffer_id);
-    opi->total_len      = htons(total_len);
-    opi->in_port        = htons(in_port);
-    opi->reason         = reason;
-    opi->pad            = 0;
-    send_openflow_buffer(dp, buffer, NULL);
-}
-
-static void fill_port_desc(struct datapath *dp, struct sw_port *p,
-                           struct ofp_phy_port *desc)
-{
-    desc->port_no = htons(port_no(dp, p));
-    strncpy((char *) desc->name, netdev_get_name(p->netdev),
-            sizeof desc->name);
-    desc->name[sizeof desc->name - 1] = '\0';
-    memcpy(desc->hw_addr, netdev_get_etheraddr(p->netdev), ETH_ADDR_LEN);
-    desc->config = htonl(p->config);
-    desc->state = htonl(p->state);
-    desc->curr = htonl(netdev_get_features(p->netdev, NETDEV_FEAT_CURRENT));
-    desc->supported = htonl(netdev_get_features(p->netdev, 
-                NETDEV_FEAT_SUPPORTED));
-    desc->advertised = htonl(netdev_get_features(p->netdev, 
-                NETDEV_FEAT_ADVERTISED));
-    desc->peer = htonl(netdev_get_features(p->netdev, NETDEV_FEAT_PEER));
-}
-
-static void
-dp_send_features_reply(struct datapath *dp, const struct sender *sender)
-{
-    struct ofpbuf *buffer;
-    struct ofp_switch_features *ofr;
-    struct sw_port *p;
-
-    ofr = make_openflow_reply(sizeof *ofr, OFPT_FEATURES_REPLY,
-                               sender, &buffer);
-    ofr->datapath_id  = htonll(dp->id); 
-    ofr->n_tables     = dp->chain->n_tables;
-    ofr->n_buffers    = htonl(N_PKT_BUFFERS);
-    ofr->capabilities = htonl(OFP_SUPPORTED_CAPABILITIES);
-    ofr->actions      = htonl(OFP_SUPPORTED_ACTIONS);
-    LIST_FOR_EACH (p, struct sw_port, node, &dp->port_list) {
-        struct ofp_phy_port *opp = ofpbuf_put_zeros(buffer, sizeof *opp);
-        fill_port_desc(dp, p, opp);
-    }
-    send_openflow_buffer(dp, buffer, sender);
-}
-
-void
-dp_update_port_flags(struct datapath *dp, const struct ofp_port_mod *opm)
-{
-    int port_no = ntohs(opm->port_no);
-    if (port_no < DP_MAX_PORTS) {
-        struct sw_port *p = &dp->ports[port_no];
-
-        /* Make sure the port id hasn't changed since this was sent */
-        if (memcmp(opm->hw_addr, netdev_get_etheraddr(p->netdev),
-                         ETH_ADDR_LEN) != 0) {
-            return;
-        }
-
-
-        if (opm->mask) {
-            uint32_t config_mask = ntohl(opm->mask);
-            p->config &= ~config_mask;
-            p->config |= ntohl(opm->config) & config_mask;
-        }
-
-        if (opm->mask & htonl(OFPPC_PORT_DOWN)) {
-            if ((opm->config & htonl(OFPPC_PORT_DOWN))
-                && (p->config & OFPPC_PORT_DOWN) == 0) {
-                p->config |= OFPPC_PORT_DOWN;
-                netdev_turn_flags_off(p->netdev, NETDEV_UP, true);
-            } else if ((opm->config & htonl(OFPPC_PORT_DOWN)) == 0
-                       && (p->config & OFPPC_PORT_DOWN)) {
-                p->config &= ~OFPPC_PORT_DOWN;
-                netdev_turn_flags_on(p->netdev, NETDEV_UP, true);
-            }
-        }
-    }
-}
-
-/* Update the port status field of the bridge port.  A non-zero return
- * value indicates some field has changed. 
- *
- * NB: Callers of this function may hold the RCU read lock, so any
- * additional checks must not sleep.
- */
-static int
-update_port_status(struct sw_port *p)
-{
-    int retval;
-    enum netdev_flags flags;
-    uint32_t orig_config = p->config;
-    uint32_t orig_state = p->state;
-
-    if (netdev_get_flags(p->netdev, &flags) < 0) {
-        VLOG_WARN_RL(&rl, "could not get netdev flags for %s", 
-                     netdev_get_name(p->netdev));
-        return 0;
-    } else {
-        if (flags & NETDEV_UP) {
-            p->config &= ~OFPPC_PORT_DOWN;
-        } else {
-            p->config |= OFPPC_PORT_DOWN;
-        } 
-    }
-
-    /* Not all cards support this getting link status, so don't warn on
-     * error. */
-    retval = netdev_get_link_status(p->netdev);
-    if (retval == 1) {
-        p->state &= ~OFPPS_LINK_DOWN;
-    } else if (retval == 0) {
-        p->state |= OFPPS_LINK_DOWN;
-    } 
-
-    return ((orig_config != p->config) || (orig_state != p->state));
-}
-
-static void
-send_port_status(struct sw_port *p, uint8_t status) 
-{
-    struct ofpbuf *buffer;
-    struct ofp_port_status *ops;
-    ops = make_openflow_xid(sizeof *ops, OFPT_PORT_STATUS, 0, &buffer);
-    ops->reason = status;
-    memset(ops->pad, 0, sizeof ops->pad);
-    fill_port_desc(p->dp, p, &ops->desc);
-
-    send_openflow_buffer(p->dp, buffer, NULL);
-}
-
-void
-send_flow_expired(struct datapath *dp, struct sw_flow *flow,
-                  enum ofp_flow_expired_reason reason)
-{
-    struct ofpbuf *buffer;
-    struct ofp_flow_expired *ofe;
-    ofe = make_openflow_xid(sizeof *ofe, OFPT_FLOW_EXPIRED, 0, &buffer);
-    flow_fill_match(&ofe->match, &flow->key);
-
-    ofe->priority = htons(flow->priority);
-    ofe->reason = reason;
-    memset(ofe->pad, 0, sizeof ofe->pad);
-
-    ofe->duration     = htonl(time_now() - flow->created);
-    memset(ofe->pad2, 0, sizeof ofe->pad2);
-    ofe->packet_count = htonll(flow->packet_count);
-    ofe->byte_count   = htonll(flow->byte_count);
-    send_openflow_buffer(dp, buffer, NULL);
-}
-
-void
-dp_send_error_msg(struct datapath *dp, const struct sender *sender,
-                  uint16_t type, uint16_t code, const void *data, size_t len)
-{
-    struct ofpbuf *buffer;
-    struct ofp_error_msg *oem;
-    oem = make_openflow_reply(sizeof(*oem)+len, OFPT_ERROR, sender, &buffer);
-    oem->type = htons(type);
-    oem->code = htons(code);
-    memcpy(oem->data, data, len);
-    send_openflow_buffer(dp, buffer, sender);
-}
-
-static void
-fill_flow_stats(struct ofpbuf *buffer, struct sw_flow *flow,
-                int table_idx, time_t now)
-{
-    struct ofp_flow_stats *ofs;
-    int length = sizeof *ofs + flow->sf_acts->actions_len;
-    ofs = ofpbuf_put_zeros(buffer, length);
-    ofs->length          = htons(length);
-    ofs->table_id        = table_idx;
-    ofs->match.wildcards = htonl(flow->key.wildcards);
-    ofs->match.in_port   = flow->key.flow.in_port;
-    memcpy(ofs->match.dl_src, flow->key.flow.dl_src, ETH_ADDR_LEN);
-    memcpy(ofs->match.dl_dst, flow->key.flow.dl_dst, ETH_ADDR_LEN);
-    ofs->match.dl_vlan   = flow->key.flow.dl_vlan;
-    ofs->match.dl_type   = flow->key.flow.dl_type;
-    ofs->match.nw_src    = flow->key.flow.nw_src;
-    ofs->match.nw_dst    = flow->key.flow.nw_dst;
-    ofs->match.nw_proto  = flow->key.flow.nw_proto;
-    ofs->match.tp_src    = flow->key.flow.tp_src;
-    ofs->match.tp_dst    = flow->key.flow.tp_dst;
-    ofs->duration        = htonl(now - flow->created);
-    ofs->priority        = htons(flow->priority);
-    ofs->idle_timeout    = htons(flow->idle_timeout);
-    ofs->hard_timeout    = htons(flow->hard_timeout);
-    ofs->packet_count    = htonll(flow->packet_count);
-    ofs->byte_count      = htonll(flow->byte_count);
-    memcpy(ofs->actions, flow->sf_acts->actions, flow->sf_acts->actions_len);
-}
-
-\f
-/* 'buffer' was received on 'p', which may be a a physical switch port or a
- * null pointer.  Process it according to 'dp''s flow table.  Returns 0 if
- * successful, in which case 'buffer' is destroyed, or -ESRCH if there is no
- * matching flow, in which case 'buffer' still belongs to the caller. */
-int run_flow_through_tables(struct datapath *dp, struct ofpbuf *buffer,
-                            struct sw_port *p)
-{
-    struct sw_flow_key key;
-    struct sw_flow *flow;
-
-    key.wildcards = 0;
-    if (flow_extract(buffer, p ? port_no(dp, p) : OFPP_NONE, &key.flow)
-        && (dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) {
-        /* Drop fragment. */
-        ofpbuf_delete(buffer);
-        return 0;
-    }
-       if (p && p->config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP)
-        && p->config & (!eth_addr_equals(key.flow.dl_dst, stp_eth_addr)
-                       ? OFPPC_NO_RECV : OFPPC_NO_RECV_STP)) {
-               ofpbuf_delete(buffer);
-               return 0;
-       }
-
-    flow = chain_lookup(dp->chain, &key);
-    if (flow != NULL) {
-        flow_used(flow, buffer);
-        execute_actions(dp, buffer, &key, flow->sf_acts->actions, 
-                        flow->sf_acts->actions_len, false);
-        return 0;
-    } else {
-        return -ESRCH;
-    }
-}
-
-/* 'buffer' was received on 'p', which may be a a physical switch port or a
- * null pointer.  Process it according to 'dp''s flow table, sending it up to
- * the controller if no flow matches.  Takes ownership of 'buffer'. */
-void fwd_port_input(struct datapath *dp, struct ofpbuf *buffer,
-                    struct sw_port *p)
-{
-    if (run_flow_through_tables(dp, buffer, p)) {
-        dp_output_control(dp, buffer, port_no(dp, p),
-                          dp->miss_send_len, OFPR_NO_MATCH);
-    }
-}
-
-static int
-recv_features_request(struct datapath *dp, const struct sender *sender,
-                      const void *msg) 
-{
-    dp_send_features_reply(dp, sender);
-    return 0;
-}
-
-static int
-recv_get_config_request(struct datapath *dp, const struct sender *sender,
-                        const void *msg) 
-{
-    struct ofpbuf *buffer;
-    struct ofp_switch_config *osc;
-
-    osc = make_openflow_reply(sizeof *osc, OFPT_GET_CONFIG_REPLY,
-                              sender, &buffer);
-
-    osc->flags = htons(dp->flags);
-    osc->miss_send_len = htons(dp->miss_send_len);
-
-    return send_openflow_buffer(dp, buffer, sender);
-}
-
-static int
-recv_set_config(struct datapath *dp, const struct sender *sender UNUSED,
-                const void *msg)
-{
-    const struct ofp_switch_config *osc = msg;
-    int flags;
-
-    flags = ntohs(osc->flags) & (OFPC_SEND_FLOW_EXP | OFPC_FRAG_MASK);
-    if ((flags & OFPC_FRAG_MASK) != OFPC_FRAG_NORMAL
-        && (flags & OFPC_FRAG_MASK) != OFPC_FRAG_DROP) {
-        flags = (flags & ~OFPC_FRAG_MASK) | OFPC_FRAG_DROP;
-    }
-    dp->flags = flags;
-    dp->miss_send_len = ntohs(osc->miss_send_len);
-    return 0;
-}
-
-static int
-recv_packet_out(struct datapath *dp, const struct sender *sender,
-                const void *msg)
-{
-    const struct ofp_packet_out *opo = msg;
-    struct sw_flow_key key;
-    uint16_t v_code;
-    struct ofpbuf *buffer;
-    size_t actions_len = ntohs(opo->actions_len);
-
-    if (actions_len > (ntohs(opo->header.length) - sizeof *opo)) {
-        VLOG_DBG_RL(&rl, "message too short for number of actions");
-        return -EINVAL;
-    }
-
-    if (ntohl(opo->buffer_id) == (uint32_t) -1) {
-        /* FIXME: can we avoid copying data here? */
-        int data_len = ntohs(opo->header.length) - sizeof *opo - actions_len;
-        buffer = ofpbuf_new(data_len);
-        ofpbuf_put(buffer, (uint8_t *)opo->actions + actions_len, data_len);
-    } else {
-        buffer = retrieve_buffer(ntohl(opo->buffer_id));
-        if (!buffer) {
-            return -ESRCH; 
-        }
-    }
-    flow_extract(buffer, ntohs(opo->in_port), &key.flow);
-
-    v_code = validate_actions(dp, &key, opo->actions, actions_len);
-    if (v_code != ACT_VALIDATION_OK) {
-        dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code,
-                  msg, ntohs(opo->header.length));
-        goto error;
-    }
-
-    execute_actions(dp, buffer, &key, opo->actions, actions_len, true);
-
-    return 0;
-
-error:
-    ofpbuf_delete(buffer);
-    return -EINVAL;
-}
-
-static int
-recv_port_mod(struct datapath *dp, const struct sender *sender UNUSED,
-              const void *msg)
-{
-    const struct ofp_port_mod *opm = msg;
-
-    dp_update_port_flags(dp, opm);
-
-    return 0;
-}
-
-static int
-add_flow(struct datapath *dp, const struct sender *sender,
-        const struct ofp_flow_mod *ofm)
-{
-    int error = -ENOMEM;
-    uint16_t v_code;
-    struct sw_flow *flow; 
-    size_t actions_len = ntohs(ofm->header.length) - sizeof *ofm;
-
-    /* Allocate memory. */
-    flow = flow_alloc(actions_len);
-    if (flow == NULL)
-        goto error;
-
-    flow_extract_match(&flow->key, &ofm->match);
-
-    v_code = validate_actions(dp, &flow->key, ofm->actions, actions_len);
-    if (v_code != ACT_VALIDATION_OK) {
-        dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code,
-                  ofm, ntohs(ofm->header.length));
-        goto error_free_flow;
-    }
-
-    /* Fill out flow. */
-    flow->priority = flow->key.wildcards ? ntohs(ofm->priority) : -1;
-    flow->idle_timeout = ntohs(ofm->idle_timeout);
-    flow->hard_timeout = ntohs(ofm->hard_timeout);
-    flow->used = flow->created = time_now();
-    flow->sf_acts->actions_len = actions_len;
-    flow->byte_count = 0;
-    flow->packet_count = 0;
-    memcpy(flow->sf_acts->actions, ofm->actions, actions_len);
-
-    /* Act. */
-    error = chain_insert(dp->chain, flow);
-    if (error == -ENOBUFS) {
-        dp_send_error_msg(dp, sender, OFPET_FLOW_MOD_FAILED, 
-                OFPFMFC_ALL_TABLES_FULL, ofm, ntohs(ofm->header.length));
-        goto error_free_flow; 
-    } else if (error) {
-        goto error_free_flow; 
-    }
-    error = 0;
-    if (ntohl(ofm->buffer_id) != UINT32_MAX) {
-        struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id));
-        if (buffer) {
-            struct sw_flow_key key;
-            uint16_t in_port = ntohs(ofm->match.in_port);
-            flow_used(flow, buffer);
-            flow_extract(buffer, in_port, &key.flow);
-            execute_actions(dp, buffer, &key, 
-                    ofm->actions, actions_len, false);
-        } else {
-            error = -ESRCH; 
-        }
-    }
-    return error;
-
-error_free_flow:
-    flow_free(flow);
-error:
-    if (ntohl(ofm->buffer_id) != (uint32_t) -1)
-        discard_buffer(ntohl(ofm->buffer_id));
-    return error;
-}
-
-static int
-mod_flow(struct datapath *dp, const struct sender *sender,
-        const struct ofp_flow_mod *ofm)
-{
-    int error = -ENOMEM;
-    uint16_t v_code;
-    size_t actions_len;
-    struct sw_flow_key key;
-    uint16_t priority;
-    int strict;
-
-    flow_extract_match(&key, &ofm->match);
-    actions_len = ntohs(ofm->header.length) - sizeof *ofm;
-    v_code = validate_actions(dp, &key, ofm->actions, actions_len);
-    if (v_code != ACT_VALIDATION_OK) {
-        dp_send_error_msg(dp, sender, OFPET_BAD_ACTION, v_code,
-                  ofm, ntohs(ofm->header.length));
-        goto error;
-    }
-
-    priority = key.wildcards ? ntohs(ofm->priority) : -1;
-    strict = (ofm->command == htons(OFPFC_MODIFY_STRICT)) ? 1 : 0;
-    chain_modify(dp->chain, &key, priority, strict, ofm->actions, actions_len);
-
-    if (ntohl(ofm->buffer_id) != UINT32_MAX) {
-        struct ofpbuf *buffer = retrieve_buffer(ntohl(ofm->buffer_id));
-        if (buffer) {
-            struct sw_flow_key skb_key;
-            uint16_t in_port = ntohs(ofm->match.in_port);
-            flow_extract(buffer, in_port, &skb_key.flow);
-            execute_actions(dp, buffer, &skb_key,
-                            ofm->actions, actions_len, false);
-        } else {
-            error = -ESRCH; 
-        }
-    }
-    return error;
-
-error:
-    if (ntohl(ofm->buffer_id) != (uint32_t) -1)
-        discard_buffer(ntohl(ofm->buffer_id));
-    return error;
-}
-
-static int
-recv_flow(struct datapath *dp, const struct sender *sender,
-          const void *msg)
-{
-    const struct ofp_flow_mod *ofm = msg;
-    uint16_t command = ntohs(ofm->command);
-
-    if (command == OFPFC_ADD) {
-        return add_flow(dp, sender, ofm);
-    } else if ((command == OFPFC_MODIFY) || (command == OFPFC_MODIFY_STRICT)) {
-        return mod_flow(dp, sender, ofm);
-    }  else if (command == OFPFC_DELETE) {
-        struct sw_flow_key key;
-        flow_extract_match(&key, &ofm->match);
-        return chain_delete(dp->chain, &key, ofm->out_port, 0, 0) ? 0 : -ESRCH;
-    } else if (command == OFPFC_DELETE_STRICT) {
-        struct sw_flow_key key;
-        uint16_t priority;
-        flow_extract_match(&key, &ofm->match);
-        priority = key.wildcards ? ntohs(ofm->priority) : -1;
-        return chain_delete(dp->chain, &key, ofm->out_port, 
-                priority, 1) ? 0 : -ESRCH;
-    } else {
-        return -ENODEV;
-    }
-}
-
-static int desc_stats_dump(struct datapath *dp, void *state,
-                              struct ofpbuf *buffer)
-{
-    struct ofp_desc_stats *ods = ofpbuf_put_zeros(buffer, sizeof *ods);
-
-    strncpy(ods->mfr_desc, &mfr_desc, sizeof ods->mfr_desc);
-    strncpy(ods->hw_desc, &hw_desc, sizeof ods->hw_desc);
-    strncpy(ods->sw_desc, &sw_desc, sizeof ods->sw_desc);
-    strncpy(ods->serial_num, &serial_num, sizeof ods->serial_num);
-
-    return 0;
-}
-
-struct flow_stats_state {
-    int table_idx;
-    struct sw_table_position position;
-    struct ofp_flow_stats_request rq;
-    time_t now;
-
-    struct ofpbuf *buffer;
-};
-
-#define MAX_FLOW_STATS_BYTES 4096
-
-static int flow_stats_init(struct datapath *dp, const void *body, int body_len,
-                           void **state)
-{
-    const struct ofp_flow_stats_request *fsr = body;
-    struct flow_stats_state *s = xmalloc(sizeof *s);
-    s->table_idx = fsr->table_id == 0xff ? 0 : fsr->table_id;
-    memset(&s->position, 0, sizeof s->position);
-    s->rq = *fsr;
-    *state = s;
-    return 0;
-}
-
-static int flow_stats_dump_callback(struct sw_flow *flow, void *private)
-{
-    struct flow_stats_state *s = private;
-    fill_flow_stats(s->buffer, flow, s->table_idx, s->now);
-    return s->buffer->size >= MAX_FLOW_STATS_BYTES;
-}
-
-static int flow_stats_dump(struct datapath *dp, void *state,
-                           struct ofpbuf *buffer)
-{
-    struct flow_stats_state *s = state;
-    struct sw_flow_key match_key;
-
-    flow_extract_match(&match_key, &s->rq.match);
-    s->buffer = buffer;
-    s->now = time_now();
-    while (s->table_idx < dp->chain->n_tables
-           && (s->rq.table_id == 0xff || s->rq.table_id == s->table_idx))
-    {
-        struct sw_table *table = dp->chain->tables[s->table_idx];
-
-        if (table->iterate(table, &match_key, s->rq.out_port,
-                    &s->position, flow_stats_dump_callback, s))
-            break;
-
-        s->table_idx++;
-        memset(&s->position, 0, sizeof s->position);
-    }
-    return s->buffer->size >= MAX_FLOW_STATS_BYTES;
-}
-
-static void flow_stats_done(void *state)
-{
-    free(state);
-}
-
-struct aggregate_stats_state {
-    struct ofp_aggregate_stats_request rq;
-};
-
-static int aggregate_stats_init(struct datapath *dp,
-                                const void *body, int body_len,
-                                void **state)
-{
-    const struct ofp_aggregate_stats_request *rq = body;
-    struct aggregate_stats_state *s = xmalloc(sizeof *s);
-    s->rq = *rq;
-    *state = s;
-    return 0;
-}
-
-static int aggregate_stats_dump_callback(struct sw_flow *flow, void *private)
-{
-    struct ofp_aggregate_stats_reply *rpy = private;
-    rpy->packet_count += flow->packet_count;
-    rpy->byte_count += flow->byte_count;
-    rpy->flow_count++;
-    return 0;
-}
-
-static int aggregate_stats_dump(struct datapath *dp, void *state,
-                                struct ofpbuf *buffer)
-{
-    struct aggregate_stats_state *s = state;
-    struct ofp_aggregate_stats_request *rq = &s->rq;
-    struct ofp_aggregate_stats_reply *rpy;
-    struct sw_table_position position;
-    struct sw_flow_key match_key;
-    int table_idx;
-
-    rpy = ofpbuf_put_zeros(buffer, sizeof *rpy);
-
-    flow_extract_match(&match_key, &rq->match);
-    table_idx = rq->table_id == 0xff ? 0 : rq->table_id;
-    memset(&position, 0, sizeof position);
-    while (table_idx < dp->chain->n_tables
-           && (rq->table_id == 0xff || rq->table_id == table_idx))
-    {
-        struct sw_table *table = dp->chain->tables[table_idx];
-        int error;
-
-        error = table->iterate(table, &match_key, rq->out_port, &position,
-                               aggregate_stats_dump_callback, rpy);
-        if (error)
-            return error;
-
-        table_idx++;
-        memset(&position, 0, sizeof position);
-    }
-
-    rpy->packet_count = htonll(rpy->packet_count);
-    rpy->byte_count = htonll(rpy->byte_count);
-    rpy->flow_count = htonl(rpy->flow_count);
-    return 0;
-}
-
-static void aggregate_stats_done(void *state) 
-{
-    free(state);
-}
-
-static int table_stats_dump(struct datapath *dp, void *state,
-                            struct ofpbuf *buffer)
-{
-    int i;
-    for (i = 0; i < dp->chain->n_tables; i++) {
-        struct ofp_table_stats *ots = ofpbuf_put_zeros(buffer, sizeof *ots);
-        struct sw_table_stats stats;
-        dp->chain->tables[i]->stats(dp->chain->tables[i], &stats);
-        strncpy(ots->name, stats.name, sizeof ots->name);
-        ots->table_id = i;
-        ots->wildcards = htonl(stats.wildcards);
-        ots->max_entries = htonl(stats.max_flows);
-        ots->active_count = htonl(stats.n_flows);
-        ots->lookup_count = htonll(stats.n_lookup);
-        ots->matched_count = htonll(stats.n_matched);
-    }
-    return 0;
-}
-
-struct port_stats_state {
-    int port;
-};
-
-static int port_stats_init(struct datapath *dp, const void *body, int body_len,
-               void **state)
-{
-    struct port_stats_state *s = xmalloc(sizeof *s);
-    s->port = 0;
-    *state = s;
-    return 0;
-}
-
-static int port_stats_dump(struct datapath *dp, void *state,
-                           struct ofpbuf *buffer)
-{
-    struct port_stats_state *s = state;
-    int i;
-
-    for (i = s->port; i < DP_MAX_PORTS; i++) {
-        struct sw_port *p = &dp->ports[i];
-        struct ofp_port_stats *ops;
-        if (!p->netdev) {
-            continue;
-        }
-        ops = ofpbuf_put_zeros(buffer, sizeof *ops);
-        ops->port_no = htons(port_no(dp, p));
-        ops->rx_packets   = htonll(p->rx_packets);
-        ops->tx_packets   = htonll(p->tx_packets);
-        ops->rx_bytes     = htonll(p->rx_bytes);
-        ops->tx_bytes     = htonll(p->tx_bytes);
-        ops->rx_dropped   = htonll(-1);
-        ops->tx_dropped   = htonll(p->tx_dropped);
-        ops->rx_errors    = htonll(-1);
-        ops->tx_errors    = htonll(-1);
-        ops->rx_frame_err = htonll(-1);
-        ops->rx_over_err  = htonll(-1);
-        ops->rx_crc_err   = htonll(-1);
-        ops->collisions   = htonll(-1);
-        ops++;
-    }
-    s->port = i;
-    return 0;
-}
-
-static void port_stats_done(void *state)
-{
-    free(state);
-}
-
-struct stats_type {
-    /* Value for 'type' member of struct ofp_stats_request. */
-    int type;
-
-    /* Minimum and maximum acceptable number of bytes in body member of
-     * struct ofp_stats_request. */
-    size_t min_body, max_body;
-
-    /* Prepares to dump some kind of statistics on 'dp'.  'body' and
-     * 'body_len' are the 'body' member of the struct ofp_stats_request.
-     * Returns zero if successful, otherwise a negative error code.
-     * May initialize '*state' to state information.  May be null if no
-     * initialization is required.*/
-    int (*init)(struct datapath *dp, const void *body, int body_len,
-            void **state);
-
-    /* Appends statistics for 'dp' to 'buffer', which initially contains a
-     * struct ofp_stats_reply.  On success, it should return 1 if it should be
-     * called again later with another buffer, 0 if it is done, or a negative
-     * errno value on failure. */
-    int (*dump)(struct datapath *dp, void *state, struct ofpbuf *buffer);
-
-    /* Cleans any state created by the init or dump functions.  May be null
-     * if no cleanup is required. */
-    void (*done)(void *state);
-};
-
-static const struct stats_type stats[] = {
-    {
-        OFPST_DESC,
-        0,
-        0,
-        NULL,
-        desc_stats_dump,
-        NULL
-    },
-    {
-        OFPST_FLOW,
-        sizeof(struct ofp_flow_stats_request),
-        sizeof(struct ofp_flow_stats_request),
-        flow_stats_init,
-        flow_stats_dump,
-        flow_stats_done
-    },
-    {
-        OFPST_AGGREGATE,
-        sizeof(struct ofp_aggregate_stats_request),
-        sizeof(struct ofp_aggregate_stats_request),
-        aggregate_stats_init,
-        aggregate_stats_dump,
-        aggregate_stats_done
-    },
-    {
-        OFPST_TABLE,
-        0,
-        0,
-        NULL,
-        table_stats_dump,
-        NULL
-    },
-    {
-        OFPST_PORT,
-        0,
-        0,
-        port_stats_init,
-        port_stats_dump,
-        port_stats_done
-    },
-};
-
-struct stats_dump_cb {
-    bool done;
-    struct ofp_stats_request *rq;
-    struct sender sender;
-    const struct stats_type *s;
-    void *state;
-};
-
-static int
-stats_dump(struct datapath *dp, void *cb_)
-{
-    struct stats_dump_cb *cb = cb_;
-    struct ofp_stats_reply *osr;
-    struct ofpbuf *buffer;
-    int err;
-
-    if (cb->done) {
-        return 0;
-    }
-
-    osr = make_openflow_reply(sizeof *osr, OFPT_STATS_REPLY, &cb->sender,
-                              &buffer);
-    osr->type = htons(cb->s->type);
-    osr->flags = 0;
-
-    err = cb->s->dump(dp, cb->state, buffer);
-    if (err >= 0) {
-        int err2;
-        if (!err) {
-            cb->done = true;
-        } else {
-            /* Buffer might have been reallocated, so find our data again. */
-            osr = ofpbuf_at_assert(buffer, 0, sizeof *osr);
-            osr->flags = ntohs(OFPSF_REPLY_MORE);
-        }
-        err2 = send_openflow_buffer(dp, buffer, &cb->sender);
-        if (err2) {
-            err = err2;
-        }
-    }
-
-    return err;
-}
-
-static void
-stats_done(void *cb_)
-{
-    struct stats_dump_cb *cb = cb_;
-    if (cb) {
-        if (cb->s->done) {
-            cb->s->done(cb->state);
-        }
-        free(cb);
-    }
-}
-
-static int
-recv_stats_request(struct datapath *dp, const struct sender *sender,
-                   const void *oh)
-{
-    const struct ofp_stats_request *rq = oh;
-    size_t rq_len = ntohs(rq->header.length);
-    const struct stats_type *st;
-    struct stats_dump_cb *cb;
-    int type, body_len;
-    int err;
-
-    type = ntohs(rq->type);
-    for (st = stats; ; st++) {
-        if (st >= &stats[ARRAY_SIZE(stats)]) {
-            VLOG_WARN_RL(&rl, "received stats request of unknown type %d",
-                         type);
-            return -EINVAL;
-        } else if (type == st->type) {
-            break;
-        }
-    }
-
-    cb = xmalloc(sizeof *cb);
-    cb->done = false;
-    cb->rq = xmemdup(rq, rq_len);
-    cb->sender = *sender;
-    cb->s = st;
-    cb->state = NULL;
-    
-    body_len = rq_len - offsetof(struct ofp_stats_request, body);
-    if (body_len < cb->s->min_body || body_len > cb->s->max_body) {
-        VLOG_WARN_RL(&rl, "stats request type %d with bad body length %d",
-                     type, body_len);
-        err = -EINVAL;
-        goto error;
-    }
-
-    if (cb->s->init) {
-        err = cb->s->init(dp, rq->body, body_len, &cb->state);
-        if (err) {
-            VLOG_WARN_RL(&rl,
-                         "failed initialization of stats request type %d: %s",
-                         type, strerror(-err));
-            goto error;
-        }
-    }
-
-    remote_start_dump(sender->remote, stats_dump, stats_done, cb);
-    return 0;
-
-error:
-    free(cb->rq);
-    free(cb);
-    return err;
-}
-
-static int
-recv_echo_request(struct datapath *dp, const struct sender *sender,
-                  const void *oh)
-{
-    return send_openflow_buffer(dp, make_echo_reply(oh), sender);
-}
-
-static int
-recv_echo_reply(struct datapath *dp UNUSED, const struct sender *sender UNUSED,
-                  const void *oh UNUSED)
-{
-    return 0;
-}
-
-/* 'msg', which is 'length' bytes long, was received from the control path.
- * Apply it to 'chain'. */
-int
-fwd_control_input(struct datapath *dp, const struct sender *sender,
-                  const void *msg, size_t length)
-{
-    int (*handler)(struct datapath *, const struct sender *, const void *);
-    struct ofp_header *oh;
-    size_t min_size;
-
-    /* Check encapsulated length. */
-    oh = (struct ofp_header *) msg;
-    if (ntohs(oh->length) > length) {
-        return -EINVAL;
-    }
-    assert(oh->version == OFP_VERSION);
-
-    /* Figure out how to handle it. */
-    switch (oh->type) {
-    case OFPT_FEATURES_REQUEST:
-        min_size = sizeof(struct ofp_header);
-        handler = recv_features_request;
-        break;
-    case OFPT_GET_CONFIG_REQUEST:
-        min_size = sizeof(struct ofp_header);
-        handler = recv_get_config_request;
-        break;
-    case OFPT_SET_CONFIG:
-        min_size = sizeof(struct ofp_switch_config);
-        handler = recv_set_config;
-        break;
-    case OFPT_PACKET_OUT:
-        min_size = sizeof(struct ofp_packet_out);
-        handler = recv_packet_out;
-        break;
-    case OFPT_FLOW_MOD:
-        min_size = sizeof(struct ofp_flow_mod);
-        handler = recv_flow;
-        break;
-    case OFPT_PORT_MOD:
-        min_size = sizeof(struct ofp_port_mod);
-        handler = recv_port_mod;
-        break;
-    case OFPT_STATS_REQUEST:
-        min_size = sizeof(struct ofp_stats_request);
-        handler = recv_stats_request;
-        break;
-    case OFPT_ECHO_REQUEST:
-        min_size = sizeof(struct ofp_header);
-        handler = recv_echo_request;
-        break;
-    case OFPT_ECHO_REPLY:
-        min_size = sizeof(struct ofp_header);
-        handler = recv_echo_reply;
-        break;
-    default:
-        dp_send_error_msg(dp, sender, OFPET_BAD_REQUEST, OFPBRC_BAD_TYPE,
-                          msg, length);
-        return -EINVAL;
-    }
-
-    /* Handle it. */
-    if (length < min_size)
-        return -EFAULT;
-    return handler(dp, sender, msg);
-}
-\f
-/* Packet buffering. */
-
-#define OVERWRITE_SECS  1
-
-struct packet_buffer {
-    struct ofpbuf *buffer;
-    uint32_t cookie;
-    time_t timeout;
-};
-
-static struct packet_buffer buffers[N_PKT_BUFFERS];
-static unsigned int buffer_idx;
-
-uint32_t save_buffer(struct ofpbuf *buffer)
-{
-    struct packet_buffer *p;
-    uint32_t id;
-
-    buffer_idx = (buffer_idx + 1) & PKT_BUFFER_MASK;
-    p = &buffers[buffer_idx];
-    if (p->buffer) {
-        /* Don't buffer packet if existing entry is less than
-         * OVERWRITE_SECS old. */
-        if (time_now() < p->timeout) { /* FIXME */
-            return -1;
-        } else {
-            ofpbuf_delete(p->buffer); 
-        }
-    }
-    /* Don't use maximum cookie value since the all-bits-1 id is
-     * special. */
-    if (++p->cookie >= (1u << PKT_COOKIE_BITS) - 1)
-        p->cookie = 0;
-    p->buffer = ofpbuf_clone(buffer);      /* FIXME */
-    p->timeout = time_now() + OVERWRITE_SECS; /* FIXME */
-    id = buffer_idx | (p->cookie << PKT_BUFFER_BITS);
-
-    return id;
-}
-
-static struct ofpbuf *retrieve_buffer(uint32_t id)
-{
-    struct ofpbuf *buffer = NULL;
-    struct packet_buffer *p;
-
-    p = &buffers[id & PKT_BUFFER_MASK];
-    if (p->cookie == id >> PKT_BUFFER_BITS) {
-        buffer = p->buffer;
-        p->buffer = NULL;
-    } else {
-        printf("cookie mismatch: %x != %x\n",
-               id >> PKT_BUFFER_BITS, p->cookie);
-    }
-
-    return buffer;
-}
-
-static void discard_buffer(uint32_t id)
-{
-    struct packet_buffer *p;
-
-    p = &buffers[id & PKT_BUFFER_MASK];
-    if (p->cookie == id >> PKT_BUFFER_BITS) {
-        ofpbuf_delete(p->buffer);
-        p->buffer = NULL;
-    }
-}
diff --git a/switch/datapath.h b/switch/datapath.h
deleted file mode 100644 (file)
index 56d5324..0000000
+++ /dev/null
@@ -1,57 +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.
- */
-
-/* Interface exported by OpenFlow module. */
-
-#ifndef DATAPATH_H
-#define DATAPATH_H 1
-
-#include <stdbool.h>
-#include <stdint.h>
-#include "ofpbuf.h"
-
-struct datapath;
-struct rconn;
-struct pvconn;
-
-int dp_new(struct datapath **, uint64_t dpid, struct rconn *);
-int dp_add_port(struct datapath *, const char *netdev);
-void dp_add_listen_pvconn(struct datapath *, struct pvconn *);
-void dp_run(struct datapath *);
-void dp_wait(struct datapath *);
-void dp_output_port(struct datapath *, struct ofpbuf *, int in_port, 
-        int out_port, bool ignore_no_fwd);
-void dp_output_control(struct datapath *, struct ofpbuf *, int in_port,
-        size_t max_len, int reason);
-
-#endif /* datapath.h */
diff --git a/switch/dp_act.c b/switch/dp_act.c
deleted file mode 100644 (file)
index 3322d9f..0000000
+++ /dev/null
@@ -1,476 +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.
- */
-
-/* Functions for executing OpenFlow actions. */
-
-#include <arpa/inet.h>
-#include "csum.h"
-#include "packets.h"
-#include "dp_act.h"
-#include "openflow/nicira-ext.h"
-#include "nx_act.h"
-
-
-static uint16_t
-validate_output(struct datapath *dp, const struct sw_flow_key *key, 
-        const struct ofp_action_header *ah) 
-{
-    struct ofp_action_output *oa = (struct ofp_action_output *)ah;
-
-    /* To prevent loops, make sure there's no action to send to the
-     * OFP_TABLE virtual port.
-     */
-    if (oa->port == htons(OFPP_NONE) || oa->port == key->flow.in_port) {
-        return OFPBAC_BAD_OUT_PORT;
-    }
-    return ACT_VALIDATION_OK;
-}
-
-static void
-do_output(struct datapath *dp, struct ofpbuf *buffer, int in_port,
-          size_t max_len, int out_port, bool ignore_no_fwd)
-{
-    if (out_port != OFPP_CONTROLLER) {
-        dp_output_port(dp, buffer, in_port, out_port, ignore_no_fwd);
-    } else {
-        dp_output_control(dp, buffer, in_port, max_len, OFPR_ACTION);
-    }
-}
-
-/* Modify vlan tag control information (TCI).  Only sets the TCI bits
- * indicated by 'mask'.  If no vlan tag is present, one is added.
- */
-static void
-modify_vlan_tci(struct ofpbuf *buffer, struct sw_flow_key *key,
-        uint16_t tci, uint16_t mask)
-{
-    struct vlan_eth_header *veh;
-
-    if (key->flow.dl_vlan != htons(OFP_VLAN_NONE)) {
-        /* Modify vlan id, but maintain other TCI values */
-        veh = buffer->l2;
-        veh->veth_tci &= ~htons(mask);
-        veh->veth_tci |= htons(tci);
-    } else {
-        /* Insert new vlan id. */
-        struct eth_header *eh = buffer->l2;
-        struct vlan_eth_header tmp;
-        memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN);
-        memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN);
-        tmp.veth_type = htons(ETH_TYPE_VLAN);
-        tmp.veth_tci = htons(tci);
-        tmp.veth_next_type = eh->eth_type;
-
-        veh = ofpbuf_push_uninit(buffer, VLAN_HEADER_LEN);
-        memcpy(veh, &tmp, sizeof tmp);
-        buffer->l2 = (char*)buffer->l2 - VLAN_HEADER_LEN;
-    }
-
-    key->flow.dl_vlan = veh->veth_tci & htons(VLAN_VID_MASK);
-}
-
-
-/* Remove an existing vlan header if it exists. */
-static void
-vlan_pull_tag(struct ofpbuf *buffer)
-{
-    struct vlan_eth_header *veh = buffer->l2;
-
-    if (veh->veth_type == htons(ETH_TYPE_VLAN)) {
-        struct eth_header tmp;
-
-        memcpy(tmp.eth_dst, veh->veth_dst, ETH_ADDR_LEN);
-        memcpy(tmp.eth_src, veh->veth_src, ETH_ADDR_LEN);
-        tmp.eth_type = veh->veth_next_type;
-
-        buffer->size -= VLAN_HEADER_LEN;
-        buffer->data = (char*)buffer->data + VLAN_HEADER_LEN;
-        buffer->l2 = (char*)buffer->l2 + VLAN_HEADER_LEN;
-        memcpy(buffer->data, &tmp, sizeof tmp);
-    }
-}
-
-static void
-set_vlan_vid(struct ofpbuf *buffer, struct sw_flow_key *key, 
-        const struct ofp_action_header *ah)
-{
-    struct ofp_action_vlan_vid *va = (struct ofp_action_vlan_vid *)ah;
-    uint16_t tci = ntohs(va->vlan_vid);
-
-    modify_vlan_tci(buffer, key, tci, VLAN_VID_MASK);
-}
-
-static void
-set_vlan_pcp(struct ofpbuf *buffer, struct sw_flow_key *key, 
-        const struct ofp_action_header *ah)
-{
-    struct ofp_action_vlan_pcp *va = (struct ofp_action_vlan_pcp *)ah;
-    uint16_t tci = (uint16_t)va->vlan_pcp << 13;
-
-    modify_vlan_tci(buffer, key, tci, VLAN_PCP_MASK);
-}
-
-static void
-strip_vlan(struct ofpbuf *buffer, struct sw_flow_key *key, 
-        const struct ofp_action_header *ah)
-{
-    vlan_pull_tag(buffer);
-    key->flow.dl_vlan = htons(OFP_VLAN_NONE);
-}
-
-static void
-set_dl_addr(struct ofpbuf *buffer, struct sw_flow_key *key, 
-        const struct ofp_action_header *ah)
-{
-    struct ofp_action_dl_addr *da = (struct ofp_action_dl_addr *)ah;
-    struct eth_header *eh = buffer->l2;
-
-    if (da->type == htons(OFPAT_SET_DL_SRC)) {
-        memcpy(eh->eth_src, da->dl_addr, sizeof eh->eth_src);
-    } else {
-        memcpy(eh->eth_dst, da->dl_addr, sizeof eh->eth_dst);
-    }
-}
-
-static void
-set_nw_addr(struct ofpbuf *buffer, struct sw_flow_key *key, 
-        const struct ofp_action_header *ah)
-{
-    struct ofp_action_nw_addr *na = (struct ofp_action_nw_addr *)ah;
-    uint16_t eth_proto = ntohs(key->flow.dl_type);
-
-    if (eth_proto == ETH_TYPE_IP) {
-        struct ip_header *nh = buffer->l3;
-        uint8_t nw_proto = key->flow.nw_proto;
-        uint32_t new, *field;
-
-        new = na->nw_addr;
-        field = na->type == OFPAT_SET_NW_SRC ? &nh->ip_src : &nh->ip_dst;
-        if (nw_proto == IP_TYPE_TCP) {
-            struct tcp_header *th = buffer->l4;
-            th->tcp_csum = recalc_csum32(th->tcp_csum, *field, new);
-        } else if (nw_proto == IP_TYPE_UDP) {
-            struct udp_header *th = buffer->l4;
-            if (th->udp_csum) {
-                th->udp_csum = recalc_csum32(th->udp_csum, *field, new);
-                if (!th->udp_csum) {
-                    th->udp_csum = 0xffff;
-                }
-            }
-        }
-        nh->ip_csum = recalc_csum32(nh->ip_csum, *field, new);
-        *field = new;
-    }
-}
-
-static void
-set_tp_port(struct ofpbuf *buffer, struct sw_flow_key *key, 
-        const struct ofp_action_header *ah)
-{
-    struct ofp_action_tp_port *ta = (struct ofp_action_tp_port *)ah;
-    uint16_t eth_proto = ntohs(key->flow.dl_type);
-
-    if (eth_proto == ETH_TYPE_IP) {
-        uint8_t nw_proto = key->flow.nw_proto;
-        uint16_t new, *field;
-
-        new = ta->tp_port;
-        if (nw_proto == IP_TYPE_TCP) {
-            struct tcp_header *th = buffer->l4;
-            field = ta->type == OFPAT_SET_TP_SRC ? &th->tcp_src : &th->tcp_dst;
-            th->tcp_csum = recalc_csum16(th->tcp_csum, *field, new);
-            *field = new;
-        } else if (nw_proto == IP_TYPE_UDP) {
-            struct udp_header *th = buffer->l4;
-            field = ta->type == OFPAT_SET_TP_SRC ? &th->udp_src : &th->udp_dst;
-            th->udp_csum = recalc_csum16(th->udp_csum, *field, new);
-            *field = new;
-        }
-    }
-}
-
-struct openflow_action {
-    size_t min_size;
-    size_t max_size;
-    uint16_t (*validate)(struct datapath *dp, 
-            const struct sw_flow_key *key,
-            const struct ofp_action_header *ah);
-    void (*execute)(struct ofpbuf *buffer,
-            struct sw_flow_key *key, 
-            const struct ofp_action_header *ah);
-};
-
-static const struct openflow_action of_actions[] = {
-    [OFPAT_OUTPUT] = {
-        sizeof(struct ofp_action_output),
-        sizeof(struct ofp_action_output),
-        validate_output,
-        NULL                   /* This is optimized into execute_actions */
-    },
-    [OFPAT_SET_VLAN_VID] = {
-        sizeof(struct ofp_action_vlan_vid),
-        sizeof(struct ofp_action_vlan_vid),
-        NULL,
-        set_vlan_vid
-    },
-    [OFPAT_SET_VLAN_PCP] = {
-        sizeof(struct ofp_action_vlan_pcp),
-        sizeof(struct ofp_action_vlan_pcp),
-        NULL,
-        set_vlan_pcp
-    },
-    [OFPAT_STRIP_VLAN] = {
-        sizeof(struct ofp_action_header),
-        sizeof(struct ofp_action_header),
-        NULL,
-        strip_vlan
-    },
-    [OFPAT_SET_DL_SRC] = {
-        sizeof(struct ofp_action_dl_addr),
-        sizeof(struct ofp_action_dl_addr),
-        NULL,
-        set_dl_addr
-    },
-    [OFPAT_SET_DL_DST] = {
-        sizeof(struct ofp_action_dl_addr),
-        sizeof(struct ofp_action_dl_addr),
-        NULL,
-        set_dl_addr
-    },
-    [OFPAT_SET_NW_SRC] = {
-        sizeof(struct ofp_action_nw_addr),
-        sizeof(struct ofp_action_nw_addr),
-        NULL,
-        set_nw_addr
-    },
-    [OFPAT_SET_NW_DST] = {
-        sizeof(struct ofp_action_nw_addr),
-        sizeof(struct ofp_action_nw_addr),
-        NULL,
-        set_nw_addr
-    },
-    [OFPAT_SET_TP_SRC] = {
-        sizeof(struct ofp_action_tp_port),
-        sizeof(struct ofp_action_tp_port),
-        NULL,
-        set_tp_port
-    },
-    [OFPAT_SET_TP_DST] = {
-        sizeof(struct ofp_action_tp_port),
-        sizeof(struct ofp_action_tp_port),
-        NULL,
-        set_tp_port
-    }
-    /* OFPAT_VENDOR is not here, since it would blow up the array size. */
-};
-
-/* Validate built-in OpenFlow actions.  Either returns ACT_VALIDATION_OK
- * or an OFPET_BAD_ACTION error code. */
-static uint16_t 
-validate_ofpat(struct datapath *dp, const struct sw_flow_key *key, 
-        const struct ofp_action_header *ah, uint16_t type, uint16_t len)
-{
-    int ret = ACT_VALIDATION_OK;
-    const struct openflow_action *act = &of_actions[type];
-
-    if ((len < act->min_size) || (len > act->max_size)) {
-        return OFPBAC_BAD_LEN;
-    }
-
-    if (act->validate) {
-        ret = act->validate(dp, key, ah);
-    }
-
-    return ret;
-}
-
-/* Validate vendor-defined actions.  Either returns ACT_VALIDATION_OK
- * or an OFPET_BAD_ACTION error code. */
-static uint16_t 
-validate_vendor(struct datapath *dp, const struct sw_flow_key *key, 
-        const struct ofp_action_header *ah, uint16_t len)
-{
-    struct ofp_action_vendor_header *avh;
-    int ret = ACT_VALIDATION_OK;
-
-    if (len < sizeof(struct ofp_action_vendor_header)) {
-        return OFPBAC_BAD_LEN;
-    }
-
-    avh = (struct ofp_action_vendor_header *)ah;
-
-    switch(ntohl(avh->vendor)) {
-    case NX_VENDOR_ID: 
-        ret = nx_validate_act(dp, key, avh, len);
-        break;
-
-    default:
-        return OFPBAC_BAD_VENDOR;
-    }
-
-    return ret;
-}
-
-/* Validates a list of actions.  If a problem is found, a code for the
- * OFPET_BAD_ACTION error type is returned.  If the action list validates, 
- * ACT_VALIDATION_OK is returned. */
-uint16_t 
-validate_actions(struct datapath *dp, const struct sw_flow_key *key,
-        const struct ofp_action_header *actions, size_t actions_len)
-{
-    uint8_t *p = (uint8_t *)actions;
-    int err;
-
-    while (actions_len >= sizeof(struct ofp_action_header)) {
-        struct ofp_action_header *ah = (struct ofp_action_header *)p;
-        size_t len = ntohs(ah->len);
-        uint16_t type;
-
-        /* Make there's enough remaining data for the specified length
-         * and that the action length is a multiple of 64 bits. */
-        if ((actions_len < len) || (len % 8) != 0) {
-            return OFPBAC_BAD_LEN;
-        }
-
-        type = ntohs(ah->type);
-        if (type < ARRAY_SIZE(of_actions)) {
-            err = validate_ofpat(dp, key, ah, type, len);
-            if (err != ACT_VALIDATION_OK) {
-                return err;
-            }
-        } else if (type == OFPAT_VENDOR) {
-            err = validate_vendor(dp, key, ah, len);
-            if (err != ACT_VALIDATION_OK) {
-                return err;
-            }
-        } else {
-            return OFPBAC_BAD_TYPE;
-        }
-
-        p += len;
-        actions_len -= len;
-    }
-
-    /* Check if there's any trailing garbage. */
-    if (actions_len != 0) {
-        return OFPBAC_BAD_LEN;
-    }
-
-    return ACT_VALIDATION_OK;
-}
-
-/* Execute a built-in OpenFlow action against 'buffer'. */
-static void
-execute_ofpat(struct ofpbuf *buffer, struct sw_flow_key *key, 
-        const struct ofp_action_header *ah, uint16_t type)
-{
-    const struct openflow_action *act = &of_actions[type];
-
-    if (act->execute) {
-        act->execute(buffer, key, ah);
-    }
-}
-
-/* Execute a vendor-defined action against 'buffer'. */
-static void
-execute_vendor(struct ofpbuf *buffer, const struct sw_flow_key *key, 
-        const struct ofp_action_header *ah)
-{
-    struct ofp_action_vendor_header *avh 
-            = (struct ofp_action_vendor_header *)ah;
-
-    switch(ntohl(avh->vendor)) {
-    case NX_VENDOR_ID: 
-        nx_execute_act(buffer, key, avh);
-        break;
-
-    default:
-        /* This should not be possible due to prior validation. */
-        printf("attempt to execute action with unknown vendor: %#x\n", 
-                ntohl(avh->vendor));
-        break;
-    }
-}
-
-/* Execute a list of actions against 'buffer'. */
-void execute_actions(struct datapath *dp, struct ofpbuf *buffer,
-             struct sw_flow_key *key,
-             const struct ofp_action_header *actions, size_t actions_len,
-             int ignore_no_fwd)
-{
-    /* Every output action needs a separate clone of 'buffer', but the common
-     * case is just a single output action, so that doing a clone and then
-     * freeing the original buffer is wasteful.  So the following code is
-     * slightly obscure just to avoid that. */
-    int prev_port;
-    size_t max_len=0;     /* Initialze to make compiler happy */
-    uint16_t in_port = ntohs(key->flow.in_port);
-    uint8_t *p = (uint8_t *)actions;
-
-    prev_port = -1;
-
-    /* The action list was already validated, so we can be a bit looser
-     * in our sanity-checking. */
-    while (actions_len > 0) {
-        struct ofp_action_header *ah = (struct ofp_action_header *)p;
-        size_t len = htons(ah->len);
-
-        if (prev_port != -1) {
-            do_output(dp, ofpbuf_clone(buffer), in_port, max_len, 
-                    prev_port, ignore_no_fwd);
-            prev_port = -1;
-        }
-
-        if (ah->type == htons(OFPAT_OUTPUT)) {
-            struct ofp_action_output *oa = (struct ofp_action_output *)p;
-            prev_port = ntohs(oa->port);
-            max_len = ntohs(oa->max_len);
-        } else {
-            uint16_t type = ntohs(ah->type);
-
-            if (type < ARRAY_SIZE(of_actions)) {
-                execute_ofpat(buffer, key, ah, type);
-            } else if (type == OFPAT_VENDOR) {
-                execute_vendor(buffer, key, ah);
-            }
-        }
-
-        p += len;
-        actions_len -= len;
-    }
-    if (prev_port != -1) {
-        do_output(dp, buffer, in_port, max_len, prev_port, ignore_no_fwd);
-    } else {
-        ofpbuf_delete(buffer);
-    }
-}
diff --git a/switch/dp_act.h b/switch/dp_act.h
deleted file mode 100644 (file)
index e0181fa..0000000
+++ /dev/null
@@ -1,49 +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.
- */
-
-#ifndef DP_ACT_H
-#define DP_ACT_H 1
-
-#include "openflow/openflow.h"
-#include "switch-flow.h"
-#include "datapath.h"
-
-#define ACT_VALIDATION_OK ((uint16_t)-1)
-
-uint16_t validate_actions(struct datapath *, const struct sw_flow_key *,
-               const struct ofp_action_header *, size_t);
-void execute_actions(struct datapath *, struct ofpbuf *,
-               struct sw_flow_key *, const struct ofp_action_header *, 
-               size_t action_len, int ignore_no_fwd);
-
-#endif /* dp_act.h */
diff --git a/switch/nx_act.c b/switch/nx_act.c
deleted file mode 100644 (file)
index e2a6d4f..0000000
+++ /dev/null
@@ -1,52 +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.
- */
-
-/* Functions for Nicira-extended actions. */
-#include "openflow/nicira-ext.h"
-#include "nx_act.h"
-
-uint16_t
-nx_validate_act(struct datapath *dp, const struct sw_flow_key *key,
-               const struct ofp_action_vendor_header *avh, uint16_t len)
-{
-       /* Nothing to validate yet */
-       return OFPBAC_BAD_VENDOR_TYPE;
-}
-
-void
-nx_execute_act(struct ofpbuf *buffer, const struct sw_flow_key *key,
-               const struct ofp_action_vendor_header *avh)
-{
-       /* Nothing to execute yet */
-}
-
diff --git a/switch/nx_act.h b/switch/nx_act.h
deleted file mode 100644 (file)
index 92d1065..0000000
+++ /dev/null
@@ -1,48 +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.
- */
-
-#ifndef NX_ACT_H
-#define NX_ACT_H 1
-
-#include "switch-flow.h"
-#include "datapath.h"
-
-
-uint16_t nx_validate_act(struct datapath *dp, const struct sw_flow_key *key,
-               const struct ofp_action_vendor_header *avh, uint16_t len);
-
-void nx_execute_act(struct ofpbuf *buffer, 
-               const struct sw_flow_key *key,
-               const struct ofp_action_vendor_header *avh);
-
-#endif /* nx_act.h */
diff --git a/switch/switch-flow.c b/switch/switch-flow.c
deleted file mode 100644 (file)
index 82eee55..0000000
+++ /dev/null
@@ -1,298 +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 <config.h>
-#include "switch-flow.h"
-#include <arpa/inet.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include "ofpbuf.h"
-#include "openflow/openflow.h"
-#include "packets.h"
-#include "timeval.h"
-
-/* Internal function used to compare fields in flow. */
-static inline int
-flow_fields_match(const struct flow *a, const struct flow *b, uint16_t w,
-                  uint32_t src_mask, uint32_t dst_mask)
-{
-    return ((w & OFPFW_IN_PORT || a->in_port == b->in_port)
-            && (w & OFPFW_DL_VLAN || a->dl_vlan == b->dl_vlan)
-            && (w & OFPFW_DL_SRC || eth_addr_equals(a->dl_src, b->dl_src))
-            && (w & OFPFW_DL_DST || eth_addr_equals(a->dl_dst, b->dl_dst))
-            && (w & OFPFW_DL_TYPE || a->dl_type == b->dl_type)
-            && !((a->nw_src ^ b->nw_src) & src_mask)
-            && !((a->nw_dst ^ b->nw_dst) & dst_mask)
-            && (w & OFPFW_NW_PROTO || a->nw_proto == b->nw_proto)
-            && (w & OFPFW_TP_SRC || a->tp_src == b->tp_src)
-            && (w & OFPFW_TP_DST || a->tp_dst == b->tp_dst));
-}
-
-static uint32_t make_nw_mask(int n_wild_bits)
-{
-    n_wild_bits &= (1u << OFPFW_NW_SRC_BITS) - 1;
-    return n_wild_bits < 32 ? htonl(~((1u << n_wild_bits) - 1)) : 0;
-}
-
-/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal
- * modulo wildcards in 'b', zero otherwise. */
-inline int
-flow_matches_1wild(const struct sw_flow_key *a, const struct sw_flow_key *b)
-{
-    return flow_fields_match(&a->flow, &b->flow, b->wildcards,
-                             b->nw_src_mask, b->nw_dst_mask);
-}
-
-/* Returns nonzero if 'a' and 'b' match, that is, if their fields are equal
- * modulo wildcards in 'a' or 'b', zero otherwise. */
-inline int
-flow_matches_2wild(const struct sw_flow_key *a, const struct sw_flow_key *b)
-{
-    return flow_fields_match(&a->flow, &b->flow, a->wildcards | b->wildcards,
-                             a->nw_src_mask & b->nw_src_mask,
-                             a->nw_dst_mask & b->nw_dst_mask);
-}
-
-/* Returns nonzero if 't' (the table entry's key) and 'd' (the key 
- * describing the match) match, that is, if their fields are 
- * equal modulo wildcards, zero otherwise.  If 'strict' is nonzero, the
- * wildcards must match in both 't_key' and 'd_key'.  Note that the
- * table's wildcards are ignored unless 'strict' is set. */
-int
-flow_matches_desc(const struct sw_flow_key *t, const struct sw_flow_key *d, 
-        int strict)
-{
-    if (strict && d->wildcards != t->wildcards) {
-        return 0;
-    }
-    return flow_matches_1wild(t, d);
-}
-
-void
-flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
-{
-    to->wildcards = ntohl(from->wildcards) & OFPFW_ALL;
-    to->flow.reserved = 0;
-    to->flow.in_port = from->in_port;
-    to->flow.dl_vlan = from->dl_vlan;
-    memcpy(to->flow.dl_src, from->dl_src, ETH_ADDR_LEN);
-    memcpy(to->flow.dl_dst, from->dl_dst, ETH_ADDR_LEN);
-    to->flow.dl_type = from->dl_type;
-
-    to->flow.nw_src = to->flow.nw_dst = to->flow.nw_proto = 0;
-    to->flow.tp_src = to->flow.tp_dst = 0;
-
-#define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST)
-#define OFPFW_NW (OFPFW_NW_SRC_MASK | OFPFW_NW_DST_MASK | OFPFW_NW_PROTO)
-    if (to->wildcards & OFPFW_DL_TYPE) {
-        /* Can't sensibly match on network or transport headers if the
-         * data link type is unknown. */
-        to->wildcards |= OFPFW_NW | OFPFW_TP;
-    } else if (from->dl_type == htons(ETH_TYPE_IP)) {
-        to->flow.nw_src   = from->nw_src;
-        to->flow.nw_dst   = from->nw_dst;
-        to->flow.nw_proto = from->nw_proto;
-
-        if (to->wildcards & OFPFW_NW_PROTO) {
-            /* Can't sensibly match on transport headers if the network
-             * protocol is unknown. */
-            to->wildcards |= OFPFW_TP;
-        } else if (from->nw_proto == IPPROTO_TCP 
-                || from->nw_proto == IPPROTO_UDP
-                || from->nw_proto == IPPROTO_ICMP) {
-            to->flow.tp_src = from->tp_src;
-            to->flow.tp_dst = from->tp_dst;
-        } else {
-            /* Transport layer fields are undefined.  Mark them as
-             * exact-match to allow such flows to reside in table-hash,
-             * instead of falling into table-linear. */
-            to->wildcards &= ~OFPFW_TP;
-        }
-    } else {
-        /* Network and transport layer fields are undefined.  Mark them
-         * as exact-match to allow such flows to reside in table-hash,
-         * instead of falling into table-linear. */
-        to->wildcards &= ~(OFPFW_NW | OFPFW_TP);
-    }
-
-       /* We set these late because code above adjusts to->wildcards. */
-       to->nw_src_mask = make_nw_mask(to->wildcards >> OFPFW_NW_SRC_SHIFT);
-       to->nw_dst_mask = make_nw_mask(to->wildcards >> OFPFW_NW_DST_SHIFT);
-}
-
-void
-flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from)
-{
-    to->wildcards = htonl(from->wildcards);
-    to->in_port   = from->flow.in_port;
-    to->dl_vlan   = from->flow.dl_vlan;
-    memcpy(to->dl_src, from->flow.dl_src, ETH_ADDR_LEN);
-    memcpy(to->dl_dst, from->flow.dl_dst, ETH_ADDR_LEN);
-    to->dl_type   = from->flow.dl_type;
-    to->nw_src        = from->flow.nw_src;
-    to->nw_dst        = from->flow.nw_dst;
-    to->nw_proto  = from->flow.nw_proto;
-    to->tp_src        = from->flow.tp_src;
-    to->tp_dst        = from->flow.tp_dst;
-    to->pad           = 0;
-}
-
-/* Allocates and returns a new flow with room for 'actions_len' actions. 
- * Returns the new flow or a null pointer on failure. */
-struct sw_flow *
-flow_alloc(size_t actions_len)
-{
-    struct sw_flow_actions *sfa;
-    size_t size = sizeof *sfa + actions_len;
-    struct sw_flow *flow = malloc(sizeof *flow);
-    if (!flow)
-        return NULL;
-
-    sfa = malloc(size);
-    if (!sfa) {
-        free(flow);
-        return NULL;
-    }
-    sfa->actions_len = actions_len;
-    flow->sf_acts = sfa;
-    return flow;
-}
-
-/* Frees 'flow' immediately. */
-void
-flow_free(struct sw_flow *flow)
-{
-    if (!flow) {
-        return; 
-    }
-    free(flow->sf_acts);
-    free(flow);
-}
-
-/* Copies 'actions' into a newly allocated structure for use by 'flow'
- * and frees the structure that defined the previous actions. */
-void flow_replace_acts(struct sw_flow *flow, 
-        const struct ofp_action_header *actions, size_t actions_len)
-{
-    struct sw_flow_actions *sfa;
-    int size = sizeof *sfa + actions_len;
-
-    sfa = malloc(size);
-    if (unlikely(!sfa))
-        return;
-
-    sfa->actions_len = actions_len;
-    memcpy(sfa->actions, actions, actions_len);
-
-    free(flow->sf_acts);
-    flow->sf_acts = sfa;
-
-    return;
-}
-
-/* Prints a representation of 'key' to the kernel log. */
-void
-print_flow(const struct sw_flow_key *key)
-{
-    const struct flow *f = &key->flow;
-    printf("wild%08x port%04x:vlan%04x mac%02x:%02x:%02x:%02x:%02x:%02x"
-           "->%02x:%02x:%02x:%02x:%02x:%02x "
-           "proto%04x ip%u.%u.%u.%u->%u.%u.%u.%u port%d->%d\n",
-           key->wildcards, ntohs(f->in_port), ntohs(f->dl_vlan),
-           f->dl_src[0], f->dl_src[1], f->dl_src[2],
-           f->dl_src[3], f->dl_src[4], f->dl_src[5],
-           f->dl_dst[0], f->dl_dst[1], f->dl_dst[2],
-           f->dl_dst[3], f->dl_dst[4], f->dl_dst[5],
-           ntohs(f->dl_type),
-           ((unsigned char *)&f->nw_src)[0],
-           ((unsigned char *)&f->nw_src)[1],
-           ((unsigned char *)&f->nw_src)[2],
-           ((unsigned char *)&f->nw_src)[3],
-           ((unsigned char *)&f->nw_dst)[0],
-           ((unsigned char *)&f->nw_dst)[1],
-           ((unsigned char *)&f->nw_dst)[2],
-           ((unsigned char *)&f->nw_dst)[3],
-           ntohs(f->tp_src), ntohs(f->tp_dst));
-}
-
-bool flow_timeout(struct sw_flow *flow)
-{
-    time_t now = time_now();
-    if (flow->idle_timeout != OFP_FLOW_PERMANENT
-        && now > flow->used + flow->idle_timeout) {
-        flow->reason = OFPER_IDLE_TIMEOUT;
-        return true;
-    } else if (flow->hard_timeout != OFP_FLOW_PERMANENT
-               && now > flow->created + flow->hard_timeout) {
-        flow->reason = OFPER_HARD_TIMEOUT;
-        return true;
-    } else {
-        return false;
-    }
-}
-
-/* Returns nonzero if 'flow' contains an output action to 'out_port' or
- * has the value OFPP_NONE. 'out_port' is in network-byte order. */
-int flow_has_out_port(struct sw_flow *flow, uint16_t out_port)
-{
-    struct sw_flow_actions *sf_acts = flow->sf_acts;
-    size_t actions_len = sf_acts->actions_len;
-    uint8_t *p = (uint8_t *)sf_acts->actions;
-
-    if (out_port == htons(OFPP_NONE))
-        return 1;
-
-    while (actions_len > 0) {
-        struct ofp_action_header *ah = (struct ofp_action_header *)p;
-        size_t len = ntohs(ah->len);
-
-        if (ah->type == htons(OFPAT_OUTPUT)) {
-            struct ofp_action_output *oa = (struct ofp_action_output *)p;
-            if (oa->port == out_port) {
-                return 1;
-            }
-        }
-        p += len;
-        actions_len -= len;
-    }
-
-    return 0;
-}
-
-void flow_used(struct sw_flow *flow, struct ofpbuf *buffer)
-{
-    flow->used = time_now();
-    flow->packet_count++;
-    flow->byte_count += buffer->size;
-}
diff --git a/switch/switch-flow.h b/switch/switch-flow.h
deleted file mode 100644 (file)
index ef0497c..0000000
+++ /dev/null
@@ -1,95 +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.
- */
-
-#ifndef SWITCH_FLOW_H
-#define SWITCH_FLOW_H 1
-
-#include <time.h>
-#include "openflow/openflow.h"
-#include "flow.h"
-#include "list.h"
-
-struct ofp_match;
-
-/* Identification data for a flow. */
-struct sw_flow_key {
-    struct flow flow;           /* Flow data (in network byte order). */
-    uint32_t wildcards;         /* Wildcard fields (in host byte order). */
-    uint32_t nw_src_mask;       /* 1-bit in each significant nw_src bit. */
-    uint32_t nw_dst_mask;       /* 1-bit in each significant nw_dst bit. */
-};
-
-struct sw_flow_actions {
-    size_t actions_len;
-    struct ofp_action_header actions[0];
-};
-
-struct sw_flow {
-    struct sw_flow_key key;
-
-    uint16_t priority;          /* Only used on entries with wildcards. */
-    uint16_t idle_timeout;      /* Idle time before discarding (seconds). */
-    uint16_t hard_timeout;      /* Hard expiration time (seconds) */
-    time_t used;                /* Last used time. */
-    time_t created;             /* When the flow was created. */
-    uint64_t packet_count;      /* Number of packets seen. */
-    uint64_t byte_count;        /* Number of bytes seen. */
-    uint8_t reason;             /* Reason flow expired (one of OFPER_*). */
-
-    struct sw_flow_actions *sf_acts;
-
-    /* Private to table implementations. */
-    struct list node;
-    struct list iter_node;
-    unsigned long int serial;
-};
-
-int flow_matches_1wild(const struct sw_flow_key *, const struct sw_flow_key *);
-int flow_matches_2wild(const struct sw_flow_key *, const struct sw_flow_key *);
-int flow_matches_desc(const struct sw_flow_key *, const struct sw_flow_key *, 
-                     int);
-int flow_has_out_port(struct sw_flow *flow, uint16_t out_port);
-struct sw_flow *flow_alloc(size_t);
-void flow_free(struct sw_flow *);
-void flow_deferred_free(struct sw_flow *);
-void flow_deferred_free_acts(struct sw_flow_actions *);
-void flow_replace_acts(struct sw_flow *, const struct ofp_action_header *, 
-        size_t);
-void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from);
-void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from);
-
-void print_flow(const struct sw_flow_key *);
-bool flow_timeout(struct sw_flow *flow);
-void flow_used(struct sw_flow *flow, struct ofpbuf *buffer);
-
-#endif /* switch-flow.h */
diff --git a/switch/switch.8.in b/switch/switch.8.in
deleted file mode 100644 (file)
index c6aa606..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-.TH secchan 8 "May 2008" "OpenFlow" "OpenFlow Manual"
-
-.SH NAME
-switch \- userspace implementation of OpenFlow switch
-
-.SH SYNOPSIS
-.B switch
-[\fIoptions\fR]
-\fB-i\fR \fInetdev\fR[\fB,\fInetdev\fR]...
-\fIcontroller\fR
-
-.SH DESCRIPTION
-The \fBswitch\fR is a userspace implementation of an OpenFlow switch.
-It implements all three parts of the OpenFlow switch specification: a
-``flow table'' in which each flow entry is associated with an action
-telling the switch how to process the flow; a ``secure channel''
-connecting the switch to a remote process (a controller), allowing
-commands and packets to be sent between the controller and the switch;
-and an OpenFlow protocol implementation.
-
-\fBswitch\fR monitors one or more network device interfaces,
-forwarding packets between them according to the entries in the flow
-table.  It also maintains a connection to an OpenFlow controller over
-a TCP or SSL connection, relaying packets that do not match a flow
-table entry to the controller and executing commands sent by the
-controller.
-
-For access to network devices, the switch program must normally run as
-root.
-
-The mandatory \fIcontroller\fR argument specifies how to connect to
-the OpenFlow controller.  It takes one of the following forms:
-
-.TP
-\fBssl:\fIhost\fR[\fB:\fIport\fR]
-The specified SSL \fIport\fR (default: 6633) on the given remote
-\fIhost\fR.  The \fB--private-key\fR, \fB--certificate\fR, and
-\fB--ca-cert\fR options are mandatory when this form is used.
-
-.TP
-\fBtcp:\fIhost\fR[\fB:\fIport\fR]
-The specified TCP \fIport\fR (default: 6633) on the given remote
-\fIhost\fR.
-
-.TP
-\fBunix:\fIfile\fR
-The Unix domain server socket named \fIfile\fR.
-
-.SH OPTIONS
-.TP
-\fB-i\fR, \fB--interfaces=\fR\fInetdev\fR[\fB,\fInetdev\fR]...
-Specifies each \fInetdev\fR (e.g., \fBeth0\fR) as a switch port.  The
-specified network devices should not have any configured IP addresses.
-This option may be given any number of times to specify additional
-network devices.
-
-.TP
-\fB-d\fR, \fB--datapath-id=\fIdpid\fR
-Specifies the OpenFlow switch ID (a 48-bit number that uniquely
-identifies a controller) as \fIdpid\fR, which consists of exactly 12
-hex digits.  Without this option, \fBswitch\fR picks an ID randomly.
-
-.TP
-\fB--max-backoff=\fIsecs\fR
-Sets the maximum time between attempts to connect to the controller to
-\fIsecs\fR, which must be at least 1.  The actual interval between
-connection attempts starts at 1 second and doubles on each failing
-attempt until it reaches the maximum.  The default maximum backoff
-time is 15 seconds.
-
-.TP
-\fB-p\fR, \fB--private-key=\fIprivkey.pem\fR
-Specifies a PEM file containing the private key used as the switch's
-identity for SSL connections to the controller.
-
-.TP
-\fB-c\fR, \fB--certificate=\fIcert.pem\fR
-Specifies a PEM file containing a certificate, signed by the
-controller's certificate authority (CA), that certifies the switch's
-private key to identify a trustworthy switch.
-
-.TP
-\fB-C\fR, \fB--ca-cert=\fIcacert.pem\fR
-Specifies a PEM file containing the CA certificate used to verify that
-the switch is connected to a trustworthy controller.
-
-.TP
-\fB-P\fR[\fIpidfile\fR], \fB--pidfile\fR[\fB=\fIpidfile\fR]
-Causes a file (by default, \fBswitch.pid\fR) to be created indicating
-the PID of the running process.  If \fIpidfile\fR is not specified, or
-if it does not begin with \fB/\fR, then it is created in
-\fB@RUNDIR@\fR.
-
-.TP
-\fB-f\fR, \fB--force\fR
-By default, when \fB-P\fR or \fB--pidfile\fR is specified and the
-specified pidfile already exists and is locked by a running process,
-\fBswitch\fR refuses to start.  Specify \fB-f\fR or \fB--force\fR
-to cause it to instead overwrite the pidfile.
-
-When \fB-P\fR or \fB--pidfile\fR is not specified, this option has no
-effect.
-
-.TP
-\fB-D\fR, \fB--detach\fR
-Causes \fBswitch\fR to detach itself from the foreground session and
-run as a background process.
-
-.TP
-.BR \-h ", " \-\^\-help
-Prints a brief help message to the console.
-
-@VLOG_OPTIONS@
-
-.TP
-.BR \-V ", " \-\^\-version
-Prints version information to the console.
-
-.SH BUGS
-
-The userspace switch implementation lags significantly behind the
-kernel-based switch, both in implementation quality and performance.
-It should only be used when the kernel-based switch cannot be.
-
-General-purpose support for VLAN tag rewriting is precluded by the
-Linux kernel AF_PACKET implementation.
-
-.SH "SEE ALSO"
-
-.BR dpctl (8),
-.BR ofp-pki (8),
-.BR controller (8),
-.BR vlogconf (8)
diff --git a/switch/switch.c b/switch/switch.c
deleted file mode 100644 (file)
index fba8858..0000000
+++ /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 <config.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "command-line.h"
-#include "daemon.h"
-#include "datapath.h"
-#include "fault.h"
-#include "openflow/openflow.h"
-#include "poll-loop.h"
-#include "queue.h"
-#include "util.h"
-#include "rconn.h"
-#include "timeval.h"
-#include "vconn.h"
-#include "vconn-ssl.h"
-#include "vlog-socket.h"
-
-#define THIS_MODULE VLM_switch
-#include "vlog.h"
-
-
-/* Strings to describe the manufacturer, hardware, and software.  This data 
- * is queriable through the switch description stats message. */
-char mfr_desc[DESC_STR_LEN] = "Nicira Networks";
-char hw_desc[DESC_STR_LEN] = "Reference User-Space Switch";
-char sw_desc[DESC_STR_LEN] = VERSION;
-char serial_num[SERIAL_NUM_LEN] = "None";
-
-static void parse_options(int argc, char *argv[]);
-static void usage(void) NO_RETURN;
-
-static const char *listen_pvconn_name;
-static struct datapath *dp;
-static uint64_t dpid = UINT64_MAX;
-static char *port_list;
-
-/* --max-backoff: Maximum interval between controller connection attempts, in
- * seconds. */
-static int max_backoff = 15;
-
-static void add_ports(struct datapath *dp, char *port_list);
-
-int
-main(int argc, char *argv[])
-{
-    struct rconn *rconn;
-    int error;
-
-    set_program_name(argv[0]);
-    register_fault_handlers();
-    time_init();
-    vlog_init();
-    parse_options(argc, argv);
-    signal(SIGPIPE, SIG_IGN);
-
-    if (argc - optind != 1) {
-        ofp_fatal(0, "missing controller argument; use --help for usage");
-    }
-
-    rconn = rconn_create(60, max_backoff);
-    error = rconn_connect(rconn, argv[optind]);
-    if (error == EAFNOSUPPORT) {
-        ofp_fatal(0, "no support for %s vconn", argv[optind]);
-    }
-    error = dp_new(&dp, dpid, rconn);
-    if (listen_pvconn_name) {
-        struct pvconn *listen_pvconn;
-        int retval;
-
-        retval = pvconn_open(listen_pvconn_name, &listen_pvconn);
-        if (retval && retval != EAGAIN) {
-            ofp_fatal(retval, "opening %s", listen_pvconn_name);
-        }
-        dp_add_listen_pvconn(dp, listen_pvconn);
-    }
-    if (error) {
-        ofp_fatal(error, "could not create datapath");
-    }
-    if (port_list) {
-        add_ports(dp, port_list); 
-    }
-
-    die_if_already_running();
-    daemonize();
-
-    error = vlog_server_listen(NULL, NULL);
-    if (error) {
-        ofp_fatal(error, "could not listen for vlog connections");
-    }
-
-    for (;;) {
-        dp_run(dp);
-        dp_wait(dp);
-        poll_block();
-    }
-
-    return 0;
-}
-
-static void
-add_ports(struct datapath *dp, char *port_list)
-{
-    char *port, *save_ptr;
-
-    /* Glibc 2.7 has a bug in strtok_r when compiling with optimization that
-     * can cause segfaults here:
-     * http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614.
-     * Using ",," instead of the obvious "," works around it. */
-    for (port = strtok_r(port_list, ",,", &save_ptr); port;
-         port = strtok_r(NULL, ",,", &save_ptr)) {
-        int error = dp_add_port(dp, port);
-        if (error) {
-            ofp_fatal(error, "failed to add port %s", port);
-        }
-    }
-}
-
-static void
-parse_options(int argc, char *argv[])
-{
-    enum {
-        OPT_MAX_BACKOFF = UCHAR_MAX + 1,
-        OPT_MFR_DESC,
-        OPT_HW_DESC,
-        OPT_SW_DESC,
-        OPT_SERIAL_NUM,
-        OPT_BOOTSTRAP_CA_CERT
-    };
-
-    static struct option long_options[] = {
-        {"interfaces",  required_argument, 0, 'i'},
-        {"datapath-id", required_argument, 0, 'd'},
-        {"max-backoff", required_argument, 0, OPT_MAX_BACKOFF},
-        {"listen",      required_argument, 0, 'l'},
-        {"verbose",     optional_argument, 0, 'v'},
-        {"help",        no_argument, 0, 'h'},
-        {"version",     no_argument, 0, 'V'},
-        {"mfr-desc",    required_argument, 0, OPT_MFR_DESC},
-        {"hw-desc",     required_argument, 0, OPT_HW_DESC},
-        {"sw-desc",     required_argument, 0, OPT_SW_DESC},
-        {"serial_num",  required_argument, 0, OPT_SERIAL_NUM},
-        DAEMON_LONG_OPTIONS,
-#ifdef HAVE_OPENSSL
-        VCONN_SSL_LONG_OPTIONS
-        {"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
-#endif
-        {0, 0, 0, 0},
-    };
-    char *short_options = long_options_to_short_options(long_options);
-
-    for (;;) {
-        int indexptr;
-        int c;
-
-        c = getopt_long(argc, argv, short_options, long_options, &indexptr);
-        if (c == -1) {
-            break;
-        }
-
-        switch (c) {
-        case 'd':
-            if (strlen(optarg) != 12
-                || strspn(optarg, "0123456789abcdefABCDEF") != 12) {
-                ofp_fatal(0, "argument to -d or --datapath-id must be "
-                          "exactly 12 hex digits");
-            }
-            dpid = strtoll(optarg, NULL, 16);
-            if (!dpid) {
-                ofp_fatal(0, "argument to -d or --datapath-id must "
-                          "be nonzero");
-            }
-            break;
-
-        case 'h':
-            usage();
-
-        case 'V':
-            printf("%s %s compiled "__DATE__" "__TIME__"\n",
-                   program_name, VERSION BUILDNR);
-            exit(EXIT_SUCCESS);
-
-        case 'v':
-            vlog_set_verbosity(optarg);
-            break;
-
-        case 'i':
-            if (!port_list) {
-                port_list = optarg;
-            } else {
-                port_list = xasprintf("%s,%s", port_list, optarg);
-            }
-            break;
-
-        case OPT_MAX_BACKOFF:
-            max_backoff = atoi(optarg);
-            if (max_backoff < 1) {
-                ofp_fatal(0, "--max-backoff argument must be at least 1");
-            } else if (max_backoff > 3600) {
-                max_backoff = 3600;
-            }
-            break;
-
-        case OPT_MFR_DESC:
-            strncpy(mfr_desc, optarg, sizeof mfr_desc);
-            break;
-
-        case OPT_HW_DESC:
-            strncpy(hw_desc, optarg, sizeof hw_desc);
-            break;
-
-        case OPT_SW_DESC:
-            strncpy(sw_desc, optarg, sizeof sw_desc);
-            break;
-
-        case OPT_SERIAL_NUM:
-            strncpy(serial_num, optarg, sizeof serial_num);
-            break;
-
-        case 'l':
-            if (listen_pvconn_name) {
-                ofp_fatal(0, "-l or --listen may be only specified once");
-            }
-            listen_pvconn_name = optarg;
-            break;
-
-        DAEMON_OPTION_HANDLERS
-
-#ifdef HAVE_OPENSSL
-        VCONN_SSL_OPTION_HANDLERS
-
-        case OPT_BOOTSTRAP_CA_CERT:
-            vconn_ssl_set_ca_cert_file(optarg, true);
-            break;
-#endif
-
-        case '?':
-            exit(EXIT_FAILURE);
-
-        default:
-            abort();
-        }
-    }
-    free(short_options);
-}
-
-static void
-usage(void)
-{
-    printf("%s: userspace OpenFlow switch\n"
-           "usage: %s [OPTIONS] CONTROLLER\n"
-           "where CONTROLLER is an active OpenFlow connection method.\n",
-           program_name, program_name);
-    vconn_usage(true, true, true);
-    printf("\nConfiguration options:\n"
-           "  -i, --interfaces=NETDEV[,NETDEV]...\n"
-           "                          add specified initial switch ports\n"
-           "  -d, --datapath-id=ID    Use ID as the OpenFlow switch ID\n"
-           "                          (ID must consist of 12 hex digits)\n"
-           "  --max-backoff=SECS      max time between controller connection\n"
-           "                          attempts (default: 15 seconds)\n"
-           "  -l, --listen=METHOD     allow management connections on METHOD\n"
-           "                          (a passive OpenFlow connection method)\n");
-    daemon_usage();
-    vlog_usage();
-    printf("\nOther options:\n"
-           "  -h, --help              display this help message\n"
-           "  -V, --version           display version information\n");
-    exit(EXIT_SUCCESS);
-}
diff --git a/switch/table-hash.c b/switch/table-hash.c
deleted file mode 100644 (file)
index 6b5e945..0000000
+++ /dev/null
@@ -1,426 +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 <config.h>
-#include "table.h"
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include "crc32.h"
-#include "datapath.h"
-#include "flow.h"
-#include "switch-flow.h"
-
-struct sw_table_hash {
-    struct sw_table swt;
-    struct crc32 crc32;
-    unsigned int n_flows;
-    unsigned int bucket_mask; /* Number of buckets minus 1. */
-    struct sw_flow **buckets;
-};
-
-static struct sw_flow **find_bucket(struct sw_table *swt,
-                                    const struct sw_flow_key *key)
-{
-    struct sw_table_hash *th = (struct sw_table_hash *) swt;
-    unsigned int crc = crc32_calculate(&th->crc32, key, 
-            offsetof(struct sw_flow_key, wildcards));
-    return &th->buckets[crc & th->bucket_mask];
-}
-
-static struct sw_flow *table_hash_lookup(struct sw_table *swt,
-                                         const struct sw_flow_key *key)
-{
-    struct sw_flow *flow = *find_bucket(swt, key);
-    return flow && !flow_compare(&flow->key.flow, &key->flow) ? flow : NULL;
-}
-
-static int table_hash_insert(struct sw_table *swt, struct sw_flow *flow)
-{
-    struct sw_table_hash *th = (struct sw_table_hash *) swt;
-    struct sw_flow **bucket;
-    int retval;
-
-    if (flow->key.wildcards != 0)
-        return 0;
-
-    bucket = find_bucket(swt, &flow->key);
-    if (*bucket == NULL) {
-        th->n_flows++;
-        *bucket = flow;
-        retval = 1;
-    } else {
-        struct sw_flow *old_flow = *bucket;
-        if (!flow_compare(&old_flow->key.flow, &flow->key.flow)) {
-            *bucket = flow;
-            flow_free(old_flow);
-            retval = 1;
-        } else {
-            retval = 0;
-        }
-    }
-    return retval;
-}
-
-static int table_hash_modify(struct sw_table *swt, 
-        const struct sw_flow_key *key, uint16_t priority, int strict,
-        const struct ofp_action_header *actions, size_t actions_len) 
-{
-    struct sw_table_hash *th = (struct sw_table_hash *) swt;
-    unsigned int count = 0;
-
-    if (key->wildcards == 0) {
-        struct sw_flow **bucket = find_bucket(swt, key);
-        struct sw_flow *flow = *bucket;
-        if (flow && flow_matches_desc(&flow->key, key, strict)
-                && (!strict || (flow->priority == priority))) {
-            flow_replace_acts(flow, actions, actions_len);
-            count = 1;
-        }
-    } else {
-        unsigned int i;
-
-        for (i = 0; i <= th->bucket_mask; i++) {
-            struct sw_flow **bucket = &th->buckets[i];
-            struct sw_flow *flow = *bucket;
-            if (flow && flow_matches_desc(&flow->key, key, strict)
-                    && (!strict || (flow->priority == priority))) {
-                flow_replace_acts(flow, actions, actions_len);
-                count++;
-            }
-        }
-    }
-    return count;
-}
-
-/* Caller must update n_flows. */
-static void
-do_delete(struct sw_flow **bucket)
-{
-    flow_free(*bucket);
-    *bucket = NULL;
-}
-
-/* Returns number of deleted flows.  We can igonre the priority
- * argument, since all exact-match entries are the same (highest)
- * priority. */
-static int table_hash_delete(struct sw_table *swt,
-                             const struct sw_flow_key *key, 
-                             uint16_t out_port,
-                             uint16_t priority, int strict)
-{
-    struct sw_table_hash *th = (struct sw_table_hash *) swt;
-    unsigned int count = 0;
-
-    if (key->wildcards == 0) {
-        struct sw_flow **bucket = find_bucket(swt, key);
-        struct sw_flow *flow = *bucket;
-        if (flow && !flow_compare(&flow->key.flow, &key->flow)
-                && flow_has_out_port(flow, out_port)) {
-            do_delete(bucket);
-            count = 1;
-        }
-    } else {
-        unsigned int i;
-
-        for (i = 0; i <= th->bucket_mask; i++) {
-            struct sw_flow **bucket = &th->buckets[i];
-            struct sw_flow *flow = *bucket;
-            if (flow && flow_matches_desc(&flow->key, key, strict)
-                    && flow_has_out_port(flow, out_port)) {
-                do_delete(bucket);
-                count++;
-            }
-        }
-    }
-    th->n_flows -= count;
-    return count;
-}
-
-static void table_hash_timeout(struct sw_table *swt, struct list *deleted)
-{
-    struct sw_table_hash *th = (struct sw_table_hash *) swt;
-    unsigned int i;
-
-    for (i = 0; i <= th->bucket_mask; i++) {
-        struct sw_flow **bucket = &th->buckets[i];
-        struct sw_flow *flow = *bucket;
-        if (flow && flow_timeout(flow)) {
-            list_push_back(deleted, &flow->node);
-            *bucket = NULL;
-            th->n_flows--;
-        }
-    }
-}
-
-static void table_hash_destroy(struct sw_table *swt)
-{
-    struct sw_table_hash *th = (struct sw_table_hash *) swt;
-    unsigned int i;
-    for (i = 0; i <= th->bucket_mask; i++) {
-        if (th->buckets[i]) {
-            flow_free(th->buckets[i]); 
-        }
-    }
-    free(th->buckets);
-    free(th);
-}
-
-static int table_hash_iterate(struct sw_table *swt,
-                              const struct sw_flow_key *key, uint16_t out_port,
-                              struct sw_table_position *position,
-                              int (*callback)(struct sw_flow *, void *private),
-                              void *private) 
-{
-    struct sw_table_hash *th = (struct sw_table_hash *) swt;
-
-    if (position->private[0] > th->bucket_mask)
-        return 0;
-
-    if (key->wildcards == 0) {
-        struct sw_flow *flow = table_hash_lookup(swt, key);
-        position->private[0] = -1;
-        if (!flow || !flow_has_out_port(flow, out_port)) {
-            return 0;
-        }
-        return callback(flow, private);
-    } else {
-        int i;
-
-        for (i = position->private[0]; i <= th->bucket_mask; i++) {
-            struct sw_flow *flow = th->buckets[i];
-            if (flow && flow_matches_1wild(&flow->key, key)
-                    && flow_has_out_port(flow, out_port)) {
-                int error = callback(flow, private);
-                if (error) {
-                    position->private[0] = i + 1;
-                    return error;
-                }
-            }
-        }
-        return 0;
-    }
-}
-
-static void table_hash_stats(struct sw_table *swt,
-                             struct sw_table_stats *stats) 
-{
-    struct sw_table_hash *th = (struct sw_table_hash *) swt;
-    stats->name = "hash";
-    stats->wildcards = 0;        /* No wildcards are supported. */
-    stats->n_flows   = th->n_flows;
-    stats->max_flows = th->bucket_mask + 1;
-    stats->n_lookup  = swt->n_lookup;
-    stats->n_matched = swt->n_matched;
-}
-
-struct sw_table *table_hash_create(unsigned int polynomial,
-                                   unsigned int n_buckets)
-{
-    struct sw_table_hash *th;
-    struct sw_table *swt;
-
-    th = malloc(sizeof *th);
-    if (th == NULL)
-        return NULL;
-    memset(th, '\0', sizeof *th);
-
-    assert(!(n_buckets & (n_buckets - 1)));
-    th->buckets = calloc(n_buckets, sizeof *th->buckets);
-    if (th->buckets == NULL) {
-        printf("failed to allocate %u buckets\n", n_buckets);
-        free(th);
-        return NULL;
-    }
-    th->n_flows = 0;
-    th->bucket_mask = n_buckets - 1;
-
-    swt = &th->swt;
-    swt->lookup = table_hash_lookup;
-    swt->insert = table_hash_insert;
-    swt->modify = table_hash_modify;
-    swt->delete = table_hash_delete;
-    swt->timeout = table_hash_timeout;
-    swt->destroy = table_hash_destroy;
-    swt->iterate = table_hash_iterate;
-    swt->stats = table_hash_stats;
-
-    crc32_init(&th->crc32, polynomial);
-
-    return swt;
-}
-
-/* Double-hashing table. */
-
-struct sw_table_hash2 {
-    struct sw_table swt;
-    struct sw_table *subtable[2];
-};
-
-static struct sw_flow *table_hash2_lookup(struct sw_table *swt,
-                                          const struct sw_flow_key *key)
-{
-    struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
-    int i;
-        
-    for (i = 0; i < 2; i++) {
-        struct sw_flow *flow = *find_bucket(t2->subtable[i], key);
-        if (flow && !flow_compare(&flow->key.flow, &key->flow))
-            return flow;
-    }
-    return NULL;
-}
-
-static int table_hash2_insert(struct sw_table *swt, struct sw_flow *flow)
-{
-    struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
-
-    if (table_hash_insert(t2->subtable[0], flow))
-        return 1;
-    return table_hash_insert(t2->subtable[1], flow);
-}
-
-static int table_hash2_modify(struct sw_table *swt, 
-        const struct sw_flow_key *key, uint16_t priority, int strict,
-        const struct ofp_action_header *actions, size_t actions_len) 
-{
-    struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
-    return (table_hash_modify(t2->subtable[0], key, priority, strict,
-                    actions, actions_len)
-            + table_hash_modify(t2->subtable[1], key, priority, strict,
-                    actions, actions_len));
-}
-
-static int table_hash2_delete(struct sw_table *swt,
-                              const struct sw_flow_key *key, 
-                              uint16_t out_port,
-                              uint16_t priority, int strict)
-{
-    struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
-    return (table_hash_delete(t2->subtable[0], key, out_port, priority, strict)
-            + table_hash_delete(t2->subtable[1], key, out_port, priority, 
-                strict));
-}
-
-static void table_hash2_timeout(struct sw_table *swt, struct list *deleted)
-{
-    struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
-    table_hash_timeout(t2->subtable[0], deleted);
-    table_hash_timeout(t2->subtable[1], deleted);
-}
-
-static void table_hash2_destroy(struct sw_table *swt)
-{
-    struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
-    table_hash_destroy(t2->subtable[0]);
-    table_hash_destroy(t2->subtable[1]);
-    free(t2);
-}
-
-static int table_hash2_iterate(struct sw_table *swt,
-                               const struct sw_flow_key *key, 
-                               uint16_t out_port,
-                               struct sw_table_position *position,
-                               int (*callback)(struct sw_flow *, void *),
-                               void *private)
-{
-    struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
-    int i;
-
-    for (i = position->private[1]; i < 2; i++) {
-        int error = table_hash_iterate(t2->subtable[i], key, out_port, 
-                                       position, callback, private);
-        if (error) {
-            return error;
-        }
-        position->private[0] = 0;
-        position->private[1]++;
-    }
-    return 0;
-}
-
-static void table_hash2_stats(struct sw_table *swt,
-                              struct sw_table_stats *stats)
-{
-    struct sw_table_hash2 *t2 = (struct sw_table_hash2 *) swt;
-    struct sw_table_stats substats[2];
-    int i;
-
-    for (i = 0; i < 2; i++)
-        table_hash_stats(t2->subtable[i], &substats[i]);
-    stats->name = "hash2";
-    stats->wildcards = 0;        /* No wildcards are supported. */
-    stats->n_flows   = substats[0].n_flows + substats[1].n_flows;
-    stats->max_flows = substats[0].max_flows + substats[1].max_flows;
-    stats->n_lookup  = swt->n_lookup;
-    stats->n_matched = swt->n_matched;
-}
-
-struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0,
-                                    unsigned int poly1, unsigned int buckets1)
-
-{
-    struct sw_table_hash2 *t2;
-    struct sw_table *swt;
-
-    t2 = malloc(sizeof *t2);
-    if (t2 == NULL)
-        return NULL;
-    memset(t2, '\0', sizeof *t2);
-
-    t2->subtable[0] = table_hash_create(poly0, buckets0);
-    if (t2->subtable[0] == NULL)
-        goto out_free_t2;
-
-    t2->subtable[1] = table_hash_create(poly1, buckets1);
-    if (t2->subtable[1] == NULL)
-        goto out_free_subtable0;
-
-    swt = &t2->swt;
-    swt->lookup = table_hash2_lookup;
-    swt->insert = table_hash2_insert;
-    swt->modify = table_hash2_modify;
-    swt->delete = table_hash2_delete;
-    swt->timeout = table_hash2_timeout;
-    swt->destroy = table_hash2_destroy;
-    swt->iterate = table_hash2_iterate;
-    swt->stats = table_hash2_stats;
-
-    return swt;
-
-out_free_subtable0:
-    table_hash_destroy(t2->subtable[0]);
-out_free_t2:
-    free(t2);
-    return NULL;
-}
diff --git a/switch/table-linear.c b/switch/table-linear.c
deleted file mode 100644 (file)
index 1ec6951..0000000
+++ /dev/null
@@ -1,243 +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 <config.h>
-#include "table.h"
-#include <stdlib.h>
-#include "flow.h"
-#include "list.h"
-#include "openflow/openflow.h"
-#include "switch-flow.h"
-#include "datapath.h"
-
-struct sw_table_linear {
-    struct sw_table swt;
-
-    unsigned int max_flows;
-    unsigned int n_flows;
-    struct list flows;
-    struct list iter_flows;
-    unsigned long int next_serial;
-};
-
-static struct sw_flow *table_linear_lookup(struct sw_table *swt,
-                                           const struct sw_flow_key *key)
-{
-    struct sw_table_linear *tl = (struct sw_table_linear *) swt;
-    struct sw_flow *flow;
-    LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) {
-        if (flow_matches_1wild(key, &flow->key))
-            return flow;
-    }
-    return NULL;
-}
-
-static int table_linear_insert(struct sw_table *swt, struct sw_flow *flow)
-{
-    struct sw_table_linear *tl = (struct sw_table_linear *) swt;
-    struct sw_flow *f;
-
-    /* Loop through the existing list of entries.  New entries will
-     * always be placed behind those with equal priority.  Just replace 
-     * any flows that match exactly.
-     */
-    LIST_FOR_EACH (f, struct sw_flow, node, &tl->flows) {
-        if (f->priority == flow->priority
-                && f->key.wildcards == flow->key.wildcards
-                && flow_matches_2wild(&f->key, &flow->key)) {
-            flow->serial = f->serial;
-            list_replace(&flow->node, &f->node);
-            list_replace(&flow->iter_node, &f->iter_node);
-            flow_free(f);
-            return 1;
-        }
-
-        if (f->priority < flow->priority)
-            break;
-    }
-
-    /* Make sure there's room in the table. */
-    if (tl->n_flows >= tl->max_flows) {
-        return 0;
-    }
-    tl->n_flows++;
-
-    /* Insert the entry immediately in front of where we're pointing. */
-    flow->serial = tl->next_serial++;
-    list_insert(&f->node, &flow->node);
-    list_push_front(&tl->iter_flows, &flow->iter_node);
-
-    return 1;
-}
-
-static int table_linear_modify(struct sw_table *swt,
-                const struct sw_flow_key *key, uint16_t priority, int strict,
-                const struct ofp_action_header *actions, size_t actions_len)
-{
-    struct sw_table_linear *tl = (struct sw_table_linear *) swt;
-    struct sw_flow *flow;
-    unsigned int count = 0;
-
-    LIST_FOR_EACH (flow, struct sw_flow, node, &tl->flows) {
-        if (flow_matches_desc(&flow->key, key, strict)
-                && (!strict || (flow->priority == priority))) {
-            flow_replace_acts(flow, actions, actions_len);
-            count++;
-        }
-    }
-    return count;
-}
-
-static void
-do_delete(struct sw_flow *flow) 
-{
-    list_remove(&flow->node);
-    list_remove(&flow->iter_node);
-    flow_free(flow);
-}
-
-static int table_linear_delete(struct sw_table *swt,
-                               const struct sw_flow_key *key, 
-                               uint16_t out_port,
-                               uint16_t priority, int strict)
-{
-    struct sw_table_linear *tl = (struct sw_table_linear *) swt;
-    struct sw_flow *flow, *n;
-    unsigned int count = 0;
-
-    LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) {
-        if (flow_matches_desc(&flow->key, key, strict)
-                && flow_has_out_port(flow, out_port)
-                && (!strict || (flow->priority == priority))) {
-            do_delete(flow);
-            count++;
-        }
-    }
-    tl->n_flows -= count;
-    return count;
-}
-
-static void table_linear_timeout(struct sw_table *swt, struct list *deleted)
-{
-    struct sw_table_linear *tl = (struct sw_table_linear *) swt;
-    struct sw_flow *flow, *n;
-
-    LIST_FOR_EACH_SAFE (flow, n, struct sw_flow, node, &tl->flows) {
-        if (flow_timeout(flow)) {
-            list_remove(&flow->node);
-            list_remove(&flow->iter_node);
-            list_push_back(deleted, &flow->node);
-            tl->n_flows--;
-        }
-    }
-}
-
-static void table_linear_destroy(struct sw_table *swt)
-{
-    struct sw_table_linear *tl = (struct sw_table_linear *) swt;
-
-    while (!list_is_empty(&tl->flows)) {
-        struct sw_flow *flow = CONTAINER_OF(list_front(&tl->flows),
-                                            struct sw_flow, node);
-        list_remove(&flow->node);
-        flow_free(flow);
-    }
-    free(tl);
-}
-
-static int table_linear_iterate(struct sw_table *swt,
-                                const struct sw_flow_key *key,
-                                uint16_t out_port,
-                                struct sw_table_position *position,
-                                int (*callback)(struct sw_flow *, void *),
-                                void *private)
-{
-    struct sw_table_linear *tl = (struct sw_table_linear *) swt;
-    struct sw_flow *flow;
-    unsigned long start;
-
-    start = ~position->private[0];
-    LIST_FOR_EACH (flow, struct sw_flow, iter_node, &tl->iter_flows) {
-        if (flow->serial <= start 
-                && flow_matches_2wild(key, &flow->key)
-                && flow_has_out_port(flow, out_port)) {
-            int error = callback(flow, private);
-            if (error) {
-                position->private[0] = ~(flow->serial - 1);
-                return error;
-            }
-        }
-    }
-    return 0;
-}
-
-static void table_linear_stats(struct sw_table *swt,
-                               struct sw_table_stats *stats)
-{
-    struct sw_table_linear *tl = (struct sw_table_linear *) swt;
-    stats->name = "linear";
-    stats->wildcards = OFPFW_ALL;
-    stats->n_flows   = tl->n_flows;
-    stats->max_flows = tl->max_flows;
-    stats->n_lookup  = swt->n_lookup;
-    stats->n_matched = swt->n_matched;
-}
-
-
-struct sw_table *table_linear_create(unsigned int max_flows)
-{
-    struct sw_table_linear *tl;
-    struct sw_table *swt;
-
-    tl = calloc(1, sizeof *tl);
-    if (tl == NULL)
-        return NULL;
-
-    swt = &tl->swt;
-    swt->lookup = table_linear_lookup;
-    swt->insert = table_linear_insert;
-    swt->modify = table_linear_modify;
-    swt->delete = table_linear_delete;
-    swt->timeout = table_linear_timeout;
-    swt->destroy = table_linear_destroy;
-    swt->iterate = table_linear_iterate;
-    swt->stats = table_linear_stats;
-
-    tl->max_flows = max_flows;
-    tl->n_flows = 0;
-    list_init(&tl->flows);
-    list_init(&tl->iter_flows);
-    tl->next_serial = 0;
-
-    return swt;
-}
diff --git a/switch/table.h b/switch/table.h
deleted file mode 100644 (file)
index 011591c..0000000
+++ /dev/null
@@ -1,142 +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.
- */
-
-/* Individual switching tables.  Generally grouped together in a chain (see
- * chain.h). */
-
-#ifndef TABLE_H
-#define TABLE_H 1
-
-#include <stddef.h>
-#include <stdint.h>
-
-struct sw_flow;
-struct sw_flow_key;
-struct ofp_action_header;
-struct list;
-
-/* Table statistics. */
-struct sw_table_stats {
-    const char *name;            /* Human-readable name. */
-    uint32_t wildcards;          /* Bitmap of OFPFW_* wildcards that are
-                                    supported by the table. */
-    unsigned int n_flows;        /* Number of active flows. */
-    unsigned int max_flows;      /* Flow capacity. */
-    unsigned long int n_lookup;  /* Number of packets looked up. */
-    unsigned long int n_matched; /* Number of packets that have hit. */
-};
-
-/* Position within an iteration of a sw_table.
- *
- * The contents are private to the table implementation, except that a position
- * initialized to all-zero-bits represents the start of a table. */
-struct sw_table_position {
-    unsigned long private[4];
-};
-
-/* A single table of flows.  */
-struct sw_table {
-    /* The number of packets that have been looked up and matched,
-     * respecitvely.  To make these 100% accurate, they should be atomic.  
-     * However, we're primarily concerned about speed. */
-    unsigned long long n_lookup;
-    unsigned long long n_matched;
-
-    /* Searches 'table' for a flow matching 'key', which must not have any
-     * wildcard fields.  Returns the flow if successful, a null pointer
-     * otherwise. */
-    struct sw_flow *(*lookup)(struct sw_table *table,
-                              const struct sw_flow_key *key);
-
-    /* Inserts 'flow' into 'table', replacing any duplicate flow.  Returns
-     * 0 if successful or a negative error.  Error can be due to an
-     * over-capacity table or because the flow is not one of the kind that
-     * the table accepts.
-     *
-     * If successful, 'flow' becomes owned by 'table', otherwise it is
-     * retained by the caller. */
-    int (*insert)(struct sw_table *table, struct sw_flow *flow);
-
-    /* Modifies the actions in 'table' that match 'key'.  If 'strict'
-     * set, wildcards and priority must match.  Returns the number of flows 
-     * that were modified. */
-    int (*modify)(struct sw_table *table, const struct sw_flow_key *key,
-            uint16_t priority, int strict,
-            const struct ofp_action_header *actions, size_t actions_len);
-
-    /* Deletes from 'table' any and all flows that match 'key' from
-     * 'table'.  If 'out_port' is not OFPP_NONE, then matching entries
-     * must have that port as an argument for an output action.  If 
-     * 'strict' is set, wildcards and priority must match.  Returns the 
-     * number of flows that were deleted. */
-    int (*delete)(struct sw_table *table, const struct sw_flow_key *key, 
-                  uint16_t out_port, uint16_t priority, int strict);
-
-    /* Performs timeout processing on all the flow entries in 'table'.
-     * Appends all the flow entries removed from 'table' to 'deleted' for the
-     * caller to free. */
-    void (*timeout)(struct sw_table *table, struct list *deleted);
-
-    /* Destroys 'table', which must not have any users. */
-    void (*destroy)(struct sw_table *table);
-
-    /* Iterates through the flow entries in 'table', passing each one
-     * matches 'key' and output port 'out_port' to 'callback'.  The 
-     * callback function should return 0 to continue iteration or a 
-     * nonzero error code to stop.  The iterator function returns either 
-     * 0 if the table iteration completed or the value returned by the 
-     * callback function otherwise.
-     *
-     * The iteration starts at 'position', which may be initialized to
-     * all-zero-bits to iterate from the beginning of the table.  If the
-     * iteration terminates due to an error from the callback function,
-     * 'position' is updated to a value that can be passed back to the
-     * iterator function to resume iteration later with the following
-     * flow. */
-    int (*iterate)(struct sw_table *table,
-               const struct sw_flow_key *key, uint16_t out_port,
-               struct sw_table_position *position,
-               int (*callback)(struct sw_flow *flow, void *private),
-               void *private);
-
-    /* Dumps statistics for 'table' into 'stats'. */
-    void (*stats)(struct sw_table *table, struct sw_table_stats *stats);
-};
-
-struct sw_table *table_hash_create(unsigned int polynomial,
-                                   unsigned int n_buckets);
-struct sw_table *table_hash2_create(unsigned int poly0, unsigned int buckets0,
-                                    unsigned int poly1, unsigned int buckets1);
-struct sw_table *table_linear_create(unsigned int max_flows);
-
-#endif /* table.h */
index ad992c5..f2414e5 100644 (file)
@@ -1,7 +1,7 @@
 .TH udatapath 8 "May 2008" "OpenFlow" "OpenFlow Manual"
 
 .SH NAME
 .TH udatapath 8 "May 2008" "OpenFlow" "OpenFlow Manual"
 
 .SH NAME
-udatapath \- userspace implementation of OpenFlow switch
+udatapath \- userspace implementation of datapath for OpenFlow switch
 
 .SH SYNOPSIS
 .B udatapath
 
 .SH SYNOPSIS
 .B udatapath
index 595148e..6f86124 100644 (file)
@@ -505,6 +505,6 @@ Delete the datapath:
 .SH "SEE ALSO"
 
 .BR secchan (8),
 .SH "SEE ALSO"
 
 .BR secchan (8),
-.BR switch (8),
 .BR controller (8),
 .BR controller (8),
+.BR udatapath (8),
 .BR vlogconf (8)
 .BR vlogconf (8)
index 58bee97..99572da 100644 (file)
@@ -318,8 +318,8 @@ Prints a help usage message and exits.
 
 .SH "SEE ALSO"
 
 
 .SH "SEE ALSO"
 
-.BR ofp\-pki\-cgi (8),
+.BR controller (8),
 .BR dpctl (8),
 .BR dpctl (8),
-.BR switch (8),
+.BR ofp\-pki\-cgi (8),
 .BR secchan (8),
 .BR secchan (8),
-.BR controller (8)
+.BR udatapath (8)