From: Ben Pfaff Date: Tue, 6 Jan 2009 22:01:20 +0000 (-0800) Subject: Remove userspace switch in favor of the superior userspace datapath. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cbde61ac45a40c4ed41693a894d87d97b3479963;p=openvswitch Remove userspace switch in favor of the superior userspace datapath. --- diff --git a/INSTALL b/INSTALL index 8f558b41..fc7d3f7c 100644 --- a/INSTALL +++ b/INSTALL @@ -8,8 +8,8 @@ reference implementation of OpenFlow. Please send any comments to: 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 @@ -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. - - 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. @@ -184,8 +175,6 @@ distribution in the ordinary way using "configure" and "make". - Tests: various binaries in tests/. - - Switch executable: switch/switch. - 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. - 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 @@ -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 - switch. + datapath-based switch. - 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 - switch. + datapath-based switch. 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. -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 ============ @@ -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. - The (deprecated) userspace switch does not support in-band - control. - 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. -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 ============= @@ -744,9 +664,8 @@ controllerca subdirectory contains controller certificate authority 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 @@ -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, -respectively, of switch and secchan would point to these files. +respectively, of secchan would point to these files. Bug Reporting ------------- diff --git a/Makefile.am b/Makefile.am index dadf8480..84fb6e79 100644 --- a/Makefile.am +++ b/Makefile.am @@ -64,7 +64,6 @@ include lib/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 diff --git a/README b/README index 28cfab9c..8b9b7bd2 100644 --- a/README +++ b/README @@ -30,10 +30,10 @@ Specification [2]. 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. @@ -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). -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 diff --git a/controller/controller.8.in b/controller/controller.8.in index b608c939..a2662523 100644 --- a/controller/controller.8.in +++ b/controller/controller.8.in @@ -171,6 +171,6 @@ To bind locally to port 6633 (the default) and wait for incoming connections fro .SH "SEE ALSO" .BR dpctl (8), -.BR switch (8), .BR secchan (8), +.BR udatapath (8), .BR vlogconf (8) diff --git a/debian/openflow-switch.README.Debian b/debian/openflow-switch.README.Debian index d4b1cb37..d9a931c1 100644 --- a/debian/openflow-switch.README.Debian +++ b/debian/openflow-switch.README.Debian @@ -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 -* This package does not yet support the userspace switch - implementation. +* This package does not yet support the userspace datapath-based + switch implementation. + + -- Ben Pfaff , Tue, 6 Jan 2009 13:52:33 -0800 diff --git a/debian/openflow-switch.install b/debian/openflow-switch.install index 53dc04dc..5a864ba0 100644 --- a/debian/openflow-switch.install +++ b/debian/openflow-switch.install @@ -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 diff --git a/debian/openflow-switch.manpages b/debian/openflow-switch.manpages index e50d9978..b79db3d3 100644 --- a/debian/openflow-switch.manpages +++ b/debian/openflow-switch.manpages @@ -1,6 +1,5 @@ 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 diff --git a/secchan/secchan.8.in b/secchan/secchan.8.in index 79380d02..66bed8fe 100644 --- a/secchan/secchan.8.in +++ b/secchan/secchan.8.in @@ -467,5 +467,5 @@ Prints version information to the console. .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 index c55f1fad..00000000 --- a/switch/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/Makefile -/Makefile.in -/switch -/switch.8 diff --git a/switch/TODO b/switch/TODO deleted file mode 100644 index c4377330..00000000 --- a/switch/TODO +++ /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 index d9826f4c..00000000 --- a/switch/automake.mk +++ /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 index 8f09c00e..00000000 --- a/switch/chain.c +++ /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 -#include "chain.h" -#include -#include -#include -#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 index 9ffe072d..00000000 --- a/switch/chain.h +++ /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 -#include - -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 index f6c2c0b3..00000000 --- a/switch/crc32.c +++ /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 -#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 index 355aefdf..00000000 --- a/switch/crc32.h +++ /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 -#include - -#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 index 452d471b..00000000 --- a/switch/datapath.c +++ /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 -#include -#include -#include -#include -#include -#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); -} - - -/* '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); -} - -/* 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 index 56d5324f..00000000 --- a/switch/datapath.h +++ /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 -#include -#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 index 3322d9fe..00000000 --- a/switch/dp_act.c +++ /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 -#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 index e0181fad..00000000 --- a/switch/dp_act.h +++ /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 index e2a6d4f6..00000000 --- a/switch/nx_act.c +++ /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 index 92d10654..00000000 --- a/switch/nx_act.h +++ /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 index 82eee55d..00000000 --- a/switch/switch-flow.c +++ /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 -#include "switch-flow.h" -#include -#include -#include -#include -#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 index ef0497c8..00000000 --- a/switch/switch-flow.h +++ /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 -#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 index c6aa6060..00000000 --- a/switch/switch.8.in +++ /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 index fba88585..00000000 --- a/switch/switch.c +++ /dev/null @@ -1,308 +0,0 @@ -/* Copyright (c) 2008 The Board of Trustees of The Leland Stanford - * Junior University - * - * We are making the OpenFlow specification and associated documentation - * (Software) available for public use and benefit with the expectation - * that others will use, modify and enhance the Software and contribute - * those enhancements back to the community. However, since we would - * like to make the Software available for broadest use, with as few - * restrictions as possible permission is hereby granted, free of - * charge, to any person obtaining a copy of this Software to deal in - * the Software under the copyrights without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * The name and trademarks of copyright holder(s) may NOT be used in - * advertising or publicity pertaining to the Software or any - * derivatives without specific, written prior permission. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#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 index 6b5e9457..00000000 --- a/switch/table-hash.c +++ /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 -#include "table.h" -#include -#include -#include -#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 index 1ec6951c..00000000 --- a/switch/table-linear.c +++ /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 -#include "table.h" -#include -#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 index 011591c6..00000000 --- a/switch/table.h +++ /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 -#include - -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 */ diff --git a/udatapath/udatapath.8.in b/udatapath/udatapath.8.in index ad992c5d..f2414e5c 100644 --- a/udatapath/udatapath.8.in +++ b/udatapath/udatapath.8.in @@ -1,7 +1,7 @@ .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 diff --git a/utilities/dpctl.8.in b/utilities/dpctl.8.in index 595148e9..6f861247 100644 --- a/utilities/dpctl.8.in +++ b/utilities/dpctl.8.in @@ -505,6 +505,6 @@ Delete the datapath: .SH "SEE ALSO" .BR secchan (8), -.BR switch (8), .BR controller (8), +.BR udatapath (8), .BR vlogconf (8) diff --git a/utilities/ofp-pki.8.in b/utilities/ofp-pki.8.in index 58bee973..99572da3 100644 --- a/utilities/ofp-pki.8.in +++ b/utilities/ofp-pki.8.in @@ -318,8 +318,8 @@ Prints a help usage message and exits. .SH "SEE ALSO" -.BR ofp\-pki\-cgi (8), +.BR controller (8), .BR dpctl (8), -.BR switch (8), +.BR ofp\-pki\-cgi (8), .BR secchan (8), -.BR controller (8) +.BR udatapath (8)