Merge branch 'master' of ssh://git.onelab.eu/git/sliver-openvswitch
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Thu, 4 Apr 2013 14:24:57 +0000 (16:24 +0200)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Thu, 4 Apr 2013 14:24:57 +0000 (16:24 +0200)
214 files changed:
AUTHORS
CodingStyle
FAQ
INSTALL
INSTALL.RHEL
Makefile.am
NEWS
OPENFLOW-1.1+
README
README-lisp [new file with mode: 0644]
acinclude.m4
build-aux/extract-ofp-errors
configure.ac
datapath/CAPWAP.txt [deleted file]
datapath/Modules.mk
datapath/actions.c
datapath/datapath.c
datapath/datapath.h
datapath/flow.c
datapath/flow.h
datapath/linux/.gitignore
datapath/linux/Modules.mk
datapath/linux/compat/include/linux/bug.h [deleted file]
datapath/linux/compat/include/linux/etherdevice.h
datapath/linux/compat/include/linux/if_ether.h
datapath/linux/compat/include/linux/if_vlan.h
datapath/linux/compat/include/linux/kernel.h
datapath/linux/compat/include/linux/list.h [new file with mode: 0644]
datapath/linux/compat/include/linux/netdevice.h
datapath/linux/compat/include/linux/rculist.h
datapath/linux/compat/include/linux/rcupdate.h
datapath/linux/compat/include/linux/skbuff.h
datapath/tunnel.c
datapath/tunnel.h
datapath/vport-capwap.c [deleted file]
datapath/vport-capwap.h [deleted file]
datapath/vport-gre.c
datapath/vport-internal_dev.c
datapath/vport-lisp.c [new file with mode: 0644]
datapath/vport-vxlan.c
datapath/vport.c
datapath/vport.h
debian/changelog
debian/control
debian/copyright.in
debian/ifupdown.sh
debian/openvswitch-switch.init
include/linux/automake.mk
include/linux/if_ether.h [new file with mode: 0644]
include/linux/openvswitch.h
include/openflow/nicira-ext.h
include/openflow/openflow-1.1.h
include/openflow/openflow-1.3.h
include/openvswitch/automake.mk
include/openvswitch/tunnel.h [deleted file]
lib/automake.mk
lib/autopath.c [deleted file]
lib/autopath.h [deleted file]
lib/bond.c
lib/bond.h
lib/classifier.c
lib/classifier.h
lib/dpif-linux.c
lib/dpif-netdev.c
lib/dpif.h
lib/flow.c
lib/flow.h
lib/json.c
lib/json.h
lib/jsonrpc.c
lib/jsonrpc.h
lib/list.h
lib/match.c
lib/match.h
lib/meta-flow.c
lib/meta-flow.h
lib/netdev-dummy.c
lib/netdev-linux.c
lib/netdev-vport.c
lib/netdev.c
lib/netdev.h
lib/netlink-socket.c
lib/nx-match.c
lib/nx-match.h
lib/odp-util.c
lib/odp-util.h
lib/ofp-actions.c
lib/ofp-actions.h
lib/ofp-msgs.c
lib/ofp-msgs.h
lib/ofp-parse.c
lib/ofp-print.c
lib/ofp-util.c
lib/ofp-util.def
lib/ofp-util.h
lib/ofpbuf.c
lib/ofpbuf.h
lib/ovsdb-data.c
lib/ovsdb-data.h
lib/ovsdb-idl.c
lib/ovsdb-idl.h
lib/packets.c
lib/packets.h
lib/pcap-file.c [moved from lib/pcap.c with 99% similarity]
lib/pcap-file.h [moved from lib/pcap.h with 92% similarity]
lib/poll-loop.c
lib/process.c
lib/reconnect.c
lib/simap.c
lib/simap.h
lib/socket-util.c
lib/stream-unix.c
lib/timeval.c
lib/timeval.h
lib/unixctl.c
lib/util.c
lib/vlog.c
lib/vlog.h
lib/worker.c
manpages.mk
ofproto/connmgr.c
ofproto/connmgr.h
ofproto/in-band.c
ofproto/ofproto-dpif.c
ofproto/ofproto-provider.h
ofproto/ofproto.c
ofproto/ofproto.h
ofproto/tunnel.c
ofproto/tunnel.h
ovsdb/file.c
ovsdb/jsonrpc-server.c
ovsdb/log.c
ovsdb/ovsdb-idlc.in
ovsdb/ovsdb-tool.c
ovsdb/ovsdb.h
planetlab/exp-tool/Makefile
planetlab/exp-tool/tunproxy.c [new file with mode: 0644]
planetlab/scripts/sliver-ovs.in
python/ovs/db/types.py
python/ovs/stream.py
python/ovs/vlog.py
rhel/README.RHEL
rhel/automake.mk
rhel/etc_init.d_openvswitch
rhel/etc_logrotate.d_openvswitch
rhel/etc_sysconfig_network-scripts_ifup-ovs
rhel/openvswitch-kmod-rhel6.spec.in
rhel/openvswitch-kmod.files [new file with mode: 0644]
tests/atlocal.in
tests/automake.mk
tests/autopath.at [deleted file]
tests/interface-reconfigure.at
tests/jsonrpc-py.at
tests/jsonrpc.at
tests/lacp.at
tests/learn.at
tests/library.at
tests/odp.at
tests/ofp-actions.at
tests/ofp-print.at
tests/ofproto-dpif.at
tests/ofproto-macros.at
tests/ofproto.at
tests/ovs-monitor-ipsec.at
tests/ovs-ofctl.at
tests/ovs-vsctl.at
tests/ovs-xapi-sync.at
tests/ovsdb-execution.at
tests/ovsdb-idl.at
tests/ovsdb-macros.at
tests/ovsdb-monitor.at
tests/ovsdb-server.at
tests/ovsdb-tool.at
tests/test-bundle.c
tests/test-classifier.c
tests/test-flows.c
tests/test-json.c
tests/test-multipath.c
tests/test-odp.c
tests/test-ovsdb.c
tests/test-sflow.c [new file with mode: 0644]
tests/test-unix-socket.py [new file with mode: 0644]
tests/testsuite.at
tests/tunnel.at
tests/vconn.at
utilities/bugtool/automake.mk
utilities/bugtool/ovs-bugtool-ovs-appctl-dpif [new file with mode: 0755]
utilities/bugtool/ovs-bugtool-ovs-ofctl-dump-flows [new file with mode: 0755]
utilities/bugtool/ovs-bugtool-ovs-ofctl-show [new file with mode: 0755]
utilities/bugtool/ovs-bugtool-vsctl-show
utilities/bugtool/ovs-bugtool.8.in
utilities/bugtool/ovs-bugtool.in
utilities/bugtool/plugins/network-status/openvswitch.xml
utilities/ovs-ctl.in
utilities/ovs-dpctl.8.in
utilities/ovs-dpctl.c
utilities/ovs-lib.in
utilities/ovs-ofctl.8.in
utilities/ovs-ofctl.c
utilities/ovs-pki.in
utilities/ovs-save
utilities/ovs-vsctl.8.in
utilities/ovs-vsctl.c
vswitchd/bridge.c
vswitchd/ovs-vswitchd.8.in
vswitchd/vswitch.ovsschema
vswitchd/vswitch.xml
xenserver/README
xenserver/etc_init.d_openvswitch
xenserver/etc_logrotate.d_openvswitch
xenserver/etc_xapi.d_plugins_openvswitch-cfg-update
xenserver/openvswitch-xen.spec.in
xenserver/opt_xensource_libexec_InterfaceReconfigureVswitch.py
xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py

diff --git a/AUTHORS b/AUTHORS
index 2e55522..2ca0c2b 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -6,6 +6,7 @@ Alexey I. Froloff       raorn@altlinux.org
 Andrew Evans            aevans@nicira.com
 Andrew Lambeth          wal@nicira.com
 Andy Southgate          andy.southgate@citrix.com
+Andy Zhou               azhou@nicira.com
 Anupam Chanda           achanda@nicira.com
 Arun Sharma             arun.sharma@calsoftinc.com
 Ben Pfaff               blp@nicira.com
@@ -15,6 +16,7 @@ Bryan Phillippe         bp@toroki.com
 Casey Barker            crbarker@google.com
 Chris Wright            chrisw@sous-sol.org
 Chuck Short             zulcss@ubuntu.com
+Damien Millescamps      damien.millescamps@6wind.com
 Dan Carpenter           dan.carpenter@oracle.com
 Dan Wendlandt           dan@nicira.com
 Daniel Roman            droman@nicira.com
@@ -48,6 +50,7 @@ Keith Amidon            keith@nicira.com
 Krishna Kondaka         kkondaka@vmware.com
 Kyle Mestery            kmestery@cisco.com
 Leo Alterman            lalterman@nicira.com
+Lorand Jakab            lojakab@cisco.com
 Luca Giraudo            lgiraudo@nicira.com
 Martin Casado           casado@nicira.com
 Mehak Mahajan           mmahajan@nicira.com
@@ -61,6 +64,7 @@ Pravin B Shelar         pshelar@nicira.com
 Raju Subramanian        rsubramanian@nicira.com
 Ravi Kerur              Ravi.Kerur@telekom.com
 Reid Price              reid@nicira.com
+Rich Lane               rlane@bigswitch.com
 Rob Hoes                rob.hoes@citrix.com
 Romain Lenglet          romain.lenglet@berabera.info
 Sajjad Lateef           slateef@nicira.com
@@ -68,6 +72,7 @@ Sanjay Sane             ssane@nicira.com
 Shan Wei                davidshan@tencent.com
 Shih-Hao Li             shli@nicira.com
 Simon Horman            horms@verge.net.au
+Stephane A. Sezer       sas@cd80.net
 SUGYO Kazushi           sugyo.org@gmail.com
 Tadaaki Nagao           nagao@stratosphere.co.jp
 Tetsuo NAKAGAWA         nakagawa@mxc.nes.nec.co.jp
@@ -111,6 +116,7 @@ Bryan Fulton            bryan@nicira.com
 Bryan Osoro             bosoro@nicira.com
 Cedric Hobbs            cedric@nicira.com
 Dave Walker             DaveWalker@ubuntu.com
+David Palma             palma@onesource.pt
 Derek Cormier           derek.cormier@lab.ntt.co.jp
 Duffie Cooley           dcooley@nicira.com
 DK Moon                 dkmoon@nicira.com
@@ -138,6 +144,7 @@ Jan Medved              jmedved@juniper.net
 Janis Hamme             janis.hamme@student.kit.edu
 Jari Sundell            sundell.software@gmail.com
 Jed Daniels             openvswitch@jeddaniels.com
+Jeff Merrick            jmerrick@vmware.com
 Jeongkeun Lee           jklee@hp.com
 Jing Ai                 ai_jing2000@hotmail.com
 Joan Cirer              joan@ev0.net
index ee7a0e6..22f0f45 100644 (file)
@@ -249,6 +249,18 @@ details.  (Some compilers also assume that the "if" branch is the more
 common case, so this can be a real form of optimization as well.)
 
 
+RETURN VALUES
+
+  For functions that return a success or failure indication, prefer
+one of the following return value conventions:
+
+    * An "int" where 0 indicates success and a positive errno value
+      indicates a reason for failure.
+
+    * A "bool" where true indicates success and false indicates
+      failure.
+
+
 MACROS
 
   Don't define an object-like macro if an enum can be used instead.
diff --git a/FAQ b/FAQ
index 1a2c4f8..7488112 100644 (file)
--- a/FAQ
+++ b/FAQ
@@ -113,7 +113,6 @@ A: You can start by joining the mailing lists and helping to answer
        http://openvswitch.org/mlists/
 
 
-
 Releases
 --------
 
@@ -167,7 +166,7 @@ Q: What features are not available in the Open vSwitch kernel datapath
 
 A: The kernel module in upstream Linux 3.3 and later does not include
    tunnel virtual ports, that is, interfaces with type "gre",
-   "ipsec_gre", "gre64", "ipsec_gre64", "vxlan", or "capwap".  It is
+   "ipsec_gre", "gre64", "ipsec_gre64", "vxlan", or "lisp".  It is
    possible to create tunnels in Linux and attach them to Open vSwitch
    as system devices.  However, they cannot be dynamically created
    through the OVSDB protocol or set the tunnel ids as a flow action.
@@ -320,6 +319,55 @@ A: No.  ERSPAN is an undocumented proprietary protocol.  As an
    alternative, Open vSwitch supports mirroring to a GRE tunnel (see
    above).
 
+Q: Why are there so many different ways to dump flows?
+
+A: Open vSwitch uses different kinds of flows for different purposes:
+
+      - OpenFlow flows are the most important kind of flow.  OpenFlow
+        controllers use these flows to define a switch's policy.
+        OpenFlow flows support wildcards, priorities, and multiple
+        tables.
+
+        When in-band control is in use, Open vSwitch sets up a few
+        "hidden" flows, with priority higher than a controller or the
+        user can configure, that are not visible via OpenFlow.  (See
+        the "Controller" section of the FAQ for more information
+        about hidden flows.)
+
+      - The Open vSwitch software switch implementation uses a second
+        kind of flow internally.  These flows, called "exact-match"
+        or "datapath" or "kernel" flows, do not support wildcards or
+        priorities and comprise only a single table, which makes them
+        suitable for caching.   OpenFlow flows and exact-match flows
+        also support different actions and number ports differently.
+
+        Exact-match flows are an implementation detail that is
+        subject to change in future versions of Open vSwitch.  Even
+        with the current version of Open vSwitch, hardware switch
+        implementations do not necessarily use exact-match flows.
+
+  Each of the commands for dumping flows has a different purpose:
+
+      - "ovs-ofctl dump-flows <br>" dumps OpenFlow flows, excluding
+        hidden flows.  This is the most commonly useful form of flow
+        dump.  (Unlike the other commands, this should work with any
+        OpenFlow switch, not just Open vSwitch.)
+
+      - "ovs-appctl bridge/dump-flows <br>" dumps OpenFlow flows,
+        including hidden flows.  This is occasionally useful for
+        troubleshooting suspected issues with in-band control.
+
+      - "ovs-dpctl dump-flows [dp]" dumps the exact-match flow table
+        entries for a Linux kernel-based datapath.  In Open vSwitch
+        1.10 and later, ovs-vswitchd merges multiple switches into a
+        single datapath, so it will show all the flows on all your
+        kernel-based switches.  This command can occasionally be
+        useful for debugging.
+
+      - "ovs-appctl dpif/dump-flows <br>", new in Open vSwitch 1.10,
+        dumps exact-match flows for only the specified bridge,
+        regardless of the type.
+
 
 Configuration Problems
 ----------------------
@@ -447,6 +495,12 @@ A: Wireless base stations generally only allow packets with the source
    point, so the same problems will show up with the Linux bridge or
    any other way to do bridging.
 
+Q: I can't seem to add my PPP interface to an Open vSwitch bridge.
+
+A: PPP most commonly carries IP packets, but Open vSwitch works only
+   with Ethernet frames.  The correct way to interface PPP to an
+   Ethernet network is usually to use routing instead of switching.
+
 Q: Is there any documentation on the database tables and fields?
 
 A: Yes.  ovs-vswitchd.conf.db(5) is a comprehensive reference.
@@ -520,6 +574,11 @@ A: Suppose that you want to set up bridge br0 connected to physical
 
        ovs-vsctl -- --all destroy QoS -- --all destroy Queue
 
+   If you do want to keep some QoS or Queue records, or the Open
+   vSwitch you are using is older than version 1.8 (which added the
+   --all option), then you will have to destroy QoS and Queue records
+   individually.
+
 Q: I configured Quality of Service (QoS) in my OpenFlow network by
    adding records to the QoS and Queue table, but the results aren't
    what I expect.
@@ -743,8 +802,16 @@ A: The configuration for VLANs in the Open vSwitch database (e.g. via
    You can use "normal switching" as a component of your OpenFlow
    actions, e.g. by putting "normal" into the lists of actions on
    ovs-ofctl or by outputting to OFPP_NORMAL from an OpenFlow
-   controller.  This will only be suitable for some situations,
-   though.
+   controller.  In situations where this is not suitable, you can
+   implement VLAN handling yourself, e.g.:
+
+       - If a packet comes in on an access port, and the flow table
+         needs to send it out on a trunk port, then the flow can add
+         the appropriate VLAN tag with the "mod_vlan_vid" action.
+
+       - If a packet comes in on a trunk port, and the flow table
+         needs to send it out on an access port, then the flow can
+         strip the VLAN tag with the "strip_vlan" action.
 
 Q: I configured ports on a bridge as access ports with different VLAN
    tags, like this:
@@ -778,7 +845,7 @@ A: Open vSwitch 1.9 and earlier support only OpenFlow 1.0 (plus
    for OpenFlow 1.2 and 1.3.  On these versions of Open vSwitch, the
    following command enables OpenFlow 1.0, 1.2, and 1.3 on bridge br0:
 
-       ovs-vsctl set bridge br0 protocols=openflow10,openflow12,openflow13
+       ovs-vsctl set bridge br0 protocols=OpenFlow10,OpenFlow12,OpenFlow13
 
    Support for OpenFlow 1.1 is incomplete enough that it cannot yet be
    enabled, even experimentally.
@@ -938,9 +1005,6 @@ A: Yes, Open vSwitch makes individual bond interfaces visible as
          controller is not configured, this happens implicitly to
          every packet.)
 
-       - The "autopath" Nicira extension action.  However, "autopath"
-         is deprecated and scheduled for removal in February 2013.
-
        - Mirrors configured for output to a bonded port.
 
    It would make a lot of sense for Open vSwitch to present a bond as
@@ -948,6 +1012,88 @@ A: Yes, Open vSwitch makes individual bond interfaces visible as
    implementation of such a feature, please bring it up on the Open
    vSwitch development mailing list at dev@openvswitch.org.
 
+Q: I have a sophisticated network setup involving Open vSwitch, VMs or
+   multiple hosts, and other components.  The behavior isn't what I
+   expect.  Help!
+
+A: To debug network behavior problems, trace the path of a packet,
+   hop-by-hop, from its origin in one host to a remote host.  If
+   that's correct, then trace the path of the response packet back to
+   the origin.
+
+   Usually a simple ICMP echo request and reply ("ping") packet is
+   good enough.  Start by initiating an ongoing "ping" from the origin
+   host to a remote host.  If you are tracking down a connectivity
+   problem, the "ping" will not display any successful output, but
+   packets are still being sent.  (In this case the packets being sent
+   are likely ARP rather than ICMP.)
+
+   Tools available for tracing include the following:
+
+       - "tcpdump" and "wireshark" for observing hops across network
+         devices, such as Open vSwitch internal devices and physical
+         wires.
+
+       - "ovs-appctl dpif/dump-flows <br>" in Open vSwitch 1.10 and
+         later or "ovs-dpctl dump-flows <br>" in earlier versions.
+         These tools allow one to observe the actions being taken on
+         packets in ongoing flows.
+
+         See ovs-vswitchd(8) for "ovs-appctl dpif/dump-flows"
+         documentation, ovs-dpctl(8) for "ovs-dpctl dump-flows"
+         documentation, and "Why are there so many different ways to
+         dump flows?" above for some background.
+
+       - "ovs-appctl ofproto/trace" to observe the logic behind how
+         ovs-vswitchd treats packets.  See ovs-vswitchd(8) for
+         documentation.  You can out more details about a given flow
+         that "ovs-dpctl dump-flows" displays, by cutting and pasting
+         a flow from the output into an "ovs-appctl ofproto/trace"
+         command.
+
+       - SPAN, RSPAN, and ERSPAN features of physical switches, to
+         observe what goes on at these physical hops.
+
+   Starting at the origin of a given packet, observe the packet at
+   each hop in turn.  For example, in one plausible scenario, you
+   might:
+
+       1. "tcpdump" the "eth" interface through which an ARP egresses
+          a VM, from inside the VM.
+
+       2. "tcpdump" the "vif" or "tap" interface through which the ARP
+          ingresses the host machine.
+
+       3. Use "ovs-dpctl dump-flows" to spot the ARP flow and observe
+          the host interface through which the ARP egresses the
+          physical machine.  You may need to use "ovs-dpctl show" to
+          interpret the port numbers.  If the output seems surprising,
+          you can use "ovs-appctl ofproto/trace" to observe details of
+          how ovs-vswitchd determined the actions in the "ovs-dpctl
+          dump-flows" output.
+
+       4. "tcpdump" the "eth" interface through which the ARP egresses
+          the physical machine.
+
+       5. "tcpdump" the "eth" interface through which the ARP
+          ingresses the physical machine, at the remote host that
+          receives the ARP.
+
+       6. Use "ovs-dpctl dump-flows" to spot the ARP flow on the
+          remote host that receives the ARP and observe the VM "vif"
+          or "tap" interface to which the flow is directed.  Again,
+          "ovs-dpctl show" and "ovs-appctl ofproto/trace" might help.
+
+       7. "tcpdump" the "vif" or "tap" interface to which the ARP is
+          directed.
+
+       8. "tcpdump" the "eth" interface through which the ARP
+          ingresses a VM, from inside the VM.
+
+   It is likely that during one of these steps you will figure out the
+   problem.  If not, then follow the ARP reply back to the origin, in
+   reverse.
+
 Contact 
 -------
 
diff --git a/INSTALL b/INSTALL
index 275e86e..5d62a90 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -202,12 +202,15 @@ Prerequisites section, follow the procedure below to build.
    For improved warnings if you installed "sparse" (see
    "Prerequisites"), add C=1 to the "make" command line.
 
-4. Become root by running "su" or another program.
+4. Consider running the testsuite.  Refer to "Running the Testsuite"
+   below, for instructions.
 
-5. Run "make install" to install the executables and manpages into the
+5. Become root by running "su" or another program.
+
+6. Run "make install" to install the executables and manpages into the
    running system, by default under /usr/local.
 
-6. If you built kernel modules, you may load them with "insmod", e.g.:
+7. If you built kernel modules, you may load them with "insmod", e.g.:
 
       % insmod datapath/linux/openvswitch.ko
 
@@ -267,7 +270,7 @@ Prerequisites section, follow the procedure below to build.
 
       % make modules_install
 
-7. Initialize the configuration database using ovsdb-tool, e.g.:
+8. Initialize the configuration database using ovsdb-tool, e.g.:
 
       % mkdir -p /usr/local/etc/openvswitch
       % ovsdb-tool create /usr/local/etc/openvswitch/conf.db vswitchd/vswitch.ovsschema
@@ -341,6 +344,59 @@ also upgrade the database schema:
 4. Start the Open vSwitch daemons as described under "Building and
    Installing Open vSwitch for Linux or FreeBSD" above.
 
+Running the Testsuite
+=====================
+
+Open vSwitch includes a testsuite.  Before you submit patches
+upstream, we advise that you run the tests and ensure that they pass.
+If you add new features to Open vSwitch, then adding tests for those
+features will ensure your features don't break as developers modify
+other areas of Open vSwitch.
+
+You must configure and build Open vSwitch (steps 1 through 3 in
+"Building and Installing Open vSwitch for Linux or FreeBSD" above)
+before you run the testsuite.  You do not need to install Open vSwitch
+or to build or load the kernel module to run the testsuite.  You do
+not need supervisor privilege to run the testsuite.
+
+To run all the unit tests in Open vSwitch, one at a time:
+      make check
+This takes under 5 minutes on a modern desktop system.
+
+To run all the unit tests in Open vSwitch, up to 8 in parallel:
+      make check TESTSUITEFLAGS=-j8
+This takes under a minute on a modern 4-core desktop system.
+
+To see a list of all the available tests, run:
+      make check TESTSUITEFLAGS=--list
+
+To run only a subset of tests, e.g. test 123 and tests 477 through 484:
+      make check TESTSUITEFLAGS='123 477-484'
+(Tests do not have inter-dependencies, so you may run any subset.)
+
+To run tests matching a keyword, e.g. "ovsdb":
+      make check TESTSUITEFLAGS='-k ovsdb'
+
+To see a complete list of test options:
+      make check TESTSUITEFLAGS=--help
+
+The results of a testing run are reported in tests/testsuite.log.
+Please report test failures as bugs and include the testsuite.log in
+your report.
+
+If you have "valgrind" installed, then you can also run the testsuite
+under valgrind by using "make check-valgrind" in place of "make
+check".  All the same options are available via TESTSUITEFLAGS.  When
+you do this, the "valgrind" results for test <N> are reported in files
+named tests/testsuite.dir/<N>/valgrind.*.  You may find that the
+valgrind results are easier to interpret if you put "-q" in
+~/.valgrindrc, since that reduces the amount of
+
+Sometimes a few tests may fail on some runs but not others.  This is
+usually a bug in the testsuite, not a bug in Open vSwitch itself.  If
+you find that a test fails intermittently, please report it, since the
+developers may not have noticed.
+
 Bug Reporting
 -------------
 
index 874d337..eaa2e7c 100644 (file)
@@ -85,7 +85,8 @@ RHEL.  On RHEL 5, the default RPM source directory is
     which is usually: "kmod-openvswitch", "kmod-openvswitch-xen", and
     "kmod-openvswitch-PAE".
 
-7b. On RHEL 6, to build the Open vSwitch kernel module, run:
+7b. On RHEL 6, to build the Open vSwitch kernel module, copy
+    rhel/openvswitch-kmod.files into the RPM source directory and run:
 
        rpmbuild -bb rhel/openvswitch-kmod-rhel6.spec
 
index bd5e2fc..5dce7aa 100644 (file)
@@ -56,6 +56,7 @@ EXTRA_DIST = \
        OPENFLOW-1.1+ \
        PORTING \
        README-gcov \
+       README-lisp \
        REPORTING-BUGS \
        SubmittingPatches \
        WHY-OVS \
diff --git a/NEWS b/NEWS
index 1164962..cbbe06b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,40 +1,85 @@
-post-v1.9.0
---------------------
+post-v1.10.0
+---------------------
+    - Stable bond mode has been removed.
+    - The autopath action has been removed.
+    - New support for the data encapsulation format of the LISP tunnel
+      protocol (RFC 6830).  An external control plane or manual flow
+      setup is required for EID-to-RLOC mapping.
+    - OpenFlow:
+      * The "dec_mpls_ttl" and "set_mpls_ttl" actions from OpenFlow
+        1.1 and later are now implemented.
+      * New "stack" extension for use in actions, to push and pop from
+        NXM fields.
+    - ovs-dpctl:
+      * New debugging commands "add-flow", "mod-flow", "del-flow".
+
+
+v1.10.0 - xx xxx xxxx
+---------------------
     - Bridge compatibility support has been removed.  Any uses that
       rely on ovs-brcompatd will have to stick with Open vSwitch 1.9.x
       or adapt to native Open vSwitch support (e.g. use ovs-vsctl instead
       of brctl).
     - The maximum size of the MAC learning table is now configurable.
-    - New support for the VXLAN tunnel protocol (see the IETF draft here:
-      http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-02).
     - With the Linux datapath, packets for new flows are now queued
       separately on a per-port basis, so it should no longer be
       possible for a large number of new flows arriving on one port to
       prevent new flows from being processed on other ports.
-    - Many "ovs-vsctl" database commands now accept an --if-exists option.
-      Please refer to the ovs-vsctl manpage for details.
-    - New "vlog/disable-rate-limit" and "vlog/enable-rate-limit" commands
-      available through ovs-appctl allow control over logging rate limits.
-    - The OpenFlow "dp_desc" may now be configured by setting the value of 
-      other-config:dp-desc in the Bridge table.
-    - Path MTU discovery is no longer supported.
+    - ovs-vsctl:
+      * Previously ovs-vsctl would retry connecting to the database forever,
+        causing it to hang if ovsdb-server was not running.  Now, ovs-vsctl
+        only tries once by default (use --retry to try forever).  This change
+        means that you may want to remove uses of --timeout to avoid hangs
+        in ovs-vsctl calls.
+      * Many "ovs-vsctl" database commands now accept an --if-exists option.
+        Please refer to the ovs-vsctl manpage for details.
+    - OpenFlow:
+      - Experimental support for newer versions of OpenFlow.  See
+        the "What versions of OpenFlow does Open vSwitch support?"
+        question in the FAQ for more details.
+      - The OpenFlow "dp_desc" may now be configured by setting the
+        value of other-config:dp-desc in the Bridge table.
+      - It is possible to request the OpenFlow port number with the
+        "ofport_request" column in the Interface table.
+      - The NXM flow_removed message now reports the OpenFlow table ID
+        from which the flow was removed.
+    - Tunneling:
+      - New support for the VXLAN tunnel protocol (see the IETF draft here:
+        http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-03).
+      - Tunneling requires the version of the kernel module paired with
+        Open vSwitch 1.9.0 or later.
+      - Inheritance of the Don't Fragment bit in IP tunnels (df_inherit)
+        is no longer supported.
+      - Path MTU discovery is no longer supported.
+      - CAPWAP tunneling support removed.
+      - Tunnels with multicast destination ports are no longer supported.
+    - ovs-dpctl:
+      - The "dump-flows" and "del-flows" no longer require an argument
+        if only one datapath exists.
+    - ovs-appctl:
+      - New "vlog/disable-rate-limit" and "vlog/enable-rate-limit"
+        commands available allow control over logging rate limits.
+      - New "dpif/dump-dps", "dpif/show", and "dpif/dump-flows" command
+        that mimic the equivalent ovs-dpctl commands.
+    - The ofproto library is now responsible for assigning OpenFlow port
+      numbers.  An ofproto implementation should assign them when
+      port_construct() is called.
+    - All dpif-based bridges of a particular type share a common
+      datapath called "ovs-<type>", e.g. "ovs-system".  The ovs-dpctl
+      commands will now return information on that shared datapath.  To
+      get the equivalent bridge-specific information, use the new
+      "ovs-appctl dpif/*" commands.
     - Backward-incompatible changes:
       - Earlier Open vSwitch versions treated ANY as a wildcard in flow
         syntax.  OpenFlow 1.1 adds a port named ANY, which introduces a
         conflict.  ANY was rarely used in flow syntax, so we chose to
         retire that meaning of ANY in favor of the OpenFlow 1.1 meaning.
-    - Inheritance of the Don't Fragment bit in IP tunnels (df_inherit) is
-      no longer supported.
-    - Patch ports are implemented in userspace.
-    - Tunneling requires the version of the kernel module paired with Open
-      vSwitch 1.9.0 or later.
+    - Patch ports no longer require kernel support, so they now work
+      with FreeBSD and the kernel module built into Linux 3.3 and later.
 
 
-v1.9.0 - xx xxx xxxx
---------------------
-    - The tunneling code no longer assumes input and output keys are symmetric.
-      If they are not, PMTUD needs to be disabled for tunneling to work. Note
-      this only applies to flow-based keys.
+v1.9.0 - 26 Feb 2013
+------------------------
     - Datapath:
       - Support for ipv6 set action.
       - SKB mark matching and setting.
@@ -49,8 +94,14 @@ v1.9.0 - xx xxx xxxx
       - Allow bitwise masking for SHA and THA fields in ARP, SLL and TLL
         fields in IPv6 neighbor discovery messages, and IPv6 flow label.
       - Adds support for writing to the metadata field for a flow.
-      - It is possible to request the OpenFlow port number with the
-        "ofport_request" column in the Interface table.
+    - Tunneling:
+      - The tunneling code no longer assumes input and output keys are
+        symmetric.  If they are not, PMTUD needs to be disabled for
+        tunneling to work. Note this only applies to flow-based keys.
+      - New support for a nonstandard form of GRE that supports a 64-bit key.
+      - Tunnel Path MTU Discovery default value was set to 'disabled'.
+        This feature is deprecated and will be removed soon.
+      - Tunnel header caching removed.
     - ovs-ofctl:
       - Commands and actions that accept port numbers now also accept keywords
         that represent those ports (such as LOCAL, NONE, and ALL).  This is
@@ -60,31 +111,14 @@ v1.9.0 - xx xxx xxxx
     - ovs-dpctl:
       - Support requesting the port number with the "port_no" option in
         the "add-if" command.
-      - The "dump-flows" and "del-flows" no longer require an argument
-        if only one datapath exists.
-    - ovs-appctl:
-      - New "dpif/dump-dps", "dpif/show", and "dpif/dump-flows" command
-        that mimic the equivalent ovs-dpctl commands.
     - ovs-pki: The "online PKI" features have been removed, along with
       the ovs-pki-cgi program that facilitated it, because of some
       alarmist insecurity claims.  We do not believe that these claims
       are true, but because we do not know of any users for this
       feature it seems better on balance to remove it.  (The ovs-pki-cgi
       program was not included in distribution packaging.)
-    - Tunnel Path MTU Discovery default value was set to 'disabled'.  This
-      feature is deprecated and will be removed soon.
     - ovsdb-server now enforces the immutability of immutable columns.  This
       was not enforced in earlier versions due to an oversight.
-    - New support for a nonstandard form of GRE that supports a 64-bit key.
-    - The ofproto library is now responsible for assigning OpenFlow port
-      numbers.  An ofproto implementation should assign them when
-      port_construct() is called.
-    - All dpif-based bridges of a particular type share a common
-      datapath called "ovs-<type>", e.g. "ovs-system".  The ovs-dpctl
-      commands will now return information on that shared datapath.  To
-      get the equivalent bridge-specific information, use the new
-      "ovs-appctl dpif/*" commands.
-    - Tunnel header caching removed.
     - The following features are now deprecated.  They will be removed no
       earlier than February 2013.  Please email dev@openvswitch.org with
       concerns.
@@ -99,8 +133,9 @@ v1.9.0 - xx xxx xxxx
       data in ARP packets.
 
 
-v1.8.0 - xx xxx xxxx
+v1.8.0 - 26 Feb 2013
 ------------------------
+    *** Internal only release ***
     - New FAQ.  Please send updates and additions!
     - Authors of controllers, please read the new section titled "Action
       Reproduction" in DESIGN, which describes an Open vSwitch change in
index 2c55cfe..b6a4222 100644 (file)
@@ -66,12 +66,6 @@ probably incomplete.
       specified.  Check that OVS implements the new behavior, fix it
       if not.
 
-    * On OF1.1+ flow_mods, DELETE now ignores buffer_id.
-
-    * OFPST_PORT and OFPST_QUEUE stats.  These differ little from
-      OF1.0 to OF1.1 (just the size of the port number field) but do
-      require abstraction (Done?).
-
     * OFPT_TABLE_MOD stats.  This is new in OF1.1, so we need to
       implement it.  It should be implemented so that the default OVS
       behavior does not change.
@@ -79,8 +73,7 @@ probably incomplete.
     * Document how OVS does packet buffering.
 
     * MPLS.  Simon Horman maintains a patch series that adds this
-      feature.  It needs review and possible revision before it is
-      merged.
+      feature.  This is partially merged.
 
     * SCTP.  Joe Stringer maintains a patch series that adds this
       feature.  It has received review comments that need to be
@@ -99,7 +92,7 @@ OpenFlow 1.2
 
 OpenFlow 1.2 support requires OpenFlow 1.1 as a prerequisite, plus the
 following additional work.  (This is based on the change log at the
-end of the OF1.2 spec.  I didnt compare the specs carefully yet.)
+end of the OF1.2 spec.  I didn't compare the specs carefully yet.)
 
     * Use new OpenFlow extensible error infrastructure, on OF1.2+
       only, instead of the OVS-specific extension used until now.
@@ -120,9 +113,6 @@ end of the OF1.2 spec.  I didn’t compare the specs carefully yet.)
 
         * Update DESIGN to describe OF1.2 behavior also.
 
-    * Implement OFPT_ROLE_REQUEST.  Patch submitted by Jarno
-      Rajahalme, currently under revision.
-
     * Add ability to turn off packet buffering with OFPCML_NO_BUFFER.
 
 OpenFlow 1.3
@@ -131,7 +121,7 @@ OpenFlow 1.3
 OpenFlow 1.3 support requires OpenFlow 1.2 as a prerequisite, plus the
 following additional work.  (This is based on the change log at the
 end of the OF1.3 spec, reusing most of the section titles directly.  I
-didnt compare the specs carefully yet.)
+didn't compare the specs carefully yet.)
 
     * Add support for multipart requests.
 
@@ -148,28 +138,28 @@ didn’t compare the specs carefully yet.)
       and design requirements.  Might be politically difficult to add
       directly to the kernel module, since its functionality overlaps
       with tc.  Ideally, therefore, we could implement these somehow
-      with tc, but I havent investigated whether that makes sense.
+      with tc, but I haven't investigated whether that makes sense.
 
-    * Per-connection event filtering.  OF1.3 adopted Open vSwitchs
+    * Per-connection event filtering.  OF1.3 adopted Open vSwitch's
       existing design for this feature so implementation should be
       easy.
 
     * Auxiliary connections.  These are optional, so a minimal
       implementation would not need them.  An implementation in
-      generic code might be a weeks worth of work.  The value of an
+      generic code might be a week's worth of work.  The value of an
       implementation in generic code is questionable, though, since
       much of the benefit of axuiliary connections is supposed to be
       to take advantage of hardware support.  (We could make the
       kernel module somehow send packets across the auxiliary
-      connections directly, for some kind of “hardware” support, if we
+      connections directly, for some kind of "hardware" support, if we
       judged it useful enough.)
 
     * MPLS BoS matching.  (Included in Simon's MPLS series?)
 
-    * Provider Backbone Bridge tagging.  I dont plan to implement
-      this (but wed accept an implementation).
+    * Provider Backbone Bridge tagging.  I don't plan to implement
+      this (but we'd accept an implementation).
 
-    * Rework tag order.  Im not sure whether we need to do anything
+    * Rework tag order.  I'm not sure whether we need to do anything
       for this.
 
     * Duration for stats.
@@ -202,7 +192,7 @@ Please consider the following:
       tree).
 
     * The patch submission guidelines (see SubmittingPatches).  I
-      recommend using “git send-email”, which automatically follows a
+      recommend using "git send-email", which automatically follows a
       lot of those guidelines.
 
 Bug Reporting
diff --git a/README b/README
index dc5f05e..f6ffa84 100644 (file)
--- a/README
+++ b/README
@@ -24,7 +24,7 @@ vSwitch supports the following features:
     * NIC bonding with or without LACP on upstream switch
     * NetFlow, sFlow(R), and mirroring for increased visibility
     * QoS (Quality of Service) configuration, plus policing
-    * GRE, GRE over IPSEC, CAPWAP, and VXLAN tunneling
+    * GRE, GRE over IPSEC, VXLAN, and LISP tunneling
     * 802.1ag connectivity fault management
     * OpenFlow 1.0 plus numerous extensions
     * Transactional configuration database with C and Python bindings
diff --git a/README-lisp b/README-lisp
new file mode 100644 (file)
index 0000000..7c9071a
--- /dev/null
@@ -0,0 +1,68 @@
+Using LISP tunneling
+====================
+
+LISP is a layer 3 tunneling mechanism, meaning that encapsulated packets do
+not carry Ethernet headers, and ARP requests shouldn't be sent over the
+tunnel.  Because of this, there are some additional steps required for setting
+up LISP tunnels in Open vSwitch, until support for L3 tunnels will improve.
+
+This guide assumes a point-to-point tunnel between two VMs connected to OVS
+bridges on different hypervisors connected via IPv4.  Of course, more than one
+VM may be connected to any of the hypervisors, using the same LISP tunnel, and
+a hypervisor may be connected to several hypervisors over different LISP
+tunnels.
+
+There are several scenarios:
+
+  1) the VMs have IP addresses in the same subnet and the hypervisors are also
+     in a single subnet (although one different from the VM's);
+  2) the VMs have IP addresses in the same subnet but the hypervisors are
+     separated by a router;
+  3) the VMs are in different subnets.
+
+In cases 1) and 3) ARP resolution can work as normal: ARP traffic is
+configured not to go through the LISP tunnel.  For case 1) ARP is able to
+reach the other VM, if both OVS instances default to MAC address learning.
+Case 3) requires the hypervisor be configured as the default router for the
+VMs.
+
+In case 2) the VMs expect ARP replies from each other, but this is not
+possible over a layer 3 tunnel.  One solution is to have static MAC address
+entries preconfigured on the VMs (e.g., `arp -f /etc/ethers` on startup on
+Unix based VMs), or have the hypervisor do proxy ARP.
+
+On the receiving side, the packet arrives without the original MAC header.
+The LISP tunneling code attaches a header with harcoded source and destination
+MAC addres 02:00:00:00:00:00.  This address has all bits set to 0, except the
+locally administered bit, in order to avoid potential collisions with existing
+allocations.  In order for packets to reach their intended destination, the
+destination MAC address needs to be rewritten.  This can be done using the
+flow table.
+
+See below for an example setup, and the associated flow rules to enable LISP
+tunneling.
+
+               +---+                               +---+
+               |VM1|                               |VM2|
+               +---+                               +---+
+                 |                                   |
+            +--[tap0]--+                       +--[tap0]---+
+            |          |                       |           |
+        [lisp0] OVS1 [eth0]-----------------[eth0] OVS2 [lisp0]
+            |          |                       |           |
+            +----------+                       +-----------+
+
+On each hypervisor, interfaces tap0, eth0, and lisp0 are added to a single
+bridge instance, and become numbered 1, 2, and 3 respectively:
+
+    ovs-vsctl add-br br0
+    ovs-vsctl add-port br0 tap0
+    ovs-vsctl add-port br0 eth0
+    ovs-vsctl add-port br0 lisp0 -- set Interface lisp0 type=lisp options:remote_ip=<OVSx_IP>
+
+Flows on br0 are configured as follows:
+
+    priority=3,dl_dst=02:00:00:00:00:00,action=mod_dl_dst:<VMx_MAC>,output:1
+    priority=2,in_port=1,dl_type=0x0806,action=NORMAL
+    priority=1,in_port=1,dl_type=0x0800,vlan_tci=0,nw_src=<EID_prefix>,action=output:3
+    priority=0,action=NORMAL
index 02dc952..19a47dd 100644 (file)
@@ -1,6 +1,6 @@
 # -*- autoconf -*-
 
-# Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -215,6 +215,10 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
 
   OVS_GREP_IFELSE([$KSRC/include/linux/err.h], [ERR_CAST])
 
+  OVS_GREP_IFELSE([$KSRC/include/linux/etherdevice.h], [eth_hw_addr_random])
+
+  OVS_GREP_IFELSE([$KSRC/include/linux/if_vlan.h], [vlan_set_encap_proto])
+
   OVS_GREP_IFELSE([$KSRC/include/linux/in.h], [ipv4_is_multicast])
 
   OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [dev_disable_lro])
@@ -249,6 +253,7 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
                   [OVS_DEFINE([HAVE_SKB_WARN_LRO])])
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [consume_skb])
   OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [skb_frag_page])
+  OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [skb_reset_mac_len])
 
   OVS_GREP_IFELSE([$KSRC/include/linux/string.h], [kmemdup], [],
                   [OVS_GREP_IFELSE([$KSRC/include/linux/slab.h], [kmemdup])])
@@ -290,6 +295,8 @@ AC_DEFUN([OVS_CHECK_IF_PACKET],
    fi])
 
 dnl Checks for net/if_dl.h.
+dnl
+dnl (We use this as a proxy for checking whether we're building on FreeBSD.)
 AC_DEFUN([OVS_CHECK_IF_DL],
   [AC_CHECK_HEADER([net/if_dl.h],
                    [HAVE_IF_DL=yes],
@@ -298,6 +305,9 @@ AC_DEFUN([OVS_CHECK_IF_DL],
    if test "$HAVE_IF_DL" = yes; then
       AC_DEFINE([HAVE_IF_DL], [1],
                 [Define to 1 if net/if_dl.h is available.])
+
+      # On FreeBSD we use libpcap to access network devices.
+      AC_SEARCH_LIBS([pcap_open_live], [pcap])
    fi])
 
 dnl Checks for buggy strtok_r.
index fd53001..965e322 100755 (executable)
@@ -113,25 +113,25 @@ def parseTaggedName():
     return name
 
 def print_enum(tag, constants, storage_class):
-    print """
+    print ("""
 %(storage_class)sconst char *
 %(tag)s_to_string(uint16_t value)
 {
     switch (value) {\
 """ % {"tag": tag,
        "bufferlen": len(tag) + 32,
-       "storage_class": storage_class}
+       "storage_class": storage_class})
     for constant in constants:
-        print "    case %s: return \"%s\";" % (constant, constant)
-    print """\
+        print ("    case %s: return \"%s\";" % (constant, constant))
+    print ("""\
     }
     return NULL;
 }\
-""" % {"tag": tag}
+""" % {"tag": tag})
 
 def usage():
     argv0 = os.path.basename(sys.argv[0])
-    print '''\
+    print ('''\
 %(argv0)s, for extracting OpenFlow error codes from header files
 usage: %(argv0)s FILE [FILE...]
 
@@ -141,7 +141,7 @@ strings, for use as lib/ofp-errors.c in the Open vSwitch source tree.
 
 This program is specialized for reading lib/ofp-errors.h.  It will not
 work on arbitrary header files without extensions.\
-''' % {"argv0": argv0}
+''' % {"argv0": argv0})
     sys.exit(0)
 
 def extract_ofp_errors(filenames):
@@ -278,14 +278,14 @@ def extract_ofp_errors(filenames):
 
         inputFile.close()
 
-    for fn, ln in expected_errors.itervalues():
+    for fn, ln in expected_errors.values():
         sys.stderr.write("%s:%d: expected duplicate not used.\n" % (fn, ln))
         n_errors += 1
 
     if n_errors:
         sys.exit(1)
 
-    print """\
+    print ("""\
 /* Generated automatically; do not modify!     -*- buffer-read-only: t -*- */
 
 #define OFPERR_N_ERRORS %d
@@ -307,14 +307,14 @@ static const char *error_comments[OFPERR_N_ERRORS] = {
 """ % (len(names),
        '\n'.join('    "%s",' % name for name in names),
        '\n'.join('    "%s",' % re.sub(r'(["\\])', r'\\\1', comment)
-                 for comment in comments))
+                 for comment in comments)))
 
     def output_domain(map, name, description, version):
-        print """
+        print ("""
 static enum ofperr
 %s_decode(uint16_t type, uint16_t code)
 {
-    switch ((type << 16) | code) {""" % name
+    switch ((type << 16) | code) {""" % name)
         found = set()
         for enum in names:
             if enum not in map:
@@ -326,20 +326,20 @@ static enum ofperr
             if value in found:
                 continue
             found.add(value)
-            print "    case (%d << 16) | %d:" % (type_, code)
-            print "        return OFPERR_%s;" % enum
-        print """\
+            print ("    case (%d << 16) | %d:" % (type_, code))
+            print ("        return OFPERR_%s;" % enum)
+        print ("""\
     }
 
     return 0;
-}"""
+}""")
 
-        print """
+        print ("""
 static const struct ofperr_domain %s = {
     "%s",
     %d,
     %s_decode,
-    {""" % (name, description, version, name)
+    {""" % (name, description, version, name))
         for enum in names:
             if enum in map:
                 type_, code = map[enum]
@@ -347,10 +347,10 @@ static const struct ofperr_domain %s = {
                     code = -1
             else:
                 type_ = code = -1
-            print "        { %2d, %3d }, /* %s */" % (type_, code, enum)
-        print """\
+            print ("        { %2d, %3d }, /* %s */" % (type_, code, enum))
+        print ("""\
     },
-};"""
+};""")
 
     output_domain(reverse["OF1.0"], "ofperr_of10", "OpenFlow 1.0", 0x01)
     output_domain(reverse["OF1.1"], "ofperr_of11", "OpenFlow 1.1", 0x02)
index bcfb227..79fb46e 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 AC_PREREQ(2.64)
-AC_INIT(openvswitch, 1.9.90, ovs-bugs@openvswitch.org)
+AC_INIT(openvswitch, 1.10.90, ovs-bugs@openvswitch.org)
 AC_CONFIG_SRCDIR([datapath/datapath.c])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_AUX_DIR([build-aux])
@@ -44,7 +44,6 @@ AC_SYS_LARGEFILE
 AC_SEARCH_LIBS([pow], [m])
 AC_SEARCH_LIBS([clock_gettime], [rt])
 AC_SEARCH_LIBS([timer_create], [rt])
-AC_SEARCH_LIBS([pcap_open_live], [pcap])
 
 OVS_CHECK_ESX
 OVS_CHECK_COVERAGE
@@ -62,7 +61,7 @@ OVS_CHECK_STRTOK_R
 AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec],
   [], [], [[#include <sys/stat.h>]])
 AC_CHECK_FUNCS([mlockall strnlen strsignal getloadavg statvfs setmntent])
-AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h execinfo.h])
+AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h execinfo.h])
 
 OVS_CHECK_PKIDIR
 OVS_CHECK_RUNDIR
diff --git a/datapath/CAPWAP.txt b/datapath/CAPWAP.txt
deleted file mode 100644 (file)
index 5ab6d53..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-
-References:
-* http://www.rfc-editor.org/rfc/rfc5415.txt
-
-
-The CAPWAP header layout is summarized as follows:
-
-
-        0                   1                   2                   3
-        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |CAPWAP Preamble|  HLEN   |   RID   | WBID    |T|F|L|W|M|K|Flags|
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |          Fragment ID          |     Frag Offset         |Rsvd |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |                 (optional) Radio MAC Address                  |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |            (optional) Wireless Specific Information           |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |                        Payload ....                           |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-The spec defines an optional Wireless Specific Information field which can be
-used to pass arbitrary data in the encapsulation layer:
-
-   Wireless Specific Information:  This optional field may be used to carry
-      per-packet information.  This field is only present if the
-      'W' bit is set.  The WBID field in the CAPWAP Header is used to
-      identify the format of the WSI optional field. The HLEN field assumes
-      4-byte alignment, and this field MUST be padded with zeroes (0x00) if it
-      is not 4-byte aligned.
-
-      The Wireless-Specific Information field uses the following format:
-
-        0                   1                   2                   3
-        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |    Length     |                Data...
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-      Length:  The 8-bit field contains the length of the data field,
-         with a maximum size of 255.
-
-      Data:  Wireless-specific information, defined by the wireless-
-         specific binding specified in the CAPWAP Header's WBID field.
-
-
-   WBID:  A 5-bit field that is the wireless binding identifier.  The
-      identifier will indicate the type of wireless packet associated
-      with the radio.  The following values are defined:
-
-      0 -  Reserved
-      1 -  IEEE 802.11
-      2 -  Reserved
-      3 -  EPCGlobal [EPCGlobal]
-
-      When Open vSwitch uses this field, it writes the value:
-      30 - Open vSwitch data
-
-
-Open vSwitch can make use of this field to pass additional packet routing
-information. When needed, it sets the 'W' bit to indicates the WSI field is
-added, and fills the field as follows:
-
-        0                   1                   2                   3
-        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |  WSI_LEN      |K|      Flags  |             Reserved          |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-       |   (optional) 64bit Tunnel Key                                 |
-       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
-       K - flag bit to identify presence of a 64bit tunnel key.
-
-
-Adding WSI fields:  Fields must be written and read in consitent order.  New
-fields may be added, but the existing fields always come first.
index 54c6f13..9941123 100644 (file)
@@ -16,9 +16,9 @@ openvswitch_sources = \
        tunnel.c \
        vlan.c \
        vport.c \
-       vport-capwap.c \
        vport-gre.c \
        vport-internal_dev.c \
+       vport-lisp.c \
        vport-netdev.c \
        vport-vxlan.c
 
@@ -31,13 +31,11 @@ openvswitch_headers = \
        tunnel.h \
        vlan.h \
        vport.h \
-       vport-capwap.h \
        vport-internal_dev.h \
        vport-netdev.h
 
 openvswitch_extras = \
-       README \
-       CAPWAP.txt
+       README
 
 dist_sources = $(foreach module,$(dist_modules),$($(module)_sources))
 dist_headers = $(foreach module,$(dist_modules),$($(module)_headers))
index f638ffc..0dac658 100644 (file)
@@ -38,8 +38,7 @@
 #include "vport.h"
 
 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
-                             const struct nlattr *attr, int len,
-                             struct ovs_key_ipv4_tunnel *tun_key, bool keep_skb);
+                             const struct nlattr *attr, int len, bool keep_skb);
 
 static int make_writable(struct sk_buff *skb, int write_len)
 {
@@ -61,7 +60,7 @@ static int __pop_vlan_tci(struct sk_buff *skb, __be16 *current_tci)
 
        if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
                skb->csum = csum_sub(skb->csum, csum_partial(skb->data
-                                       + ETH_HLEN, VLAN_HLEN, 0));
+                                       + (2 * ETH_ALEN), VLAN_HLEN, 0));
 
        vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);
        *current_tci = vhdr->h_vlan_TCI;
@@ -118,7 +117,7 @@ static int push_vlan(struct sk_buff *skb, const struct ovs_action_push_vlan *vla
 
                if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
                        skb->csum = csum_add(skb->csum, csum_partial(skb->data
-                                       + ETH_HLEN, VLAN_HLEN, 0));
+                                       + (2 * ETH_ALEN), VLAN_HLEN, 0));
 
        }
        __vlan_hwaccel_put_tag(skb, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
@@ -399,8 +398,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb,
 }
 
 static int sample(struct datapath *dp, struct sk_buff *skb,
-                 const struct nlattr *attr,
-                 struct ovs_key_ipv4_tunnel *tun_key)
+                 const struct nlattr *attr)
 {
        const struct nlattr *acts_list = NULL;
        const struct nlattr *a;
@@ -421,12 +419,11 @@ static int sample(struct datapath *dp, struct sk_buff *skb,
        }
 
        return do_execute_actions(dp, skb, nla_data(acts_list),
-                                 nla_len(acts_list), tun_key, true);
+                                 nla_len(acts_list), true);
 }
 
 static int execute_set_action(struct sk_buff *skb,
-                                const struct nlattr *nested_attr,
-                                struct ovs_key_ipv4_tunnel *tun_key)
+                                const struct nlattr *nested_attr)
 {
        int err = 0;
 
@@ -439,22 +436,6 @@ static int execute_set_action(struct sk_buff *skb,
                skb_set_mark(skb, nla_get_u32(nested_attr));
                break;
 
-       case OVS_KEY_ATTR_TUN_ID:
-               /* If we're only using the TUN_ID action, store the value in a
-                * temporary instance of struct ovs_key_ipv4_tunnel on the stack.
-                * If both IPV4_TUNNEL and TUN_ID are being used together we
-                * can't write into the IPV4_TUNNEL action, so make a copy and
-                * write into that version.
-                */
-               if (!OVS_CB(skb)->tun_key)
-                       memset(tun_key, 0, sizeof(*tun_key));
-               else if (OVS_CB(skb)->tun_key != tun_key)
-                       memcpy(tun_key, OVS_CB(skb)->tun_key, sizeof(*tun_key));
-               OVS_CB(skb)->tun_key = tun_key;
-
-               OVS_CB(skb)->tun_key->tun_id = nla_get_be64(nested_attr);
-               break;
-
        case OVS_KEY_ATTR_IPV4_TUNNEL:
                OVS_CB(skb)->tun_key = nla_data(nested_attr);
                break;
@@ -485,8 +466,7 @@ static int execute_set_action(struct sk_buff *skb,
 
 /* Execute a list of actions against 'skb'. */
 static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
-                       const struct nlattr *attr, int len,
-                       struct ovs_key_ipv4_tunnel *tun_key, bool keep_skb)
+                       const struct nlattr *attr, int len, bool keep_skb)
 {
        /* Every output action needs a separate clone of 'skb', but the common
         * case is just a single output action, so that doing a clone and
@@ -525,11 +505,11 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
                        break;
 
                case OVS_ACTION_ATTR_SET:
-                       err = execute_set_action(skb, nla_data(a), tun_key);
+                       err = execute_set_action(skb, nla_data(a));
                        break;
 
                case OVS_ACTION_ATTR_SAMPLE:
-                       err = sample(dp, skb, a, tun_key);
+                       err = sample(dp, skb, a);
                        break;
                }
 
@@ -552,7 +532,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
 
 /* We limit the number of times that we pass into execute_actions()
  * to avoid blowing out the stack in the event that we have a loop. */
-#define MAX_LOOPS 5
+#define MAX_LOOPS 4
 
 struct loop_counter {
        u8 count;               /* Count. */
@@ -576,7 +556,6 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb)
        struct sw_flow_actions *acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
        struct loop_counter *loop;
        int error;
-       struct ovs_key_ipv4_tunnel tun_key;
 
        /* Check whether we've looped too much. */
        loop = &__get_cpu_var(loop_counters);
@@ -590,7 +569,7 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb)
 
        OVS_CB(skb)->tun_key = NULL;
        error = do_execute_actions(dp, skb, acts->actions,
-                                        acts->actions_len, &tun_key, false);
+                                        acts->actions_len, false);
 
        /* Check whether sub-actions looped too much. */
        if (unlikely(loop->looping))
index 04a5e7f..9cd4b0e 100644 (file)
@@ -71,6 +71,13 @@ static DECLARE_DELAYED_WORK(rehash_flow_wq, rehash_flow_table);
 
 int ovs_net_id __read_mostly;
 
+static void ovs_notify(struct sk_buff *skb, struct genl_info *info,
+                      struct genl_multicast_group *grp)
+{
+       genl_notify(skb, genl_info_net(info), info->snd_portid,
+                   grp->id, info->nlhdr, GFP_KERNEL);
+}
+
 /**
  * DOC: Locking:
  *
@@ -158,11 +165,10 @@ static struct hlist_head *vport_hash_bucket(const struct datapath *dp,
 struct vport *ovs_lookup_vport(const struct datapath *dp, u16 port_no)
 {
        struct vport *vport;
-       struct hlist_node *n;
        struct hlist_head *head;
 
        head = vport_hash_bucket(dp, port_no);
-       hlist_for_each_entry_rcu(vport, n, head, dp_hash_node) {
+       hlist_for_each_entry_rcu(vport, head, dp_hash_node) {
                if (vport->port_no == port_no)
                        return vport;
        }
@@ -202,41 +208,37 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
        struct datapath *dp = p->dp;
        struct sw_flow *flow;
        struct dp_stats_percpu *stats;
+       struct sw_flow_key key;
        u64 *stats_counter;
        int error;
+       int key_len;
 
        stats = this_cpu_ptr(dp->stats_percpu);
 
-       if (!OVS_CB(skb)->flow) {
-               struct sw_flow_key key;
-               int key_len;
-
-               /* Extract flow from 'skb' into 'key'. */
-               error = ovs_flow_extract(skb, p->port_no, &key, &key_len);
-               if (unlikely(error)) {
-                       kfree_skb(skb);
-                       return;
-               }
-
-               /* Look up flow. */
-               flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table),
-                                          &key, key_len);
-               if (unlikely(!flow)) {
-                       struct dp_upcall_info upcall;
-
-                       upcall.cmd = OVS_PACKET_CMD_MISS;
-                       upcall.key = &key;
-                       upcall.userdata = NULL;
-                       upcall.portid = p->upcall_portid;
-                       ovs_dp_upcall(dp, skb, &upcall);
-                       consume_skb(skb);
-                       stats_counter = &stats->n_missed;
-                       goto out;
-               }
+       /* Extract flow from 'skb' into 'key'. */
+       error = ovs_flow_extract(skb, p->port_no, &key, &key_len);
+       if (unlikely(error)) {
+               kfree_skb(skb);
+               return;
+       }
 
-               OVS_CB(skb)->flow = flow;
+       /* Look up flow. */
+       flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table), &key, key_len);
+       if (unlikely(!flow)) {
+               struct dp_upcall_info upcall;
+
+               upcall.cmd = OVS_PACKET_CMD_MISS;
+               upcall.key = &key;
+               upcall.userdata = NULL;
+               upcall.portid = p->upcall_portid;
+               ovs_dp_upcall(dp, skb, &upcall);
+               consume_skb(skb);
+               stats_counter = &stats->n_missed;
+               goto out;
        }
 
+       OVS_CB(skb)->flow = flow;
+
        stats_counter = &stats->n_hit;
        ovs_flow_used(OVS_CB(skb)->flow, skb);
        ovs_execute_actions(dp, skb);
@@ -306,7 +308,7 @@ static int queue_gso_packets(struct net *net, int dp_ifindex,
        struct sk_buff *segs, *nskb;
        int err;
 
-       segs = skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM);
+       segs = __skb_gso_segment(skb, NETIF_F_SG | NETIF_F_HW_CSUM, false);
        if (IS_ERR(segs))
                return PTR_ERR(segs);
 
@@ -343,6 +345,43 @@ static int queue_gso_packets(struct net *net, int dp_ifindex,
        return err;
 }
 
+static size_t key_attr_size(void)
+{
+       return    nla_total_size(4)   /* OVS_KEY_ATTR_PRIORITY */
+               + nla_total_size(0)   /* OVS_KEY_ATTR_TUNNEL */
+                 + nla_total_size(8)   /* OVS_TUNNEL_KEY_ATTR_ID */
+                 + nla_total_size(4)   /* OVS_TUNNEL_KEY_ATTR_IPV4_SRC */
+                 + nla_total_size(4)   /* OVS_TUNNEL_KEY_ATTR_IPV4_DST */
+                 + nla_total_size(1)   /* OVS_TUNNEL_KEY_ATTR_TOS */
+                 + nla_total_size(1)   /* OVS_TUNNEL_KEY_ATTR_TTL */
+                 + nla_total_size(0)   /* OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT */
+                 + nla_total_size(0)   /* OVS_TUNNEL_KEY_ATTR_CSUM */
+               + nla_total_size(4)   /* OVS_KEY_ATTR_IN_PORT */
+               + nla_total_size(4)   /* OVS_KEY_ATTR_SKB_MARK */
+               + nla_total_size(12)  /* OVS_KEY_ATTR_ETHERNET */
+               + nla_total_size(2)   /* OVS_KEY_ATTR_ETHERTYPE */
+               + nla_total_size(4)   /* OVS_KEY_ATTR_8021Q */
+               + nla_total_size(0)   /* OVS_KEY_ATTR_ENCAP */
+               + nla_total_size(2)   /* OVS_KEY_ATTR_ETHERTYPE */
+               + nla_total_size(40)  /* OVS_KEY_ATTR_IPV6 */
+               + nla_total_size(2)   /* OVS_KEY_ATTR_ICMPV6 */
+               + nla_total_size(28); /* OVS_KEY_ATTR_ND */
+}
+
+static size_t upcall_msg_size(const struct sk_buff *skb,
+                             const struct nlattr *userdata)
+{
+       size_t size = NLMSG_ALIGN(sizeof(struct ovs_header))
+               + nla_total_size(skb->len) /* OVS_PACKET_ATTR_PACKET */
+               + nla_total_size(key_attr_size()); /* OVS_PACKET_ATTR_KEY */
+
+       /* OVS_PACKET_ATTR_USERDATA */
+       if (userdata)
+               size += NLA_ALIGN(userdata->nla_len);
+
+       return size;
+}
+
 static int queue_userspace_packet(struct net *net, int dp_ifindex,
                                  struct sk_buff *skb,
                                  const struct dp_upcall_info *upcall_info)
@@ -351,7 +390,6 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
        struct sk_buff *nskb = NULL;
        struct sk_buff *user_skb; /* to be queued to userspace */
        struct nlattr *nla;
-       unsigned int len;
        int err;
 
        if (vlan_tx_tag_present(skb)) {
@@ -371,13 +409,7 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
                goto out;
        }
 
-       len = sizeof(struct ovs_header);
-       len += nla_total_size(skb->len);
-       len += nla_total_size(FLOW_BUFSIZE);
-       if (upcall_info->cmd == OVS_PACKET_CMD_ACTION)
-               len += nla_total_size(8);
-
-       user_skb = genlmsg_new(len, GFP_ATOMIC);
+       user_skb = genlmsg_new(upcall_msg_size(skb, upcall_info->userdata), GFP_ATOMIC);
        if (!user_skb) {
                err = -ENOMEM;
                goto out;
@@ -392,13 +424,15 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
        nla_nest_end(user_skb, nla);
 
        if (upcall_info->userdata)
-               nla_put_u64(user_skb, OVS_PACKET_ATTR_USERDATA,
-                           nla_get_u64(upcall_info->userdata));
+               __nla_put(user_skb, OVS_PACKET_ATTR_USERDATA,
+                         nla_len(upcall_info->userdata),
+                         nla_data(upcall_info->userdata));
 
        nla = __nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, skb->len);
 
        skb_copy_and_csum_dev(skb, nla_data(nla));
 
+       genlmsg_end(user_skb, upcall);
        err = genlmsg_unicast(net, user_skb, upcall_info->portid);
 
 out:
@@ -602,7 +636,6 @@ static int validate_set(const struct nlattr *a,
        int err;
 
        case OVS_KEY_ATTR_PRIORITY:
-       case OVS_KEY_ATTR_TUN_ID:
        case OVS_KEY_ATTR_ETHERNET:
                break;
 
@@ -678,7 +711,7 @@ static int validate_userspace(const struct nlattr *attr)
 {
        static const struct nla_policy userspace_policy[OVS_USERSPACE_ATTR_MAX + 1] =   {
                [OVS_USERSPACE_ATTR_PID] = {.type = NLA_U32 },
-               [OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_U64 },
+               [OVS_USERSPACE_ATTR_USERDATA] = {.type = NLA_UNSPEC },
        };
        struct nlattr *a[OVS_USERSPACE_ATTR_MAX + 1];
        int error;
@@ -819,8 +852,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
 
        err = -EINVAL;
        if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] ||
-           !a[OVS_PACKET_ATTR_ACTIONS] ||
-           nla_len(a[OVS_PACKET_ATTR_PACKET]) < ETH_HLEN)
+           !a[OVS_PACKET_ATTR_ACTIONS])
                goto err;
 
        len = nla_len(a[OVS_PACKET_ATTR_PACKET]);
@@ -830,7 +862,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
                goto err;
        skb_reserve(packet, NET_IP_ALIGN);
 
-       memcpy(__skb_put(packet, len), nla_data(a[OVS_PACKET_ATTR_PACKET]), len);
+       nla_memcpy(__skb_put(packet, len), a[OVS_PACKET_ATTR_PACKET], len);
 
        skb_reset_mac_header(packet);
        eth = eth_hdr(packet);
@@ -838,7 +870,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
        /* Normally, setting the skb 'protocol' field would be handled by a
         * call to eth_type_trans(), but it assumes there's a sending
         * device, which we may not have. */
-       if (ntohs(eth->h_proto) >= 1536)
+       if (ntohs(eth->h_proto) >= ETH_P_802_3_MIN)
                packet->protocol = eth->h_proto;
        else
                packet->protocol = htons(ETH_P_802_2);
@@ -895,7 +927,11 @@ err:
 }
 
 static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
-       [OVS_PACKET_ATTR_PACKET] = { .type = NLA_UNSPEC },
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
+       [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN },
+#else
+       [OVS_PACKET_ATTR_PACKET] = { .minlen = ETH_HLEN },
+#endif
        [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
        [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
 };
@@ -1046,6 +1082,16 @@ static int actions_to_attr(const struct nlattr *attr, int len, struct sk_buff *s
        return 0;
 }
 
+static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts)
+{
+       return NLMSG_ALIGN(sizeof(struct ovs_header))
+               + nla_total_size(key_attr_size()) /* OVS_FLOW_ATTR_KEY */
+               + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */
+               + nla_total_size(1) /* OVS_FLOW_ATTR_TCP_FLAGS */
+               + nla_total_size(8) /* OVS_FLOW_ATTR_USED */
+               + nla_total_size(acts->actions_len); /* OVS_FLOW_ATTR_ACTIONS */
+}
+
 /* Called with genl_lock. */
 static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
                                  struct sk_buff *skb, u32 portid,
@@ -1134,25 +1180,11 @@ error:
 static struct sk_buff *ovs_flow_cmd_alloc_info(struct sw_flow *flow)
 {
        const struct sw_flow_actions *sf_acts;
-       int len;
 
        sf_acts = rcu_dereference_protected(flow->sf_acts,
                                            lockdep_genl_is_held());
 
-       /* OVS_FLOW_ATTR_KEY */
-       len = nla_total_size(FLOW_BUFSIZE);
-       /* OVS_FLOW_ATTR_ACTIONS */
-       len += nla_total_size(sf_acts->actions_len);
-       /* OVS_FLOW_ATTR_STATS */
-       len += nla_total_size(sizeof(struct ovs_flow_stats));
-       /* OVS_FLOW_ATTR_TCP_FLAGS */
-       len += nla_total_size(1);
-       /* OVS_FLOW_ATTR_USED */
-       len += nla_total_size(8);
-
-       len += NLMSG_ALIGN(sizeof(struct ovs_header));
-
-       return genlmsg_new(len, GFP_KERNEL);
+       return genlmsg_new(ovs_flow_cmd_msg_size(sf_acts), GFP_KERNEL);
 }
 
 static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow,
@@ -1281,9 +1313,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (!IS_ERR(reply))
-               genl_notify(reply, genl_info_net(info), info->snd_portid,
-                          ovs_dp_flow_multicast_group.id, info->nlhdr,
-                          GFP_KERNEL);
+               ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
        else
                netlink_set_err(GENL_SOCK(sock_net(skb->sk)), 0,
                                ovs_dp_flow_multicast_group.id, PTR_ERR(reply));
@@ -1370,8 +1400,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
 
        ovs_flow_deferred_free(flow);
 
-       genl_notify(reply, genl_info_net(info), info->snd_portid,
-                   ovs_dp_flow_multicast_group.id, info->nlhdr, GFP_KERNEL);
+       ovs_notify(reply, info, &ovs_dp_flow_multicast_group);
        return 0;
 }
 
@@ -1453,6 +1482,16 @@ static struct genl_multicast_group ovs_dp_datapath_multicast_group = {
        .name = OVS_DATAPATH_MCGROUP
 };
 
+static size_t ovs_dp_cmd_msg_size(void)
+{
+       size_t msgsize = NLMSG_ALIGN(sizeof(struct ovs_header));
+
+       msgsize += nla_total_size(IFNAMSIZ);
+       msgsize += nla_total_size(sizeof(struct ovs_dp_stats));
+
+       return msgsize;
+}
+
 static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb,
                                u32 portid, u32 seq, u32 flags, u8 cmd)
 {
@@ -1491,7 +1530,7 @@ static struct sk_buff *ovs_dp_cmd_build_info(struct datapath *dp, u32 portid,
        struct sk_buff *skb;
        int retval;
 
-       skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       skb = genlmsg_new(ovs_dp_cmd_msg_size(), GFP_KERNEL);
        if (!skb)
                return ERR_PTR(-ENOMEM);
 
@@ -1605,9 +1644,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
 
        rtnl_unlock();
 
-       genl_notify(reply, genl_info_net(info), info->snd_portid,
-                   ovs_dp_datapath_multicast_group.id, info->nlhdr,
-                   GFP_KERNEL);
+       ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
        return 0;
 
 err_destroy_local_port:
@@ -1636,9 +1673,9 @@ static void __dp_destroy(struct datapath *dp)
 
        for (i = 0; i < DP_VPORT_HASH_BUCKETS; i++) {
                struct vport *vport;
-               struct hlist_node *node, *n;
+               struct hlist_node *n;
 
-               hlist_for_each_entry_safe(vport, node, n, &dp->ports[i], dp_hash_node)
+               hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node)
                        if (vport->port_no != OVSP_LOCAL)
                                ovs_dp_detach_port(vport);
        }
@@ -1679,9 +1716,7 @@ static int ovs_dp_cmd_del(struct sk_buff *skb, struct genl_info *info)
 
        __dp_destroy(dp);
 
-       genl_notify(reply, genl_info_net(info), info->snd_portid,
-                   ovs_dp_datapath_multicast_group.id, info->nlhdr,
-                   GFP_KERNEL);
+       ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
 
        return 0;
 }
@@ -1709,9 +1744,7 @@ static int ovs_dp_cmd_set(struct sk_buff *skb, struct genl_info *info)
                return 0;
        }
 
-       genl_notify(reply, genl_info_net(info), info->snd_portid,
-                   ovs_dp_datapath_multicast_group.id, info->nlhdr,
-                   GFP_KERNEL);
+       ovs_notify(reply, info, &ovs_dp_datapath_multicast_group);
 
        return 0;
 }
@@ -1860,10 +1893,8 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, u32 portid,
                return ERR_PTR(-ENOMEM);
 
        retval = ovs_vport_cmd_fill_info(vport, skb, portid, seq, 0, cmd);
-       if (retval < 0) {
-               kfree_skb(skb);
-               return ERR_PTR(retval);
-       }
+       BUG_ON(retval < 0);
+
        return skb;
 }
 
@@ -1967,6 +1998,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (IS_ERR(vport))
                goto exit_unlock;
 
+       err = 0;
        if (a[OVS_VPORT_ATTR_STATS])
                ovs_vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS]));
 
@@ -1977,8 +2009,8 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
                ovs_dp_detach_port(vport);
                goto exit_unlock;
        }
-       genl_notify(reply, genl_info_net(info), info->snd_portid,
-                   ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
+
+       ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
 
 exit_unlock:
        rtnl_unlock();
@@ -2008,10 +2040,16 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
            nla_get_u32(a[OVS_VPORT_ATTR_TYPE]) != vport->ops->type)
                err = -EINVAL;
 
+       reply = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!reply) {
+               err = -ENOMEM;
+               goto exit_unlock;
+       }
+
        if (!err && a[OVS_VPORT_ATTR_OPTIONS])
                err = ovs_vport_set_options(vport, a[OVS_VPORT_ATTR_OPTIONS]);
        if (err)
-               goto exit_unlock;
+               goto exit_free;
 
        if (a[OVS_VPORT_ATTR_STATS])
                ovs_vport_set_stats(vport, nla_data(a[OVS_VPORT_ATTR_STATS]));
@@ -2019,17 +2057,17 @@ static int ovs_vport_cmd_set(struct sk_buff *skb, struct genl_info *info)
        if (a[OVS_VPORT_ATTR_UPCALL_PID])
                vport->upcall_portid = nla_get_u32(a[OVS_VPORT_ATTR_UPCALL_PID]);
 
-       reply = ovs_vport_cmd_build_info(vport, info->snd_portid,
-                                        info->snd_seq, OVS_VPORT_CMD_NEW);
-       if (IS_ERR(reply)) {
-               netlink_set_err(GENL_SOCK(sock_net(skb->sk)), 0,
-                               ovs_dp_vport_multicast_group.id, PTR_ERR(reply));
-               goto exit_unlock;
-       }
+       err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
+                                     info->snd_seq, 0, OVS_VPORT_CMD_NEW);
+       BUG_ON(err < 0);
+
+       ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
 
-       genl_notify(reply, genl_info_net(info), info->snd_portid,
-                   ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
+       rtnl_unlock();
+       return 0;
 
+exit_free:
+       kfree_skb(reply);
 exit_unlock:
        rtnl_unlock();
 exit:
@@ -2064,10 +2102,10 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
        if (IS_ERR(reply))
                goto exit_unlock;
 
+       err = 0;
        ovs_dp_detach_port(vport);
 
-       genl_notify(reply, genl_info_net(info), info->snd_portid,
-                   ovs_dp_vport_multicast_group.id, info->nlhdr, GFP_KERNEL);
+       ovs_notify(reply, info, &ovs_dp_vport_multicast_group);
 
 exit_unlock:
        rtnl_unlock();
@@ -2123,10 +2161,9 @@ static int ovs_vport_cmd_dump(struct sk_buff *skb, struct netlink_callback *cb)
        rcu_read_lock();
        for (i = bucket; i < DP_VPORT_HASH_BUCKETS; i++) {
                struct vport *vport;
-               struct hlist_node *n;
 
                j = 0;
-               hlist_for_each_entry_rcu(vport, n, &dp->ports[i], dp_hash_node) {
+               hlist_for_each_entry_rcu(vport, &dp->ports[i], dp_hash_node) {
                        if (j >= skip &&
                            ovs_vport_cmd_fill_info(vport, skb,
                                                    NETLINK_CB(cb->skb).portid,
@@ -2312,13 +2349,9 @@ static int __init dp_init(void)
        if (err)
                goto error_genl_exec;
 
-       err = ovs_tnl_init();
-       if (err)
-               goto error_wq;
-
        err = ovs_flow_init();
        if (err)
-               goto error_tnl_exit;
+               goto error_wq;
 
        err = ovs_vport_init();
        if (err)
@@ -2348,8 +2381,6 @@ error_vport_exit:
        ovs_vport_exit();
 error_flow_exit:
        ovs_flow_exit();
-error_tnl_exit:
-       ovs_tnl_exit();
 error_wq:
        ovs_workqueues_exit();
 error_genl_exec:
@@ -2367,7 +2398,6 @@ static void dp_cleanup(void)
        rcu_barrier();
        ovs_vport_exit();
        ovs_flow_exit();
-       ovs_tnl_exit();
        ovs_workqueues_exit();
        genl_exec_exit();
 }
index 2b93348..9bc98fb 100644 (file)
@@ -120,7 +120,7 @@ struct ovs_skb_cb {
  * struct dp_upcall - metadata to include with a packet to send to userspace
  * @cmd: One of %OVS_PACKET_CMD_*.
  * @key: Becomes %OVS_PACKET_ATTR_KEY.  Must be nonnull.
- * @userdata: If nonnull, its u64 value is extracted and passed to userspace as
+ * @userdata: If nonnull, its variable-length value is passed to userspace as
  * %OVS_PACKET_ATTR_USERDATA.
  * @portid: Netlink PID to which packet should be sent.  If @portid is 0 then no
  * packet is sent and the packet is accounted in the datapath's @n_lost
index fad9e19..841e8be 100644 (file)
@@ -299,10 +299,10 @@ void ovs_flow_tbl_destroy(struct flow_table *table)
        for (i = 0; i < table->n_buckets; i++) {
                struct sw_flow *flow;
                struct hlist_head *head = flex_array_get(table->buckets, i);
-               struct hlist_node *node, *n;
+               struct hlist_node *n;
                int ver = table->node_ver;
 
-               hlist_for_each_entry_safe(flow, node, n, head, hash_node[ver]) {
+               hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) {
                        hlist_del_rcu(&flow->hash_node[ver]);
                        ovs_flow_free(flow);
                }
@@ -332,7 +332,6 @@ struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *la
 {
        struct sw_flow *flow;
        struct hlist_head *head;
-       struct hlist_node *n;
        int ver;
        int i;
 
@@ -340,7 +339,7 @@ struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *la
        while (*bucket < table->n_buckets) {
                i = 0;
                head = flex_array_get(table->buckets, *bucket);
-               hlist_for_each_entry_rcu(flow, n, head, hash_node[ver]) {
+               hlist_for_each_entry_rcu(flow, head, hash_node[ver]) {
                        if (i < *last) {
                                i++;
                                continue;
@@ -375,11 +374,10 @@ static void flow_table_copy_flows(struct flow_table *old, struct flow_table *new
        for (i = 0; i < old->n_buckets; i++) {
                struct sw_flow *flow;
                struct hlist_head *head;
-               struct hlist_node *n;
 
                head = flex_array_get(old->buckets, i);
 
-               hlist_for_each_entry(flow, n, head, hash_node[old_ver])
+               hlist_for_each_entry(flow, head, hash_node[old_ver])
                        __flow_tbl_insert(new, flow);
        }
        old->keep_flows = true;
@@ -484,7 +482,7 @@ static __be16 parse_ethertype(struct sk_buff *skb)
        proto = *(__be16 *) skb->data;
        __skb_pull(skb, sizeof(__be16));
 
-       if (ntohs(proto) >= 1536)
+       if (ntohs(proto) >= ETH_P_802_3_MIN)
                return proto;
 
        if (skb->len < sizeof(struct llc_snap_hdr))
@@ -500,7 +498,11 @@ static __be16 parse_ethertype(struct sk_buff *skb)
                return htons(ETH_P_802_2);
 
        __skb_pull(skb, sizeof(struct llc_snap_hdr));
-       return llc->ethertype;
+
+       if (ntohs(llc->ethertype) >= ETH_P_802_3_MIN)
+               return llc->ethertype;
+
+       return htons(ETH_P_802_2);
 }
 
 static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
@@ -793,7 +795,6 @@ struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table,
                                struct sw_flow_key *key, int key_len)
 {
        struct sw_flow *flow;
-       struct hlist_node *n;
        struct hlist_head *head;
        u8 *_key;
        int key_start;
@@ -804,7 +805,7 @@ struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table,
 
        _key = (u8 *) key + key_start;
        head = find_bucket(table, hash);
-       hlist_for_each_entry_rcu(flow, n, head, hash_node[table->node_ver]) {
+       hlist_for_each_entry_rcu(flow, head, hash_node[table->node_ver]) {
 
                if (flow->hash == hash &&
                    !memcmp((u8 *)&flow->key + key_start, _key, key_len - key_start)) {
@@ -824,9 +825,9 @@ void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
 
 void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow)
 {
+       BUG_ON(table->count == 0);
        hlist_del_rcu(&flow->hash_node[table->node_ver]);
        table->count--;
-       BUG_ON(table->count < 0);
 }
 
 /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute.  */
@@ -847,9 +848,6 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
        [OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp),
        [OVS_KEY_ATTR_ND] = sizeof(struct ovs_key_nd),
        [OVS_KEY_ATTR_TUNNEL] = -1,
-
-       /* Not upstream. */
-       [OVS_KEY_ATTR_TUN_ID] = sizeof(__be64),
 };
 
 static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
@@ -1133,25 +1131,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
                attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK);
        }
 
-       if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID) &&
-           attrs & (1ULL << OVS_KEY_ATTR_TUNNEL)) {
-               __be64 tun_id;
-
-               err = ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], &swkey->tun_key);
-               if (err)
-                       return err;
-
-               if (!(swkey->tun_key.tun_flags & OVS_TNL_F_KEY))
-                       return -EINVAL;
-
-               tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
-               if (tun_id != swkey->tun_key.tun_id)
-                       return -EINVAL;
-
-               attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID);
-               attrs &= ~(1ULL << OVS_KEY_ATTR_TUNNEL);
-       } else if (attrs & (1ULL << OVS_KEY_ATTR_TUNNEL)) {
-
+       if (attrs & (1ULL << OVS_KEY_ATTR_TUNNEL)) {
                err = ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], &swkey->tun_key);
                if (err)
                        return err;
@@ -1201,7 +1181,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 
        if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) {
                swkey->eth.type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
-               if (ntohs(swkey->eth.type) < 1536)
+               if (ntohs(swkey->eth.type) < ETH_P_802_3_MIN)
                        return -EINVAL;
                attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE);
        } else {
@@ -1301,7 +1281,6 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru
        struct ovs_key_ipv4_tunnel *tun_key = &flow->key.tun_key;
        const struct nlattr *nla;
        int rem;
-       __be64 tun_id = 0;
 
        flow->key.phy.in_port = DP_MAX_PORTS;
        flow->key.phy.priority = 0;
@@ -1322,38 +1301,10 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru
                                flow->key.phy.priority = nla_get_u32(nla);
                                break;
 
-                       case OVS_KEY_ATTR_TUN_ID:
-                               tun_id = nla_get_be64(nla);
-
-                               if (tun_key->ipv4_dst) {
-                                       if (!(tun_key->tun_flags & OVS_TNL_F_KEY))
-                                               return -EINVAL;
-                                       if (tun_key->tun_id != tun_id)
-                                               return -EINVAL;
-                                       break;
-                               }
-                               tun_key->tun_id = tun_id;
-                               tun_key->tun_flags |= OVS_TNL_F_KEY;
-
-                               break;
-
                        case OVS_KEY_ATTR_TUNNEL:
-                               if (tun_key->tun_flags & OVS_TNL_F_KEY) {
-                                       tun_id = tun_key->tun_id;
-                                       err = ipv4_tun_from_nlattr(nla, tun_key);
-                                       if (err)
-                                               return err;
-
-                                       if (!(tun_key->tun_flags & OVS_TNL_F_KEY))
-                                               return -EINVAL;
-
-                                       if (tun_key->tun_id != tun_id)
-                                               return -EINVAL;
-                               } else {
-                                       err = ipv4_tun_from_nlattr(nla, tun_key);
-                                       if (err)
-                                               return err;
-                               }
+                               err = ipv4_tun_from_nlattr(nla, tun_key);
+                               if (err)
+                                       return err;
                                break;
 
                        case OVS_KEY_ATTR_IN_PORT:
@@ -1394,10 +1345,6 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
            ipv4_tun_to_nlattr(skb, &swkey->tun_key))
                goto nla_put_failure;
 
-       if ((swkey->tun_key.tun_flags & OVS_TNL_F_KEY) &&
-           nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->tun_key.tun_id))
-               goto nla_put_failure;
-
        if (swkey->phy.in_port != DP_MAX_PORTS &&
            nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port))
                goto nla_put_failure;
index 6949640..dba66cf 100644 (file)
@@ -158,43 +158,13 @@ int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *,
 void ovs_flow_used(struct sw_flow *, struct sk_buff *);
 u64 ovs_flow_used_time(unsigned long flow_jiffies);
 
-/* Upper bound on the length of a nlattr-formatted flow key.  The longest
- * nlattr-formatted flow key would be:
- *
- *                                     struct  pad  nl hdr  total
- *                                     ------  ---  ------  -----
- *  OVS_KEY_ATTR_PRIORITY                4    --     4      8
- *  OVS_KEY_ATTR_TUN_ID                  8    --     4     12
- *  OVS_KEY_ATTR_TUNNEL                  0    --     4      4
- *  - OVS_TUNNEL_KEY_ATTR_ID             8    --     4     12
- *  - OVS_TUNNEL_KEY_ATTR_IPV4_SRC       4    --     4      8
- *  - OVS_TUNNEL_KEY_ATTR_IPV4_DST       4    --     4      8
- *  - OVS_TUNNEL_KEY_ATTR_TOS            1    3      4      8
- *  - OVS_TUNNEL_KEY_ATTR_TTL            1    3      4      8
- *  - OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT  0    --     4      4
- *  - OVS_TUNNEL_KEY_ATTR_CSUM           0    --     4      4
- *  OVS_KEY_ATTR_IN_PORT                 4    --     4      8
- *  OVS_KEY_ATTR_SKB_MARK                4    --     4      8
- *  OVS_KEY_ATTR_ETHERNET               12    --     4     16
- *  OVS_KEY_ATTR_ETHERTYPE               2     2     4      8  (outer VLAN ethertype)
- *  OVS_KEY_ATTR_8021Q                   4    --     4      8
- *  OVS_KEY_ATTR_ENCAP                   0    --     4      4  (VLAN encapsulation)
- *  OVS_KEY_ATTR_ETHERTYPE               2     2     4      8  (inner VLAN ethertype)
- *  OVS_KEY_ATTR_IPV6                   40    --     4     44
- *  OVS_KEY_ATTR_ICMPV6                  2     2     4      8
- *  OVS_KEY_ATTR_ND                     28    --     4     32
- *  ----------------------------------------------------------
- *  total                                                 220
- */
-#define FLOW_BUFSIZE 220
-
 int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *);
 int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
                      const struct nlattr *);
 int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len,
                                   const struct nlattr *attr);
 
-#define MAX_ACTIONS_BUFSIZE    (16 * 1024)
+#define MAX_ACTIONS_BUFSIZE    (32 * 1024)
 #define TBL_MIN_BUCKETS                1024
 
 struct flow_table {
index 901b2a8..16fbc8a 100644 (file)
 /tmp
 /tunnel.c
 /vlan.c
-/vport-capwap.c
 /vport-generic.c
 /vport-gre.c
 /vport-internal_dev.c
+/vport-lisp.c
 /vport-netdev.c
 /vport-patch.c
 /vport-vxlan.c
index 4fabc45..4324336 100644 (file)
@@ -14,7 +14,6 @@ openvswitch_sources += \
        linux/compat/workqueue.c
 openvswitch_headers += \
        linux/compat/include/asm/percpu.h \
-       linux/compat/include/linux/bug.h \
        linux/compat/include/linux/compiler.h \
        linux/compat/include/linux/compiler-gcc.h \
        linux/compat/include/linux/cpumask.h \
@@ -36,6 +35,7 @@ openvswitch_headers += \
        linux/compat/include/linux/jiffies.h \
        linux/compat/include/linux/kernel.h \
        linux/compat/include/linux/kobject.h \
+       linux/compat/include/linux/list.h \
        linux/compat/include/linux/lockdep.h \
        linux/compat/include/linux/log2.h \
        linux/compat/include/linux/mutex.h \
diff --git a/datapath/linux/compat/include/linux/bug.h b/datapath/linux/compat/include/linux/bug.h
deleted file mode 100644 (file)
index d24e68e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __BUG_H_WRAPPER
-#define __BUG_H_WRAPPER 1
-
-#include_next <linux/bug.h>
-
-#ifndef BUILD_BUG_ON_NOT_POWER_OF_2
-/* Force a compilation error if a constant expression is not a power of 2 */
-#define BUILD_BUG_ON_NOT_POWER_OF_2(n)                 \
-       BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0))
-#endif
-
-#endif
index b2c3353..eb7123e 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/version.h>
 #include_next <linux/etherdevice.h>
 
+#ifndef HAVE_ETH_HW_ADDR_RANDOM
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
 static inline void eth_hw_addr_random(struct net_device *dev)
 {
@@ -15,6 +16,7 @@ static inline void eth_hw_addr_random(struct net_device *dev)
        dev_hw_addr_random(dev, dev->dev_addr);
 }
 #endif
+#endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)
 #define eth_mac_addr rpl_eth_mac_addr
index 41cc053..85b0d22 100644 (file)
@@ -16,4 +16,8 @@
 
 #endif /* linux kernel < 2.6.30 */
 
+#ifndef ETH_P_802_3_MIN
+#define ETH_P_802_3_MIN        0x0600
+#endif
+
 #endif
index dc4b15e..b8b1961 100644 (file)
@@ -55,7 +55,7 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
 #define VLAN_TAG_PRESENT       VLAN_CFI_MASK
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
+#ifndef HAVE_VLAN_SET_ENCAP_PROTO
 static inline void vlan_set_encap_proto(struct sk_buff *skb, struct vlan_hdr *vhdr)
 {
        __be16 proto;
index 069839b..2fa5cc8 100644 (file)
@@ -7,10 +7,6 @@
 #endif
 
 #include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)
-/* BUILD_BUG_ON_NOT_POWER_OF_2 definition */
-#include <linux/bug.h>
-#endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
 #undef pr_emerg
diff --git a/datapath/linux/compat/include/linux/list.h b/datapath/linux/compat/include/linux/list.h
new file mode 100644 (file)
index 0000000..4446779
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef __LINUX_LIST_WRAPPER_H
+#define __LINUX_LIST_WRAPPER_H 1
+
+#include_next <linux/list.h>
+
+#ifndef hlist_entry_safe
+#define hlist_entry_safe(ptr, type, member) \
+       (ptr) ? hlist_entry(ptr, type, member) : NULL
+
+#undef hlist_for_each_entry
+#define hlist_for_each_entry(pos, head, member)                                \
+       for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
+            pos;                                                       \
+            pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
+
+#undef hlist_for_each_entry_safe
+#define hlist_for_each_entry_safe(pos, n, head, member)                \
+       for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
+            pos && ({ n = pos->member.next; 1; });                     \
+            pos = hlist_entry_safe(n, typeof(*pos), member))
+
+#endif
+
+#endif
index 0c2f2f4..71aad87 100644 (file)
@@ -154,4 +154,17 @@ static inline int rpl_netif_needs_gso(struct sk_buff *skb, int features)
 }
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0)
+typedef u32 netdev_features_t;
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
+static inline struct sk_buff *__skb_gso_segment(struct sk_buff *skb,
+                                               netdev_features_t features,
+                                               bool tx_path)
+{
+       return skb_gso_segment(skb, features);
+}
+#endif
+
 #endif
index 64e3905..365d126 100644 (file)
@@ -7,6 +7,7 @@
 #else
 /* Prior to 2.6.26, the contents of rculist.h were part of list.h. */
 #include <linux/list.h>
+#include <linux/rcupdate.h>
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
@@ -20,4 +21,18 @@ static inline void hlist_del_init_rcu(struct hlist_node *n)
 }
 #endif
 
+#ifndef hlist_first_rcu
+#define hlist_first_rcu(head)   (*((struct hlist_node __rcu **)(&(head)->first)))
+#define hlist_next_rcu(node)    (*((struct hlist_node __rcu **)(&(node)->next)))
+#define hlist_pprev_rcu(node)   (*((struct hlist_node __rcu **)((node)->pprev)))
+#endif
+
+#undef hlist_for_each_entry_rcu
+#define hlist_for_each_entry_rcu(pos, head, member)                    \
+       for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\
+                       typeof(*(pos)), member);                        \
+               pos;                                                    \
+               pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(\
+                       &(pos)->member)), typeof(*(pos)), member))
+
 #endif
index 99459ea..20cdedf 100644 (file)
 #define rcu_dereference_protected(p, c) (p)
 #endif
 
+#ifndef rcu_dereference_raw
+#define rcu_dereference_raw(p) rcu_dereference_check(p, 1)
+#endif
+
 #ifndef HAVE_RCU_READ_LOCK_HELD
 static inline int rcu_read_lock_held(void)
 {
index 7fbe9d8..d485b39 100644 (file)
@@ -245,7 +245,7 @@ static inline struct page *skb_frag_page(const skb_frag_t *frag)
 }
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,40)
+#ifndef HAVE_SKB_RESET_MAC_LEN
 static inline void skb_reset_mac_len(struct sk_buff *skb)
 {
        skb->mac_len = skb->network_header - skb->mac_header;
index 6193891..057aaed 100644 (file)
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/if_arp.h>
-#include <linux/if_ether.h>
-#include <linux/ip.h>
-#include <linux/if_vlan.h>
-#include <linux/igmp.h>
 #include <linux/in.h>
 #include <linux/in_route.h>
 #include <linux/inetdevice.h>
 #include <linux/version.h>
 #include <linux/workqueue.h>
 #include <linux/rculist.h>
-
-#include <net/dsfield.h>
-#include <net/dst.h>
-#include <net/icmp.h>
-#include <net/inet_ecn.h>
-#include <net/ip.h>
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-#include <net/ipv6.h>
-#endif
 #include <net/route.h>
 #include <net/xfrm.h>
 
 #include "checksum.h"
+#include "compat.h"
 #include "datapath.h"
 #include "tunnel.h"
 #include "vlan.h"
 #include "vport.h"
-#include "vport-internal_dev.h"
-
-#define PORT_TABLE_SIZE  1024
-
-static struct hlist_head *port_table __read_mostly;
-
-/*
- * These are just used as an optimization: they don't require any kind of
- * synchronization because we could have just as easily read the value before
- * the port change happened.
- */
-static unsigned int key_local_remote_ports __read_mostly;
-static unsigned int key_remote_ports __read_mostly;
-static unsigned int key_multicast_ports __read_mostly;
-static unsigned int local_remote_ports __read_mostly;
-static unsigned int remote_ports __read_mostly;
-static unsigned int null_ports __read_mostly;
-static unsigned int multicast_ports __read_mostly;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
 #define rt_dst(rt) (rt->dst)
@@ -74,247 +43,6 @@ static unsigned int multicast_ports __read_mostly;
 #define rt_dst(rt) (rt->u.dst)
 #endif
 
-static struct vport *tnl_vport_to_vport(const struct tnl_vport *tnl_vport)
-{
-       return vport_from_priv(tnl_vport);
-}
-
-static void free_config_rcu(struct rcu_head *rcu)
-{
-       struct tnl_mutable_config *c = container_of(rcu, struct tnl_mutable_config, rcu);
-       kfree(c);
-}
-
-/* Frees the portion of 'mutable' that requires RTNL and thus can't happen
- * within an RCU callback.  Fortunately this part doesn't require waiting for
- * an RCU grace period.
- */
-static void free_mutable_rtnl(struct tnl_mutable_config *mutable)
-{
-       ASSERT_RTNL();
-       if (ipv4_is_multicast(mutable->key.daddr) && mutable->mlink) {
-               struct in_device *in_dev;
-               in_dev = inetdev_by_index(port_key_get_net(&mutable->key), mutable->mlink);
-               if (in_dev)
-                       ip_mc_dec_group(in_dev, mutable->key.daddr);
-       }
-}
-
-static void assign_config_rcu(struct vport *vport,
-                             struct tnl_mutable_config *new_config)
-{
-       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       struct tnl_mutable_config *old_config;
-
-       old_config = rtnl_dereference(tnl_vport->mutable);
-       rcu_assign_pointer(tnl_vport->mutable, new_config);
-
-       free_mutable_rtnl(old_config);
-       call_rcu(&old_config->rcu, free_config_rcu);
-}
-
-static unsigned int *find_port_pool(const struct tnl_mutable_config *mutable)
-{
-       bool is_multicast = ipv4_is_multicast(mutable->key.daddr);
-
-       if (mutable->flags & TNL_F_IN_KEY_MATCH) {
-               if (mutable->key.saddr)
-                       return &local_remote_ports;
-               else if (is_multicast)
-                       return &multicast_ports;
-               else
-                       return &remote_ports;
-       } else {
-               if (mutable->key.saddr)
-                       return &key_local_remote_ports;
-               else if (is_multicast)
-                       return &key_multicast_ports;
-               else if (mutable->key.daddr)
-                       return &key_remote_ports;
-               else
-                       return &null_ports;
-       }
-}
-
-static u32 port_hash(const struct port_lookup_key *key)
-{
-       return jhash2((u32 *)key, (PORT_KEY_LEN / sizeof(u32)), 0);
-}
-
-static struct hlist_head *find_bucket(u32 hash)
-{
-       return &port_table[(hash & (PORT_TABLE_SIZE - 1))];
-}
-
-static void port_table_add_port(struct vport *vport)
-{
-       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       const struct tnl_mutable_config *mutable;
-       u32 hash;
-
-       mutable = rtnl_dereference(tnl_vport->mutable);
-       hash = port_hash(&mutable->key);
-       hlist_add_head_rcu(&tnl_vport->hash_node, find_bucket(hash));
-
-       (*find_port_pool(rtnl_dereference(tnl_vport->mutable)))++;
-}
-
-static void port_table_move_port(struct vport *vport,
-                     struct tnl_mutable_config *new_mutable)
-{
-       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       u32 hash;
-
-       hash = port_hash(&new_mutable->key);
-       hlist_del_init_rcu(&tnl_vport->hash_node);
-       hlist_add_head_rcu(&tnl_vport->hash_node, find_bucket(hash));
-
-       (*find_port_pool(rtnl_dereference(tnl_vport->mutable)))--;
-       assign_config_rcu(vport, new_mutable);
-       (*find_port_pool(rtnl_dereference(tnl_vport->mutable)))++;
-}
-
-static void port_table_remove_port(struct vport *vport)
-{
-       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-
-       hlist_del_init_rcu(&tnl_vport->hash_node);
-
-       (*find_port_pool(rtnl_dereference(tnl_vport->mutable)))--;
-}
-
-static struct vport *port_table_lookup(struct port_lookup_key *key,
-                                      const struct tnl_mutable_config **pmutable)
-{
-       struct hlist_node *n;
-       struct hlist_head *bucket;
-       u32 hash = port_hash(key);
-       struct tnl_vport *tnl_vport;
-
-       bucket = find_bucket(hash);
-
-       hlist_for_each_entry_rcu(tnl_vport, n, bucket, hash_node) {
-               struct tnl_mutable_config *mutable;
-
-               mutable = rcu_dereference_rtnl(tnl_vport->mutable);
-               if (!memcmp(&mutable->key, key, PORT_KEY_LEN)) {
-                       *pmutable = mutable;
-                       return tnl_vport_to_vport(tnl_vport);
-               }
-       }
-
-       return NULL;
-}
-
-struct vport *ovs_tnl_find_port(struct net *net, __be32 saddr, __be32 daddr,
-                               __be64 key, int tunnel_type,
-                               const struct tnl_mutable_config **mutable)
-{
-       struct port_lookup_key lookup;
-       struct vport *vport;
-       bool is_multicast = ipv4_is_multicast(saddr);
-
-       port_key_set_net(&lookup, net);
-       lookup.saddr = saddr;
-       lookup.daddr = daddr;
-
-       /* First try for exact match on in_key. */
-       lookup.in_key = key;
-       lookup.tunnel_type = tunnel_type | TNL_T_KEY_EXACT;
-       if (!is_multicast && key_local_remote_ports) {
-               vport = port_table_lookup(&lookup, mutable);
-               if (vport)
-                       return vport;
-       }
-       if (key_remote_ports) {
-               lookup.saddr = 0;
-               vport = port_table_lookup(&lookup, mutable);
-               if (vport)
-                       return vport;
-
-               lookup.saddr = saddr;
-       }
-
-       /* Then try matches that wildcard in_key. */
-       lookup.in_key = 0;
-       lookup.tunnel_type = tunnel_type | TNL_T_KEY_MATCH;
-       if (!is_multicast && local_remote_ports) {
-               vport = port_table_lookup(&lookup, mutable);
-               if (vport)
-                       return vport;
-       }
-       if (remote_ports) {
-               lookup.saddr = 0;
-               vport = port_table_lookup(&lookup, mutable);
-               if (vport)
-                       return vport;
-       }
-
-       if (is_multicast) {
-               lookup.saddr = 0;
-               lookup.daddr = saddr;
-               if (key_multicast_ports) {
-                       lookup.tunnel_type = tunnel_type | TNL_T_KEY_EXACT;
-                       lookup.in_key = key;
-                       vport = port_table_lookup(&lookup, mutable);
-                       if (vport)
-                               return vport;
-               }
-               if (multicast_ports) {
-                       lookup.tunnel_type = tunnel_type | TNL_T_KEY_MATCH;
-                       lookup.in_key = 0;
-                       vport = port_table_lookup(&lookup, mutable);
-                       if (vport)
-                               return vport;
-               }
-       }
-
-       if (null_ports) {
-               lookup.daddr = 0;
-               lookup.saddr = 0;
-               lookup.in_key = 0;
-               lookup.tunnel_type = tunnel_type;
-               vport = port_table_lookup(&lookup, mutable);
-               if (vport)
-                       return vport;
-       }
-       return NULL;
-}
-
-static void ecn_decapsulate(struct sk_buff *skb)
-{
-       if (unlikely(INET_ECN_is_ce(OVS_CB(skb)->tun_key->ipv4_tos))) {
-               __be16 protocol = skb->protocol;
-
-               skb_set_network_header(skb, ETH_HLEN);
-
-               if (protocol == htons(ETH_P_8021Q)) {
-                       if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN)))
-                               return;
-
-                       protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
-                       skb_set_network_header(skb, VLAN_ETH_HLEN);
-               }
-
-               if (protocol == htons(ETH_P_IP)) {
-                       if (unlikely(!pskb_may_pull(skb, skb_network_offset(skb)
-                           + sizeof(struct iphdr))))
-                               return;
-
-                       IP_ECN_set_ce(ip_hdr(skb));
-               }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-               else if (protocol == htons(ETH_P_IPV6)) {
-                       if (unlikely(!pskb_may_pull(skb, skb_network_offset(skb)
-                           + sizeof(struct ipv6hdr))))
-                               return;
-
-                       IP6_ECN_set_ce(ipv6_hdr(skb));
-               }
-#endif
-       }
-}
-
 /**
  *     ovs_tnl_rcv - ingress point for generic tunnel code
  *
@@ -337,7 +65,7 @@ void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb)
        skb_reset_mac_header(skb);
        eh = eth_hdr(skb);
 
-       if (likely(ntohs(eh->h_proto) >= 1536))
+       if (likely(ntohs(eh->h_proto) >= ETH_P_802_3_MIN))
                skb->protocol = eh->h_proto;
        else
                skb->protocol = htons(ETH_P_802_2);
@@ -346,8 +74,6 @@ void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb)
        nf_reset(skb);
        skb_clear_rxhash(skb);
        secpath_reset(skb);
-
-       ecn_decapsulate(skb);
        vlan_set_tci(skb, 0);
 
        if (unlikely(compute_ip_summed(skb, false))) {
@@ -360,7 +86,7 @@ void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb)
 
 static struct rtable *find_route(struct net *net,
                __be32 *saddr, __be32 daddr, u8 ipproto,
-               u8 tos)
+               u8 tos, u32 skb_mark)
 {
        struct rtable *rt;
        /* Tunnel configuration keeps DSCP part of TOS bits, But Linux
@@ -370,7 +96,13 @@ static struct rtable *find_route(struct net *net,
        struct flowi fl = { .nl_u = { .ip4_u = {
                                        .daddr = daddr,
                                        .saddr = *saddr,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+                                       .fwmark = skb_mark,
+#endif
                                        .tos   = RT_TOS(tos) } },
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+                                       .mark = skb_mark,
+#endif
                                        .proto = ipproto };
 
        if (unlikely(ip_route_output_key(net, &rt, &fl)))
@@ -381,6 +113,7 @@ static struct rtable *find_route(struct net *net,
        struct flowi4 fl = { .daddr = daddr,
                             .saddr = *saddr,
                             .flowi4_tos = RT_TOS(tos),
+                            .flowi4_mark = skb_mark,
                             .flowi4_proto = ipproto };
 
        rt = ip_route_output_key(net, &fl);
@@ -409,7 +142,6 @@ static bool need_linearize(const struct sk_buff *skb)
 }
 
 static struct sk_buff *handle_offloads(struct sk_buff *skb,
-                                      const struct tnl_mutable_config *mutable,
                                       const struct rtable *rt,
                                       int tunnel_hlen)
 {
@@ -435,7 +167,7 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb,
        if (skb_is_gso(skb)) {
                struct sk_buff *nskb;
 
-               nskb = skb_gso_segment(skb, 0);
+               nskb = __skb_gso_segment(skb, 0, false);
                if (IS_ERR(nskb)) {
                        kfree_skb(skb);
                        err = PTR_ERR(nskb);
@@ -471,177 +203,71 @@ error:
        return ERR_PTR(err);
 }
 
-static int send_frags(struct sk_buff *skb,
-                     int tunnel_hlen)
+/* Compute source UDP port for outgoing packet.
+ * Currently we use the flow hash.
+ */
+u16 ovs_tnl_get_src_port(struct sk_buff *skb)
 {
-       int sent_len;
-
-       sent_len = 0;
-       while (skb) {
-               struct sk_buff *next = skb->next;
-               int frag_len = skb->len - tunnel_hlen;
-               int err;
-
-               skb->next = NULL;
-               memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-
-               err = ip_local_out(skb);
-               skb = next;
-               if (unlikely(net_xmit_eval(err)))
-                       goto free_frags;
-               sent_len += frag_len;
-       }
-
-       return sent_len;
-
-free_frags:
-       /*
-        * There's no point in continuing to send fragments once one has been
-        * dropped so just free the rest.  This may help improve the congestion
-        * that caused the first packet to be dropped.
-        */
-       ovs_tnl_free_linked_skbs(skb);
-       return sent_len;
+       int low;
+       int high;
+       unsigned int range;
+       u32 hash = OVS_CB(skb)->flow->hash;
+
+       inet_get_local_port_range(&low, &high);
+       range = (high - low) + 1;
+       return (((u64) hash * range) >> 32) + low;
 }
 
 int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
 {
        struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       const struct tnl_mutable_config *mutable = rcu_dereference(tnl_vport->mutable);
-       enum vport_err_type err = VPORT_E_TX_ERROR;
        struct rtable *rt;
-       struct ovs_key_ipv4_tunnel tun_key;
+       __be32 saddr;
        int sent_len = 0;
        int tunnel_hlen;
-       __be16 frag_off;
-       __be32 daddr;
-       __be32 saddr;
-       u8 ttl;
-       u8 tos;
 
-       /* Validate the protocol headers before we try to use them. */
-       if (skb->protocol == htons(ETH_P_8021Q) &&
-           !vlan_tx_tag_present(skb)) {
-               if (unlikely(!pskb_may_pull(skb, VLAN_ETH_HLEN)))
-                       goto error_free;
-
-               skb->protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
-               skb_set_network_header(skb, VLAN_ETH_HLEN);
-       }
-
-       if (skb->protocol == htons(ETH_P_IP)) {
-               if (unlikely(!pskb_may_pull(skb, skb_network_offset(skb)
-                   + sizeof(struct iphdr))))
-                       skb->protocol = 0;
-       }
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-       else if (skb->protocol == htons(ETH_P_IPV6)) {
-               if (unlikely(!pskb_may_pull(skb, skb_network_offset(skb)
-                   + sizeof(struct ipv6hdr))))
-                       skb->protocol = 0;
-       }
-#endif
-
-       /* If OVS_CB(skb)->tun_key is NULL, point it at the local tun_key here,
-        * and zero it out.
-        */
-       if (!OVS_CB(skb)->tun_key) {
-               memset(&tun_key, 0, sizeof(tun_key));
-               OVS_CB(skb)->tun_key = &tun_key;
-       }
-
-       tunnel_hlen = tnl_vport->tnl_ops->hdr_len(mutable, OVS_CB(skb)->tun_key);
-       if (unlikely(tunnel_hlen < 0)) {
-               err = VPORT_E_TX_DROPPED;
+       if (unlikely(!OVS_CB(skb)->tun_key))
                goto error_free;
-       }
-       tunnel_hlen += sizeof(struct iphdr);
-
-       if (OVS_CB(skb)->tun_key->ipv4_dst) {
-               daddr = OVS_CB(skb)->tun_key->ipv4_dst;
-               saddr = OVS_CB(skb)->tun_key->ipv4_src;
-               tos = OVS_CB(skb)->tun_key->ipv4_tos;
-               ttl = OVS_CB(skb)->tun_key->ipv4_ttl;
-                frag_off = OVS_CB(skb)->tun_key->tun_flags &
-                               OVS_TNL_F_DONT_FRAGMENT ?  htons(IP_DF) : 0;
-       } else {
-               u8 inner_tos;
-               daddr = mutable->key.daddr;
-               saddr = mutable->key.saddr;
-
-               if (unlikely(!daddr)) {
-                       /* Trying to sent packet from Null-port without
-                        * tunnel info? Drop this packet. */
-                       err = VPORT_E_TX_DROPPED;
-                       goto error_free;
-               }
-
-               /* ToS */
-               if (skb->protocol == htons(ETH_P_IP))
-                       inner_tos = ip_hdr(skb)->tos;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-               else if (skb->protocol == htons(ETH_P_IPV6))
-                       inner_tos = ipv6_get_dsfield(ipv6_hdr(skb));
-#endif
-               else
-                       inner_tos = 0;
-
-               if (mutable->flags & TNL_F_TOS_INHERIT)
-                       tos = inner_tos;
-               else
-                       tos = mutable->tos;
-
-               tos = INET_ECN_encapsulate(tos, inner_tos);
-
-               /* TTL */
-               ttl = mutable->ttl;
-               if (mutable->flags & TNL_F_TTL_INHERIT) {
-                       if (skb->protocol == htons(ETH_P_IP))
-                               ttl = ip_hdr(skb)->ttl;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-                       else if (skb->protocol == htons(ETH_P_IPV6))
-                               ttl = ipv6_hdr(skb)->hop_limit;
-#endif
-               }
-
-               frag_off = mutable->flags & TNL_F_DF_DEFAULT ? htons(IP_DF) : 0;
-       }
 
        /* Route lookup */
-       rt = find_route(port_key_get_net(&mutable->key), &saddr, daddr,
-                         tnl_vport->tnl_ops->ipproto, tos);
+       saddr = OVS_CB(skb)->tun_key->ipv4_src;
+       rt = find_route(ovs_dp_get_net(vport->dp),
+                       &saddr,
+                       OVS_CB(skb)->tun_key->ipv4_dst,
+                       tnl_vport->tnl_ops->ipproto,
+                       OVS_CB(skb)->tun_key->ipv4_tos,
+                       skb_get_mark(skb));
        if (IS_ERR(rt))
                goto error_free;
 
-       /* Reset SKB */
-       nf_reset(skb);
-       secpath_reset(skb);
-       skb_dst_drop(skb);
-       skb_clear_rxhash(skb);
-
        /* Offloading */
-       skb = handle_offloads(skb, mutable, rt, tunnel_hlen);
+       tunnel_hlen = tnl_vport->tnl_ops->hdr_len(OVS_CB(skb)->tun_key);
+       tunnel_hlen += sizeof(struct iphdr);
+
+       skb = handle_offloads(skb, rt, tunnel_hlen);
        if (IS_ERR(skb)) {
                skb = NULL;
                goto err_free_rt;
        }
 
-       /* TTL Fixup. */
-       if (!OVS_CB(skb)->tun_key->ipv4_dst) {
-               if (!(mutable->flags & TNL_F_TTL_INHERIT)) {
-                       if (!ttl)
-                               ttl = ip4_dst_hoplimit(&rt_dst(rt));
-               }
-       }
+       /* Reset SKB */
+       nf_reset(skb);
+       secpath_reset(skb);
+       skb_dst_drop(skb);
+       skb_clear_rxhash(skb);
 
        while (skb) {
-               struct iphdr *iph;
                struct sk_buff *next_skb = skb->next;
+               struct iphdr *iph;
+               int frag_len;
+               int err;
+
                skb->next = NULL;
 
                if (unlikely(vlan_deaccel_tag(skb)))
                        goto next;
 
+               frag_len = skb->len;
                skb_push(skb, tunnel_hlen);
                skb_reset_network_header(skb);
                skb_set_transport_header(skb, sizeof(struct iphdr));
@@ -651,25 +277,37 @@ int ovs_tnl_send(struct vport *vport, struct sk_buff *skb)
                else
                        skb_dst_set(skb, &rt_dst(rt));
 
+               /* Push Tunnel header. */
+               tnl_vport->tnl_ops->build_header(vport, skb, tunnel_hlen);
+
                /* Push IP header. */
                iph = ip_hdr(skb);
                iph->version    = 4;
                iph->ihl        = sizeof(struct iphdr) >> 2;
                iph->protocol   = tnl_vport->tnl_ops->ipproto;
-               iph->daddr      = daddr;
+               iph->daddr      = OVS_CB(skb)->tun_key->ipv4_dst;
                iph->saddr      = saddr;
-               iph->tos        = tos;
-               iph->ttl        = ttl;
-               iph->frag_off   = frag_off;
-               ip_select_ident(iph, &rt_dst(rt), NULL);
+               iph->tos        = OVS_CB(skb)->tun_key->ipv4_tos;
+               iph->ttl        = OVS_CB(skb)->tun_key->ipv4_ttl;
+               iph->frag_off   = OVS_CB(skb)->tun_key->tun_flags &
+                                 OVS_TNL_F_DONT_FRAGMENT ?  htons(IP_DF) : 0;
+               /*
+                * Allow our local IP stack to fragment the outer packet even
+                * if the DF bit is set as a last resort.  We also need to
+                * force selection of an IP ID here with __ip_select_ident(),
+                * as ip_select_ident() assumes a proper ID is not needed when
+                * when the DF bit is set.
+                */
+               skb->local_df = 1;
+               __ip_select_ident(iph, skb_dst(skb), 0);
 
-               /* Push Tunnel header. */
-               skb = tnl_vport->tnl_ops->build_header(vport, mutable,
-                                                       &rt_dst(rt), skb, tunnel_hlen);
-               if (unlikely(!skb))
+               memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+
+               err = ip_local_out(skb);
+               if (unlikely(net_xmit_eval(err)))
                        goto next;
 
-               sent_len += send_frags(skb, tunnel_hlen);
+               sent_len += frag_len;
 
 next:
                skb = next_skb;
@@ -683,123 +321,17 @@ next:
 err_free_rt:
        ip_rt_put(rt);
 error_free:
-       ovs_tnl_free_linked_skbs(skb);
-       ovs_vport_record_error(vport, err);
+       kfree_skb(skb);
+       ovs_vport_record_error(vport, VPORT_E_TX_ERROR);
        return sent_len;
 }
 
-static const struct nla_policy tnl_policy[OVS_TUNNEL_ATTR_MAX + 1] = {
-       [OVS_TUNNEL_ATTR_FLAGS]    = { .type = NLA_U32 },
-       [OVS_TUNNEL_ATTR_DST_IPV4] = { .type = NLA_U32 },
-       [OVS_TUNNEL_ATTR_SRC_IPV4] = { .type = NLA_U32 },
-       [OVS_TUNNEL_ATTR_OUT_KEY]  = { .type = NLA_U64 },
-       [OVS_TUNNEL_ATTR_IN_KEY]   = { .type = NLA_U64 },
-       [OVS_TUNNEL_ATTR_TOS]      = { .type = NLA_U8 },
-       [OVS_TUNNEL_ATTR_TTL]      = { .type = NLA_U8 },
-       [OVS_TUNNEL_ATTR_DST_PORT] = { .type = NLA_U16 },
-};
-
-/* Sets OVS_TUNNEL_ATTR_* fields in 'mutable', which must initially be
- * zeroed. */
-static int tnl_set_config(struct net *net, struct nlattr *options,
-                         const struct tnl_ops *tnl_ops,
-                         const struct vport *cur_vport,
-                         struct tnl_mutable_config *mutable)
-{
-       const struct vport *old_vport;
-       const struct tnl_mutable_config *old_mutable;
-       struct nlattr *a[OVS_TUNNEL_ATTR_MAX + 1];
-       int err;
-
-       port_key_set_net(&mutable->key, net);
-       mutable->key.tunnel_type = tnl_ops->tunnel_type;
-       if (!options)
-               goto out;
-
-       err = nla_parse_nested(a, OVS_TUNNEL_ATTR_MAX, options, tnl_policy);
-       if (err)
-               return err;
-
-       /* Process attributes possibly useful for null_ports first */
-       if (a[OVS_TUNNEL_ATTR_DST_PORT])
-               mutable->dst_port =
-                       htons(nla_get_u16(a[OVS_TUNNEL_ATTR_DST_PORT]));
-
-       if (a[OVS_TUNNEL_ATTR_DST_IPV4])
-               mutable->key.daddr = nla_get_be32(a[OVS_TUNNEL_ATTR_DST_IPV4]);
-
-       /* Skip the rest if configuring a null_port */
-       if (!mutable->key.daddr)
-               goto out;
-
-       if (a[OVS_TUNNEL_ATTR_FLAGS])
-               mutable->flags = nla_get_u32(a[OVS_TUNNEL_ATTR_FLAGS])
-                       & TNL_F_PUBLIC;
-
-       if (a[OVS_TUNNEL_ATTR_SRC_IPV4]) {
-               if (ipv4_is_multicast(mutable->key.daddr))
-                       return -EINVAL;
-               mutable->key.saddr = nla_get_be32(a[OVS_TUNNEL_ATTR_SRC_IPV4]);
-       }
-
-       if (a[OVS_TUNNEL_ATTR_TOS]) {
-               mutable->tos = nla_get_u8(a[OVS_TUNNEL_ATTR_TOS]);
-               /* Reject ToS config with ECN bits set. */
-               if (mutable->tos & INET_ECN_MASK)
-                       return -EINVAL;
-       }
-
-       if (a[OVS_TUNNEL_ATTR_TTL])
-               mutable->ttl = nla_get_u8(a[OVS_TUNNEL_ATTR_TTL]);
-
-       if (!a[OVS_TUNNEL_ATTR_IN_KEY]) {
-               mutable->key.tunnel_type |= TNL_T_KEY_MATCH;
-               mutable->flags |= TNL_F_IN_KEY_MATCH;
-       } else {
-               mutable->key.tunnel_type |= TNL_T_KEY_EXACT;
-               mutable->key.in_key = nla_get_be64(a[OVS_TUNNEL_ATTR_IN_KEY]);
-       }
-
-       if (!a[OVS_TUNNEL_ATTR_OUT_KEY])
-               mutable->flags |= TNL_F_OUT_KEY_ACTION;
-       else
-               mutable->out_key = nla_get_be64(a[OVS_TUNNEL_ATTR_OUT_KEY]);
-
-       mutable->mlink = 0;
-       if (ipv4_is_multicast(mutable->key.daddr)) {
-               struct net_device *dev;
-               struct rtable *rt;
-               __be32 saddr = mutable->key.saddr;
-
-               rt = find_route(port_key_get_net(&mutable->key),
-                            &saddr, mutable->key.daddr,
-                            tnl_ops->ipproto, mutable->tos);
-               if (IS_ERR(rt))
-                       return -EADDRNOTAVAIL;
-               dev = rt_dst(rt).dev;
-               ip_rt_put(rt);
-               if (__in_dev_get_rtnl(dev) == NULL)
-                       return -EADDRNOTAVAIL;
-               mutable->mlink = dev->ifindex;
-               ip_mc_inc_group(__in_dev_get_rtnl(dev), mutable->key.daddr);
-       }
-
-out:
-       old_vport = port_table_lookup(&mutable->key, &old_mutable);
-       if (old_vport && old_vport != cur_vport)
-               return -EEXIST;
-
-       return 0;
-}
-
 struct vport *ovs_tnl_create(const struct vport_parms *parms,
                             const struct vport_ops *vport_ops,
                             const struct tnl_ops *tnl_ops)
 {
        struct vport *vport;
        struct tnl_vport *tnl_vport;
-       struct tnl_mutable_config *mutable;
-       int initial_frag_id;
        int err;
 
        vport = ovs_vport_alloc(sizeof(struct tnl_vport), vport_ops, parms);
@@ -813,126 +345,24 @@ struct vport *ovs_tnl_create(const struct vport_parms *parms,
        strcpy(tnl_vport->name, parms->name);
        tnl_vport->tnl_ops = tnl_ops;
 
-       mutable = kzalloc(sizeof(struct tnl_mutable_config), GFP_KERNEL);
-       if (!mutable) {
-               err = -ENOMEM;
-               goto error_free_vport;
-       }
-
-       get_random_bytes(&initial_frag_id, sizeof(int));
-       atomic_set(&tnl_vport->frag_id, initial_frag_id);
-
-       err = tnl_set_config(ovs_dp_get_net(parms->dp), parms->options, tnl_ops,
-                            NULL, mutable);
-       if (err)
-               goto error_free_mutable;
-
-       rcu_assign_pointer(tnl_vport->mutable, mutable);
-
-       port_table_add_port(vport);
        return vport;
 
-error_free_mutable:
-       free_mutable_rtnl(mutable);
-       kfree(mutable);
-error_free_vport:
-       ovs_vport_free(vport);
 error:
        return ERR_PTR(err);
 }
 
-int ovs_tnl_set_options(struct vport *vport, struct nlattr *options)
-{
-       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       const struct tnl_mutable_config *old_mutable;
-       struct tnl_mutable_config *mutable;
-       int err;
-
-       old_mutable = rtnl_dereference(tnl_vport->mutable);
-       if (!old_mutable->key.daddr)
-               return -EINVAL;
-
-       mutable = kzalloc(sizeof(struct tnl_mutable_config), GFP_KERNEL);
-       if (!mutable) {
-               err = -ENOMEM;
-               goto error;
-       }
-
-       /* Parse the others configured by userspace. */
-       err = tnl_set_config(ovs_dp_get_net(vport->dp), options, tnl_vport->tnl_ops,
-                            vport, mutable);
-       if (err)
-               goto error_free;
-
-       if (port_hash(&mutable->key) != port_hash(&old_mutable->key))
-               port_table_move_port(vport, mutable);
-       else
-               assign_config_rcu(vport, mutable);
-
-       return 0;
-
-error_free:
-       free_mutable_rtnl(mutable);
-       kfree(mutable);
-error:
-       return err;
-}
-
-int ovs_tnl_get_options(const struct vport *vport, struct sk_buff *skb)
-{
-       const struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       const struct tnl_mutable_config *mutable = rcu_dereference_rtnl(tnl_vport->mutable);
-
-       if (mutable->dst_port && nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT,
-                                            ntohs(mutable->dst_port)))
-               goto nla_put_failure;
-
-       /* Skip the rest for null_ports */
-       if (!mutable->key.daddr)
-               return 0;
-
-       if (nla_put_be32(skb, OVS_TUNNEL_ATTR_DST_IPV4, mutable->key.daddr))
-               goto nla_put_failure;
-       if (nla_put_u32(skb, OVS_TUNNEL_ATTR_FLAGS,
-                       mutable->flags & TNL_F_PUBLIC))
-               goto nla_put_failure;
-       if (!(mutable->flags & TNL_F_IN_KEY_MATCH) &&
-           nla_put_be64(skb, OVS_TUNNEL_ATTR_IN_KEY, mutable->key.in_key))
-               goto nla_put_failure;
-       if (!(mutable->flags & TNL_F_OUT_KEY_ACTION) &&
-           nla_put_be64(skb, OVS_TUNNEL_ATTR_OUT_KEY, mutable->out_key))
-               goto nla_put_failure;
-       if (mutable->key.saddr &&
-           nla_put_be32(skb, OVS_TUNNEL_ATTR_SRC_IPV4, mutable->key.saddr))
-               goto nla_put_failure;
-       if (mutable->tos && nla_put_u8(skb, OVS_TUNNEL_ATTR_TOS, mutable->tos))
-               goto nla_put_failure;
-       if (mutable->ttl && nla_put_u8(skb, OVS_TUNNEL_ATTR_TTL, mutable->ttl))
-               goto nla_put_failure;
-
-       return 0;
-
-nla_put_failure:
-       return -EMSGSIZE;
-}
-
 static void free_port_rcu(struct rcu_head *rcu)
 {
        struct tnl_vport *tnl_vport = container_of(rcu,
                                                   struct tnl_vport, rcu);
 
-       kfree((struct tnl_mutable __force *)tnl_vport->mutable);
-       ovs_vport_free(tnl_vport_to_vport(tnl_vport));
+       ovs_vport_free(vport_from_priv(tnl_vport));
 }
 
 void ovs_tnl_destroy(struct vport *vport)
 {
        struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       struct tnl_mutable_config *mutable;
 
-       mutable = rtnl_dereference(tnl_vport->mutable);
-       port_table_remove_port(vport);
-       free_mutable_rtnl(mutable);
        call_rcu(&tnl_vport->rcu, free_port_rcu);
 }
 
@@ -941,32 +371,3 @@ const char *ovs_tnl_get_name(const struct vport *vport)
        const struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
        return tnl_vport->name;
 }
-
-void ovs_tnl_free_linked_skbs(struct sk_buff *skb)
-{
-       while (skb) {
-               struct sk_buff *next = skb->next;
-               kfree_skb(skb);
-               skb = next;
-       }
-}
-
-int ovs_tnl_init(void)
-{
-       int i;
-
-       port_table = kmalloc(PORT_TABLE_SIZE * sizeof(struct hlist_head *),
-                            GFP_KERNEL);
-       if (!port_table)
-               return -ENOMEM;
-
-       for (i = 0; i < PORT_TABLE_SIZE; i++)
-               INIT_HLIST_HEAD(&port_table[i]);
-
-       return 0;
-}
-
-void ovs_tnl_exit(void)
-{
-       kfree(port_table);
-}
index 7e4d1a6..e853146 100644 (file)
 #include <net/netns/generic.h>
 
 #include "flow.h"
-#include "openvswitch/tunnel.h"
 #include "vport.h"
 
-/*
- * The absolute minimum fragment size.  Note that there are many other
- * definitions of the minimum MTU.
- */
-#define IP_MIN_MTU 68
-
-/*
- * One of these goes in struct tnl_ops and in tnl_find_port().
- * These values are in the same namespace as other TNL_T_* values, so
- * only the least significant 10 bits are available to define protocol
- * identifiers.
- */
-#define TNL_T_PROTO_GRE                0
-#define TNL_T_PROTO_GRE64      1
-#define TNL_T_PROTO_CAPWAP     2
-#define TNL_T_PROTO_VXLAN      3
-
-/* These flags are only needed when calling tnl_find_port(). */
-#define TNL_T_KEY_EXACT                (1 << 10)
-#define TNL_T_KEY_MATCH                (1 << 11)
-
-/* Private flags not exposed to userspace in this form. */
-#define TNL_F_IN_KEY_MATCH     (1 << 16) /* Store the key in tun_id to
-                                          * match in flow table. */
-#define TNL_F_OUT_KEY_ACTION   (1 << 17) /* Get the key from a SET_TUNNEL
-                                          * action. */
-
-/* All public tunnel flags. */
-#define TNL_F_PUBLIC (TNL_F_CSUM | TNL_F_TOS_INHERIT | TNL_F_TTL_INHERIT | \
-                     TNL_F_DF_DEFAULT | TNL_F_IPSEC)
-
-/**
- * struct port_lookup_key - Tunnel port key, used as hash table key.
- * @in_key: Key to match on input, 0 for wildcard.
- * @net: Network namespace of the port.
- * @saddr: IPv4 source address to match, 0 to accept any source address.
- * @daddr: IPv4 destination of tunnel.
- * @tunnel_type: Set of TNL_T_* flags that define lookup.
- */
-struct port_lookup_key {
-       __be64 in_key;
-#ifdef CONFIG_NET_NS
-       struct net *net;
-#endif
-       __be32 saddr;
-       __be32 daddr;
-       u32    tunnel_type;
-};
-
-#define PORT_KEY_LEN   (offsetof(struct port_lookup_key, tunnel_type) + \
-                        FIELD_SIZEOF(struct port_lookup_key, tunnel_type))
-
-static inline struct net *port_key_get_net(const struct port_lookup_key *key)
-{
-       return read_pnet(&key->net);
-}
-
-static inline void port_key_set_net(struct port_lookup_key *key, struct net *net)
-{
-       write_pnet(&key->net, net);
-}
-
-/**
- * struct tnl_mutable_config - modifiable configuration for a tunnel.
- * @key: Used as key for tunnel port.  Configured via OVS_TUNNEL_ATTR_*
- * attributes.
- * @rcu: RCU callback head for deferred destruction.
- * @tunnel_hlen: Tunnel header length.
- * @out_key: Key to use on output, 0 if this tunnel has no fixed output key.
- * @flags: TNL_F_* flags.
- * @tos: IPv4 TOS value to use for tunnel, 0 if no fixed TOS.
- * @ttl: IPv4 TTL value to use for tunnel, 0 if no fixed TTL.
- */
-struct tnl_mutable_config {
-       struct port_lookup_key key;
-       struct rcu_head rcu;
-
-       /* Configured via OVS_TUNNEL_ATTR_* attributes. */
-       __be64  out_key;
-       u32     flags;
-       u8      tos;
-       u8      ttl;
-       __be16  dst_port;
-
-       /* Multicast configuration. */
-       int     mlink;
-};
-
 struct tnl_ops {
-       u32 tunnel_type;        /* Put the TNL_T_PROTO_* type in here. */
        u8 ipproto;             /* The IP protocol for the tunnel. */
 
        /*
         * Returns the length of the tunnel header that will be added in
-        * build_header() (i.e. excludes the IP header).  Returns a negative
-        * error code if the configuration is invalid.
+        * build_header() (i.e. excludes the IP header).
         */
-       int (*hdr_len)(const struct tnl_mutable_config *,
-                      const struct ovs_key_ipv4_tunnel *);
+       int (*hdr_len)(const struct ovs_key_ipv4_tunnel *);
        /*
-        * Returns a linked list of SKBs with tunnel headers (multiple
-        * packets may be generated in the event of fragmentation).  Space
-        * will have already been allocated at the start of the packet equal
-        * to sizeof(struct iphdr) + value returned by hdr_len().  The IP
-        * header will have already been constructed.
-        */
-       struct sk_buff *(*build_header)(const struct vport *,
-                                        const struct tnl_mutable_config *,
-                                        struct dst_entry *, struct sk_buff *,
-                                        int tunnel_hlen);
+       * Builds header for given SKB.  Space will have already been
+       * allocated at the start of the packet equal
+       * to sizeof(struct iphdr) + value returned by hdr_len().
+       */
+       void (*build_header)(const struct vport *, struct sk_buff *,
+                            int tunnel_hlen);
 };
 
 struct tnl_vport {
        struct rcu_head rcu;
-       struct hlist_node hash_node;
 
+       __be16 dst_port;
        char name[IFNAMSIZ];
        const struct tnl_ops *tnl_ops;
-
-       struct tnl_mutable_config __rcu *mutable;
-
-       /*
-        * ID of last fragment sent (for tunnel protocols with direct support
-        * fragmentation).  If the protocol relies on IP fragmentation then
-        * this is not needed.
-        */
-       atomic_t frag_id;
 };
 
 struct vport *ovs_tnl_create(const struct vport_parms *, const struct vport_ops *,
                             const struct tnl_ops *);
 void ovs_tnl_destroy(struct vport *);
 
-int ovs_tnl_set_options(struct vport *, struct nlattr *);
-int ovs_tnl_get_options(const struct vport *, struct sk_buff *);
-
 const char *ovs_tnl_get_name(const struct vport *vport);
 int ovs_tnl_send(struct vport *vport, struct sk_buff *skb);
 void ovs_tnl_rcv(struct vport *vport, struct sk_buff *skb);
+u16 ovs_tnl_get_src_port(struct sk_buff *skb);
 
-struct vport *ovs_tnl_find_port(struct net *net, __be32 saddr, __be32 daddr,
-                               __be64 key, int tunnel_type,
-                               const struct tnl_mutable_config **mutable);
-bool ovs_tnl_frag_needed(struct vport *vport,
-                        const struct tnl_mutable_config *mutable,
-                        struct sk_buff *skb, unsigned int mtu);
-void ovs_tnl_free_linked_skbs(struct sk_buff *skb);
-
-int ovs_tnl_init(void);
-void ovs_tnl_exit(void);
 static inline struct tnl_vport *tnl_vport_priv(const struct vport *vport)
 {
        return vport_priv(vport);
@@ -197,25 +80,4 @@ static inline void tnl_tun_key_init(struct ovs_key_ipv4_tunnel *tun_key,
               sizeof(*tun_key) - OVS_TUNNEL_KEY_SIZE);
 }
 
-static inline void tnl_get_param(const struct tnl_mutable_config *mutable,
-                                const struct ovs_key_ipv4_tunnel *tun_key,
-                                u32 *flags,  __be64 *out_key)
-{
-       if (tun_key->ipv4_dst) {
-               *flags = 0;
-
-               if (tun_key->tun_flags & OVS_TNL_F_KEY)
-                       *flags = TNL_F_OUT_KEY_ACTION;
-               if (tun_key->tun_flags & OVS_TNL_F_CSUM)
-                       *flags |= TNL_F_CSUM;
-               *out_key = tun_key->tun_id;
-       } else {
-               *flags = mutable->flags;
-               if (mutable->flags & TNL_F_OUT_KEY_ACTION)
-                       *out_key = tun_key->tun_id;
-               else
-                       *out_key = mutable->out_key;
-       }
-}
-
 #endif /* tunnel.h */
diff --git a/datapath/vport-capwap.c b/datapath/vport-capwap.c
deleted file mode 100644 (file)
index 56e6394..0000000
+++ /dev/null
@@ -1,851 +0,0 @@
-/*
- * Copyright (c) 2007-2012 Nicira, Inc.
- * Distributed under the terms of the GNU GPL version 2.
- *
- * Significant portions of this file may be copied from parts of the Linux
- * kernel, by Linus Torvalds and others.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/version.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
-
-#include <linux/if.h>
-#include <linux/in.h>
-#include <linux/ip.h>
-#include <linux/list.h>
-#include <linux/net.h>
-#include <net/net_namespace.h>
-
-#include <net/icmp.h>
-#include <net/inet_frag.h>
-#include <net/ip.h>
-#include <net/protocol.h>
-#include <net/udp.h>
-
-#include "datapath.h"
-#include "tunnel.h"
-#include "vport.h"
-
-#define CAPWAP_SRC_PORT 58881
-#define CAPWAP_DST_PORT 58882
-
-#define CAPWAP_FRAG_TIMEOUT (30 * HZ)
-#define CAPWAP_FRAG_MAX_MEM (256 * 1024)
-#define CAPWAP_FRAG_PRUNE_MEM (192 * 1024)
-#define CAPWAP_FRAG_SECRET_INTERVAL (10 * 60 * HZ)
-
-/*
- * The CAPWAP header is a mess, with all kinds of odd size bit fields that
- * cross byte boundaries, which are difficult to represent correctly in
- * various byte orderings.  Luckily we only care about a few permutations, so
- * statically create them and we can do very fast parsing by checking all 12
- * fields in one go.
- */
-#define CAPWAP_PREAMBLE_MASK __cpu_to_be32(0xFF000000)
-#define CAPWAP_HLEN_SHIFT    17
-#define CAPWAP_HLEN_MASK     __cpu_to_be32(0x00F80000)
-#define CAPWAP_RID_MASK      __cpu_to_be32(0x0007C000)
-#define CAPWAP_WBID_MASK     __cpu_to_be32(0x00003E00)
-#define CAPWAP_F_MASK        __cpu_to_be32(0x000001FF)
-
-#define CAPWAP_F_FRAG        __cpu_to_be32(0x00000080)
-#define CAPWAP_F_LASTFRAG    __cpu_to_be32(0x00000040)
-#define CAPWAP_F_WSI         __cpu_to_be32(0x00000020)
-#define CAPWAP_F_RMAC        __cpu_to_be32(0x00000010)
-
-#define CAPWAP_RMAC_LEN      4
-
-/*  Standard CAPWAP looks for a WBID value of 2.
- *  When we insert WSI field, use WBID value of 30, which has been
- *  proposed for all "experimental" usage - users with no reserved WBID value
- *  of their own.
-*/
-#define CAPWAP_WBID_30   __cpu_to_be32(0x00003C00)
-#define CAPWAP_WBID_2    __cpu_to_be32(0x00000200)
-
-#define FRAG_HDR (CAPWAP_F_FRAG)
-#define FRAG_LAST_HDR (FRAG_HDR | CAPWAP_F_LASTFRAG)
-
-/* Keyed packet, WBID 30, and length long enough to include WSI key */
-#define CAPWAP_KEYED (CAPWAP_WBID_30 | CAPWAP_F_WSI | htonl(20 << CAPWAP_HLEN_SHIFT))
-/* A backward-compatible packet, WBID 2 and length of 2 words (no WSI fields) */
-#define CAPWAP_NO_WSI (CAPWAP_WBID_2 | htonl(8 << CAPWAP_HLEN_SHIFT))
-
-/* Mask for all parts of header that must be 0. */
-#define CAPWAP_ZERO_MASK (CAPWAP_PREAMBLE_MASK | \
-               (CAPWAP_F_MASK ^ (CAPWAP_F_WSI | CAPWAP_F_FRAG | CAPWAP_F_LASTFRAG | CAPWAP_F_RMAC)))
-
-struct capwaphdr {
-       __be32 begin;
-       __be16 frag_id;
-       /* low 3 bits of frag_off are reserved */
-       __be16 frag_off;
-};
-
-/*
- * We use the WSI field to hold additional tunnel data.
- * The first eight bits store the size of the wsi data in bytes.
- */
-struct capwaphdr_wsi {
-       u8 wsi_len;
-       u8 flags;
-       __be16 reserved_padding;
-};
-
-struct capwaphdr_wsi_key {
-       __be64 key;
-};
-
-/* Flag indicating a 64bit key is stored in WSI data field */
-#define CAPWAP_WSI_F_KEY64 0x80
-
-static struct capwaphdr *capwap_hdr(const struct sk_buff *skb)
-{
-       return (struct capwaphdr *)(udp_hdr(skb) + 1);
-}
-
-/*
- * The fragment offset is actually the high 13 bits of the last 16 bit field,
- * so we would normally need to right shift 3 places.  However, it stores the
- * offset in 8 byte chunks, which would involve a 3 place left shift.  So we
- * just mask off the last 3 bits and be done with it.
- */
-#define FRAG_OFF_MASK (~0x7U)
-
-/*
- * The minimum header length.  The header may be longer if the optional
- * WSI field is used.
- */
-#define CAPWAP_MIN_HLEN (sizeof(struct udphdr) + sizeof(struct capwaphdr))
-
-struct frag_match {
-       __be32 saddr;
-       __be32 daddr;
-       __be16 id;
-};
-
-struct frag_queue {
-       struct inet_frag_queue ifq;
-       struct frag_match match;
-};
-
-struct frag_skb_cb {
-       u16 offset;
-};
-#define FRAG_CB(skb) ((struct frag_skb_cb *)(skb)->cb)
-
-static struct sk_buff *fragment(struct sk_buff *, const struct vport *,
-                               struct dst_entry *dst, unsigned int hlen);
-static struct sk_buff *defrag(struct sk_buff *, bool frag_last);
-
-static void capwap_frag_init(struct inet_frag_queue *, void *match);
-static unsigned int capwap_frag_hash(struct inet_frag_queue *);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
-static int capwap_frag_match(struct inet_frag_queue *, void *match);
-#else
-static bool capwap_frag_match(struct inet_frag_queue *, void *match);
-#endif
-static void capwap_frag_expire(unsigned long ifq);
-
-static struct inet_frags frag_state = {
-       .constructor    = capwap_frag_init,
-       .qsize          = sizeof(struct frag_queue),
-       .hashfn         = capwap_frag_hash,
-       .match          = capwap_frag_match,
-       .frag_expire    = capwap_frag_expire,
-       .secret_interval = CAPWAP_FRAG_SECRET_INTERVAL,
-};
-
-static int capwap_hdr_len(const struct tnl_mutable_config *mutable,
-                         const struct ovs_key_ipv4_tunnel *tun_key)
-{
-       int size = CAPWAP_MIN_HLEN;
-       u32 flags;
-       __be64 out_key;
-
-       tnl_get_param(mutable, tun_key, &flags, &out_key);
-
-       /* CAPWAP has no checksums. */
-       if (flags & TNL_F_CSUM)
-               return -EINVAL;
-
-       /* if keys are specified, then add WSI field */
-       if (out_key || (flags & TNL_F_OUT_KEY_ACTION)) {
-               size += sizeof(struct capwaphdr_wsi) +
-                       sizeof(struct capwaphdr_wsi_key);
-       }
-
-       return size;
-}
-
-static struct sk_buff *capwap_build_header(const struct vport *vport,
-                                           const struct tnl_mutable_config *mutable,
-                                           struct dst_entry *dst,
-                                           struct sk_buff *skb,
-                                           int tunnel_hlen)
-{
-       struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
-       struct udphdr *udph = udp_hdr(skb);
-       struct capwaphdr *cwh = (struct capwaphdr *)(udph + 1);
-       u32 flags;
-       __be64 out_key;
-
-       tnl_get_param(mutable, tun_key, &flags, &out_key);
-
-       udph->source = htons(CAPWAP_SRC_PORT);
-       udph->dest = htons(CAPWAP_DST_PORT);
-       udph->check = 0;
-
-       cwh->frag_id = 0;
-       cwh->frag_off = 0;
-
-       if (out_key || flags & TNL_F_OUT_KEY_ACTION) {
-               /* first field in WSI is key */
-               struct capwaphdr_wsi *wsi = (struct capwaphdr_wsi *)(cwh + 1);
-
-               cwh->begin = CAPWAP_KEYED;
-
-               /* -1 for wsi_len byte, not included in length as per spec */
-               wsi->wsi_len = sizeof(struct capwaphdr_wsi) - 1
-                       + sizeof(struct capwaphdr_wsi_key);
-               wsi->flags = CAPWAP_WSI_F_KEY64;
-               wsi->reserved_padding = 0;
-
-               if (out_key) {
-                       struct capwaphdr_wsi_key *opt = (struct capwaphdr_wsi_key *)(wsi + 1);
-                       opt->key = out_key;
-               }
-       } else {
-               /* make packet readable by old capwap code */
-               cwh->begin = CAPWAP_NO_WSI;
-       }
-       udph->len = htons(skb->len - skb_transport_offset(skb));
-
-       if (unlikely(skb->len - skb_network_offset(skb) > dst_mtu(dst))) {
-               unsigned int hlen = skb_transport_offset(skb) + capwap_hdr_len(mutable, tun_key);
-               skb = fragment(skb, vport, dst, hlen);
-       }
-
-       return skb;
-}
-
-static int process_capwap_wsi(struct sk_buff *skb, __be64 *key, bool *key_present)
-{
-       struct capwaphdr *cwh = capwap_hdr(skb);
-       struct capwaphdr_wsi *wsi;
-       int hdr_len;
-       int rmac_len = 0;
-       int wsi_len;
-
-       if (((cwh->begin & CAPWAP_WBID_MASK) != CAPWAP_WBID_30))
-               return 0;
-
-       if (cwh->begin & CAPWAP_F_RMAC)
-               rmac_len = CAPWAP_RMAC_LEN;
-
-       hdr_len = ntohl(cwh->begin & CAPWAP_HLEN_MASK) >> CAPWAP_HLEN_SHIFT;
-
-       if (unlikely(sizeof(struct capwaphdr) + rmac_len + sizeof(struct capwaphdr_wsi) > hdr_len))
-               return -EINVAL;
-
-       /* read wsi header to find out how big it really is */
-       wsi = (struct capwaphdr_wsi *)((u8 *)(cwh + 1) + rmac_len);
-       /* +1 for length byte not included in wsi_len */
-       wsi_len = 1 + wsi->wsi_len;
-
-       if (unlikely(sizeof(struct capwaphdr) + rmac_len + wsi_len != hdr_len))
-               return -EINVAL;
-
-       wsi_len -= sizeof(struct capwaphdr_wsi);
-
-       if (wsi->flags & CAPWAP_WSI_F_KEY64) {
-               struct capwaphdr_wsi_key *opt;
-
-               if (unlikely(wsi_len < sizeof(struct capwaphdr_wsi_key)))
-                       return -EINVAL;
-
-               opt = (struct capwaphdr_wsi_key *)(wsi + 1);
-               *key = opt->key;
-               *key_present = true;
-       } else {
-               *key_present = false;
-       }
-
-       return 0;
-}
-
-static struct sk_buff *process_capwap_proto(struct sk_buff *skb, __be64 *key, bool *key_present)
-{
-       struct capwaphdr *cwh = capwap_hdr(skb);
-       int hdr_len = sizeof(struct udphdr);
-
-       if (unlikely((cwh->begin & CAPWAP_ZERO_MASK) != 0))
-               goto error;
-
-       hdr_len += ntohl(cwh->begin & CAPWAP_HLEN_MASK) >> CAPWAP_HLEN_SHIFT;
-       if (unlikely(hdr_len < CAPWAP_MIN_HLEN))
-               goto error;
-
-       if (unlikely(!pskb_may_pull(skb, hdr_len + ETH_HLEN)))
-               goto error;
-
-       cwh = capwap_hdr(skb);
-       __skb_pull(skb, hdr_len);
-       skb_postpull_rcsum(skb, skb_transport_header(skb), hdr_len + ETH_HLEN);
-
-       if (cwh->begin & CAPWAP_F_FRAG) {
-               skb = defrag(skb, (__force bool)(cwh->begin & CAPWAP_F_LASTFRAG));
-               if (!skb)
-                       return NULL;
-               cwh = capwap_hdr(skb);
-       }
-
-       if ((cwh->begin & CAPWAP_F_WSI) && process_capwap_wsi(skb, key, key_present))
-               goto error;
-
-       return skb;
-error:
-       kfree_skb(skb);
-       return NULL;
-}
-
-/* Called with rcu_read_lock and BH disabled. */
-static int capwap_rcv(struct sock *sk, struct sk_buff *skb)
-{
-       struct vport *vport;
-       const struct tnl_mutable_config *mutable;
-       struct iphdr *iph;
-       struct ovs_key_ipv4_tunnel tun_key;
-       __be64 key = 0;
-       bool key_present = false;
-
-       if (unlikely(!pskb_may_pull(skb, CAPWAP_MIN_HLEN + ETH_HLEN)))
-               goto error;
-
-       skb = process_capwap_proto(skb, &key, &key_present);
-       if (unlikely(!skb))
-               goto out;
-
-       iph = ip_hdr(skb);
-       vport = ovs_tnl_find_port(sock_net(sk), iph->daddr, iph->saddr, key,
-                                 TNL_T_PROTO_CAPWAP, &mutable);
-       if (unlikely(!vport)) {
-               icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
-               goto error;
-       }
-
-       if (key_present && mutable->key.daddr &&
-                        !(mutable->flags & TNL_F_IN_KEY_MATCH)) {
-               key_present = false;
-               key = 0;
-       }
-
-       tnl_tun_key_init(&tun_key, iph, key, key_present ? OVS_TNL_F_KEY : 0);
-       OVS_CB(skb)->tun_key = &tun_key;
-
-       ovs_tnl_rcv(vport, skb);
-       goto out;
-
-error:
-       kfree_skb(skb);
-out:
-       return 0;
-}
-
-static const struct tnl_ops capwap_tnl_ops = {
-       .tunnel_type    = TNL_T_PROTO_CAPWAP,
-       .ipproto        = IPPROTO_UDP,
-       .hdr_len        = capwap_hdr_len,
-       .build_header   = capwap_build_header,
-};
-
-static inline struct capwap_net *ovs_get_capwap_net(struct net *net)
-{
-       struct ovs_net *ovs_net = net_generic(net, ovs_net_id);
-       return &ovs_net->vport_net.capwap;
-}
-
-/* Arbitrary value.  Irrelevant as long as it's not 0 since we set the handler. */
-#define UDP_ENCAP_CAPWAP 10
-static int init_socket(struct net *net)
-{
-       int err;
-       struct capwap_net *capwap_net = ovs_get_capwap_net(net);
-       struct sockaddr_in sin;
-
-       if (capwap_net->n_tunnels) {
-               capwap_net->n_tunnels++;
-               return 0;
-       }
-
-       err = sock_create_kern(AF_INET, SOCK_DGRAM, 0,
-                              &capwap_net->capwap_rcv_socket);
-       if (err)
-               goto error;
-
-       /* release net ref. */
-       sk_change_net(capwap_net->capwap_rcv_socket->sk, net);
-
-       sin.sin_family = AF_INET;
-       sin.sin_addr.s_addr = htonl(INADDR_ANY);
-       sin.sin_port = htons(CAPWAP_DST_PORT);
-
-       err = kernel_bind(capwap_net->capwap_rcv_socket,
-                         (struct sockaddr *)&sin,
-                         sizeof(struct sockaddr_in));
-       if (err)
-               goto error_sock;
-
-       udp_sk(capwap_net->capwap_rcv_socket->sk)->encap_type = UDP_ENCAP_CAPWAP;
-       udp_sk(capwap_net->capwap_rcv_socket->sk)->encap_rcv = capwap_rcv;
-
-       capwap_net->frag_state.timeout          = CAPWAP_FRAG_TIMEOUT;
-       capwap_net->frag_state.high_thresh      = CAPWAP_FRAG_MAX_MEM;
-       capwap_net->frag_state.low_thresh       = CAPWAP_FRAG_PRUNE_MEM;
-
-       inet_frags_init_net(&capwap_net->frag_state);
-       udp_encap_enable();
-       capwap_net->n_tunnels++;
-       return 0;
-
-error_sock:
-       sk_release_kernel(capwap_net->capwap_rcv_socket->sk);
-error:
-       pr_warn("cannot register capwap protocol handler : %d\n", err);
-       return err;
-}
-
-static void release_socket(struct net *net)
-{
-       struct capwap_net *capwap_net = ovs_get_capwap_net(net);
-
-       capwap_net->n_tunnels--;
-       if (capwap_net->n_tunnels)
-               return;
-
-       inet_frags_exit_net(&capwap_net->frag_state, &frag_state);
-       sk_release_kernel(capwap_net->capwap_rcv_socket->sk);
-}
-
-static struct vport *capwap_create(const struct vport_parms *parms)
-{
-       struct vport *vport;
-       int err;
-
-       err = init_socket(ovs_dp_get_net(parms->dp));
-       if (err)
-               return ERR_PTR(err);
-
-       vport = ovs_tnl_create(parms, &ovs_capwap_vport_ops, &capwap_tnl_ops);
-       if (IS_ERR(vport))
-               release_socket(ovs_dp_get_net(parms->dp));
-
-       return vport;
-}
-
-static void capwap_destroy(struct vport *vport)
-{
-       ovs_tnl_destroy(vport);
-       release_socket(ovs_dp_get_net(vport->dp));
-}
-
-static int capwap_init(void)
-{
-       inet_frags_init(&frag_state);
-       return 0;
-}
-
-static void capwap_exit(void)
-{
-       inet_frags_fini(&frag_state);
-}
-
-static void copy_skb_metadata(struct sk_buff *from, struct sk_buff *to)
-{
-       to->pkt_type = from->pkt_type;
-       to->priority = from->priority;
-       to->protocol = from->protocol;
-       skb_dst_set(to, dst_clone(skb_dst(from)));
-       to->dev = from->dev;
-       to->mark = from->mark;
-
-       if (from->sk)
-               skb_set_owner_w(to, from->sk);
-
-#ifdef CONFIG_NET_SCHED
-       to->tc_index = from->tc_index;
-#endif
-#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
-       to->ipvs_property = from->ipvs_property;
-#endif
-       skb_copy_secmark(to, from);
-}
-
-static struct sk_buff *fragment(struct sk_buff *skb, const struct vport *vport,
-                               struct dst_entry *dst, unsigned int hlen)
-{
-       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       unsigned int headroom;
-       unsigned int max_frame_len = dst_mtu(dst) + skb_network_offset(skb);
-       struct sk_buff *result = NULL, *list_cur = NULL;
-       unsigned int remaining;
-       unsigned int offset;
-       __be16 frag_id;
-
-       if (hlen + ~FRAG_OFF_MASK + 1 > max_frame_len) {
-               if (net_ratelimit())
-                       pr_warn("capwap link mtu (%d) is less than minimum packet (%d)\n",
-                               dst_mtu(dst),
-                               hlen - skb_network_offset(skb) + ~FRAG_OFF_MASK + 1);
-               goto error;
-       }
-
-       remaining = skb->len - hlen;
-       offset = 0;
-       frag_id = htons(atomic_inc_return(&tnl_vport->frag_id));
-
-       headroom = dst->header_len + 16;
-       if (!skb_network_offset(skb))
-               headroom += LL_RESERVED_SPACE(dst->dev);
-
-       while (remaining) {
-               struct sk_buff *skb2;
-               int frag_size;
-               struct udphdr *udph;
-               struct capwaphdr *cwh;
-
-               frag_size = min(remaining, max_frame_len - hlen);
-               if (remaining > frag_size)
-                       frag_size &= FRAG_OFF_MASK;
-
-               skb2 = alloc_skb(headroom + hlen + frag_size, GFP_ATOMIC);
-               if (!skb2)
-                       goto error;
-
-               skb_reserve(skb2, headroom);
-               __skb_put(skb2, hlen + frag_size);
-
-               if (skb_network_offset(skb))
-                       skb_reset_mac_header(skb2);
-               skb_set_network_header(skb2, skb_network_offset(skb));
-               skb_set_transport_header(skb2, skb_transport_offset(skb));
-
-               /* Copy (Ethernet)/IP/UDP/CAPWAP header. */
-               copy_skb_metadata(skb, skb2);
-               skb_copy_from_linear_data(skb, skb2->data, hlen);
-
-               /* Copy this data chunk. */
-               if (skb_copy_bits(skb, hlen + offset, skb2->data + hlen, frag_size))
-                       BUG();
-
-               udph = udp_hdr(skb2);
-               udph->len = htons(skb2->len - skb_transport_offset(skb2));
-
-               cwh = capwap_hdr(skb2);
-               if (remaining > frag_size)
-                       cwh->begin |= FRAG_HDR;
-               else
-                       cwh->begin |= FRAG_LAST_HDR;
-               cwh->frag_id = frag_id;
-               cwh->frag_off = htons(offset);
-
-               if (result) {
-                       list_cur->next = skb2;
-                       list_cur = skb2;
-               } else
-                       result = list_cur = skb2;
-
-               offset += frag_size;
-               remaining -= frag_size;
-       }
-
-       consume_skb(skb);
-       return result;
-
-error:
-       ovs_tnl_free_linked_skbs(result);
-       kfree_skb(skb);
-       return NULL;
-}
-
-/* All of the following functions relate to fragmentation reassembly. */
-
-static struct frag_queue *ifq_cast(struct inet_frag_queue *ifq)
-{
-       return container_of(ifq, struct frag_queue, ifq);
-}
-
-static u32 frag_hash(struct frag_match *match)
-{
-       return jhash_3words((__force u16)match->id, (__force u32)match->saddr,
-                           (__force u32)match->daddr,
-                           frag_state.rnd) & (INETFRAGS_HASHSZ - 1);
-}
-
-static struct frag_queue *queue_find(struct netns_frags *ns_frag_state,
-                                    struct frag_match *match)
-{
-       struct inet_frag_queue *ifq;
-
-       read_lock(&frag_state.lock);
-
-       ifq = inet_frag_find(ns_frag_state, &frag_state, match, frag_hash(match));
-       if (!ifq)
-               return NULL;
-
-       /* Unlock happens inside inet_frag_find(). */
-
-       return ifq_cast(ifq);
-}
-
-static struct sk_buff *frag_reasm(struct frag_queue *fq, struct net_device *dev)
-{
-       struct sk_buff *head = fq->ifq.fragments;
-       struct sk_buff *frag;
-
-       /* Succeed or fail, we're done with this queue. */
-       inet_frag_kill(&fq->ifq, &frag_state);
-
-       if (fq->ifq.len > 65535)
-               return NULL;
-
-       /* Can't have the head be a clone. */
-       if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
-               return NULL;
-
-       /*
-        * We're about to build frag list for this SKB.  If it already has a
-        * frag list, alloc a new SKB and put the existing frag list there.
-        */
-       if (skb_shinfo(head)->frag_list) {
-               int i;
-               int paged_len = 0;
-
-               frag = alloc_skb(0, GFP_ATOMIC);
-               if (!frag)
-                       return NULL;
-
-               frag->next = head->next;
-               head->next = frag;
-               skb_shinfo(frag)->frag_list = skb_shinfo(head)->frag_list;
-               skb_shinfo(head)->frag_list = NULL;
-
-               for (i = 0; i < skb_shinfo(head)->nr_frags; i++)
-                       paged_len += skb_shinfo(head)->frags[i].size;
-               frag->len = frag->data_len = head->data_len - paged_len;
-               head->data_len -= frag->len;
-               head->len -= frag->len;
-
-               frag->ip_summed = head->ip_summed;
-               atomic_add(frag->truesize, &fq->ifq.net->mem);
-       }
-
-       skb_shinfo(head)->frag_list = head->next;
-       atomic_sub(head->truesize, &fq->ifq.net->mem);
-
-       /* Properly account for data in various packets. */
-       for (frag = head->next; frag; frag = frag->next) {
-               head->data_len += frag->len;
-               head->len += frag->len;
-
-               if (head->ip_summed != frag->ip_summed)
-                       head->ip_summed = CHECKSUM_NONE;
-               else if (head->ip_summed == CHECKSUM_COMPLETE)
-                       head->csum = csum_add(head->csum, frag->csum);
-
-               head->truesize += frag->truesize;
-               atomic_sub(frag->truesize, &fq->ifq.net->mem);
-       }
-
-       head->next = NULL;
-       head->dev = dev;
-       head->tstamp = fq->ifq.stamp;
-       fq->ifq.fragments = NULL;
-
-       return head;
-}
-
-static struct sk_buff *frag_queue(struct frag_queue *fq, struct sk_buff *skb,
-                                 u16 offset, bool frag_last)
-{
-       struct sk_buff *prev, *next;
-       struct net_device *dev;
-       int end;
-
-       if (fq->ifq.last_in & INET_FRAG_COMPLETE)
-               goto error;
-
-       if (!skb->len)
-               goto error;
-
-       end = offset + skb->len;
-
-       if (frag_last) {
-               /*
-                * Last fragment, shouldn't already have data past our end or
-                * have another last fragment.
-                */
-               if (end < fq->ifq.len || fq->ifq.last_in & INET_FRAG_LAST_IN)
-                       goto error;
-
-               fq->ifq.last_in |= INET_FRAG_LAST_IN;
-               fq->ifq.len = end;
-       } else {
-               /* Fragments should align to 8 byte chunks. */
-               if (end & ~FRAG_OFF_MASK)
-                       goto error;
-
-               if (end > fq->ifq.len) {
-                       /*
-                        * Shouldn't have data past the end, if we already
-                        * have one.
-                        */
-                       if (fq->ifq.last_in & INET_FRAG_LAST_IN)
-                               goto error;
-
-                       fq->ifq.len = end;
-               }
-       }
-
-       /* Find where we fit in. */
-       prev = NULL;
-       for (next = fq->ifq.fragments; next != NULL; next = next->next) {
-               if (FRAG_CB(next)->offset >= offset)
-                       break;
-               prev = next;
-       }
-
-       /*
-        * Overlapping fragments aren't allowed.  We shouldn't start before
-        * the end of the previous fragment.
-        */
-       if (prev && FRAG_CB(prev)->offset + prev->len > offset)
-               goto error;
-
-       /* We also shouldn't end after the beginning of the next fragment. */
-       if (next && end > FRAG_CB(next)->offset)
-               goto error;
-
-       FRAG_CB(skb)->offset = offset;
-
-       /* Link into list. */
-       skb->next = next;
-       if (prev)
-               prev->next = skb;
-       else
-               fq->ifq.fragments = skb;
-
-       dev = skb->dev;
-       skb->dev = NULL;
-
-       fq->ifq.stamp = skb->tstamp;
-       fq->ifq.meat += skb->len;
-       atomic_add(skb->truesize, &fq->ifq.net->mem);
-       if (offset == 0)
-               fq->ifq.last_in |= INET_FRAG_FIRST_IN;
-
-       /* If we have all fragments do reassembly. */
-       if (fq->ifq.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
-           fq->ifq.meat == fq->ifq.len)
-               return frag_reasm(fq, dev);
-
-       write_lock(&frag_state.lock);
-       list_move_tail(&fq->ifq.lru_list, &fq->ifq.net->lru_list);
-       write_unlock(&frag_state.lock);
-
-       return NULL;
-
-error:
-       kfree_skb(skb);
-       return NULL;
-}
-
-static struct sk_buff *defrag(struct sk_buff *skb, bool frag_last)
-{
-       struct iphdr *iph = ip_hdr(skb);
-       struct capwaphdr *cwh = capwap_hdr(skb);
-       struct capwap_net *capwap_net = ovs_get_capwap_net(dev_net(skb->dev));
-       struct netns_frags *ns_frag_state = &capwap_net->frag_state;
-       struct frag_match match;
-       u16 frag_off;
-       struct frag_queue *fq;
-
-       inet_frag_evictor(ns_frag_state, &frag_state, false);
-
-       match.daddr = iph->daddr;
-       match.saddr = iph->saddr;
-       match.id = cwh->frag_id;
-       frag_off = ntohs(cwh->frag_off) & FRAG_OFF_MASK;
-
-       fq = queue_find(ns_frag_state, &match);
-       if (fq) {
-               spin_lock(&fq->ifq.lock);
-               skb = frag_queue(fq, skb, frag_off, frag_last);
-               spin_unlock(&fq->ifq.lock);
-
-               inet_frag_put(&fq->ifq, &frag_state);
-
-               return skb;
-       }
-
-       kfree_skb(skb);
-       return NULL;
-}
-
-static void capwap_frag_init(struct inet_frag_queue *ifq, void *match_)
-{
-       struct frag_match *match = match_;
-
-       ifq_cast(ifq)->match = *match;
-}
-
-static unsigned int capwap_frag_hash(struct inet_frag_queue *ifq)
-{
-       return frag_hash(&ifq_cast(ifq)->match);
-}
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
-static int capwap_frag_match(struct inet_frag_queue *ifq, void *a_)
-#else
-static bool capwap_frag_match(struct inet_frag_queue *ifq, void *a_)
-#endif
-{
-       struct frag_match *a = a_;
-       struct frag_match *b = &ifq_cast(ifq)->match;
-
-       return a->id == b->id && a->saddr == b->saddr && a->daddr == b->daddr;
-}
-
-/* Run when the timeout for a given queue expires. */
-static void capwap_frag_expire(unsigned long ifq)
-{
-       struct frag_queue *fq;
-
-       fq = ifq_cast((struct inet_frag_queue *)ifq);
-
-       spin_lock(&fq->ifq.lock);
-
-       if (!(fq->ifq.last_in & INET_FRAG_COMPLETE))
-               inet_frag_kill(&fq->ifq, &frag_state);
-
-       spin_unlock(&fq->ifq.lock);
-       inet_frag_put(&fq->ifq, &frag_state);
-}
-
-const struct vport_ops ovs_capwap_vport_ops = {
-       .type           = OVS_VPORT_TYPE_CAPWAP,
-       .flags          = VPORT_F_TUN_ID,
-       .init           = capwap_init,
-       .exit           = capwap_exit,
-       .create         = capwap_create,
-       .destroy        = capwap_destroy,
-       .get_name       = ovs_tnl_get_name,
-       .get_options    = ovs_tnl_get_options,
-       .set_options    = ovs_tnl_set_options,
-       .send           = ovs_tnl_send,
-};
-#else
-#warning CAPWAP tunneling will not be available on kernels before 2.6.26
-#endif /* Linux kernel < 2.6.26 */
diff --git a/datapath/vport-capwap.h b/datapath/vport-capwap.h
deleted file mode 100644 (file)
index 5c0a6f8..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2012 Nicira, Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA
- */
-
-#ifndef VPORT_CAPWAP_H
-#define VPORT_CAPWAP_H 1
-
-#include <linux/net.h>
-
-struct capwap_net {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
-       struct socket *capwap_rcv_socket;
-       struct netns_frags frag_state;
-       int n_tunnels;
-#endif
-};
-
-#endif /* vport-capwap.h */
index 14c5ba3..40b96cf 100644 (file)
@@ -44,32 +44,30 @@ struct gre_base_hdr {
        __be16 protocol;
 };
 
-static int gre_hdr_len(const struct tnl_mutable_config *mutable,
-                      const struct ovs_key_ipv4_tunnel *tun_key)
+static int gre_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key)
 {
-       int len;
-       u32 flags;
-       __be64 out_key;
+       int len = GRE_HEADER_SECTION;
 
-       tnl_get_param(mutable, tun_key, &flags, &out_key);
-       len = GRE_HEADER_SECTION;
-
-       if (flags & TNL_F_CSUM)
+       if (tun_key->tun_flags & OVS_TNL_F_KEY)
+               len += GRE_HEADER_SECTION;
+       if (tun_key->tun_flags & OVS_TNL_F_CSUM)
                len += GRE_HEADER_SECTION;
+       return len;
+}
 
+static int gre64_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key)
+{
        /* Set key for GRE64 tunnels, even when key if is zero. */
-       if (out_key ||
-           mutable->key.tunnel_type & TNL_T_PROTO_GRE64 ||
-           flags & TNL_F_OUT_KEY_ACTION) {
+       int len = GRE_HEADER_SECTION +          /* GRE Hdr */
+                 GRE_HEADER_SECTION +          /* GRE Key */
+                 GRE_HEADER_SECTION;           /* GRE SEQ */
 
+       if (tun_key->tun_flags & OVS_TNL_F_CSUM)
                len += GRE_HEADER_SECTION;
-               if (mutable->key.tunnel_type & TNL_T_PROTO_GRE64)
-                       len += GRE_HEADER_SECTION;
-       }
+
        return len;
 }
 
-
 /* Returns the least-significant 32 bits of a __be64. */
 static __be32 be64_get_low32(__be64 x)
 {
@@ -89,39 +87,31 @@ static __be32 be64_get_high32(__be64 x)
 #endif
 }
 
-static struct sk_buff *gre_build_header(const struct vport *vport,
-                                        const struct tnl_mutable_config *mutable,
-                                        struct dst_entry *dst,
-                                        struct sk_buff *skb,
-                                        int tunnel_hlen)
+static void __gre_build_header(struct sk_buff *skb,
+                              int tunnel_hlen,
+                              bool is_gre64)
 {
-       u32 flags;
-       __be64 out_key;
        const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
        __be32 *options = (__be32 *)(skb_network_header(skb) + tunnel_hlen
-                                              - GRE_HEADER_SECTION);
+                       - GRE_HEADER_SECTION);
        struct gre_base_hdr *greh = (struct gre_base_hdr *) skb_transport_header(skb);
-
-       tnl_get_param(mutable, tun_key, &flags, &out_key);
-
        greh->protocol = htons(ETH_P_TEB);
        greh->flags = 0;
 
        /* Work backwards over the options so the checksum is last. */
-       if (out_key || flags & TNL_F_OUT_KEY_ACTION ||
-           mutable->key.tunnel_type & TNL_T_PROTO_GRE64) {
+       if (tun_key->tun_flags & OVS_TNL_F_KEY || is_gre64) {
                greh->flags |= GRE_KEY;
-               if (mutable->key.tunnel_type & TNL_T_PROTO_GRE64) {
+               if (is_gre64) {
                        /* Set higher 32 bits to seq. */
-                       *options = be64_get_high32(out_key);
+                       *options = be64_get_high32(tun_key->tun_id);
                        options--;
                        greh->flags |= GRE_SEQ;
                }
-               *options = be64_get_low32(out_key);
+               *options = be64_get_low32(tun_key->tun_id);
                options--;
        }
 
-       if (flags & TNL_F_CSUM) {
+       if (tun_key->tun_flags & OVS_TNL_F_CSUM) {
                greh->flags |= GRE_CSUM;
                *options = 0;
                *(__sum16 *)options = csum_fold(skb_checksum(skb,
@@ -129,16 +119,20 @@ static struct sk_buff *gre_build_header(const struct vport *vport,
                                                skb->len - skb_transport_offset(skb),
                                                0));
        }
-       /*
-        * Allow our local IP stack to fragment the outer packet even if the
-        * DF bit is set as a last resort.  We also need to force selection of
-        * an IP ID here because Linux will otherwise leave it at 0 if the
-        * packet originally had DF set.
-        */
-       skb->local_df = 1;
-       __ip_select_ident(ip_hdr(skb), dst, 0);
-
-       return skb;
+}
+
+static void gre_build_header(const struct vport *vport,
+                            struct sk_buff *skb,
+                            int tunnel_hlen)
+{
+       __gre_build_header(skb, tunnel_hlen, false);
+}
+
+static void gre64_build_header(const struct vport *vport,
+                              struct sk_buff *skb,
+                              int tunnel_hlen)
+{
+       __gre_build_header(skb, tunnel_hlen, true);
 }
 
 static __be64 key_to_tunnel_id(__be32 key, __be32 seq)
@@ -151,7 +145,7 @@ static __be64 key_to_tunnel_id(__be32 key, __be32 seq)
 }
 
 static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *tun_id,
-                       u32 *tunnel_type)
+                       bool *is_gre64)
 {
        /* IP and ICMP protocol handlers check that the IHL is valid. */
        struct gre_base_hdr *greh = (struct gre_base_hdr *)((u8 *)iph + (iph->ihl << 2));
@@ -183,16 +177,16 @@ static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *tun_id,
 
                if (greh->flags & GRE_SEQ) {
                        seq = *options;
-                       *tunnel_type = TNL_T_PROTO_GRE64;
+                       *is_gre64 = true;
                } else {
                        seq = 0;
-                       *tunnel_type = TNL_T_PROTO_GRE;
+                       *is_gre64 = false;
                }
                *tun_id = key_to_tunnel_id(gre_key, seq);
        } else {
                *tun_id = 0;
                /* Ignore GRE seq if there is no key present. */
-               *tunnel_type = TNL_T_PROTO_GRE;
+               *is_gre64 = false;
        }
 
        if (greh->flags & GRE_SEQ)
@@ -227,18 +221,12 @@ static bool check_checksum(struct sk_buff *skb)
        return (csum == 0);
 }
 
-static u32 gre_flags_to_tunnel_flags(const struct tnl_mutable_config *mutable,
-                                    __be16 gre_flags, __be64 *key)
+static u32 gre_flags_to_tunnel_flags(__be16 gre_flags, bool is_gre64)
 {
        u32 tunnel_flags = 0;
 
-       if (gre_flags & GRE_KEY) {
-               if (mutable->flags & TNL_F_IN_KEY_MATCH ||
-                   !mutable->key.daddr)
-                       tunnel_flags = OVS_TNL_F_KEY;
-               else
-                       *key = 0;
-       }
+       if (gre_flags & GRE_KEY || is_gre64)
+               tunnel_flags = OVS_TNL_F_KEY;
 
        if (gre_flags & GRE_CSUM)
                tunnel_flags |= OVS_TNL_F_CSUM;
@@ -249,37 +237,38 @@ static u32 gre_flags_to_tunnel_flags(const struct tnl_mutable_config *mutable,
 /* Called with rcu_read_lock and BH disabled. */
 static int gre_rcv(struct sk_buff *skb)
 {
+       struct ovs_net *ovs_net;
        struct vport *vport;
-       const struct tnl_mutable_config *mutable;
        int hdr_len;
        struct iphdr *iph;
        struct ovs_key_ipv4_tunnel tun_key;
        __be16 gre_flags;
        u32 tnl_flags;
        __be64 key;
-       u32 tunnel_type;
+       bool is_gre64;
 
        if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr) + ETH_HLEN)))
                goto error;
        if (unlikely(!check_checksum(skb)))
                goto error;
 
-       hdr_len = parse_header(ip_hdr(skb), &gre_flags, &key, &tunnel_type);
+       hdr_len = parse_header(ip_hdr(skb), &gre_flags, &key, &is_gre64);
        if (unlikely(hdr_len < 0))
                goto error;
 
-       if (unlikely(!pskb_may_pull(skb, hdr_len + ETH_HLEN)))
+       ovs_net = net_generic(dev_net(skb->dev), ovs_net_id);
+       if (is_gre64)
+               vport = rcu_dereference(ovs_net->vport_net.gre64_vport);
+       else
+               vport = rcu_dereference(ovs_net->vport_net.gre_vport);
+       if (unlikely(!vport))
                goto error;
 
-       iph = ip_hdr(skb);
-       vport = ovs_tnl_find_port(dev_net(skb->dev), iph->daddr, iph->saddr, key,
-                                 tunnel_type, &mutable);
-       if (unlikely(!vport)) {
-               icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+       if (unlikely(!pskb_may_pull(skb, hdr_len + ETH_HLEN)))
                goto error;
-       }
 
-       tnl_flags = gre_flags_to_tunnel_flags(mutable, gre_flags, &key);
+       iph = ip_hdr(skb);
+       tnl_flags = gre_flags_to_tunnel_flags(gre_flags, is_gre64);
        tnl_tun_key_init(&tun_key, iph, key, tnl_flags);
        OVS_CB(skb)->tun_key = &tun_key;
 
@@ -294,30 +283,6 @@ error:
        return 0;
 }
 
-static const struct tnl_ops gre_tnl_ops = {
-       .tunnel_type    = TNL_T_PROTO_GRE,
-       .ipproto        = IPPROTO_GRE,
-       .hdr_len        = gre_hdr_len,
-       .build_header   = gre_build_header,
-};
-
-static struct vport *gre_create(const struct vport_parms *parms)
-{
-       return ovs_tnl_create(parms, &ovs_gre_vport_ops, &gre_tnl_ops);
-}
-
-static const struct tnl_ops gre64_tnl_ops = {
-       .tunnel_type    = TNL_T_PROTO_GRE64,
-       .ipproto        = IPPROTO_GRE,
-       .hdr_len        = gre_hdr_len,
-       .build_header   = gre_build_header,
-};
-
-static struct vport *gre_create64(const struct vport_parms *parms)
-{
-       return ovs_tnl_create(parms, &ovs_gre64_vport_ops, &gre64_tnl_ops);
-}
-
 static const struct net_protocol gre_protocol_handlers = {
        .handler        =       gre_rcv,
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
@@ -352,28 +317,93 @@ static void gre_exit(void)
        inet_del_protocol(&gre_protocol_handlers, IPPROTO_GRE);
 }
 
+/* GRE vport. */
+static const struct tnl_ops gre_tnl_ops = {
+       .ipproto        = IPPROTO_GRE,
+       .hdr_len        = gre_hdr_len,
+       .build_header   = gre_build_header,
+};
+
+static struct vport *gre_create(const struct vport_parms *parms)
+{
+       struct net *net = ovs_dp_get_net(parms->dp);
+       struct ovs_net *ovs_net;
+       struct vport *vport;
+
+       ovs_net = net_generic(net, ovs_net_id);
+       if (rtnl_dereference(ovs_net->vport_net.gre_vport))
+               return ERR_PTR(-EEXIST);
+
+       vport = ovs_tnl_create(parms, &ovs_gre_vport_ops, &gre_tnl_ops);
+
+       rcu_assign_pointer(ovs_net->vport_net.gre_vport, vport);
+       return vport;
+}
+
+static void gre_tnl_destroy(struct vport *vport)
+{
+       struct net *net = ovs_dp_get_net(vport->dp);
+       struct ovs_net *ovs_net;
+
+       ovs_net = net_generic(net, ovs_net_id);
+
+       rcu_assign_pointer(ovs_net->vport_net.gre_vport, NULL);
+       ovs_tnl_destroy(vport);
+}
+
 const struct vport_ops ovs_gre_vport_ops = {
        .type           = OVS_VPORT_TYPE_GRE,
        .flags          = VPORT_F_TUN_ID,
        .init           = gre_init,
        .exit           = gre_exit,
        .create         = gre_create,
-       .destroy        = ovs_tnl_destroy,
+       .destroy        = gre_tnl_destroy,
        .get_name       = ovs_tnl_get_name,
-       .get_options    = ovs_tnl_get_options,
-       .set_options    = ovs_tnl_set_options,
        .send           = ovs_tnl_send,
 };
 
+/* GRE64 vport. */
+static const struct tnl_ops gre64_tnl_ops = {
+       .ipproto        = IPPROTO_GRE,
+       .hdr_len        = gre64_hdr_len,
+       .build_header   = gre64_build_header,
+};
+
+static struct vport *gre64_create(const struct vport_parms *parms)
+{
+       struct net *net = ovs_dp_get_net(parms->dp);
+       struct ovs_net *ovs_net;
+       struct vport *vport;
+
+       ovs_net = net_generic(net, ovs_net_id);
+       if (rtnl_dereference(ovs_net->vport_net.gre64_vport))
+               return ERR_PTR(-EEXIST);
+
+       vport = ovs_tnl_create(parms, &ovs_gre64_vport_ops, &gre64_tnl_ops);
+
+       rcu_assign_pointer(ovs_net->vport_net.gre64_vport, vport);
+       return vport;
+}
+
+
+static void gre64_tnl_destroy(struct vport *vport)
+{
+       struct net *net = ovs_dp_get_net(vport->dp);
+       struct ovs_net *ovs_net;
+
+       ovs_net = net_generic(net, ovs_net_id);
+
+       rcu_assign_pointer(ovs_net->vport_net.gre64_vport, NULL);
+       ovs_tnl_destroy(vport);
+}
+
 const struct vport_ops ovs_gre64_vport_ops = {
        .type           = OVS_VPORT_TYPE_GRE64,
        .flags          = VPORT_F_TUN_ID,
        .init           = gre_init,
        .exit           = gre_exit,
-       .create         = gre_create64,
-       .destroy        = ovs_tnl_destroy,
+       .create         = gre64_create,
+       .destroy        = gre64_tnl_destroy,
        .get_name       = ovs_tnl_get_name,
-       .get_options    = ovs_tnl_get_options,
-       .set_options    = ovs_tnl_set_options,
        .send           = ovs_tnl_send,
 };
index a5f2d75..003e880 100644 (file)
@@ -92,7 +92,6 @@ static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
        }
 
        vlan_copy_skb_tci(skb);
-       OVS_CB(skb)->flow = NULL;
 
        rcu_read_lock();
        ovs_vport_receive(internal_dev_priv(netdev)->vport, skb);
@@ -115,7 +114,7 @@ static int internal_dev_stop(struct net_device *netdev)
 static void internal_dev_getinfo(struct net_device *netdev,
                                 struct ethtool_drvinfo *info)
 {
-       strcpy(info->driver, "openvswitch");
+       strlcpy(info->driver, "openvswitch", sizeof(info->driver));
 }
 
 static const struct ethtool_ops internal_dev_ethtool_ops = {
@@ -289,7 +288,7 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb)
 
 const struct vport_ops ovs_internal_vport_ops = {
        .type           = OVS_VPORT_TYPE_INTERNAL,
-       .flags          = VPORT_F_REQUIRED | VPORT_F_FLOW,
+       .flags          = VPORT_F_REQUIRED,
        .create         = internal_dev_create,
        .destroy        = internal_dev_destroy,
        .get_name       = ovs_netdev_get_name,
diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c
new file mode 100644 (file)
index 0000000..1fff5ae
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2011 Nicira, Inc.
+ * Copyright (c) 2013 Cisco Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/net.h>
+#include <linux/rculist.h>
+#include <linux/udp.h>
+
+#include <net/icmp.h>
+#include <net/ip.h>
+#include <net/udp.h>
+
+#include "datapath.h"
+#include "tunnel.h"
+#include "vport.h"
+
+
+/*
+ *  LISP encapsulation header:
+ *
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |N|L|E|V|I|flags|            Nonce/Map-Version                  |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                 Instance ID/Locator Status Bits               |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+
+/**
+ * struct lisphdr - LISP header
+ * @nonce_present: Flag indicating the presence of a 24 bit nonce value.
+ * @locator_status_bits_present: Flag indicating the presence of Locator Status
+ *                               Bits (LSB).
+ * @solicit_echo_nonce: Flag indicating the use of the echo noncing mechanism.
+ * @map_version_present: Flag indicating the use of mapping versioning.
+ * @instance_id_present: Flag indicating the presence of a 24 bit Instance ID.
+ * @reserved_flags: 3 bits reserved for future flags.
+ * @nonce: 24 bit nonce value.
+ * @map_version: 24 bit mapping version.
+ * @locator_status_bits: Locator Status Bits: 32 bits when instance_id_present
+ *                       is not set, 8 bits when it is.
+ * @instance_id: 24 bit Instance ID
+ */
+struct lisphdr {
+#ifdef __LITTLE_ENDIAN_BITFIELD
+       __u8 reserved_flags:3;
+       __u8 instance_id_present:1;
+       __u8 map_version_present:1;
+       __u8 solicit_echo_nonce:1;
+       __u8 locator_status_bits_present:1;
+       __u8 nonce_present:1;
+#else
+       __u8 nonce_present:1;
+       __u8 locator_status_bits_present:1;
+       __u8 solicit_echo_nonce:1;
+       __u8 map_version_present:1;
+       __u8 instance_id_present:1;
+       __u8 reserved_flags:3;
+#endif
+       union {
+               __u8 nonce[3];
+               __u8 map_version[3];
+       } u1;
+       union {
+               __be32 locator_status_bits;
+               struct {
+                       __u8 instance_id[3];
+                       __u8 locator_status_bits;
+               } word2;
+       } u2;
+};
+
+#define LISP_HLEN (sizeof(struct udphdr) + sizeof(struct lisphdr))
+
+static inline int lisp_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key)
+{
+       return LISP_HLEN;
+}
+
+/**
+ * struct lisp_port - Keeps track of open UDP ports
+ * @list: list element.
+ * @vport: vport for the tunnel.
+ * @socket: The socket created for this port number.
+ */
+struct lisp_port {
+       struct list_head list;
+       struct vport *vport;
+       struct socket *lisp_rcv_socket;
+       struct rcu_head rcu;
+};
+
+static LIST_HEAD(lisp_ports);
+
+static struct lisp_port *lisp_find_port(struct net *net, __be16 port)
+{
+       struct lisp_port *lisp_port;
+
+       list_for_each_entry_rcu(lisp_port, &lisp_ports, list) {
+               struct tnl_vport *tnl_vport = tnl_vport_priv(lisp_port->vport);
+
+               if (tnl_vport->dst_port == port &&
+                       net_eq(sock_net(lisp_port->lisp_rcv_socket->sk), net))
+                       return lisp_port;
+       }
+
+       return NULL;
+}
+
+static inline struct lisphdr *lisp_hdr(const struct sk_buff *skb)
+{
+       return (struct lisphdr *)(udp_hdr(skb) + 1);
+}
+
+static int lisp_tnl_send(struct vport *vport, struct sk_buff *skb)
+{
+       int tnl_len;
+       int network_offset = skb_network_offset(skb);
+
+       /* We only encapsulate IPv4 and IPv6 packets */
+       switch (skb->protocol) {
+       case htons(ETH_P_IP):
+       case htons(ETH_P_IPV6):
+               /* Pop off "inner" Ethernet header */
+               skb_pull(skb, network_offset);
+               tnl_len = ovs_tnl_send(vport, skb);
+               return tnl_len > 0 ? tnl_len + network_offset : tnl_len;
+       default:
+               kfree_skb(skb);
+               return 0;
+       }
+}
+
+/* Convert 64 bit tunnel ID to 24 bit Instance ID. */
+static void tunnel_id_to_instance_id(__be64 tun_id, __u8 *iid)
+{
+
+#ifdef __BIG_ENDIAN
+       iid[0] = (__force __u8)(tun_id >> 16);
+       iid[1] = (__force __u8)(tun_id >> 8);
+       iid[2] = (__force __u8)tun_id;
+#else
+       iid[0] = (__force __u8)((__force u64)tun_id >> 40);
+       iid[1] = (__force __u8)((__force u64)tun_id >> 48);
+       iid[2] = (__force __u8)((__force u64)tun_id >> 56);
+#endif
+}
+
+/* Convert 24 bit Instance ID to 64 bit tunnel ID. */
+static __be64 instance_id_to_tunnel_id(__u8 *iid)
+{
+#ifdef __BIG_ENDIAN
+       return (iid[0] << 16) | (iid[1] << 8) | iid[2];
+#else
+       return (__force __be64)(((__force u64)iid[0] << 40) |
+                               ((__force u64)iid[1] << 48) |
+                               ((__force u64)iid[2] << 56));
+#endif
+}
+
+static void lisp_build_header(const struct vport *vport,
+                             struct sk_buff *skb,
+                             int tunnel_hlen)
+{
+       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+       struct udphdr *udph = udp_hdr(skb);
+       struct lisphdr *lisph = (struct lisphdr *)(udph + 1);
+       const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
+
+       udph->dest = tnl_vport->dst_port;
+       udph->source = htons(ovs_tnl_get_src_port(skb));
+       udph->check = 0;
+       udph->len = htons(skb->len - skb_transport_offset(skb));
+
+       lisph->nonce_present = 0;       /* We don't support echo nonce algorithm */
+       lisph->locator_status_bits_present = 1; /* Set LSB */
+       lisph->solicit_echo_nonce = 0;  /* No echo noncing */
+       lisph->map_version_present = 0; /* No mapping versioning, nonce instead */
+       lisph->instance_id_present = 1; /* Store the tun_id as Instance ID  */
+       lisph->reserved_flags = 0;      /* Reserved flags, set to 0  */
+
+       lisph->u1.nonce[0] = 0;
+       lisph->u1.nonce[1] = 0;
+       lisph->u1.nonce[2] = 0;
+
+       tunnel_id_to_instance_id(tun_key->tun_id, &lisph->u2.word2.instance_id[0]);
+       lisph->u2.word2.locator_status_bits = 1;
+}
+
+/* Called with rcu_read_lock and BH disabled. */
+static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
+{
+       struct lisp_port *lisp_port;
+       struct lisphdr *lisph;
+       struct iphdr *iph, *inner_iph;
+       struct ovs_key_ipv4_tunnel tun_key;
+       __be64 key;
+       struct ethhdr *ethh;
+       __be16 protocol;
+
+       lisp_port = lisp_find_port(dev_net(skb->dev), udp_hdr(skb)->dest);
+       if (unlikely(!lisp_port))
+               goto error;
+
+       if (unlikely(!pskb_may_pull(skb, LISP_HLEN)))
+               goto error;
+
+       lisph = lisp_hdr(skb);
+
+       skb_pull_rcsum(skb, LISP_HLEN);
+
+       if (lisph->instance_id_present != 1)
+               key = 0;
+       else
+               key = instance_id_to_tunnel_id(&lisph->u2.word2.instance_id[0]);
+
+       /* Save outer tunnel values */
+       iph = ip_hdr(skb);
+       tnl_tun_key_init(&tun_key, iph, key, OVS_TNL_F_KEY);
+       OVS_CB(skb)->tun_key = &tun_key;
+
+       /* Drop non-IP inner packets */
+       inner_iph = (struct iphdr *)(lisph + 1);
+       switch (inner_iph->version) {
+       case 4:
+               protocol = htons(ETH_P_IP);
+               break;
+       case 6:
+               protocol = htons(ETH_P_IPV6);
+               break;
+       default:
+               goto error;
+       }
+
+       /* Add Ethernet header */
+       ethh = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+       memset(ethh, 0, ETH_HLEN);
+       ethh->h_dest[0] = 0x02;
+       ethh->h_source[0] = 0x02;
+       ethh->h_proto = protocol;
+
+       ovs_tnl_rcv(lisp_port->vport, skb);
+       goto out;
+
+error:
+       kfree_skb(skb);
+out:
+       return 0;
+}
+
+/* Arbitrary value.  Irrelevant as long as it's not 0 since we set the handler. */
+#define UDP_ENCAP_LISP 1
+static int lisp_socket_init(struct lisp_port *lisp_port, struct net *net)
+{
+       int err;
+       struct sockaddr_in sin;
+       struct tnl_vport *tnl_vport = tnl_vport_priv(lisp_port->vport);
+
+       err = sock_create_kern(AF_INET, SOCK_DGRAM, 0,
+                              &lisp_port->lisp_rcv_socket);
+       if (err)
+               goto error;
+
+       /* release net ref. */
+       sk_change_net(lisp_port->lisp_rcv_socket->sk, net);
+
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = htonl(INADDR_ANY);
+       sin.sin_port = tnl_vport->dst_port;
+
+       err = kernel_bind(lisp_port->lisp_rcv_socket, (struct sockaddr *)&sin,
+                         sizeof(struct sockaddr_in));
+       if (err)
+               goto error_sock;
+
+       udp_sk(lisp_port->lisp_rcv_socket->sk)->encap_type = UDP_ENCAP_LISP;
+       udp_sk(lisp_port->lisp_rcv_socket->sk)->encap_rcv = lisp_rcv;
+
+       udp_encap_enable();
+
+       return 0;
+
+error_sock:
+       sk_release_kernel(lisp_port->lisp_rcv_socket->sk);
+error:
+       pr_warn("cannot register lisp protocol handler: %d\n", err);
+       return err;
+}
+
+
+static void free_port_rcu(struct rcu_head *rcu)
+{
+       struct lisp_port *lisp_port = container_of(rcu,
+                       struct lisp_port, rcu);
+
+       kfree(lisp_port);
+}
+
+static void lisp_tunnel_release(struct lisp_port *lisp_port)
+{
+       if (!lisp_port)
+               return;
+       list_del_rcu(&lisp_port->list);
+       /* Release socket */
+       sk_release_kernel(lisp_port->lisp_rcv_socket->sk);
+       call_rcu(&lisp_port->rcu, free_port_rcu);
+}
+
+static int lisp_tunnel_setup(struct net *net, struct vport *vport,
+                            struct nlattr *options)
+{
+       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+       struct lisp_port *lisp_port;
+       struct nlattr *a;
+       int err;
+       u16 dst_port;
+
+       if (!options) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT);
+       if (a && nla_len(a) == sizeof(u16)) {
+               dst_port = nla_get_u16(a);
+       } else {
+               /* Require destination port from userspace. */
+               err = -EINVAL;
+               goto out;
+       }
+
+       /* Verify if we already have a socket created for this port */
+       lisp_port = lisp_find_port(net, htons(dst_port));
+       if (lisp_port) {
+               err = -EEXIST;
+               goto out;
+       }
+
+       /* Add a new socket for this port */
+       lisp_port = kzalloc(sizeof(struct lisp_port), GFP_KERNEL);
+       if (!lisp_port) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       tnl_vport->dst_port = htons(dst_port);
+       lisp_port->vport = vport;
+       list_add_tail_rcu(&lisp_port->list, &lisp_ports);
+
+       err = lisp_socket_init(lisp_port, net);
+       if (err)
+               goto error;
+
+       return 0;
+
+error:
+       list_del_rcu(&lisp_port->list);
+       kfree(lisp_port);
+out:
+       return err;
+}
+
+static int lisp_get_options(const struct vport *vport, struct sk_buff *skb)
+{
+       const struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+
+       if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(tnl_vport->dst_port)))
+               return -EMSGSIZE;
+       return 0;
+}
+
+static const struct tnl_ops ovs_lisp_tnl_ops = {
+       .ipproto        = IPPROTO_UDP,
+       .hdr_len        = lisp_hdr_len,
+       .build_header   = lisp_build_header,
+};
+
+static void lisp_tnl_destroy(struct vport *vport)
+{
+       struct lisp_port *lisp_port;
+       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
+
+       lisp_port = lisp_find_port(ovs_dp_get_net(vport->dp),
+                                  tnl_vport->dst_port);
+
+       lisp_tunnel_release(lisp_port);
+       ovs_tnl_destroy(vport);
+}
+
+static struct vport *lisp_tnl_create(const struct vport_parms *parms)
+{
+       struct vport *vport;
+       int err;
+
+       vport = ovs_tnl_create(parms, &ovs_lisp_vport_ops, &ovs_lisp_tnl_ops);
+       if (IS_ERR(vport))
+               return vport;
+
+       err = lisp_tunnel_setup(ovs_dp_get_net(parms->dp), vport,
+                               parms->options);
+       if (err) {
+               ovs_tnl_destroy(vport);
+               return ERR_PTR(err);
+       }
+
+       return vport;
+}
+
+const struct vport_ops ovs_lisp_vport_ops = {
+       .type           = OVS_VPORT_TYPE_LISP,
+       .flags          = VPORT_F_TUN_ID,
+       .create         = lisp_tnl_create,
+       .destroy        = lisp_tnl_destroy,
+       .get_name       = ovs_tnl_get_name,
+       .get_options    = lisp_get_options,
+       .send           = lisp_tnl_send,
+};
+#else
+#warning LISP tunneling will not be available on kernels before 2.6.26
+#endif /* Linux kernel < 2.6.26 */
index 4f9f339..1850fc2 100644 (file)
@@ -24,8 +24,8 @@
 
 #include <linux/in.h>
 #include <linux/ip.h>
-#include <linux/list.h>
 #include <linux/net.h>
+#include <linux/rculist.h>
 #include <linux/udp.h>
 
 #include <net/icmp.h>
@@ -50,8 +50,7 @@ struct vxlanhdr {
 
 #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
 
-static inline int vxlan_hdr_len(const struct tnl_mutable_config *mutable,
-                               const struct ovs_key_ipv4_tunnel *tun_key)
+static inline int vxlan_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key)
 {
        return VXLAN_HLEN;
 }
@@ -59,25 +58,26 @@ static inline int vxlan_hdr_len(const struct tnl_mutable_config *mutable,
 /**
  * struct vxlan_port - Keeps track of open UDP ports
  * @list: list element.
- * @port: The UDP port number in network byte order.
+ * @vport: vport for the tunnel.
  * @socket: The socket created for this port number.
- * @count: How many ports are using this socket/port.
  */
 struct vxlan_port {
        struct list_head list;
-       __be16 port;
+       struct vport *vport;
        struct socket *vxlan_rcv_socket;
-       int count;
+       struct rcu_head rcu;
 };
 
 static LIST_HEAD(vxlan_ports);
 
-static struct vxlan_port *vxlan_port_exists(struct net *net, __be16 port)
+static struct vxlan_port *vxlan_find_port(struct net *net, __be16 port)
 {
        struct vxlan_port *vxlan_port;
 
-       list_for_each_entry(vxlan_port, &vxlan_ports, list) {
-               if (vxlan_port->port == port &&
+       list_for_each_entry_rcu(vxlan_port, &vxlan_ports, list) {
+               struct tnl_vport *tnl_vport = tnl_vport_priv(vxlan_port->vport);
+
+               if (tnl_vport->dst_port == port &&
                        net_eq(sock_net(vxlan_port->vxlan_rcv_socket->sk), net))
                        return vxlan_port;
        }
@@ -90,65 +90,36 @@ static inline struct vxlanhdr *vxlan_hdr(const struct sk_buff *skb)
        return (struct vxlanhdr *)(udp_hdr(skb) + 1);
 }
 
-/* Compute source port for outgoing packet.
- * Currently we use the flow hash.
- */
-static u16 get_src_port(struct sk_buff *skb)
-{
-       int low;
-       int high;
-       unsigned int range;
-       u32 hash = OVS_CB(skb)->flow->hash;
-
-        inet_get_local_port_range(&low, &high);
-        range = (high - low) + 1;
-       return (((u64) hash * range) >> 32) + low;
-}
-
-static struct sk_buff *vxlan_build_header(const struct vport *vport,
-                                         const struct tnl_mutable_config *mutable,
-                                         struct dst_entry *dst,
-                                         struct sk_buff *skb,
-                                         int tunnel_hlen)
+static void vxlan_build_header(const struct vport *vport,
+                              struct sk_buff *skb,
+                              int tunnel_hlen)
 {
+       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
        struct udphdr *udph = udp_hdr(skb);
        struct vxlanhdr *vxh = (struct vxlanhdr *)(udph + 1);
        const struct ovs_key_ipv4_tunnel *tun_key = OVS_CB(skb)->tun_key;
-       __be64 out_key;
-       u32 flags;
 
-       tnl_get_param(mutable, tun_key, &flags, &out_key);
-
-       udph->dest = mutable->dst_port;
-       udph->source = htons(get_src_port(skb));
+       udph->dest = tnl_vport->dst_port;
+       udph->source = htons(ovs_tnl_get_src_port(skb));
        udph->check = 0;
        udph->len = htons(skb->len - skb_transport_offset(skb));
 
        vxh->vx_flags = htonl(VXLAN_FLAGS);
-       vxh->vx_vni = htonl(be64_to_cpu(out_key) << 8);
-
-       /*
-        * Allow our local IP stack to fragment the outer packet even if the
-        * DF bit is set as a last resort.  We also need to force selection of
-        * an IP ID here because Linux will otherwise leave it at 0 if the
-        * packet originally had DF set.
-        */
-       skb->local_df = 1;
-       __ip_select_ident(ip_hdr(skb), dst, 0);
-
-       return skb;
+       vxh->vx_vni = htonl(be64_to_cpu(tun_key->tun_id) << 8);
 }
 
 /* Called with rcu_read_lock and BH disabled. */
 static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 {
-       struct vport *vport;
+       struct vxlan_port *vxlan_vport;
        struct vxlanhdr *vxh;
-       const struct tnl_mutable_config *mutable;
        struct iphdr *iph;
        struct ovs_key_ipv4_tunnel tun_key;
        __be64 key;
-       u32 tunnel_flags = 0;
+
+       vxlan_vport = vxlan_find_port(dev_net(skb->dev), udp_hdr(skb)->dest);
+       if (unlikely(!vxlan_vport))
+               goto error;
 
        if (unlikely(!pskb_may_pull(skb, VXLAN_HLEN + ETH_HLEN)))
                goto error;
@@ -163,24 +134,12 @@ static int vxlan_rcv(struct sock *sk, struct sk_buff *skb)
 
        key = cpu_to_be64(ntohl(vxh->vx_vni) >> 8);
 
-       iph = ip_hdr(skb);
-       vport = ovs_tnl_find_port(dev_net(skb->dev), iph->daddr, iph->saddr,
-               key, TNL_T_PROTO_VXLAN, &mutable);
-       if (unlikely(!vport)) {
-               icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
-               goto error;
-       }
-
-       if (mutable->flags & TNL_F_IN_KEY_MATCH || !mutable->key.daddr)
-               tunnel_flags = OVS_TNL_F_KEY;
-       else
-               key = 0;
-
        /* Save outer tunnel values */
-       tnl_tun_key_init(&tun_key, iph, key, tunnel_flags);
+       iph = ip_hdr(skb);
+       tnl_tun_key_init(&tun_key, iph, key, OVS_TNL_F_KEY);
        OVS_CB(skb)->tun_key = &tun_key;
 
-       ovs_tnl_rcv(vport, skb);
+       ovs_tnl_rcv(vxlan_vport->vport, skb);
        goto out;
 
 error:
@@ -195,6 +154,7 @@ static int vxlan_socket_init(struct vxlan_port *vxlan_port, struct net *net)
 {
        int err;
        struct sockaddr_in sin;
+       struct tnl_vport *tnl_vport = tnl_vport_priv(vxlan_port->vport);
 
        err = sock_create_kern(AF_INET, SOCK_DGRAM, 0,
                               &vxlan_port->vxlan_rcv_socket);
@@ -206,7 +166,7 @@ static int vxlan_socket_init(struct vxlan_port *vxlan_port, struct net *net)
 
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = htonl(INADDR_ANY);
-       sin.sin_port = vxlan_port->port;
+       sin.sin_port = tnl_vport->dst_port;
 
        err = kernel_bind(vxlan_port->vxlan_rcv_socket, (struct sockaddr *)&sin,
                          sizeof(struct sockaddr_in));
@@ -227,26 +187,33 @@ error:
        return err;
 }
 
+static void free_port_rcu(struct rcu_head *rcu)
+{
+       struct vxlan_port *vxlan_port = container_of(rcu,
+                       struct vxlan_port, rcu);
+
+       kfree(vxlan_port);
+}
+
 static void vxlan_tunnel_release(struct vxlan_port *vxlan_port)
 {
-       vxlan_port->count--;
+       if (!vxlan_port)
+               return;
 
-       if (vxlan_port->count == 0) {
-               /* Release old socket */
-               sk_release_kernel(vxlan_port->vxlan_rcv_socket->sk);
-               list_del(&vxlan_port->list);
-               kfree(vxlan_port);
-       }
+       list_del_rcu(&vxlan_port->list);
+       /* Release socket */
+       sk_release_kernel(vxlan_port->vxlan_rcv_socket->sk);
+       call_rcu(&vxlan_port->rcu, free_port_rcu);
 }
-static int vxlan_tunnel_setup(struct net *net, struct nlattr *options,
-                             struct vxlan_port **vxport)
+
+static int vxlan_tunnel_setup(struct net *net, struct vport *vport,
+                             struct nlattr *options)
 {
+       struct vxlan_port *vxlan_port;
+       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
        struct nlattr *a;
        int err;
        u16 dst_port;
-       struct vxlan_port *vxlan_port = NULL;
-
-       *vxport = NULL;
 
        if (!options) {
                err = -EINVAL;
@@ -263,11 +230,9 @@ static int vxlan_tunnel_setup(struct net *net, struct nlattr *options,
        }
 
        /* Verify if we already have a socket created for this port */
-       vxlan_port = vxlan_port_exists(net, htons(dst_port));
+       vxlan_port = vxlan_find_port(net, htons(dst_port));
        if (vxlan_port) {
-               vxlan_port->count++;
-               err = 0;
-               *vxport = vxlan_port;
+               err = -EEXIST;
                goto out;
        }
 
@@ -278,55 +243,33 @@ static int vxlan_tunnel_setup(struct net *net, struct nlattr *options,
                goto out;
        }
 
-       vxlan_port->port = htons(dst_port);
-       vxlan_port->count = 1;
-       list_add_tail(&vxlan_port->list, &vxlan_ports);
+       tnl_vport->dst_port = htons(dst_port);
+       vxlan_port->vport = vport;
+       list_add_tail_rcu(&vxlan_port->list, &vxlan_ports);
 
        err = vxlan_socket_init(vxlan_port, net);
        if (err)
                goto error;
 
-       *vxport = vxlan_port;
-       goto out;
+       return 0;
 
 error:
-       list_del(&vxlan_port->list);
+       list_del_rcu(&vxlan_port->list);
        kfree(vxlan_port);
 out:
        return err;
 }
 
-static int vxlan_set_options(struct vport *vport, struct nlattr *options)
+static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb)
 {
-       int err;
-       struct net *net = ovs_dp_get_net(vport->dp);
-       struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       struct tnl_mutable_config *config;
-       struct vxlan_port *old_port = NULL;
-       struct vxlan_port *vxlan_port = NULL;
-
-       config = rtnl_dereference(tnl_vport->mutable);
+       const struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
 
-       old_port = vxlan_port_exists(net, config->dst_port);
-
-       err = vxlan_tunnel_setup(net, options, &vxlan_port);
-       if (err)
-               goto out;
-
-       err = ovs_tnl_set_options(vport, options);
-
-       if (err)
-               vxlan_tunnel_release(vxlan_port);
-       else {
-               /* Release old socket */
-               vxlan_tunnel_release(old_port);
-       }
-out:
-       return err;
+       if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(tnl_vport->dst_port)))
+               return -EMSGSIZE;
+       return 0;
 }
 
 static const struct tnl_ops ovs_vxlan_tnl_ops = {
-       .tunnel_type    = TNL_T_PROTO_VXLAN,
        .ipproto        = IPPROTO_UDP,
        .hdr_len        = vxlan_hdr_len,
        .build_header   = vxlan_build_header,
@@ -336,15 +279,11 @@ static void vxlan_tnl_destroy(struct vport *vport)
 {
        struct vxlan_port *vxlan_port;
        struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       struct tnl_mutable_config *config;
 
-       config = rtnl_dereference(tnl_vport->mutable);
-
-       vxlan_port = vxlan_port_exists(ovs_dp_get_net(vport->dp),
-                                        config->dst_port);
+       vxlan_port = vxlan_find_port(ovs_dp_get_net(vport->dp),
+                                        tnl_vport->dst_port);
 
        vxlan_tunnel_release(vxlan_port);
-
        ovs_tnl_destroy(vport);
 }
 
@@ -352,17 +291,17 @@ static struct vport *vxlan_tnl_create(const struct vport_parms *parms)
 {
        int err;
        struct vport *vport;
-       struct vxlan_port *vxlan_port = NULL;
-
-       err = vxlan_tunnel_setup(ovs_dp_get_net(parms->dp), parms->options,
-                                &vxlan_port);
-       if (err)
-               return ERR_PTR(err);
 
        vport = ovs_tnl_create(parms, &ovs_vxlan_vport_ops, &ovs_vxlan_tnl_ops);
-
        if (IS_ERR(vport))
-               vxlan_tunnel_release(vxlan_port);
+               return vport;
+
+       err = vxlan_tunnel_setup(ovs_dp_get_net(parms->dp), vport,
+                                parms->options);
+       if (err) {
+               ovs_tnl_destroy(vport);
+               return ERR_PTR(err);
+       }
 
        return vport;
 }
@@ -373,8 +312,7 @@ const struct vport_ops ovs_vxlan_vport_ops = {
        .create         = vxlan_tnl_create,
        .destroy        = vxlan_tnl_destroy,
        .get_name       = ovs_tnl_get_name,
-       .get_options    = ovs_tnl_get_options,
-       .set_options    = vxlan_set_options,
+       .get_options    = vxlan_get_options,
        .send           = ovs_tnl_send,
 };
 #else
index 9c0942b..e9e1444 100644 (file)
@@ -42,8 +42,8 @@ static const struct vport_ops *base_vport_ops_list[] = {
        &ovs_gre_vport_ops,
        &ovs_gre64_vport_ops,
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
-       &ovs_capwap_vport_ops,
        &ovs_vxlan_vport_ops,
+       &ovs_lisp_vport_ops,
 #endif
 };
 
@@ -139,9 +139,8 @@ struct vport *ovs_vport_locate(struct net *net, const char *name)
 {
        struct hlist_head *bucket = hash_bucket(net, name);
        struct vport *vport;
-       struct hlist_node *node;
 
-       hlist_for_each_entry_rcu(vport, node, bucket, hash_node)
+       hlist_for_each_entry_rcu(vport, bucket, hash_node)
                if (!strcmp(name, vport->ops->get_name(vport)) &&
                    net_eq(ovs_dp_get_net(vport->dp), net))
                        return vport;
@@ -379,17 +378,19 @@ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats)
 int ovs_vport_get_options(const struct vport *vport, struct sk_buff *skb)
 {
        struct nlattr *nla;
+       int err;
+
+       if (!vport->ops->get_options)
+               return 0;
 
        nla = nla_nest_start(skb, OVS_VPORT_ATTR_OPTIONS);
        if (!nla)
                return -EMSGSIZE;
 
-       if (vport->ops->get_options) {
-               int err = vport->ops->get_options(vport, skb);
-               if (err) {
-                       nla_nest_cancel(skb, nla);
-                       return err;
-               }
+       err = vport->ops->get_options(vport, skb);
+       if (err) {
+               nla_nest_cancel(skb, nla);
+               return err;
        }
 
        nla_nest_end(skb, nla);
@@ -416,9 +417,6 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb)
        stats->rx_bytes += skb->len;
        u64_stats_update_end(&stats->sync);
 
-       if (!(vport->ops->flags & VPORT_F_FLOW))
-               OVS_CB(skb)->flow = NULL;
-
        if (!(vport->ops->flags & VPORT_F_TUN_ID))
                OVS_CB(skb)->tun_key = NULL;
 
index ed089a9..074c6ee 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/u64_stats_sync.h>
 
-#include "vport-capwap.h"
-
 struct vport;
 struct vport_parms;
 
+/* The following definitions are for users of the vport subsytem: */
 struct vport_net {
-       struct capwap_net capwap;
+       struct vport __rcu *gre_vport;
+       struct vport __rcu *gre64_vport;
 };
 
-/* The following definitions are for users of the vport subsytem: */
-
 int ovs_vport_init(void);
 void ovs_vport_exit(void);
 
@@ -108,8 +106,7 @@ struct vport {
 };
 
 #define VPORT_F_REQUIRED       (1 << 0) /* If init fails, module loading fails. */
-#define VPORT_F_FLOW           (1 << 1) /* Sets OVS_CB(skb)->flow. */
-#define VPORT_F_TUN_ID         (1 << 2) /* Sets OVS_CB(skb)->tun_id. */
+#define VPORT_F_TUN_ID         (1 << 1) /* Sets OVS_CB(skb)->tun_id. */
 
 /**
  * struct vport_parms - parameters for creating a new vport
@@ -230,7 +227,7 @@ extern const struct vport_ops ovs_netdev_vport_ops;
 extern const struct vport_ops ovs_internal_vport_ops;
 extern const struct vport_ops ovs_gre_vport_ops;
 extern const struct vport_ops ovs_gre64_vport_ops;
-extern const struct vport_ops ovs_capwap_vport_ops;
 extern const struct vport_ops ovs_vxlan_vport_ops;
+extern const struct vport_ops ovs_lisp_vport_ops;
 
 #endif /* vport.h */
index d3a8faf..18b0281 100644 (file)
@@ -1,16 +1,69 @@
-openvswitch (1.9.90-1) unstable; urgency=low
+openvswitch (1.10.90-1) unstable; urgency=low
    [ Open vSwitch team ]
    * New upstream version
-    - Nothing yet!  Try NEWS...
+     - Nothing yet!  Try NEWS...
 
- -- Open vSwitch team <dev@openvswitch.org>  Wed, 24 Oct 2012 16:12:57 -0700
+ -- Open vSwitch team <dev@openvswitch.org>  Mon, 04 Feb 2013 21:52:34 -0700
+
+openvswitch (1.10.0-1) unstable; urgency=low
+   [ Open vSwitch team ]
+   * New upstream version
+    - Bridge compatibility support has been removed.  Any uses that
+      rely on ovs-brcompatd will have to stick with Open vSwitch 1.9.x
+      or adapt to native Open vSwitch support (e.g. use ovs-vsctl instead
+      of brctl).
+    - The maximum size of the MAC learning table is now configurable.
+    - With the Linux datapath, packets for new flows are now queued
+      separately on a per-port basis, so it should no longer be
+      possible for a large number of new flows arriving on one port to
+      prevent new flows from being processed on other ports.
+    - Many "ovs-vsctl" database commands now accept an --if-exists option.
+      Please refer to the ovs-vsctl manpage for details.
+    - OpenFlow:
+      - Experimental support for newer versions of OpenFlow.  See
+        the "What versions of OpenFlow does Open vSwitch support?"
+        question in the FAQ for more details.
+      - The OpenFlow "dp_desc" may now be configured by setting the
+        value of other-config:dp-desc in the Bridge table.
+      - It is possible to request the OpenFlow port number with the
+        "ofport_request" column in the Interface table.
+    - Tunneling:
+      - New support for the VXLAN tunnel protocol (see the IETF draft here:
+        http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-03).
+      - Tunneling requires the version of the kernel module paired with
+        Open vSwitch 1.9.0 or later.
+      - Inheritance of the Don't Fragment bit in IP tunnels (df_inherit)
+        is no longer supported.
+      - Path MTU discovery is no longer supported.
+    - ovs-dpctl:
+      - The "dump-flows" and "del-flows" no longer require an argument
+        if only one datapath exists.
+    - ovs-appctl:
+      - New "vlog/disable-rate-limit" and "vlog/enable-rate-limit"
+        commands available allow control over logging rate limits.
+      - New "dpif/dump-dps", "dpif/show", and "dpif/dump-flows" command
+        that mimic the equivalent ovs-dpctl commands.
+    - The ofproto library is now responsible for assigning OpenFlow port
+      numbers.  An ofproto implementation should assign them when
+      port_construct() is called.
+    - All dpif-based bridges of a particular type share a common
+      datapath called "ovs-<type>", e.g. "ovs-system".  The ovs-dpctl
+      commands will now return information on that shared datapath.  To
+      get the equivalent bridge-specific information, use the new
+      "ovs-appctl dpif/*" commands.
+    - Backward-incompatible changes:
+      - Earlier Open vSwitch versions treated ANY as a wildcard in flow
+        syntax.  OpenFlow 1.1 adds a port named ANY, which introduces a
+        conflict.  ANY was rarely used in flow syntax, so we chose to
+        retire that meaning of ANY in favor of the OpenFlow 1.1 meaning.
+    - Patch ports no longer require kernel support, so they now work
+      with FreeBSD and the kernel module built into Linux 3.3 and later.
+
+ -- Open vSwitch team <dev@openvswitch.org>  Mon, 04 Feb 2013 21:52:34 -0700
 
 openvswitch (1.9.0-1) unstable; urgency=low
    [ Open vSwitch team ]
    * New upstream version
-    - The tunneling code no longer assumes input and output keys are symmetric.
-      If they are not, PMTUD needs to be disabled for tunneling to work. Note
-      this only applies to flow-based keys.
     - Datapath:
       - Support for ipv6 set action.
       - SKB mark matching and setting.
@@ -25,6 +78,14 @@ openvswitch (1.9.0-1) unstable; urgency=low
       - Allow bitwise masking for SHA and THA fields in ARP, SLL and TLL
         fields in IPv6 neighbor discovery messages, and IPv6 flow label.
       - Adds support for writing to the metadata field for a flow.
+    - Tunneling:
+      - The tunneling code no longer assumes input and output keys are
+        symmetric.  If they are not, PMTUD needs to be disabled for
+        tunneling to work. Note this only applies to flow-based keys.
+      - New support for a nonstandard form of GRE that supports a 64-bit key.
+      - Tunnel Path MTU Discovery default value was set to 'disabled'.
+        This feature is deprecated and will be removed soon.
+      - Tunnel header caching removed.
     - ovs-ofctl:
       - Commands and actions that accept port numbers now also accept keywords
         that represent those ports (such as LOCAL, NONE, and ALL).  This is
@@ -40,12 +101,8 @@ openvswitch (1.9.0-1) unstable; urgency=low
       are true, but because we do not know of any users for this
       feature it seems better on balance to remove it.  (The ovs-pki-cgi
       program was not included in distribution packaging.)
-    - Tunnel Path MTU Discovery default value was set to 'disabled'.  This
-      feature is deprecated and will be removed soon.
     - ovsdb-server now enforces the immutability of immutable columns.  This
       was not enforced in earlier versions due to an oversight.
-    - New support for a nonstandard form of GRE that supports a 64-bit key.
-    - Tunnel header caching removed.
     - The following features are now deprecated.  They will be removed no
       earlier than February 2013.  Please email dev@openvswitch.org with
       concerns.
@@ -59,11 +116,12 @@ openvswitch (1.9.0-1) unstable; urgency=low
     - The data in the RARP packets can now be matched in the same way as the
       data in ARP packets.
 
- -- Open vSwitch team <dev@openvswitch.org>  Wed, 24 Oct 2012 16:10:39 -0700
+ -- Open vSwitch team <dev@openvswitch.org>  Tue, 26 Feb 2013 11:23:19 -0700
 
 openvswitch (1.8.0-1) unstable; urgency=low
    [ Open vSwitch team ]
    * New upstream version
+    *** Internal only release ***
     - New FAQ.  Please send updates and additions!
     - Authors of controllers, please read the new section titled "Action
       Reproduction" in DESIGN, which describes an Open vSwitch change in
index ae88be2..acf47b9 100644 (file)
@@ -142,7 +142,6 @@ Depends:
  ${shlibs:Depends}, ${misc:Depends},
  openvswitch-common (= ${binary:Version}),
  openvswitch-controller (= ${binary:Version}),
- openvswitch-ipsec (= ${binary:Version}),
  openvswitch-switch (= ${binary:Version})
 Description: Debug symbols for Open vSwitch packages
  Open vSwitch is a production quality, multilayer, software-based, Ethernet
index 7d5b7b7..a1a2c3c 100644 (file)
@@ -77,7 +77,6 @@ License:
 
        include/linux/openvswitch.h
        include/openvswitch/datapath-compat.h
-       include/openvswitch/tunnel.h
 
   On Debian systems, the complete text of the GNU General Public License
   version 2 can be found in `/usr/share/common-licenses/GPL-2'.
index f6a7750..e456533 100755 (executable)
@@ -1,6 +1,6 @@
 #! /bin/sh
 
-# Copyright (c) 2012 Nicira, Inc.
+# Copyright (c) 2012, 2013 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
index 3df711f..d84c1b6 100755 (executable)
@@ -37,11 +37,6 @@ network_interfaces () {
     [ -n "${bridges}" ] && $1 --allow=ovs ${bridges}
 }
 
-ovs_ctl () {
-    set /usr/share/openvswitch/scripts/ovs-ctl "$@"
-    "$@"
-}
-
 load_kmod () {
     ovs_ctl load-kmod || exit $?
 }
index 6fba507..6ca0e40 100644 (file)
@@ -1,3 +1,4 @@
 noinst_HEADERS += \
+       include/linux/if_ether.h \
        include/linux/openvswitch.h \
        include/linux/types.h
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
new file mode 100644 (file)
index 0000000..a3cc9bc
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LINUX_IF_ETHER_H
+#define LINUX_IF_ETHER_H 1
+
+/* On Linux, this header file just includes <linux/if_ether.h>.
+ *
+ * On other platforms, this header file implements just enough of
+ * <linux/if_ether.h> to allow <linux/openvswitch.h> to work. */
+
+#if defined(HAVE_LINUX_IF_ETHER_H) || defined(__KERNEL__)
+#include_next <linux/if_ether.h>
+#else  /* no <linux/if_ether.h> */
+#define ETH_ALEN        6               /* Octets in one ethernet addr   */
+#endif
+
+#endif /* <linux/if_ether.h> */
index b12bf0c..bd2f05f 100644 (file)
@@ -41,6 +41,7 @@
 #define _LINUX_OPENVSWITCH_H 1
 
 #include <linux/types.h>
+#include <linux/if_ether.h>
 
 /**
  * struct ovs_header - header for OVS Generic Netlink messages.
@@ -148,7 +149,8 @@ enum ovs_packet_cmd {
  * for %OVS_PACKET_CMD_EXECUTE.  It has nested %OVS_ACTION_ATTR_* attributes.
  * @OVS_PACKET_ATTR_USERDATA: Present for an %OVS_PACKET_CMD_ACTION
  * notification if the %OVS_ACTION_ATTR_USERSPACE action specified an
- * %OVS_USERSPACE_ATTR_USERDATA attribute.
+ * %OVS_USERSPACE_ATTR_USERDATA attribute, with the same length and content
+ * specified there.
  *
  * These attributes follow the &struct ovs_header within the Generic Netlink
  * payload for %OVS_PACKET_* commands.
@@ -158,7 +160,7 @@ enum ovs_packet_attr {
        OVS_PACKET_ATTR_PACKET,      /* Packet data. */
        OVS_PACKET_ATTR_KEY,         /* Nested OVS_KEY_ATTR_* attributes. */
        OVS_PACKET_ATTR_ACTIONS,     /* Nested OVS_ACTION_ATTR_* attributes. */
-       OVS_PACKET_ATTR_USERDATA,    /* u64 OVS_ACTION_ATTR_USERSPACE arg. */
+       OVS_PACKET_ATTR_USERDATA,    /* OVS_ACTION_ATTR_USERSPACE arg. */
        __OVS_PACKET_ATTR_MAX
 };
 
@@ -184,8 +186,8 @@ enum ovs_vport_type {
        OVS_VPORT_TYPE_INTERNAL, /* network device implemented by datapath */
        OVS_VPORT_TYPE_GRE,      /* GRE tunnel. */
        OVS_VPORT_TYPE_VXLAN,    /* VXLAN tunnel */
-       OVS_VPORT_TYPE_CAPWAP = 102,  /* CAPWAP tunnel */
        OVS_VPORT_TYPE_GRE64 = 104, /* GRE tunnel with 64-bit keys */
+       OVS_VPORT_TYPE_LISP = 105,  /* LISP tunnel */
        __OVS_VPORT_TYPE_MAX
 };
 
@@ -233,14 +235,15 @@ enum ovs_vport_attr {
 
 #define OVS_VPORT_ATTR_MAX (__OVS_VPORT_ATTR_MAX - 1)
 
-/* OVS_VPORT_ATTR_OPTIONS attributes for patch vports. */
+/* OVS_VPORT_ATTR_OPTIONS attributes for tunnels.
+ */
 enum {
-       OVS_PATCH_ATTR_UNSPEC,
-       OVS_PATCH_ATTR_PEER,    /* name of peer vport, as a string */
-       __OVS_PATCH_ATTR_MAX
+       OVS_TUNNEL_ATTR_UNSPEC,
+       OVS_TUNNEL_ATTR_DST_PORT, /* 16-bit UDP port, used by L4 tunnels. */
+       __OVS_TUNNEL_ATTR_MAX
 };
 
-#define OVS_PATCH_ATTR_MAX (__OVS_PATCH_ATTR_MAX - 1)
+#define OVS_TUNNEL_ATTR_MAX (__OVS_TUNNEL_ATTR_MAX - 1)
 
 /* Flows. */
 
@@ -283,7 +286,8 @@ enum ovs_key_attr {
 #ifdef __KERNEL__
        OVS_KEY_ATTR_IPV4_TUNNEL,  /* struct ovs_key_ipv4_tunnel */
 #endif
-       OVS_KEY_ATTR_TUN_ID = 63,  /* be64 tunnel ID */
+
+       OVS_KEY_ATTR_MPLS = 62, /* struct ovs_key_mpls */
        __OVS_KEY_ATTR_MAX
 };
 
@@ -321,8 +325,12 @@ enum ovs_frag_type {
 #define OVS_FRAG_TYPE_MAX (__OVS_FRAG_TYPE_MAX - 1)
 
 struct ovs_key_ethernet {
-       __u8     eth_src[6];
-       __u8     eth_dst[6];
+       __u8     eth_src[ETH_ALEN];
+       __u8     eth_dst[ETH_ALEN];
+};
+
+struct ovs_key_mpls {
+       __be32 mpls_top_lse;
 };
 
 struct ovs_key_ipv4 {
@@ -368,14 +376,14 @@ struct ovs_key_arp {
        __be32 arp_sip;
        __be32 arp_tip;
        __be16 arp_op;
-       __u8   arp_sha[6];
-       __u8   arp_tha[6];
+       __u8   arp_sha[ETH_ALEN];
+       __u8   arp_tha[ETH_ALEN];
 };
 
 struct ovs_key_nd {
        __u32 nd_target[4];
-       __u8  nd_sll[6];
-       __u8  nd_tll[6];
+       __u8  nd_sll[ETH_ALEN];
+       __u8  nd_tll[ETH_ALEN];
 };
 
 /**
@@ -442,18 +450,31 @@ enum ovs_sample_attr {
  * enum ovs_userspace_attr - Attributes for %OVS_ACTION_ATTR_USERSPACE action.
  * @OVS_USERSPACE_ATTR_PID: u32 Netlink PID to which the %OVS_PACKET_CMD_ACTION
  * message should be sent.  Required.
- * @OVS_USERSPACE_ATTR_USERDATA: If present, its u64 argument is copied to the
- * %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA,
+ * @OVS_USERSPACE_ATTR_USERDATA: If present, its variable-length argument is
+ * copied to the %OVS_PACKET_CMD_ACTION message as %OVS_PACKET_ATTR_USERDATA.
  */
 enum ovs_userspace_attr {
        OVS_USERSPACE_ATTR_UNSPEC,
        OVS_USERSPACE_ATTR_PID,       /* u32 Netlink PID to receive upcalls. */
-       OVS_USERSPACE_ATTR_USERDATA,  /* u64 optional user-specified cookie. */
+       OVS_USERSPACE_ATTR_USERDATA,  /* Optional user-specified cookie. */
        __OVS_USERSPACE_ATTR_MAX
 };
 
 #define OVS_USERSPACE_ATTR_MAX (__OVS_USERSPACE_ATTR_MAX - 1)
 
+/**
+ * struct ovs_action_push_mpls - %OVS_ACTION_ATTR_PUSH_MPLS action argument.
+ * @mpls_lse: MPLS label stack entry to push.
+ * @mpls_ethertype: Ethertype to set in the encapsulating ethernet frame.
+ *
+ * The only values @mpls_ethertype should ever be given are %ETH_P_MPLS_UC and
+ * %ETH_P_MPLS_MC, indicating MPLS unicast or multicast. Other are rejected.
+ */
+struct ovs_action_push_mpls {
+       __be32 mpls_lse;
+       __be16 mpls_ethertype; /* Either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC */
+};
+
 /**
  * struct ovs_action_push_vlan - %OVS_ACTION_ATTR_PUSH_VLAN action argument.
  * @vlan_tpid: Tag protocol identifier (TPID) to push.
@@ -476,14 +497,23 @@ struct ovs_action_push_vlan {
  * @OVS_ACTION_ATTR_OUTPUT: Output packet to port.
  * @OVS_ACTION_ATTR_USERSPACE: Send packet to userspace according to nested
  * %OVS_USERSPACE_ATTR_* attributes.
- * @OVS_ACTION_ATTR_SET: Replaces the contents of an existing header.  The
- * single nested %OVS_KEY_ATTR_* attribute specifies a header to modify and its
- * value.
  * @OVS_ACTION_ATTR_PUSH_VLAN: Push a new outermost 802.1Q header onto the
  * packet.
  * @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q header off the packet.
  * @OVS_ACTION_ATTR_SAMPLE: Probabilitically executes actions, as specified in
  * the nested %OVS_SAMPLE_ATTR_* attributes.
+ * @OVS_ACTION_ATTR_SET: Replaces the contents of an existing header.  The
+ * single nested %OVS_KEY_ATTR_* attribute specifies a header to modify and its
+ * value.
+ * @OVS_ACTION_ATTR_PUSH_MPLS: Push a new MPLS label stack entry onto the
+ * top of the packets MPLS label stack. Set the ethertype of the
+ * encapsulating frame to either %ETH_P_MPLS_UC or %ETH_P_MPLS_MC to
+ * indicate the new packet contents.
+ * @OVS_ACTION_ATTR_POP_MPLS: Pop an MPLS label stack entry off of the
+ * packet's MPLS label stack.  Set the encapsulating frame's ethertype to
+ * indicate the new packet contents This could potentially still be
+ * %ETH_P_MPLS_* if the resulting MPLS label stack is not empty.  If there
+ * is no MPLS label stack, as determined by ethertype, no action is taken.
  *
  * Only a single header can be set with a single %OVS_ACTION_ATTR_SET.  Not all
  * fields within a header are modifiable, e.g. the IPv4 protocol and fragment
@@ -498,6 +528,8 @@ enum ovs_action_attr {
        OVS_ACTION_ATTR_PUSH_VLAN,    /* struct ovs_action_push_vlan. */
        OVS_ACTION_ATTR_POP_VLAN,     /* No argument. */
        OVS_ACTION_ATTR_SAMPLE,       /* Nested OVS_SAMPLE_ATTR_*. */
+       OVS_ACTION_ATTR_PUSH_MPLS,    /* struct ovs_action_push_mpls. */
+       OVS_ACTION_ATTR_POP_MPLS,     /* __be16 ethertype. */
        __OVS_ACTION_ATTR_MAX
 };
 
index 91c96b3..54fc4f9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -116,12 +116,14 @@ enum nx_hash_fields {
 /* This command enables or disables an Open vSwitch extension that allows a
  * controller to specify the OpenFlow table to which a flow should be added,
  * instead of having the switch decide which table is most appropriate as
- * required by OpenFlow 1.0.  By default, the extension is disabled.
+ * required by OpenFlow 1.0.  Because NXM was designed as an extension to
+ * OpenFlow 1.0, the extension applies equally to ofp10_flow_mod and
+ * nx_flow_mod.  By default, the extension is disabled.
  *
  * When this feature is enabled, Open vSwitch treats struct ofp10_flow_mod's
- * 16-bit 'command' member as two separate fields.  The upper 8 bits are used
- * as the table ID, the lower 8 bits specify the command as usual.  A table ID
- * of 0xff is treated like a wildcarded table ID.
+ * and struct nx_flow_mod's 16-bit 'command' member as two separate fields.
+ * The upper 8 bits are used as the table ID, the lower 8 bits specify the
+ * command as usual.  A table ID of 0xff is treated like a wildcarded table ID.
  *
  * The specific treatment of the table ID depends on the type of flow mod:
  *
@@ -292,7 +294,7 @@ enum nx_action_subtype {
     NXAST_NOTE,                 /* struct nx_action_note */
     NXAST_SET_TUNNEL64,         /* struct nx_action_set_tunnel64 */
     NXAST_MULTIPATH,            /* struct nx_action_multipath */
-    NXAST_AUTOPATH__DEPRECATED, /* struct nx_action_autopath */
+    NXAST_AUTOPATH__OBSOLETE,   /* No longer used. */
     NXAST_BUNDLE,               /* struct nx_action_bundle */
     NXAST_BUNDLE_LOAD,          /* struct nx_action_bundle */
     NXAST_RESUBMIT_TABLE,       /* struct nx_action_resubmit */
@@ -304,6 +306,12 @@ enum nx_action_subtype {
     NXAST_CONTROLLER,           /* struct nx_action_controller */
     NXAST_DEC_TTL_CNT_IDS,      /* struct nx_action_cnt_ids */
     NXAST_WRITE_METADATA,       /* struct nx_action_write_metadata */
+    NXAST_PUSH_MPLS,            /* struct nx_action_push_mpls */
+    NXAST_POP_MPLS,             /* struct nx_action_pop_mpls */
+    NXAST_SET_MPLS_TTL,         /* struct nx_action_ttl */
+    NXAST_DEC_MPLS_TTL,         /* struct nx_action_header */
+    NXAST_STACK_PUSH,           /* struct nx_action_stack */
+    NXAST_STACK_POP,            /* struct nx_action_stack */
 };
 
 /* Header for Nicira-defined actions. */
@@ -558,6 +566,23 @@ struct nx_action_reg_load {
 };
 OFP_ASSERT(sizeof(struct nx_action_reg_load) == 24);
 
+/* Action structure for NXAST_STACK_PUSH and NXAST_STACK_POP.
+ *
+ * Pushes (or pops) field[offset: offset + n_bits] to (or from)
+ * top of the stack.
+ */
+struct nx_action_stack {
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 16. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_STACK_PUSH or NXAST_STACK_POP. */
+    ovs_be16 offset;                /* Bit offset into the field. */
+    ovs_be32 field;                 /* The field used for push or pop. */
+    ovs_be16 n_bits;                /* (n_bits + 1) bits of the field. */
+    uint8_t zero[6];                /* Reserved, must be zero. */
+};
+OFP_ASSERT(sizeof(struct nx_action_stack) == 24);
+
 /* Action structure for NXAST_NOTE.
  *
  * This action has no effect.  It is variable length.  The switch does not
@@ -942,50 +967,6 @@ struct nx_action_fin_timeout {
 };
 OFP_ASSERT(sizeof(struct nx_action_fin_timeout) == 16);
 \f
-/* Action structure for NXAST_AUTOPATH.
- *
- * This action performs the following steps in sequence:
- *
- *    1. Hashes the flow using an implementation-defined hash function.
- *
- *       The hashed fields' values are drawn from the current state of the
- *       flow, including all modifications that have been made by actions up to
- *       this point.
- *
- *    2. Selects an OpenFlow 'port'.
- *
- *       'port' is selected in an implementation-defined manner, taking into
- *       account 'id' and the hash value calculated in step 1.
- *
- *       Generally a switch will have been configured with a set of ports that
- *       may be chosen given 'id'.  The switch may take into account any number
- *       of factors when choosing 'port' from its configured set.  Factors may
- *       include carrier, load, and the results of configuration protocols such
- *       as LACP.
- *
- *    3. Stores 'port' in dst[ofs:ofs+n_bits].
- *
- *       The format and semantics of 'dst' and 'ofs_nbits' are similar to those
- *       for the NXAST_REG_LOAD action.
- *
- * The switch will reject actions in which ofs+n_bits is greater than the width
- * of 'dst', with error type OFPET_BAD_ACTION, code OFPBAC_BAD_ARGUMENT.
- */
-struct nx_action_autopath {
-    ovs_be16 type;              /* OFPAT_VENDOR. */
-    ovs_be16 len;               /* Length is 24. */
-    ovs_be32 vendor;            /* NX_VENDOR_ID. */
-    ovs_be16 subtype;           /* NXAST_AUTOPATH. */
-
-    /* Where to store the result. */
-    ovs_be16 ofs_nbits;         /* (ofs << 6) | (n_bits - 1). */
-    ovs_be32 dst;               /* Destination. */
-
-    ovs_be32 id;                /* Autopath ID. */
-    ovs_be32 pad;
-};
-OFP_ASSERT(sizeof(struct nx_action_autopath) == 24);
-\f
 /* Action structure for NXAST_BUNDLE and NXAST_BUNDLE_LOAD.
  *
  * The bundle actions choose a slave from a supplied list of options.
@@ -1579,9 +1560,9 @@ OFP_ASSERT(sizeof(struct nx_action_output_reg) == 24);
 
 /* Tunnel ID.
  *
- * For a packet received via a GRE or VXLAN tunnel including a (32-bit) key, the
- * key is stored in the low 32-bits and the high bits are zeroed.  For other
- * packets, the value is 0.
+ * For a packet received via a GRE, VXLAN or LISP tunnel including a (32-bit)
+ * key, the key is stored in the low 32-bits and the high bits are zeroed.  For
+ * other packets, the value is 0.
  *
  * All zero bits, for packets not received via a keyed tunnel.
  *
@@ -1787,7 +1768,8 @@ OFP_ASSERT(sizeof(struct nx_set_flow_format) == 4);
  */
 struct nx_flow_mod {
     ovs_be64 cookie;              /* Opaque controller-issued identifier. */
-    ovs_be16 command;             /* One of OFPFC_*. */
+    ovs_be16 command;             /* OFPFC_* + possibly a table ID (see comment
+                                   * on struct nx_flow_mod_table_id). */
     ovs_be16 idle_timeout;        /* Idle time before discarding (seconds). */
     ovs_be16 hard_timeout;        /* Max time before discarding (seconds). */
     ovs_be16 priority;            /* Priority level of flow entry. */
@@ -1810,12 +1792,18 @@ struct nx_flow_mod {
 };
 OFP_ASSERT(sizeof(struct nx_flow_mod) == 32);
 
-/* NXT_FLOW_REMOVED (analogous to OFPT_FLOW_REMOVED). */
+/* NXT_FLOW_REMOVED (analogous to OFPT_FLOW_REMOVED).
+ *
+ * 'table_id' is present only in Open vSwitch 1.11 and later.  In earlier
+ * versions of Open vSwitch, this is a padding byte that is always zeroed.
+ * Therefore, a 'table_id' value of 0 indicates that the table ID is not known,
+ * and other values may be interpreted as one more than the flow's former table
+ * ID. */
 struct nx_flow_removed {
     ovs_be64 cookie;          /* Opaque controller-issued identifier. */
     ovs_be16 priority;        /* Priority level of flow entry. */
     uint8_t reason;           /* One of OFPRR_*. */
-    uint8_t pad[1];           /* Align to 32-bits. */
+    uint8_t table_id;         /* Flow's former table ID, plus one. */
     ovs_be32 duration_sec;    /* Time flow was alive in seconds. */
     ovs_be32 duration_nsec;   /* Time flow was alive in nanoseconds beyond
                                  duration_sec. */
@@ -2212,4 +2200,37 @@ struct nx_action_write_metadata {
 };
 OFP_ASSERT(sizeof(struct nx_action_write_metadata) == 32);
 
+/* Action structure for NXAST_PUSH_MPLS. */
+struct nx_action_push_mpls {
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 8. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_PUSH_MPLS. */
+    ovs_be16 ethertype;             /* Ethertype */
+    uint8_t  pad[4];
+};
+OFP_ASSERT(sizeof(struct nx_action_push_mpls) == 16);
+
+/* Action structure for NXAST_POP_MPLS. */
+struct nx_action_pop_mpls {
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 8. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_POP_MPLS. */
+    ovs_be16 ethertype;             /* Ethertype */
+    uint8_t  pad[4];
+};
+OFP_ASSERT(sizeof(struct nx_action_pop_mpls) == 16);
+
+/* Action structure for NXAST_SET_MPLS_TTL. */
+struct nx_action_mpls_ttl {
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 8. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_SET_MPLS_TTL. */
+    uint8_t  ttl;                   /* TTL */
+    uint8_t  pad[5];
+};
+OFP_ASSERT(sizeof(struct nx_action_mpls_ttl) == 16);
+
 #endif /* openflow/nicira-ext.h */
index 8dfd795..ec94cee 100644 (file)
@@ -204,8 +204,8 @@ enum ofp11_action_type {
 
     OFPAT11_PUSH_VLAN,        /* Push a new VLAN tag */
     OFPAT11_POP_VLAN,         /* Pop the outer VLAN tag */
-    OFPAT11_PUSH_MPLS,        /* Push a new MPLS tag */
-    OFPAT11_POP_MPLS,         /* Pop the outer MPLS tag */
+    OFPAT11_PUSH_MPLS,        /* Push a new MPLS Label Stack Entry */
+    OFPAT11_POP_MPLS,         /* Pop the outer MPLS Label Stack Entry */
     OFPAT11_SET_QUEUE,        /* Set queue id when outputting to a port */
     OFPAT11_GROUP,            /* Apply group. */
     OFPAT11_SET_NW_TTL,       /* IP TTL. */
index b7b877c..231bba9 100644 (file)
@@ -105,7 +105,7 @@ OFP_ASSERT(sizeof(struct ofp13_instruction_meter) == 8);
 
 enum ofp13_action_type {
     OFPAT13_PUSH_PBB = 26,     /* Push a new PBB service tag (I-TAG) */
-    OFPAT13_PPO_PBB  = 27      /* Pop the outer PBB service tag (I-TAG) */
+    OFPAT13_POP_PBB  = 27      /* Pop the outer PBB service tag (I-TAG) */
 };
 
 /* enum ofp_config_flags value OFPC_INVALID_TTL_TO_CONTROLLER
index 6cd6192..88d9529 100644 (file)
@@ -1,5 +1,4 @@
 noinst_HEADERS += \
        include/openvswitch/datapath-compat.h \
-       include/openvswitch/tunnel.h \
        include/openvswitch/types.h
 
diff --git a/include/openvswitch/tunnel.h b/include/openvswitch/tunnel.h
deleted file mode 100644 (file)
index d9f92d5..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
- *
- * This file is offered under your choice of two licenses: Apache 2.0 or GNU
- * GPL 2.0 or later.  The permission statements for each of these licenses is
- * given below.  You may license your modifications to this file under either
- * of these licenses or both.  If you wish to license your modifications under
- * only one of these licenses, delete the permission text for the other
- * license.
- *
- * ----------------------------------------------------------------------
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ----------------------------------------------------------------------
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- * ----------------------------------------------------------------------
- */
-
-#ifndef OPENVSWITCH_TUNNEL_H
-#define OPENVSWITCH_TUNNEL_H 1
-
-#include <linux/types.h>
-#include <linux/openvswitch.h>
-
-/* OVS_VPORT_ATTR_OPTIONS attributes for tunnels.
- *
- * OVS_TUNNEL_ATTR_DST_IPV4 is required for kernel tunnel ports, all other
- * attributes are optional.
- * For flow-based tunnels, only the OVS_TUNNEL_ATTR_DST_PORT is useful.
- */
-enum {
-       OVS_TUNNEL_ATTR_UNSPEC,
-       OVS_TUNNEL_ATTR_FLAGS,    /* 32-bit TNL_F_*. */
-       OVS_TUNNEL_ATTR_DST_IPV4, /* Remote IPv4 address. */
-       OVS_TUNNEL_ATTR_SRC_IPV4, /* Local IPv4 address. */
-       OVS_TUNNEL_ATTR_OUT_KEY,  /* __be64 key to use on output. */
-       OVS_TUNNEL_ATTR_IN_KEY,   /* __be64 key to match on input. */
-       OVS_TUNNEL_ATTR_TOS,      /* 8-bit TOS value. */
-       OVS_TUNNEL_ATTR_TTL,      /* 8-bit TTL value. */
-       OVS_TUNNEL_ATTR_DST_PORT, /* 16-bit UDP port, used by VXLAN. */
-       __OVS_TUNNEL_ATTR_MAX
-};
-
-#define OVS_TUNNEL_ATTR_MAX (__OVS_TUNNEL_ATTR_MAX - 1)
-
-#define TNL_F_CSUM             (1 << 0) /* Checksum packets. */
-#define TNL_F_TOS_INHERIT      (1 << 1) /* Inherit ToS from inner packet. */
-#define TNL_F_TTL_INHERIT      (1 << 2) /* Inherit TTL from inner packet. */
-/* Bit 3 was previously used for Don't Fragment inheritance. " */
-#define TNL_F_DF_DEFAULT       (1 << 4) /* Set DF bit if inherit off or
-                                         * not IP. */
-/* Bit 5 was previously used for path MTU discovery. " */
-/* Bit 6 is reserved since it was previously used for Tunnel header caching. */
-#define TNL_F_IPSEC            (1 << 7) /* Traffic is IPsec encrypted. */
-
-#endif /* openvswitch/tunnel.h */
index 58d8da2..8950c05 100644 (file)
@@ -10,8 +10,6 @@ noinst_LIBRARIES += lib/libopenvswitch.a
 lib_libopenvswitch_a_SOURCES = \
        lib/aes128.c \
        lib/aes128.h \
-       lib/autopath.c \
-       lib/autopath.h \
        lib/backtrace.c \
        lib/backtrace.h \
        lib/bitmap.c \
@@ -134,8 +132,8 @@ lib_libopenvswitch_a_SOURCES = \
        lib/ovsdb-types.h \
        lib/packets.c \
        lib/packets.h \
-       lib/pcap.c \
-       lib/pcap.h \
+       lib/pcap-file.c \
+       lib/pcap-file.h \
        lib/poll-loop.c \
        lib/poll-loop.h \
        lib/process.c \
diff --git a/lib/autopath.c b/lib/autopath.c
deleted file mode 100644 (file)
index 9da6463..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2011, 2012 Nicira, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <config.h>
-
-#include "autopath.h"
-
-#include <inttypes.h>
-#include <stdlib.h>
-
-#include "flow.h"
-#include "meta-flow.h"
-#include "nx-match.h"
-#include "ofp-actions.h"
-#include "ofp-errors.h"
-#include "ofp-util.h"
-#include "openflow/nicira-ext.h"
-#include "vlog.h"
-
-VLOG_DEFINE_THIS_MODULE(autopath);
-
-void
-autopath_parse(struct ofpact_autopath *ap, const char *s_)
-{
-    char *s;
-    char *id_str, *dst, *save_ptr;
-    uint16_t port;
-
-    ofpact_init_AUTOPATH(ap);
-
-    s = xstrdup(s_);
-    save_ptr = NULL;
-    id_str = strtok_r(s, ", ", &save_ptr);
-    dst = strtok_r(NULL, ", ", &save_ptr);
-
-    if (!dst) {
-        ovs_fatal(0, "%s: not enough arguments to autopath action", s_);
-    }
-
-    if (!ofputil_port_from_string(id_str, &port)) {
-        ovs_fatal(0, "%s: bad port number", s_);
-    }
-    ap->port = port;
-
-    mf_parse_subfield(&ap->dst, dst);
-    if (ap->dst.n_bits < 16) {
-        ovs_fatal(0, "%s: %d-bit destination field has %u possible values, "
-                  "less than required 65536",
-                  s_, ap->dst.n_bits, 1u << ap->dst.n_bits);
-    }
-
-    free(s);
-}
-
-enum ofperr
-autopath_from_openflow(const struct nx_action_autopath *nap,
-                       struct ofpact_autopath *autopath)
-{
-    ofpact_init_AUTOPATH(autopath);
-    autopath->dst.field = mf_from_nxm_header(ntohl(nap->dst));
-    autopath->dst.ofs = nxm_decode_ofs(nap->ofs_nbits);
-    autopath->dst.n_bits = nxm_decode_n_bits(nap->ofs_nbits);
-    autopath->port = ntohl(nap->id);
-
-    if (autopath->dst.n_bits < 16) {
-        VLOG_WARN("at least 16 bit destination is required for autopath "
-                  "action.");
-        return OFPERR_OFPBAC_BAD_ARGUMENT;
-    }
-
-    return autopath_check(autopath, NULL);
-}
-
-enum ofperr
-autopath_check(const struct ofpact_autopath *autopath, const struct flow *flow)
-{
-    VLOG_WARN_ONCE("The autopath action is deprecated and may be removed in"
-                   " February 2013.  Please email dev@openvswitch.org with"
-                   " concerns.");
-    return mf_check_dst(&autopath->dst, flow);
-}
-
-void
-autopath_to_nxast(const struct ofpact_autopath *autopath,
-                  struct ofpbuf *openflow)
-{
-    struct nx_action_autopath *ap;
-
-    ap = ofputil_put_NXAST_AUTOPATH__DEPRECATED(openflow);
-    ap->ofs_nbits = nxm_encode_ofs_nbits(autopath->dst.ofs,
-                                         autopath->dst.n_bits);
-    ap->dst = htonl(autopath->dst.field->nxm_header);
-    ap->id = htonl(autopath->port);
-}
diff --git a/lib/autopath.h b/lib/autopath.h
deleted file mode 100644 (file)
index 337e7d1..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2011, 2012 Nicira, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef AUTOPATH_H
-#define AUTOPATH_H 1
-
-#include <stdint.h>
-#include "ofp-errors.h"
-
-struct flow;
-struct nx_action_autopath;
-struct ofpact_autopath;
-struct ofpbuf;
-
-/* NXAST_AUTOPATH  helper functions.
- *
- * See include/openflow/nicira-ext.h for NXAST_AUTOPATH specification. */
-
-void autopath_parse(struct ofpact_autopath *, const char *);
-
-enum ofperr autopath_from_openflow(const struct nx_action_autopath *,
-                                   struct ofpact_autopath *);
-enum ofperr autopath_check(const struct ofpact_autopath *,
-                           const struct flow *);
-void autopath_to_nxast(const struct ofpact_autopath *,
-                       struct ofpbuf *openflow);
-
-#endif /* autopath.h */
index 06680ee..aca18a2 100644 (file)
@@ -75,9 +75,6 @@ struct bond_slave {
     struct list bal_node;       /* In bond_rebalance()'s 'bals' list. */
     struct list entries;        /* 'struct bond_entry's assigned here. */
     uint64_t tx_bytes;          /* Sum across 'tx_bytes' of entries. */
-
-    /* BM_STABLE specific bonding info. */
-    uint32_t stb_id;            /* ID used for 'stb_slaves' ordering. */
 };
 
 /* A bond, that is, a set of network devices grouped to improve performance or
@@ -104,9 +101,6 @@ struct bond {
     long long int next_rebalance; /* Next rebalancing time. */
     bool send_learning_packets;
 
-    /* BM_STABLE specific bonding info. */
-    tag_type stb_tag;               /* Tag associated with this bond. */
-
     /* Legacy compatibility. */
     long long int next_fake_iface_update; /* LLONG_MAX if disabled. */
 
@@ -147,8 +141,6 @@ bond_mode_from_string(enum bond_mode *balance, const char *s)
         *balance = BM_TCP;
     } else if (!strcmp(s, bond_mode_to_string(BM_SLB))) {
         *balance = BM_SLB;
-    } else if (!strcmp(s, bond_mode_to_string(BM_STABLE))) {
-        *balance = BM_STABLE;
     } else if (!strcmp(s, bond_mode_to_string(BM_AB))) {
         *balance = BM_AB;
     } else {
@@ -165,8 +157,6 @@ bond_mode_to_string(enum bond_mode balance) {
         return "balance-tcp";
     case BM_SLB:
         return "balance-slb";
-    case BM_STABLE:
-        return "stable";
     case BM_AB:
         return "active-backup";
     }
@@ -187,7 +177,6 @@ bond_create(const struct bond_settings *s)
     bond = xzalloc(sizeof *bond);
     hmap_init(&bond->slaves);
     bond->no_slaves_tag = tag_create_random();
-    bond->stb_tag = tag_create_random();
     bond->next_fake_iface_update = LLONG_MAX;
 
     bond_reconfigure(bond, s);
@@ -256,12 +245,6 @@ bond_reconfigure(struct bond *bond, const struct bond_settings *s)
     if (bond->balance != s->balance) {
         bond->balance = s->balance;
         revalidate = true;
-
-        if (bond->balance == BM_STABLE) {
-            VLOG_WARN_ONCE("Stable bond mode is deprecated and may be removed"
-                           " in February 2013. Please email"
-                           " dev@openvswitch.org with concerns.");
-        }
     }
 
     if (bond->basis != s->basis) {
@@ -303,17 +286,12 @@ bond_slave_set_netdev__(struct bond_slave *slave, struct netdev *netdev)
  * bond.  If 'slave_' already exists within 'bond' then this function
  * reconfigures the existing slave.
  *
- * 'stb_id' is used in BM_STABLE bonds to guarantee consistent slave choices
- * across restarts and distributed vswitch instances.  It should be unique per
- * slave, and preferably consistent across restarts and reconfigurations.
- *
  * 'netdev' must be the network device that 'slave_' represents.  It is owned
  * by the client, so the client must not close it before either unregistering
  * 'slave_' or destroying 'bond'.
  */
 void
-bond_slave_register(struct bond *bond, void *slave_, uint32_t stb_id,
-                    struct netdev *netdev)
+bond_slave_register(struct bond *bond, void *slave_, struct netdev *netdev)
 {
     struct bond_slave *slave = bond_slave_lookup(bond, slave_);
 
@@ -331,11 +309,6 @@ bond_slave_register(struct bond *bond, void *slave_, uint32_t stb_id,
         bond_enable_slave(slave, netdev_get_carrier(netdev), NULL);
     }
 
-    if (slave->stb_id != stb_id) {
-        slave->stb_id = stb_id;
-        bond->bond_revalidate = true;
-    }
-
     bond_slave_set_netdev__(slave, netdev);
 
     free(slave->name);
@@ -438,17 +411,12 @@ bond_run(struct bond *bond, struct tag_set *tags, enum lacp_status lacp_status)
     }
 
     if (bond->bond_revalidate) {
-        bond->bond_revalidate = false;
+        struct bond_slave *slave;
 
+        bond->bond_revalidate = false;
         bond_entry_reset(bond);
-        if (bond->balance != BM_STABLE) {
-            struct bond_slave *slave;
-
-            HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
-                tag_set_add(tags, slave->tag);
-            }
-        } else {
-            tag_set_add(tags, bond->stb_tag);
+        HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
+            tag_set_add(tags, slave->tag);
         }
         tag_set_add(tags, bond->no_slaves_tag);
     }
@@ -621,9 +589,6 @@ bond_check_admissibility(struct bond *bond, const void *slave_,
          * exception is if we locked the learning table to avoid reflections on
          * bond slaves. */
         return BV_DROP_IF_MOVED;
-
-    case BM_STABLE:
-        return BV_ACCEPT;
     }
 
     NOT_REACHED();
@@ -647,7 +612,7 @@ bond_choose_output_slave(struct bond *bond, const struct flow *flow,
 {
     struct bond_slave *slave = choose_output_slave(bond, flow, vlan, tags);
     if (slave) {
-        *tags |= bond->balance == BM_STABLE ? bond->stb_tag : slave->tag;
+        *tags |= slave->tag;
         return slave->aux;
     } else {
         *tags |= bond->no_slaves_tag;
@@ -1297,23 +1262,18 @@ bond_slave_lookup(struct bond *bond, const void *slave_)
 static void
 bond_enable_slave(struct bond_slave *slave, bool enable, struct tag_set *tags)
 {
-    struct bond *bond = slave->bond;
     slave->delay_expires = LLONG_MAX;
     if (enable != slave->enabled) {
         slave->enabled = enable;
         if (!slave->enabled) {
-            VLOG_WARN("interface %s: disabled", slave->name);
+            VLOG_INFO("interface %s: disabled", slave->name);
             if (tags) {
                 tag_set_add(tags, slave->tag);
             }
         } else {
-            VLOG_WARN("interface %s: enabled", slave->name);
+            VLOG_INFO("interface %s: enabled", slave->name);
             slave->tag = tag_create_random();
         }
-
-        if (bond->balance == BM_STABLE) {
-            bond->bond_revalidate = true;
-        }
     }
 }
 
@@ -1387,35 +1347,6 @@ lookup_bond_entry(const struct bond *bond, const struct flow *flow,
     return &bond->hash[bond_hash(bond, flow, vlan) & BOND_MASK];
 }
 
-/* This function uses Highest Random Weight hashing to choose an output slave.
- * This approach only reassigns a minimal number of flows when slaves are
- * enabled or disabled.  Unfortunately, it has O(n) performance against the
- * number of slaves.  There exist algorithms which are O(1), but have slightly
- * more complex implementations and require the use of memory.  This may need
- * to be reimplemented if it becomes a performance bottleneck. */
-static struct bond_slave *
-choose_stb_slave(const struct bond *bond, uint32_t flow_hash)
-{
-    struct bond_slave *best, *slave;
-    uint32_t best_hash;
-
-    best = NULL;
-    best_hash = 0;
-    HMAP_FOR_EACH (slave, hmap_node, &bond->slaves) {
-        if (slave->enabled) {
-            uint32_t hash;
-
-            hash = hash_2words(flow_hash, slave->stb_id);
-            if (!best || hash > best_hash) {
-                best = slave;
-                best_hash = hash;
-            }
-        }
-    }
-
-    return best;
-}
-
 static struct bond_slave *
 choose_output_slave(const struct bond *bond, const struct flow *flow,
                     uint16_t vlan, tag_type *tags)
@@ -1432,9 +1363,6 @@ choose_output_slave(const struct bond *bond, const struct flow *flow,
     case BM_AB:
         return bond->active_slave;
 
-    case BM_STABLE:
-        return choose_stb_slave(bond, bond_hash_tcp(flow, vlan, bond->basis));
-
     case BM_TCP:
         if (bond->lacp_status != LACP_NEGOTIATED) {
             /* Must have LACP negotiations for TCP balanced bonds. */
@@ -1442,9 +1370,6 @@ choose_output_slave(const struct bond *bond, const struct flow *flow,
         }
         /* Fall Through. */
     case BM_SLB:
-        if (!bond_is_balanced(bond)) {
-            return choose_stb_slave(bond, bond_hash(bond, flow, vlan));
-        }
         e = lookup_bond_entry(bond, flow, vlan);
         if (!e->slave || !e->slave->enabled) {
             e->slave = CONTAINER_OF(hmap_random_node(&bond->slaves),
@@ -1512,7 +1437,7 @@ bond_choose_active_slave(struct bond *bond, struct tag_set *tags)
 
         bond->send_learning_packets = true;
     } else if (old_active_slave) {
-        VLOG_WARN_RL(&rl, "bond %s: all interfaces disabled", bond->name);
+        VLOG_INFO_RL(&rl, "bond %s: all interfaces disabled", bond->name);
     }
 }
 
index 7329db7..6190081 100644 (file)
@@ -32,7 +32,6 @@ enum lacp_status;
 enum bond_mode {
     BM_TCP, /* Transport Layer Load Balance. */
     BM_SLB, /* Source Load Balance. */
-    BM_STABLE, /* Stable. */
     BM_AB   /* Active Backup. */
 };
 
@@ -65,8 +64,7 @@ struct bond *bond_create(const struct bond_settings *);
 void bond_destroy(struct bond *);
 
 bool bond_reconfigure(struct bond *, const struct bond_settings *);
-void bond_slave_register(struct bond *, void *slave_,
-                         uint32_t stable_id, struct netdev *);
+void bond_slave_register(struct bond *, void *slave_, struct netdev *);
 void bond_slave_set_netdev(struct bond *, void *slave_, struct netdev *);
 void bond_slave_unregister(struct bond *, const void *slave);
 
index 7192602..2d1e50b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,11 +33,19 @@ static struct cls_table *insert_table(struct classifier *,
 
 static void destroy_table(struct classifier *, struct cls_table *);
 
+static void update_tables_after_insertion(struct classifier *,
+                                          struct cls_table *,
+                                          unsigned int new_priority);
+static void update_tables_after_removal(struct classifier *,
+                                        struct cls_table *,
+                                        unsigned int del_priority);
+
 static struct cls_rule *find_match(const struct cls_table *,
                                    const struct flow *);
 static struct cls_rule *find_equal(struct cls_table *,
                                    const struct miniflow *, uint32_t hash);
-static struct cls_rule *insert_rule(struct cls_table *, struct cls_rule *);
+static struct cls_rule *insert_rule(struct classifier *,
+                                    struct cls_table *, struct cls_rule *);
 
 /* Iterates RULE over HEAD and all of the cls_rules on HEAD->list. */
 #define FOR_EACH_RULE_IN_LIST(RULE, HEAD)                               \
@@ -134,6 +142,7 @@ classifier_init(struct classifier *cls)
 {
     cls->n_rules = 0;
     hmap_init(&cls->tables);
+    list_init(&cls->tables_priority);
 }
 
 /* Destroys 'cls'.  Rules within 'cls', if any, are not freed; this is the
@@ -189,7 +198,7 @@ classifier_replace(struct classifier *cls, struct cls_rule *rule)
         table = insert_table(cls, &rule->match.mask);
     }
 
-    old_rule = insert_rule(table, rule);
+    old_rule = insert_rule(cls, table, rule);
     if (!old_rule) {
         table->n_table_rules++;
         cls->n_rules++;
@@ -235,8 +244,9 @@ classifier_remove(struct classifier *cls, struct cls_rule *rule)
 
     if (--table->n_table_rules == 0) {
         destroy_table(cls, table);
+    } else {
+        update_tables_after_removal(cls, table, rule->priority);
     }
-
     cls->n_rules--;
 }
 
@@ -250,10 +260,22 @@ classifier_lookup(const struct classifier *cls, const struct flow *flow)
     struct cls_rule *best;
 
     best = NULL;
-    HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
+    LIST_FOR_EACH (table, list_node, &cls->tables_priority) {
         struct cls_rule *rule = find_match(table, flow);
-        if (rule && (!best || rule->priority > best->priority)) {
+        if (rule) {
             best = rule;
+            LIST_FOR_EACH_CONTINUE (table, list_node, &cls->tables_priority) {
+                if (table->max_priority <= best->priority) {
+                    /* Tables in descending priority order,
+                     * can not find anything better. */
+                    return best;
+                }
+                rule = find_match(table, flow);
+                if (rule && rule->priority > best->priority) {
+                    best = rule;
+                }
+            }
+            break;
         }
     }
     return best;
@@ -274,6 +296,11 @@ classifier_find_rule_exactly(const struct classifier *cls,
         return NULL;
     }
 
+    /* Skip if there is no hope. */
+    if (target->priority > table->max_priority) {
+        return NULL;
+    }
+
     head = find_equal(table, &target->match.flow,
                       miniflow_hash_in_minimask(&target->match.flow,
                                                 &target->match.mask, 0));
@@ -312,16 +339,24 @@ classifier_rule_overlaps(const struct classifier *cls,
 {
     struct cls_table *table;
 
-    HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
+    /* Iterate tables in the descending max priority order. */
+    LIST_FOR_EACH (table, list_node, &cls->tables_priority) {
         uint32_t storage[FLOW_U32S];
         struct minimask mask;
         struct cls_rule *head;
 
+        if (target->priority > table->max_priority) {
+            break; /* Can skip this and the rest of the tables. */
+        }
+
         minimask_combine(&mask, &target->match.mask, &table->mask, storage);
         HMAP_FOR_EACH (head, hmap_node, &table->rules) {
             struct cls_rule *rule;
 
             FOR_EACH_RULE_IN_LIST (rule, head) {
+                if (rule->priority < target->priority) {
+                    break; /* Rules in descending priority order. */
+                }
                 if (rule->priority == target->priority
                     && miniflow_equal_in_minimask(&target->match.flow,
                                                   &rule->match.flow, &mask)) {
@@ -494,6 +529,7 @@ insert_table(struct classifier *cls, const struct minimask *mask)
     hmap_init(&table->rules);
     minimask_clone(&table->mask, mask);
     hmap_insert(&cls->tables, &table->hmap_node, minimask_hash(mask, 0));
+    list_push_back(&cls->tables_priority, &table->list_node);
 
     return table;
 }
@@ -504,9 +540,100 @@ destroy_table(struct classifier *cls, struct cls_table *table)
     minimask_destroy(&table->mask);
     hmap_remove(&cls->tables, &table->hmap_node);
     hmap_destroy(&table->rules);
+    list_remove(&table->list_node);
     free(table);
 }
 
+/* This function performs the following updates for 'table' in 'cls' following
+ * the addition of a new rule with priority 'new_priority' to 'table':
+ *
+ *    - Update 'table->max_priority' and 'table->max_count' if necessary.
+ *
+ *    - Update 'table''s position in 'cls->tables_priority' if necessary.
+ *
+ * This function should only be called after adding a new rule, not after
+ * replacing a rule by an identical one or modifying a rule in-place. */
+static void
+update_tables_after_insertion(struct classifier *cls, struct cls_table *table,
+                              unsigned int new_priority)
+{
+    if (new_priority == table->max_priority) {
+        ++table->max_count;
+    } else if (new_priority > table->max_priority) {
+        struct cls_table *iter;
+
+        table->max_priority = new_priority;
+        table->max_count = 1;
+
+        /* Possibly move 'table' earlier in the priority list.  If we break out
+         * of the loop, then 'table' should be moved just after that 'iter'.
+         * If the loop terminates normally, then 'iter' will be the list head
+         * and we'll move table just after that (e.g. to the front of the
+         * list). */
+        iter = table;
+        LIST_FOR_EACH_REVERSE_CONTINUE (iter, list_node,
+                                        &cls->tables_priority) {
+            if (iter->max_priority >= table->max_priority) {
+                break;
+            }
+        }
+
+        /* Move 'table' just after 'iter' (unless it's already there). */
+        if (iter->list_node.next != &table->list_node) {
+            list_splice(iter->list_node.next,
+                        &table->list_node, table->list_node.next);
+        }
+    }
+}
+
+/* This function performs the following updates for 'table' in 'cls' following
+ * the deletion of a rule with priority 'del_priority' from 'table':
+ *
+ *    - Update 'table->max_priority' and 'table->max_count' if necessary.
+ *
+ *    - Update 'table''s position in 'cls->tables_priority' if necessary.
+ *
+ * This function should only be called after removing a rule, not after
+ * replacing a rule by an identical one or modifying a rule in-place. */
+static void
+update_tables_after_removal(struct classifier *cls, struct cls_table *table,
+                            unsigned int del_priority)
+{
+    struct cls_table *iter;
+
+    if (del_priority == table->max_priority && --table->max_count == 0) {
+        struct cls_rule *head;
+
+        table->max_priority = 0;
+        HMAP_FOR_EACH (head, hmap_node, &table->rules) {
+            if (head->priority > table->max_priority) {
+                table->max_priority = head->priority;
+                table->max_count = 1;
+            } else if (head->priority == table->max_priority) {
+                ++table->max_count;
+            }
+        }
+
+        /* Possibly move 'table' later in the priority list.  If we break out
+         * of the loop, then 'table' should be moved just before that 'iter'.
+         * If the loop terminates normally, then 'iter' will be the list head
+         * and we'll move table just before that (e.g. to the back of the
+         * list). */
+        iter = table;
+        LIST_FOR_EACH_CONTINUE (iter, list_node, &cls->tables_priority) {
+            if (iter->max_priority <= table->max_priority) {
+                break;
+            }
+        }
+
+        /* Move 'table' just before 'iter' (unless it's already there). */
+        if (iter->list_node.prev != &table->list_node) {
+            list_splice(&iter->list_node,
+                        &table->list_node, table->list_node.next);
+        }
+    }
+}
+
 static struct cls_rule *
 find_match(const struct cls_table *table, const struct flow *flow)
 {
@@ -537,9 +664,11 @@ find_equal(struct cls_table *table, const struct miniflow *flow, uint32_t hash)
 }
 
 static struct cls_rule *
-insert_rule(struct cls_table *table, struct cls_rule *new)
+insert_rule(struct classifier *cls,
+            struct cls_table *table, struct cls_rule *new)
 {
     struct cls_rule *head;
+    struct cls_rule *old = NULL;
 
     new->hmap_node.hash = miniflow_hash_in_minimask(&new->match.flow,
                                                     &new->match.mask, 0);
@@ -548,7 +677,7 @@ insert_rule(struct cls_table *table, struct cls_rule *new)
     if (!head) {
         hmap_insert(&table->rules, &new->hmap_node, new->hmap_node.hash);
         list_init(&new->list);
-        return NULL;
+        goto out;
     } else {
         /* Scan the list for the insertion point that will keep the list in
          * order of decreasing priority. */
@@ -563,18 +692,24 @@ insert_rule(struct cls_table *table, struct cls_rule *new)
 
                 if (new->priority == rule->priority) {
                     list_replace(&new->list, &rule->list);
-                    return rule;
+                    old = rule;
+                    goto out;
                 } else {
                     list_insert(&rule->list, &new->list);
-                    return NULL;
+                    goto out;
                 }
             }
         }
 
         /* Insert 'new' at the end of the list. */
         list_push_back(&head->list, &new->list);
-        return NULL;
     }
+
+ out:
+    if (!old) {
+        update_tables_after_insertion(cls, table, new->priority);
+    }
+    return old;
 }
 
 static struct cls_rule *
index bc9db33..d318864 100644 (file)
@@ -41,14 +41,18 @@ extern "C" {
 struct classifier {
     int n_rules;                /* Total number of rules. */
     struct hmap tables;         /* Contains "struct cls_table"s.  */
+    struct list tables_priority; /* Tables in descending priority order */
 };
 
 /* A set of rules that all have the same fields wildcarded. */
 struct cls_table {
     struct hmap_node hmap_node; /* Within struct classifier 'tables' hmap. */
+    struct list list_node;      /* Within classifier 'tables_priority_list' */
     struct hmap rules;          /* Contains "struct cls_rule"s. */
     struct minimask mask;       /* Wildcards for fields. */
     int n_table_rules;          /* Number of rules, including duplicates. */
+    unsigned int max_priority;  /* Max priority of any rule in the table. */
+    unsigned int max_count;     /* Count of max_priority rules. */
 };
 
 /* Returns true if 'table' is a "catch-all" table that will match every
index b6eba39..7293063 100644 (file)
@@ -47,7 +47,6 @@
 #include "odp-util.h"
 #include "ofpbuf.h"
 #include "openvswitch/datapath-compat.h"
-#include "openvswitch/tunnel.h"
 #include "packets.h"
 #include "poll-loop.h"
 #include "random.h"
@@ -439,12 +438,12 @@ get_vport_type(const struct dpif_linux_vport *vport)
     case OVS_VPORT_TYPE_GRE64:
         return "gre64";
 
-    case OVS_VPORT_TYPE_CAPWAP:
-        return "capwap";
-
     case OVS_VPORT_TYPE_VXLAN:
         return "vxlan";
 
+    case OVS_VPORT_TYPE_LISP:
+        return "lisp";
+
     case OVS_VPORT_TYPE_UNSPEC:
     case __OVS_VPORT_TYPE_MAX:
         break;
@@ -468,10 +467,10 @@ netdev_to_ovs_vport_type(const struct netdev *netdev)
         return OVS_VPORT_TYPE_GRE64;
     } else if (strstr(type, "gre")) {
         return OVS_VPORT_TYPE_GRE;
-    } else if (!strcmp(type, "capwap")) {
-        return OVS_VPORT_TYPE_CAPWAP;
     } else if (!strcmp(type, "vxlan")) {
         return OVS_VPORT_TYPE_VXLAN;
+    } else if (!strcmp(type, "lisp")) {
+        return OVS_VPORT_TYPE_LISP;
     } else {
         return OVS_VPORT_TYPE_UNSPEC;
     }
@@ -482,12 +481,15 @@ dpif_linux_port_add(struct dpif *dpif_, struct netdev *netdev,
                     uint32_t *port_nop)
 {
     struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+    const struct netdev_tunnel_config *tnl_cfg;
     const char *name = netdev_vport_get_dpif_port(netdev);
     const char *type = netdev_get_type(netdev);
     struct dpif_linux_vport request, reply;
     struct nl_sock *sock = NULL;
     uint32_t upcall_pid;
     struct ofpbuf *buf;
+    uint64_t options_stub[64 / 8];
+    struct ofpbuf options;
     int error;
 
     if (dpif->epoll_fd >= 0) {
@@ -514,6 +516,15 @@ dpif_linux_port_add(struct dpif *dpif_, struct netdev *netdev,
         netdev_linux_ethtool_set_flag(netdev, ETH_FLAG_LRO, "LRO", false);
     }
 
+    tnl_cfg = netdev_get_tunnel_config(netdev);
+    if (tnl_cfg && tnl_cfg->dst_port != 0) {
+        ofpbuf_use_stack(&options, options_stub, sizeof options_stub);
+        nl_msg_put_u16(&options, OVS_TUNNEL_ATTR_DST_PORT,
+                       ntohs(tnl_cfg->dst_port));
+        request.options = options.data;
+        request.options_len = options.size;
+    }
+
     request.port_no = *port_nop;
     upcall_pid = sock ? nl_sock_pid(sock) : 0;
     request.upcall_pid = &upcall_pid;
@@ -1225,7 +1236,7 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall *upcall,
         [OVS_PACKET_ATTR_KEY] = { .type = NL_A_NESTED },
 
         /* OVS_PACKET_CMD_ACTION only. */
-        [OVS_PACKET_ATTR_USERDATA] = { .type = NL_A_U64, .optional = true },
+        [OVS_PACKET_ATTR_USERDATA] = { .type = NL_A_UNSPEC, .optional = true },
     };
 
     struct ovs_header *ovs_header;
@@ -1263,9 +1274,7 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall *upcall,
     upcall->key = CONST_CAST(struct nlattr *,
                              nl_attr_get(a[OVS_PACKET_ATTR_KEY]));
     upcall->key_len = nl_attr_get_size(a[OVS_PACKET_ATTR_KEY]);
-    upcall->userdata = (a[OVS_PACKET_ATTR_USERDATA]
-                        ? nl_attr_get_u64(a[OVS_PACKET_ATTR_USERDATA])
-                        : 0);
+    upcall->userdata = a[OVS_PACKET_ATTR_USERDATA];
     *dp_ifindex = ovs_header->dp_ifindex;
 
     return 0;
index 129839c..185fe19 100644 (file)
@@ -151,7 +151,7 @@ static int dpif_netdev_open(const struct dpif_class *, const char *name,
                             bool create, struct dpif **);
 static int dp_netdev_output_userspace(struct dp_netdev *, const struct ofpbuf *,
                                     int queue_no, const struct flow *,
-                                    uint64_t arg);
+                                    const struct nlattr *userdata);
 static void dp_netdev_execute_actions(struct dp_netdev *,
                                       struct ofpbuf *, struct flow *,
                                       const struct nlattr *actions,
@@ -1051,7 +1051,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
         dp->n_hit++;
     } else {
         dp->n_missed++;
-        dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, 0);
+        dp_netdev_output_userspace(dp, packet, DPIF_UC_MISS, &key, NULL);
     }
 }
 
@@ -1116,37 +1116,51 @@ dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
 
 static int
 dp_netdev_output_userspace(struct dp_netdev *dp, const struct ofpbuf *packet,
-                         int queue_no, const struct flow *flow, uint64_t arg)
+                           int queue_no, const struct flow *flow,
+                           const struct nlattr *userdata)
 {
     struct dp_netdev_queue *q = &dp->queues[queue_no];
-    struct dp_netdev_upcall *u;
-    struct dpif_upcall *upcall;
-    struct ofpbuf *buf;
-    size_t key_len;
-
-    if (q->head - q->tail >= MAX_QUEUE_LEN) {
-        dp->n_lost++;
-        return ENOBUFS;
-    }
+    if (q->head - q->tail < MAX_QUEUE_LEN) {
+        struct dp_netdev_upcall *u = &q->upcalls[q->head++ & QUEUE_MASK];
+        struct dpif_upcall *upcall = &u->upcall;
+        struct ofpbuf *buf = &u->buf;
+        size_t buf_size;
+
+        upcall->type = queue_no;
+
+        /* Allocate buffer big enough for everything. */
+        buf_size = ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size;
+        if (userdata) {
+            buf_size += NLA_ALIGN(userdata->nla_len);
+        }
+        ofpbuf_init(buf, buf_size);
 
-    u = &q->upcalls[q->head++ & QUEUE_MASK];
+        /* Put ODP flow. */
+        odp_flow_key_from_flow(buf, flow, flow->in_port);
+        upcall->key = buf->data;
+        upcall->key_len = buf->size;
 
-    buf = &u->buf;
-    ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
-    odp_flow_key_from_flow(buf, flow, flow->in_port);
-    key_len = buf->size;
-    ofpbuf_pull(buf, key_len);
-    ofpbuf_reserve(buf, 2);
-    ofpbuf_put(buf, packet->data, packet->size);
+        /* Put userdata. */
+        if (userdata) {
+            upcall->userdata = ofpbuf_put(buf, userdata,
+                                          NLA_ALIGN(userdata->nla_len));
+        }
 
-    upcall = &u->upcall;
-    upcall->type = queue_no;
-    upcall->packet = buf;
-    upcall->key = buf->base;
-    upcall->key_len = key_len;
-    upcall->userdata = arg;
+        /* Put packet.
+         *
+         * We adjust 'data' and 'size' in 'buf' so that only the packet itself
+         * is visible in 'upcall->packet'.  The ODP flow and (if present)
+         * userdata become part of the headroom. */
+        ofpbuf_put_zeros(buf, 2);
+        buf->data = ofpbuf_put(buf, packet->data, packet->size);
+        buf->size = packet->size;
+        upcall->packet = buf;
 
-    return 0;
+        return 0;
+    } else {
+        dp->n_lost++;
+        return ENOBUFS;
+    }
 }
 
 static void
@@ -1188,11 +1202,9 @@ dp_netdev_action_userspace(struct dp_netdev *dp,
                           struct ofpbuf *packet, struct flow *key,
                           const struct nlattr *a)
 {
-    const struct nlattr *userdata_attr;
-    uint64_t userdata;
+    const struct nlattr *userdata;
 
-    userdata_attr = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
-    userdata = userdata_attr ? nl_attr_get_u64(userdata_attr) : 0;
+    userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA);
     dp_netdev_output_userspace(dp, packet, DPIF_UC_ACTION, key, userdata);
 }
 
@@ -1206,7 +1218,6 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a)
     const struct ovs_key_udp *udp_key;
 
     switch (type) {
-    case OVS_KEY_ATTR_TUN_ID:
     case OVS_KEY_ATTR_PRIORITY:
     case OVS_KEY_ATTR_SKB_MARK:
     case OVS_KEY_ATTR_TUNNEL:
@@ -1241,6 +1252,10 @@ execute_set_action(struct ofpbuf *packet, const struct nlattr *a)
         packet_set_udp_port(packet, udp_key->udp_src, udp_key->udp_dst);
         break;
 
+     case OVS_KEY_ATTR_MPLS:
+         set_mpls_lse(packet, nl_attr_get_be32(a));
+         break;
+
      case OVS_KEY_ATTR_UNSPEC:
      case OVS_KEY_ATTR_ENCAP:
      case OVS_KEY_ATTR_ETHERTYPE:
@@ -1287,6 +1302,16 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
             eth_pop_vlan(packet);
             break;
 
+        case OVS_ACTION_ATTR_PUSH_MPLS: {
+            const struct ovs_action_push_mpls *mpls = nl_attr_get(a);
+            push_mpls(packet, mpls->mpls_ethertype, mpls->mpls_lse);
+            break;
+         }
+
+        case OVS_ACTION_ATTR_POP_MPLS:
+            pop_mpls(packet, nl_attr_get_be16(a));
+            break;
+
         case OVS_ACTION_ATTR_SET:
             execute_set_action(packet, nl_attr_get(a));
             break;
index c5e3fc8..fd05b2f 100644 (file)
@@ -540,10 +540,10 @@ const char *dpif_upcall_type_to_string(enum dpif_upcall_type);
 
 /* A packet passed up from the datapath to userspace.
  *
- * If 'key' or 'actions' is nonnull, then it points into data owned by
- * 'packet', so their memory cannot be freed separately.  (This is hardly a
- * great way to do things but it works out OK for the dpif providers and
- * clients that exist so far.)
+ * If 'key', 'actions', or 'userdata' is nonnull, then it points into data
+ * owned by 'packet', so their memory cannot be freed separately.  (This is
+ * hardly a great way to do things but it works out OK for the dpif providers
+ * and clients that exist so far.)
  */
 struct dpif_upcall {
     /* All types. */
@@ -553,7 +553,7 @@ struct dpif_upcall {
     size_t key_len;             /* Length of 'key' in bytes. */
 
     /* DPIF_UC_ACTION only. */
-    uint64_t userdata;          /* Argument to OVS_ACTION_ATTR_USERSPACE. */
+    struct nlattr *userdata;    /* Argument to OVS_ACTION_ATTR_USERSPACE. */
 };
 
 int dpif_recv_set(struct dpif *, bool enable);
index 2a3dd3d..678b8f0 100644 (file)
@@ -93,6 +93,21 @@ pull_icmpv6(struct ofpbuf *packet)
     return ofpbuf_try_pull(packet, sizeof(struct icmp6_hdr));
 }
 
+static void
+parse_mpls(struct ofpbuf *b, struct flow *flow)
+{
+    struct mpls_hdr *mh;
+
+    while ((mh = ofpbuf_try_pull(b, sizeof *mh))) {
+        if (flow->mpls_depth++ == 0) {
+            flow->mpls_lse = mh->mpls_lse;
+        }
+        if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) {
+            break;
+        }
+    }
+}
+
 static void
 parse_vlan(struct ofpbuf *b, struct flow *flow)
 {
@@ -132,7 +147,12 @@ parse_ethertype(struct ofpbuf *b)
     }
 
     ofpbuf_pull(b, sizeof *llc);
-    return llc->snap.snap_type;
+
+    if (ntohs(llc->snap.snap_type) >= ETH_TYPE_MIN) {
+        return llc->snap.snap_type;
+    }
+
+    return htons(FLOW_DL_TYPE_NONE);
 }
 
 static int
@@ -324,6 +344,8 @@ invalid:
  *
  *    - packet->l2 to the start of the Ethernet header.
  *
+ *    - packet->l2_5 to the start of the MPLS shim header.
+ *
  *    - packet->l3 to just past the Ethernet header, or just past the
  *      vlan_header if one is present, to the first byte of the payload of the
  *      Ethernet frame.
@@ -354,10 +376,11 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark,
     flow->skb_priority = skb_priority;
     flow->skb_mark = skb_mark;
 
-    packet->l2 = b.data;
-    packet->l3 = NULL;
-    packet->l4 = NULL;
-    packet->l7 = NULL;
+    packet->l2   = b.data;
+    packet->l2_5 = NULL;
+    packet->l3   = NULL;
+    packet->l4   = NULL;
+    packet->l7   = NULL;
 
     if (b.size < sizeof *eth) {
         return;
@@ -375,33 +398,15 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark,
     }
     flow->dl_type = parse_ethertype(&b);
 
-    packet->l3 = b.data;
-    flow_extract_l3_onwards(packet, flow, flow->dl_type);
-}
-
-/* Initializes l3 and higher 'flow' members from 'packet'
- *
- * This should be called by or after flow_extract()
- *
- * Initializes 'packet' header pointers as follows:
- *
- *    - packet->l4 to just past the IPv4 header, if one is present and has a
- *      correct length, and otherwise NULL.
- *
- *    - packet->l7 to just past the TCP or UDP or ICMP header, if one is
- *      present and has a correct length, and otherwise NULL.
- */
-void
-flow_extract_l3_onwards(struct ofpbuf *packet, struct flow *flow,
-                        ovs_be16 dl_type)
-{
-    struct ofpbuf b;
-
-    ofpbuf_use_const(&b, packet->l3, packet->size -
-                     (size_t)((char *)packet->l3 - (char *)packet->l2));
+    /* Parse mpls, copy l3 ttl. */
+    if (eth_type_mpls(flow->dl_type)) {
+        packet->l2_5 = b.data;
+        parse_mpls(&b, flow);
+    }
 
     /* Network layer. */
-    if (dl_type == htons(ETH_TYPE_IP)) {
+    packet->l3 = b.data;
+    if (flow->dl_type == htons(ETH_TYPE_IP)) {
         const struct ip_header *nh = pull_ip(&b);
         if (nh) {
             packet->l4 = b.data;
@@ -434,7 +439,7 @@ flow_extract_l3_onwards(struct ofpbuf *packet, struct flow *flow,
                 }
             }
         }
-    } else if (dl_type == htons(ETH_TYPE_IPV6)) {
+    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
         if (parse_ipv6(&b, flow)) {
             return;
         }
@@ -449,8 +454,8 @@ flow_extract_l3_onwards(struct ofpbuf *packet, struct flow *flow,
                 packet->l7 = b.data;
             }
         }
-    } else if (dl_type == htons(ETH_TYPE_ARP) ||
-               dl_type == htons(ETH_TYPE_RARP)) {
+    } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
+               flow->dl_type == htons(ETH_TYPE_RARP)) {
         const struct arp_eth_header *arp = pull_arp(&b);
         if (arp && arp->ar_hrd == htons(1)
             && arp->ar_pro == htons(ETH_TYPE_IP)
@@ -487,7 +492,7 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
 void
 flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     fmd->tun_id = flow->tunnel.tun_id;
     fmd->metadata = flow->metadata;
@@ -811,6 +816,37 @@ flow_set_vlan_pcp(struct flow *flow, uint8_t pcp)
     flow->vlan_tci |= htons((pcp << VLAN_PCP_SHIFT) | VLAN_CFI);
 }
 
+/* Sets the MPLS Label that 'flow' matches to 'label', which is interpreted
+ * as an OpenFlow 1.1 "mpls_label" value. */
+void
+flow_set_mpls_label(struct flow *flow, ovs_be32 label)
+{
+    set_mpls_lse_label(&flow->mpls_lse, label);
+}
+
+/* Sets the MPLS TTL that 'flow' matches to 'ttl', which should be in the
+ * range 0...255. */
+void
+flow_set_mpls_ttl(struct flow *flow, uint8_t ttl)
+{
+    set_mpls_lse_ttl(&flow->mpls_lse, ttl);
+}
+
+/* Sets the MPLS TC that 'flow' matches to 'tc', which should be in the
+ * range 0...7. */
+void
+flow_set_mpls_tc(struct flow *flow, uint8_t tc)
+{
+    set_mpls_lse_tc(&flow->mpls_lse, tc);
+}
+
+/* Sets the MPLS BOS bit that 'flow' matches to which should be 0 or 1. */
+void
+flow_set_mpls_bos(struct flow *flow, uint8_t bos)
+{
+    set_mpls_lse_bos(&flow->mpls_lse, bos);
+}
+
 /* Puts into 'b' a packet that flow_extract() would parse as having the given
  * 'flow'.
  *
@@ -898,6 +934,11 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
             memcpy(arp->ar_tha, flow->arp_tha, ETH_ADDR_LEN);
         }
     }
+
+    if (eth_type_mpls(flow->dl_type)) {
+        b->l2_5 = b->l3;
+        push_mpls(b, flow->dl_type, flow->mpls_lse);
+    }
 }
 \f
 /* Compressed flow. */
index 8e79e62..6e169d6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ struct ofpbuf;
 /* This sequence number should be incremented whenever anything involving flows
  * or the wildcarding of flows changes.  This will cause build assertion
  * failures in places which likely need to be updated. */
-#define FLOW_WC_SEQ 18
+#define FLOW_WC_SEQ 20
 
 #define FLOW_N_REGS 8
 BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
@@ -91,6 +91,8 @@ struct flow {
                                    unless in DPIF code, in which case it
                                    is the datapath port number. */
     uint32_t skb_mark;          /* Packet mark. */
+    ovs_be32 mpls_lse;          /* MPLS label stack entry. */
+    uint16_t mpls_depth;        /* Depth of MPLS stack. */
     ovs_be16 vlan_tci;          /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
     ovs_be16 dl_type;           /* Ethernet frame type. */
     ovs_be16 tp_src;            /* TCP/UDP source port. */
@@ -103,15 +105,15 @@ struct flow {
     uint8_t arp_tha[6];         /* ARP/ND target hardware address. */
     uint8_t nw_ttl;             /* IP TTL/Hop Limit. */
     uint8_t nw_frag;            /* FLOW_FRAG_* flags. */
-    uint8_t zeros[4];
+    uint8_t zeros[6];
 };
 BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
 
 #define FLOW_U32S (sizeof(struct flow) / 4)
 
 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
-BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 152 &&
-                  FLOW_WC_SEQ == 18);
+BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 160 &&
+                  FLOW_WC_SEQ == 20);
 
 /* Represents the metadata fields of struct flow. */
 struct flow_metadata {
@@ -123,8 +125,7 @@ struct flow_metadata {
 
 void flow_extract(struct ofpbuf *, uint32_t priority, uint32_t mark,
                   const struct flow_tnl *, uint16_t in_port, struct flow *);
-void flow_extract_l3_onwards(struct ofpbuf *, struct flow *,
-                             ovs_be16 dl_type);
+
 void flow_zero_wildcards(struct flow *, const struct flow_wildcards *);
 void flow_get_metadata(const struct flow *, struct flow_metadata *);
 
@@ -142,6 +143,11 @@ void flow_set_dl_vlan(struct flow *, ovs_be16 vid);
 void flow_set_vlan_vid(struct flow *, ovs_be16 vid);
 void flow_set_vlan_pcp(struct flow *, uint8_t pcp);
 
+void flow_set_mpls_label(struct flow *flow, ovs_be32 label);
+void flow_set_mpls_ttl(struct flow *flow, uint8_t ttl);
+void flow_set_mpls_tc(struct flow *flow, uint8_t tc);
+void flow_set_mpls_bos(struct flow *flow, uint8_t stack);
+
 void flow_compose(struct ofpbuf *, const struct flow *);
 
 static inline int
index 5c96851..06a9a42 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -1639,3 +1639,116 @@ json_serialize_string(const char *string, struct ds *ds)
     }
     ds_put_char(ds, '"');
 }
+\f
+static size_t
+json_string_serialized_length(const char *string)
+{
+    size_t length;
+    uint8_t c;
+
+    length = strlen("\"\"");
+
+    while ((c = *string++) != '\0') {
+        switch (c) {
+        case '"':
+        case '\\':
+        case '\b':
+        case '\f':
+        case '\n':
+        case '\r':
+        case '\t':
+            length += 2;
+            break;
+
+        default:
+            if (c >= 32) {
+                length++;
+            } else {
+                /* \uXXXX */
+                length += 6;
+            }
+            break;
+        }
+    }
+
+    return length;
+}
+
+static size_t
+json_object_serialized_length(const struct shash *object)
+{
+    size_t length = strlen("{}");
+
+    if (!shash_is_empty(object)) {
+        struct shash_node *node;
+
+        /* Commas and colons. */
+        length += 2 * shash_count(object) - 1;
+
+        SHASH_FOR_EACH (node, object) {
+            const struct json *value = node->data;
+
+            length += json_string_serialized_length(node->name);
+            length += json_serialized_length(value);
+        }
+    }
+
+    return length;
+}
+
+static size_t
+json_array_serialized_length(const struct json_array *array)
+{
+    size_t length = strlen("[]");
+
+    if (array->n) {
+        size_t i;
+
+        /* Commas. */
+        length += array->n - 1;
+
+        for (i = 0; i < array->n; i++) {
+            length += json_serialized_length(array->elems[i]);
+        }
+    }
+
+    return length;
+}
+
+/* Returns strlen(json_to_string(json, 0)), that is, the number of bytes in the
+ * JSON output by json_to_string() for 'json' when JSSF_PRETTY is not
+ * requested.  (JSSF_SORT does not affect the length of json_to_string()'s
+ * output.) */
+size_t
+json_serialized_length(const struct json *json)
+{
+    switch (json->type) {
+    case JSON_NULL:
+        return strlen("null");
+
+    case JSON_FALSE:
+        return strlen("false");
+
+    case JSON_TRUE:
+        return strlen("true");
+
+    case JSON_OBJECT:
+        return json_object_serialized_length(json->u.object);
+
+    case JSON_ARRAY:
+        return json_array_serialized_length(&json->u.array);
+
+    case JSON_INTEGER:
+        return snprintf(NULL, 0, "%lld", json->u.integer);
+
+    case JSON_REAL:
+        return snprintf(NULL, 0, "%.*g", DBL_DIG, json->u.real);
+
+    case JSON_STRING:
+        return json_string_serialized_length(json->u.string);
+
+    case JSON_N_TYPES:
+    default:
+        NOT_REACHED();
+    }
+}
index cfe9457..ef23124 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -127,6 +127,8 @@ enum {
 };
 char *json_to_string(const struct json *, int flags);
 void json_to_ds(const struct json *, int flags, struct ds *);
+
+size_t json_serialized_length(const struct json *);
 \f
 /* JSON string formatting operations. */
 
index 50073b6..1ea5398 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -744,6 +744,7 @@ struct jsonrpc_session {
     struct jsonrpc *rpc;
     struct stream *stream;
     struct pstream *pstream;
+    int last_error;
     unsigned int seqno;
     uint8_t dscp;
 };
@@ -752,14 +753,18 @@ struct jsonrpc_session {
  * acceptable to stream_open() or pstream_open().
  *
  * If 'name' is an active connection method, e.g. "tcp:127.1.2.3", the new
- * jsonrpc_session connects and reconnects, with back-off, to 'name'.
+ * jsonrpc_session connects to 'name'.  If 'retry' is true, then the new
+ * session connects and reconnects to 'name', with backoff.  If 'retry' is
+ * false, the new session will only try to connect once and after a connection
+ * failure or a disconnection jsonrpc_session_is_alive() will return false for
+ * the new session.
  *
  * If 'name' is a passive connection method, e.g. "ptcp:", the new
  * jsonrpc_session listens for connections to 'name'.  It maintains at most one
  * connection at any given time.  Any new connection causes the previous one
  * (if any) to be dropped. */
 struct jsonrpc_session *
-jsonrpc_session_open(const char *name)
+jsonrpc_session_open(const char *name, bool retry)
 {
     struct jsonrpc_session *s;
 
@@ -772,9 +777,13 @@ jsonrpc_session_open(const char *name)
     s->pstream = NULL;
     s->seqno = 0;
     s->dscp = 0;
+    s->last_error = 0;
 
     if (!pstream_verify_name(name)) {
         reconnect_set_passive(s->reconnect, true, time_msec());
+    } else if (!retry) {
+        reconnect_set_max_tries(s->reconnect, 1);
+        reconnect_set_backoff(s->reconnect, INT_MAX, INT_MAX);
     }
 
     if (!stream_or_pstream_needs_probes(name)) {
@@ -847,6 +856,8 @@ jsonrpc_session_connect(struct jsonrpc_session *s)
         error = jsonrpc_stream_open(name, &s->stream, s->dscp);
         if (!error) {
             reconnect_connecting(s->reconnect, time_msec());
+        } else {
+            s->last_error = error;
         }
     } else {
         error = s->pstream ? 0 : jsonrpc_pstream_open(name, &s->pstream,
@@ -908,6 +919,7 @@ jsonrpc_session_run(struct jsonrpc_session *s)
         if (error) {
             reconnect_disconnected(s->reconnect, time_msec(), error);
             jsonrpc_session_disconnect(s);
+            s->last_error = error;
         }
     } else if (s->stream) {
         int error;
@@ -1061,6 +1073,12 @@ jsonrpc_session_get_status(const struct jsonrpc_session *s)
     return s && s->rpc ? jsonrpc_get_status(s->rpc) : 0;
 }
 
+int
+jsonrpc_session_get_last_error(const struct jsonrpc_session *s)
+{
+    return s->last_error;
+}
+
 void
 jsonrpc_session_get_reconnect_stats(const struct jsonrpc_session *s,
                                     struct reconnect_stats *stats)
index b5acf89..0ae205d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -98,7 +98,7 @@ struct json *jsonrpc_msg_to_json(struct jsonrpc_msg *);
 \f
 /* A JSON-RPC session with reconnection. */
 
-struct jsonrpc_session *jsonrpc_session_open(const char *name);
+struct jsonrpc_session *jsonrpc_session_open(const char *name, bool retry);
 struct jsonrpc_session *jsonrpc_session_open_unreliably(struct jsonrpc *,
                                                         uint8_t);
 void jsonrpc_session_close(struct jsonrpc_session *);
@@ -117,6 +117,7 @@ bool jsonrpc_session_is_alive(const struct jsonrpc_session *);
 bool jsonrpc_session_is_connected(const struct jsonrpc_session *);
 unsigned int jsonrpc_session_get_seqno(const struct jsonrpc_session *);
 int jsonrpc_session_get_status(const struct jsonrpc_session *);
+int jsonrpc_session_get_last_error(const struct jsonrpc_session *);
 void jsonrpc_session_get_reconnect_stats(const struct jsonrpc_session *,
                                          struct reconnect_stats *);
 
index 8ffa797..55e0d0a 100644 (file)
@@ -60,10 +60,18 @@ bool list_is_short(const struct list *);
     for (ASSIGN_CONTAINER(ITER, (LIST)->next, MEMBER);                  \
          &(ITER)->MEMBER != (LIST);                                     \
          ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER))
+#define LIST_FOR_EACH_CONTINUE(ITER, MEMBER, LIST)                      \
+    for (ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER);           \
+         &(ITER)->MEMBER != (LIST);                                     \
+         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.next, MEMBER))
 #define LIST_FOR_EACH_REVERSE(ITER, MEMBER, LIST)                       \
     for (ASSIGN_CONTAINER(ITER, (LIST)->prev, MEMBER);                  \
          &(ITER)->MEMBER != (LIST);                                     \
          ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER))
+#define LIST_FOR_EACH_REVERSE_CONTINUE(ITER, MEMBER, LIST)              \
+    for (ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER);           \
+         &(ITER)->MEMBER != (LIST);                                     \
+         ASSIGN_CONTAINER(ITER, (ITER)->MEMBER.prev, MEMBER))
 #define LIST_FOR_EACH_SAFE(ITER, NEXT, MEMBER, LIST)            \
     for (ASSIGN_CONTAINER(ITER, (LIST)->next, MEMBER);          \
          (&(ITER)->MEMBER != (LIST)                             \
index bedb1a1..2aa4e89 100644 (file)
@@ -460,6 +460,57 @@ match_set_dl_vlan_pcp(struct match *match, uint8_t dl_vlan_pcp)
     match->wc.masks.vlan_tci |= htons(VLAN_CFI | VLAN_PCP_MASK);
 }
 
+/* Modifies 'match' so that the MPLS label is wildcarded. */
+void
+match_set_any_mpls_label(struct match *match)
+{
+    match->wc.masks.mpls_lse &= ~htonl(MPLS_LABEL_MASK);
+    flow_set_mpls_label(&match->flow, htonl(0));
+}
+
+/* Modifies 'match' so that it matches only packets with an MPLS header whose
+ * label equals the low 20 bits of 'mpls_label'. */
+void
+match_set_mpls_label(struct match *match, ovs_be32 mpls_label)
+{
+    match->wc.masks.mpls_lse |= htonl(MPLS_LABEL_MASK);
+    flow_set_mpls_label(&match->flow, mpls_label);
+}
+
+/* Modifies 'match' so that the MPLS TC is wildcarded. */
+void
+match_set_any_mpls_tc(struct match *match)
+{
+    match->wc.masks.mpls_lse &= ~htonl(MPLS_TC_MASK);
+    flow_set_mpls_tc(&match->flow, 0);
+}
+
+/* Modifies 'match' so that it matches only packets with an MPLS header whose
+ * Traffic Class equals the low 3 bits of 'mpls_tc'. */
+void
+match_set_mpls_tc(struct match *match, uint8_t mpls_tc)
+{
+    match->wc.masks.mpls_lse |= htonl(MPLS_TC_MASK);
+    flow_set_mpls_tc(&match->flow, mpls_tc);
+}
+
+/* Modifies 'match' so that the MPLS stack flag is wildcarded. */
+void
+match_set_any_mpls_bos(struct match *match)
+{
+    match->wc.masks.mpls_lse &= ~htonl(MPLS_BOS_MASK);
+    flow_set_mpls_bos(&match->flow, 0);
+}
+
+/* Modifies 'match' so that it matches only packets with an MPLS header whose
+ * Stack Flag equals the lower bit of 'mpls_bos' */
+void
+match_set_mpls_bos(struct match *match, uint8_t mpls_bos)
+{
+    match->wc.masks.mpls_lse |= htonl(MPLS_BOS_MASK);
+    flow_set_mpls_bos(&match->flow, mpls_bos);
+}
+
 void
 match_set_tp_src(struct match *match, ovs_be16 tp_src)
 {
@@ -767,6 +818,24 @@ format_flow_tunnel(struct ds *s, const struct match *match)
     }
 }
 
+static void
+flow_format_mpls(const struct flow *flow, struct ds *s)
+{
+    if (flow->dl_type == htons(ETH_TYPE_MPLS)) {
+        ds_put_cstr(s, "mpls");
+    } else if (flow->dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+        ds_put_cstr(s, "mplsm");
+    } else {
+        return;
+    }
+
+    ds_put_format(s, "(label:%"PRIu32",tc:%d,ttl:%d,bos:%d),",
+                  mpls_lse_to_label(flow->mpls_lse),
+                  mpls_lse_to_tc(flow->mpls_lse),
+                  mpls_lse_to_ttl(flow->mpls_lse),
+                  mpls_lse_to_bos(flow->mpls_lse));
+}
+
 /* Appends a string representation of 'match' to 's'.  If 'priority' is
  * different from OFP_DEFAULT_PRIORITY, includes it in 's'. */
 void
@@ -780,7 +849,7 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
 
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     if (priority != OFP_DEFAULT_PRIORITY) {
         ds_put_format(s, "priority=%u,", priority);
@@ -832,6 +901,8 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
             ds_put_cstr(s, "arp,");
         } else if (f->dl_type == htons(ETH_TYPE_RARP)) {
             ds_put_cstr(s, "rarp,");
+        } else if (f->mpls_depth) {
+            flow_format_mpls(f, s);
         } else {
             skip_type = false;
         }
@@ -940,6 +1011,18 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
     if (wc->masks.nw_ttl) {
         ds_put_format(s, "nw_ttl=%"PRIu8",", f->nw_ttl);
     }
+    if (wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)) {
+        ds_put_format(s, "mpls_label=%"PRIu32",",
+                 mpls_lse_to_label(f->mpls_lse));
+    }
+    if (wc->masks.mpls_lse & htonl(MPLS_TC_MASK)) {
+        ds_put_format(s, "mpls_tc=%"PRIu8",",
+                 mpls_lse_to_tc(f->mpls_lse));
+    }
+    if (wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)) {
+        ds_put_format(s, "mpls_bos=%"PRIu8",",
+                 mpls_lse_to_bos(f->mpls_lse));
+    }
     switch (wc->masks.nw_frag) {
     case FLOW_NW_FRAG_ANY | FLOW_NW_FRAG_LATER:
         ds_put_format(s, "nw_frag=%s,",
index ff0b5f2..d435aa4 100644 (file)
@@ -78,6 +78,12 @@ void match_set_vlan_vid(struct match *, ovs_be16);
 void match_set_vlan_vid_masked(struct match *, ovs_be16 vid, ovs_be16 mask);
 void match_set_any_pcp(struct match *);
 void match_set_dl_vlan_pcp(struct match *, uint8_t);
+void match_set_any_mpls_label(struct match *);
+void match_set_mpls_label(struct match *, ovs_be32);
+void match_set_any_mpls_tc(struct match *);
+void match_set_mpls_tc(struct match *, uint8_t);
+void match_set_any_mpls_bos(struct match *);
+void match_set_mpls_bos(struct match *, uint8_t);
 void match_set_tp_src(struct match *, ovs_be16);
 void match_set_tp_src_masked(struct match *, ovs_be16 port, ovs_be16 mask);
 void match_set_tp_dst(struct match *, ovs_be16);
index e25103d..6f7a3aa 100644 (file)
@@ -256,6 +256,38 @@ static const struct mf_field mf_fields[MFF_N_IDS] = {
         OXM_OF_VLAN_PCP, "OXM_OF_VLAN_PCP",
     },
 
+    /* ## ---- ## */
+    /* ## L2.5 ## */
+    /* ## ---- ## */
+    {
+        MFF_MPLS_LABEL, "mpls_label", NULL,
+        4, 20,
+        MFM_NONE,
+        MFS_DECIMAL,
+        MFP_MPLS,
+        true,
+        OXM_OF_MPLS_LABEL, "OXM_OF_MPLS_LABEL",
+        OXM_OF_MPLS_LABEL, "OXM_OF_MPLS_LABEL",
+    }, {
+        MFF_MPLS_TC, "mpls_tc", NULL,
+        1, 3,
+        MFM_NONE,
+        MFS_DECIMAL,
+        MFP_MPLS,
+        true,
+        OXM_OF_MPLS_TC, "OXM_OF_MPLS_TC",
+        OXM_OF_MPLS_TC, "OXM_OF_MPLS_TC",
+    }, {
+        MFF_MPLS_BOS, "mpls_bos", NULL,
+        1, 1,
+        MFM_NONE,
+        MFS_DECIMAL,
+        MFP_MPLS,
+        false,
+        OXM_OF_MPLS_BOS, "OXM_OF_MPLS_BOS",
+        OXM_OF_MPLS_BOS, "OXM_OF_MPLS_BOS",
+    },
+
     /* ## -- ## */
     /* ## L3 ## */
     /* ## -- ## */
@@ -678,6 +710,13 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
     case MFF_VLAN_PCP:
         return !(wc->masks.vlan_tci & htons(VLAN_PCP_MASK));
 
+    case MFF_MPLS_LABEL:
+        return !(wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK));
+    case MFF_MPLS_TC:
+        return !(wc->masks.mpls_lse & htonl(MPLS_TC_MASK));
+    case MFF_MPLS_BOS:
+        return !(wc->masks.mpls_lse & htonl(MPLS_BOS_MASK));
+
     case MFF_IPV4_SRC:
         return !wc->masks.nw_src;
     case MFF_IPV4_DST:
@@ -791,6 +830,8 @@ mf_are_prereqs_ok(const struct mf_field *mf, const struct flow *flow)
         return flow->dl_type == htons(ETH_TYPE_IPV6);
     case MFP_VLAN_VID:
         return (flow->vlan_tci & htons(VLAN_CFI)) != 0;
+    case MFP_MPLS:
+        return eth_type_mpls(flow->dl_type);
     case MFP_IP_ANY:
         return is_ip_any(flow);
 
@@ -895,6 +936,15 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
     case MFF_IPV6_LABEL:
         return !(value->be32 & ~htonl(IPV6_LABEL_MASK));
 
+    case MFF_MPLS_LABEL:
+        return !(value->be32 & ~htonl(MPLS_LABEL_MASK >> MPLS_LABEL_SHIFT));
+
+    case MFF_MPLS_TC:
+        return !(value->u8 & ~(MPLS_TC_MASK >> MPLS_TC_SHIFT));
+
+    case MFF_MPLS_BOS:
+        return !(value->u8 & ~(MPLS_BOS_MASK >> MPLS_BOS_SHIFT));
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -975,6 +1025,18 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
         value->u8 = vlan_tci_to_pcp(flow->vlan_tci);
         break;
 
+    case MFF_MPLS_LABEL:
+        value->be32 = htonl(mpls_lse_to_label(flow->mpls_lse));
+        break;
+
+    case MFF_MPLS_TC:
+        value->u8 = mpls_lse_to_tc(flow->mpls_lse);
+        break;
+
+    case MFF_MPLS_BOS:
+        value->u8 = mpls_lse_to_bos(flow->mpls_lse);
+        break;
+
     case MFF_IPV4_SRC:
         value->be32 = flow->nw_src;
         break;
@@ -1142,6 +1204,18 @@ mf_set_value(const struct mf_field *mf,
         match_set_dl_vlan_pcp(match, value->u8);
         break;
 
+    case MFF_MPLS_LABEL:
+        match_set_mpls_label(match, value->be32);
+        break;
+
+    case MFF_MPLS_TC:
+        match_set_mpls_tc(match, value->u8);
+        break;
+
+    case MFF_MPLS_BOS:
+        match_set_mpls_bos(match, value->u8);
+        break;
+
     case MFF_IPV4_SRC:
         match_set_nw_src(match, value->be32);
         break;
@@ -1309,6 +1383,18 @@ mf_set_flow_value(const struct mf_field *mf,
         flow_set_vlan_pcp(flow, value->u8);
         break;
 
+    case MFF_MPLS_LABEL:
+        flow_set_mpls_label(flow, value->be32);
+        break;
+
+    case MFF_MPLS_TC:
+        flow_set_mpls_tc(flow, value->u8);
+        break;
+
+    case MFF_MPLS_BOS:
+        flow_set_mpls_bos(flow, value->u8);
+        break;
+
     case MFF_IPV4_SRC:
         flow->nw_src = value->be32;
         break;
@@ -1445,6 +1531,7 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
 
     case MFF_METADATA:
         match_set_metadata_masked(match, htonll(0), htonll(0));
+        break;
 
     case MFF_IN_PORT:
         match->flow.in_port = 0;
@@ -1494,6 +1581,18 @@ mf_set_wild(const struct mf_field *mf, struct match *match)
         match_set_any_pcp(match);
         break;
 
+    case MFF_MPLS_LABEL:
+        match_set_any_mpls_label(match);
+        break;
+
+    case MFF_MPLS_TC:
+        match_set_any_mpls_tc(match);
+        break;
+
+    case MFF_MPLS_BOS:
+        match_set_any_mpls_bos(match);
+        break;
+
     case MFF_IPV4_SRC:
     case MFF_ARP_SPA:
         match_set_nw_src_masked(match, htonl(0), htonl(0));
@@ -1621,6 +1720,9 @@ mf_set(const struct mf_field *mf,
     case MFF_DL_VLAN:
     case MFF_DL_VLAN_PCP:
     case MFF_VLAN_PCP:
+    case MFF_MPLS_LABEL:
+    case MFF_MPLS_TC:
+    case MFF_MPLS_BOS:
     case MFF_IP_PROTO:
     case MFF_IP_TTL:
     case MFF_IP_DSCP:
@@ -1878,6 +1980,18 @@ mf_random_value(const struct mf_field *mf, union mf_value *value)
         value->u8 &= 0x07;
         break;
 
+    case MFF_MPLS_LABEL:
+        value->be32 &= htonl(MPLS_LABEL_MASK >> MPLS_LABEL_SHIFT);
+        break;
+
+    case MFF_MPLS_TC:
+        value->u8 &= MPLS_TC_MASK >> MPLS_TC_SHIFT;
+        break;
+
+    case MFF_MPLS_BOS:
+        value->u8 &= MPLS_BOS_MASK >> MPLS_BOS_SHIFT;
+        break;
+
     case MFF_N_IDS:
     default:
         NOT_REACHED();
@@ -2235,15 +2349,12 @@ mf_format_integer_string(const struct mf_field *mf, const uint8_t *valuep,
 }
 
 static void
-mf_format_frag_string(const uint8_t *valuep, const uint8_t *maskp,
-                      struct ds *s)
+mf_format_frag_string(uint8_t value, uint8_t mask, struct ds *s)
 {
     const struct frag_handling *h;
-    uint8_t value = *valuep;
-    uint8_t mask = *maskp;
 
-    value &= mask;
     mask &= FLOW_NW_FRAG_MASK;
+    value &= mask;
 
     for (h = all_frags; h < &all_frags[ARRAY_SIZE(all_frags)]; h++) {
         if (value == h->value && mask == h->mask) {
@@ -2302,7 +2413,7 @@ mf_format(const struct mf_field *mf,
         break;
 
     case MFS_FRAG:
-        mf_format_frag_string(&value->u8, &mask->u8, s);
+        mf_format_frag_string(value->u8, mask ? mask->u8 : UINT8_MAX, s);
         break;
 
     case MFS_TNL_FLAGS:
index 3675883..57f6df5 100644 (file)
@@ -78,6 +78,11 @@ enum mf_field_id {
     MFF_DL_VLAN_PCP,            /* u8 (OpenFlow 1.0 compatibility) */
     MFF_VLAN_PCP,               /* be16 (OpenFlow 1.2 compatibility) */
 
+    /* L2.5 */
+    MFF_MPLS_LABEL,             /* be32 */
+    MFF_MPLS_TC,                /* u8 */
+    MFF_MPLS_BOS,               /* u8 */
+
     /* L3. */
     MFF_IPV4_SRC,               /* be32 */
     MFF_IPV4_DST,               /* be32 */
@@ -168,6 +173,9 @@ enum mf_prereqs {
     MFP_IPV6,
     MFP_IP_ANY,
 
+    /* L2.5 requirements. */
+    MFP_MPLS,
+
     /* L2+L3 requirements. */
     MFP_TCP,                    /* On IPv4 or IPv6. */
     MFP_UDP,                    /* On IPv4 or IPv6. */
@@ -220,6 +228,9 @@ struct mf_field {
      *     - "dl_vlan_pcp" is 1 byte but only 3 bits.
      *     - "is_frag" is 1 byte but only 2 bits.
      *     - "ipv6_label" is 4 bytes but only 20 bits.
+     *     - "mpls_label" is 4 bytes but only 20 bits.
+     *     - "mpls_tc"    is 1 byte but only 3 bits.
+     *     - "mpls_bos"   is 1 byte but only 1 bit.
      */
     unsigned int n_bytes;       /* Width of the field in bytes. */
     unsigned int n_bits;        /* Number of significant bits in field. */
index f81b68e..bdb3ea1 100644 (file)
@@ -51,6 +51,7 @@ struct netdev_dev_dummy {
     unsigned int change_seq;
 
     struct list devs;           /* List of child "netdev_dummy"s. */
+    int ifindex;
 };
 
 struct netdev_dummy {
@@ -110,6 +111,7 @@ netdev_dummy_create(const struct netdev_class *class, const char *name,
     netdev_dev->mtu = 1500;
     netdev_dev->flags = 0;
     netdev_dev->change_seq = 1;
+    netdev_dev->ifindex = -EOPNOTSUPP;
     list_init(&netdev_dev->devs);
 
     shash_add(&dummy_netdev_devs, name, netdev_dev);
@@ -131,6 +133,27 @@ netdev_dummy_destroy(struct netdev_dev *netdev_dev_)
     free(netdev_dev);
 }
 
+static int
+netdev_dummy_get_config(struct netdev_dev *netdev_dev_, struct smap *args)
+{
+    struct netdev_dev_dummy *netdev_dev = netdev_dev_dummy_cast(netdev_dev_);
+
+    if (netdev_dev->ifindex >= 0) {
+        smap_add_format(args, "ifindex", "%d", netdev_dev->ifindex);
+    }
+    return 0;
+}
+
+static int
+netdev_dummy_set_config(struct netdev_dev *netdev_dev_,
+                        const struct smap *args)
+{
+    struct netdev_dev_dummy *netdev_dev = netdev_dev_dummy_cast(netdev_dev_);
+
+    netdev_dev->ifindex = smap_get_int(args, "ifindex", -EOPNOTSUPP);
+    return 0;
+}
+
 static int
 netdev_dummy_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp)
 {
@@ -204,6 +227,19 @@ netdev_dummy_drain(struct netdev *netdev_)
     return 0;
 }
 
+static int
+netdev_dummy_send(struct netdev *netdev, const void *buffer OVS_UNUSED,
+                  size_t size)
+{
+    struct netdev_dev_dummy *dev =
+        netdev_dev_dummy_cast(netdev_get_dev(netdev));
+
+    dev->stats.tx_packets++;
+    dev->stats.tx_bytes += size;
+
+    return 0;
+}
+
 static int
 netdev_dummy_set_etheraddr(struct netdev *netdev,
                            const uint8_t mac[ETH_ADDR_LEN])
@@ -270,6 +306,15 @@ netdev_dummy_set_stats(struct netdev *netdev, const struct netdev_stats *stats)
     return 0;
 }
 
+static int
+netdev_dummy_get_ifindex(const struct netdev *netdev)
+{
+    struct netdev_dev_dummy *dev =
+        netdev_dev_dummy_cast(netdev_get_dev(netdev));
+
+    return dev->ifindex;
+}
+
 static int
 netdev_dummy_update_flags(struct netdev *netdev,
                           enum netdev_flags off, enum netdev_flags on,
@@ -324,8 +369,8 @@ static const struct netdev_class dummy_class = {
 
     netdev_dummy_create,
     netdev_dummy_destroy,
-    NULL,                       /* get_config */
-    NULL,                       /* set_config */
+    netdev_dummy_get_config,
+    netdev_dummy_set_config,
     NULL,                       /* get_tunnel_config */
 
     netdev_dummy_open,
@@ -336,14 +381,14 @@ static const struct netdev_class dummy_class = {
     netdev_dummy_recv_wait,
     netdev_dummy_drain,
 
-    NULL,                       /* send */
+    netdev_dummy_send,          /* send */
     NULL,                       /* send_wait */
 
     netdev_dummy_set_etheraddr,
     netdev_dummy_get_etheraddr,
     netdev_dummy_get_mtu,
     netdev_dummy_set_mtu,
-    NULL,                       /* get_ifindex */
+    netdev_dummy_get_ifindex,
     NULL,                       /* get_carrier */
     NULL,                       /* get_carrier_resets */
     NULL,                       /* get_miimon */
@@ -443,6 +488,9 @@ netdev_dummy_receive(struct unixctl_conn *conn,
             return;
         }
 
+        dummy_dev->stats.rx_packets++;
+        dummy_dev->stats.rx_bytes += packet->size;
+
         n_listeners = 0;
         LIST_FOR_EACH (dev, node, &dummy_dev->devs) {
             if (dev->listening) {
index 5de4fa2..c0e0c40 100644 (file)
@@ -916,7 +916,7 @@ netdev_linux_send(struct netdev *netdev_, const void *data, size_t size)
 
             sock = af_packet_sock();
             if (sock < 0) {
-                return sock;
+                return -sock;
             }
 
             error = get_ifindex(netdev_, &ifindex);
@@ -4639,7 +4639,11 @@ af_packet_sock(void)
     if (sock == INT_MIN) {
         sock = socket(AF_PACKET, SOCK_RAW, 0);
         if (sock >= 0) {
-            set_nonblocking(sock);
+            int error = set_nonblocking(sock);
+            if (error) {
+                close(sock);
+                sock = -error;
+            }
         } else {
             sock = -errno;
             VLOG_ERR("failed to create packet socket: %s", strerror(errno));
index b892f8f..4aa8bb0 100644 (file)
@@ -44,6 +44,8 @@ VLOG_DEFINE_THIS_MODULE(netdev_vport);
 /* Default to the OTV port, per the VXLAN IETF draft. */
 #define VXLAN_DST_PORT 8472
 
+#define LISP_DST_PORT 4341
+
 #define DEFAULT_TTL 64
 
 struct netdev_dev_vport {
@@ -67,6 +69,7 @@ struct vport_class {
 static int netdev_vport_create(const struct netdev_class *, const char *,
                                struct netdev_dev **);
 static int get_patch_config(struct netdev_dev *, struct smap *args);
+static int get_tunnel_config(struct netdev_dev *, struct smap *args);
 static void netdev_vport_poll_notify(struct netdev_dev_vport *);
 
 static bool
@@ -110,6 +113,16 @@ netdev_vport_is_patch(const struct netdev *netdev)
     return class->get_config == get_patch_config;
 }
 
+static bool
+netdev_vport_needs_dst_port(const struct netdev_dev *dev)
+{
+    const struct netdev_class *class = netdev_dev_get_class(dev);
+    const char *type = netdev_dev_get_type(dev);
+
+    return (class->get_config == get_tunnel_config &&
+            (!strcmp("vxlan", type) || !strcmp("lisp", type)));
+}
+
 const char *
 netdev_vport_get_dpif_port(const struct netdev *netdev)
 {
@@ -117,9 +130,27 @@ netdev_vport_get_dpif_port(const struct netdev *netdev)
     const struct netdev_class *class = netdev_dev_get_class(dev);
     const char *dpif_port;
 
-    dpif_port = (is_vport_class(class)
-                 ? vport_class_cast(class)->dpif_port
-                 : NULL);
+    if (netdev_vport_needs_dst_port(dev)) {
+        const struct netdev_dev_vport *vport = netdev_vport_get_dev(netdev);
+        const char *type = netdev_dev_get_type(dev);
+        static char dpif_port_combined[IFNAMSIZ];
+
+        /*
+         * Note: IFNAMSIZ is 16 bytes long. The maximum length of a VXLAN
+         * or LISP port name below is 15 or 14 bytes respectively. Still,
+         * assert here on the size of strlen(type) in case that changes
+         * in the future.
+         */
+        ovs_assert(strlen(type) + 10 < IFNAMSIZ);
+        snprintf(dpif_port_combined, IFNAMSIZ, "%s_sys_%d", type,
+                 ntohs(vport->tnl_cfg.dst_port));
+        return dpif_port_combined;
+    } else {
+        dpif_port = (is_vport_class(class)
+                     ? vport_class_cast(class)->dpif_port
+                     : NULL);
+    }
+
     return dpif_port ? dpif_port : netdev_get_name(netdev);
 }
 
@@ -289,11 +320,7 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
     ipsec_mech_set = false;
     memset(&tnl_cfg, 0, sizeof tnl_cfg);
 
-    if (!strcmp(type, "capwap")) {
-        VLOG_WARN_ONCE("CAPWAP tunnel support is deprecated.");
-    }
-
-    needs_dst_port = !strcmp(type, "vxlan");
+    needs_dst_port = netdev_vport_needs_dst_port(dev_);
     tnl_cfg.ipsec = strstr(type, "ipsec");
     tnl_cfg.dont_fragment = true;
 
@@ -302,6 +329,10 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
             struct in_addr in_addr;
             if (lookup_ip(node->value, &in_addr)) {
                 VLOG_WARN("%s: bad %s 'remote_ip'", name, type);
+            } else if (ip_is_multicast(in_addr.s_addr)) {
+                VLOG_WARN("%s: multicast remote_ip="IP_FMT" not allowed",
+                          name, IP_ARGS(in_addr.s_addr));
+                return EINVAL;
             } else {
                 tnl_cfg.ip_dst = in_addr.s_addr;
             }
@@ -378,10 +409,15 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
     }
 
     /* Add a default destination port for VXLAN if none specified. */
-    if (needs_dst_port && !tnl_cfg.dst_port) {
+    if (!strcmp(type, "vxlan") && !tnl_cfg.dst_port) {
         tnl_cfg.dst_port = htons(VXLAN_DST_PORT);
     }
 
+    /* Add a default destination port for LISP if none specified. */
+    if (!strcmp(type, "lisp") && !tnl_cfg.dst_port) {
+        tnl_cfg.dst_port = htons(LISP_DST_PORT);
+    }
+
     if (tnl_cfg.ipsec) {
         static pid_t pid = 0;
         if (pid <= 0) {
@@ -414,14 +450,6 @@ set_tunnel_config(struct netdev_dev *dev_, const struct smap *args)
                  name, type);
         return EINVAL;
     }
-
-    if (tnl_cfg.ip_src) {
-        if (ip_is_multicast(tnl_cfg.ip_dst)) {
-            VLOG_WARN("%s: remote_ip is multicast, ignoring local_ip", name);
-            tnl_cfg.ip_src = 0;
-        }
-    }
-
     if (!tnl_cfg.ttl) {
         tnl_cfg.ttl = DEFAULT_TTL;
     }
@@ -489,7 +517,10 @@ get_tunnel_config(struct netdev_dev *dev, struct smap *args)
 
     if (tnl_cfg->dst_port) {
         uint16_t dst_port = ntohs(tnl_cfg->dst_port);
-        if (dst_port != VXLAN_DST_PORT) {
+        const char *type = netdev_dev_get_type(dev);
+
+        if ((!strcmp("vxlan", type) && dst_port != VXLAN_DST_PORT) ||
+            (!strcmp("lisp", type) && dst_port != LISP_DST_PORT)) {
             smap_add_format(args, "dst_port", "%d", dst_port);
         }
     }
@@ -661,8 +692,8 @@ netdev_vport_tunnel_register(void)
         TUNNEL_CLASS("ipsec_gre", "gre_system"),
         TUNNEL_CLASS("gre64", "gre64_system"),
         TUNNEL_CLASS("ipsec_gre64", "gre64_system"),
-        TUNNEL_CLASS("capwap", "capwap_system"),
-        TUNNEL_CLASS("vxlan", "vxlan_system")
+        TUNNEL_CLASS("vxlan", "vxlan_system"),
+        TUNNEL_CLASS("lisp", "lisp_system")
     };
 
     int i;
index d358e40..2d6360b 100644 (file)
@@ -322,35 +322,6 @@ netdev_close(struct netdev *netdev)
     }
 }
 
-/* Returns true if a network device named 'name' exists and may be opened,
- * otherwise false. */
-bool
-netdev_exists(const char *name)
-{
-    struct netdev *netdev;
-    int error;
-
-    error = netdev_open(name, "system", &netdev);
-    if (!error) {
-        netdev_close(netdev);
-        return true;
-    } else {
-        if (error != ENODEV) {
-            VLOG_WARN("failed to open network device %s: %s",
-                      name, strerror(error));
-        }
-        return false;
-    }
-}
-
-/* Returns true if a network device named 'name' is currently opened,
- * otherwise false. */
-bool
-netdev_is_open(const char *name)
-{
-    return !!shash_find_data(&netdev_dev_shash, name);
-}
-
 /* Parses 'netdev_name_', which is of the form [type@]name into its component
  * pieces.  'name' and 'type' must be freed by the caller. */
 void
index a691d70..aab9de0 100644 (file)
 extern "C" {
 #endif
 
-/* Generic interface to network devices.
+/* Generic interface to network devices ("netdev"s).
  *
- * Currently, there is a single implementation of this interface that supports
- * Linux.  The interface should be generic enough to be implementable on other
- * operating systems as well. */
+ * Every port on a switch must have a corresponding netdev that must minimally
+ * support a few operations, such as the ability to read the netdev's MTU.
+ * The PORTING file at the top of the source tree has more information in the
+ * "Writing a netdev Provider" section. */
 
 struct ofpbuf;
 struct in_addr;
@@ -113,9 +114,6 @@ void netdev_enumerate_types(struct sset *types);
 int netdev_open(const char *name, const char *type, struct netdev **);
 void netdev_close(struct netdev *);
 
-bool netdev_exists(const char *name);
-bool netdev_is_open(const char *name);
-
 void netdev_parse_name(const char *netdev_name, char **name, char **type);
 
 /* Options. */
index 847f11f..e6b10a1 100644 (file)
@@ -128,8 +128,12 @@ nl_sock_create(int protocol, struct nl_sock **sockp)
     rcvbuf = 1024 * 1024;
     if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUFFORCE,
                    &rcvbuf, sizeof rcvbuf)) {
-        VLOG_WARN_RL(&rl, "setting %d-byte socket receive buffer failed (%s)",
-                     rcvbuf, strerror(errno));
+        /* Only root can use SO_RCVBUFFORCE.  Everyone else gets EPERM.
+         * Warn only if the failure is therefore unexpected. */
+        if (errno != EPERM || !getuid()) {
+            VLOG_WARN_RL(&rl, "setting %d-byte socket receive buffer failed "
+                         "(%s)", rcvbuf, strerror(errno));
+        }
     }
 
     retval = get_socket_rcvbuf(sock->fd);
index 4d7fcd6..bfead68 100644 (file)
@@ -573,7 +573,7 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
     int match_len;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     /* Metadata. */
     if (match->wc.masks.in_port) {
@@ -615,6 +615,22 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
                     match->wc.masks.vlan_tci);
     }
 
+    /* MPLS. */
+    if (eth_type_mpls(flow->dl_type)) {
+        if (match->wc.masks.mpls_lse & htonl(MPLS_TC_MASK)) {
+            nxm_put_8(b, OXM_OF_MPLS_TC, mpls_lse_to_tc(flow->mpls_lse));
+        }
+
+        if (match->wc.masks.mpls_lse & htonl(MPLS_BOS_MASK)) {
+            nxm_put_8(b, OXM_OF_MPLS_BOS, mpls_lse_to_bos(flow->mpls_lse));
+        }
+
+        if (match->wc.masks.mpls_lse & htonl(MPLS_LABEL_MASK)) {
+            nxm_put_32(b, OXM_OF_MPLS_LABEL,
+                       htonl(mpls_lse_to_label(flow->mpls_lse)));
+        }
+    }
+
     /* L3. */
     if (flow->dl_type == htons(ETH_TYPE_IP)) {
         /* IP. */
@@ -1201,22 +1217,19 @@ set_field_to_ofast(const struct ofpact_reg_load *load,
                       struct ofpbuf *openflow)
 {
     const struct mf_field *mf = load->dst.field;
+    uint16_t padded_value_len = ROUND_UP(mf->n_bytes, 8);
     struct ofp12_action_set_field *oasf;
-    uint16_t padded_value_len;
-
-    oasf = ofputil_put_OFPAT12_SET_FIELD(openflow);
-    oasf->dst = htonl(mf->oxm_header);
+    char *value;
 
     /* Set field is the only action of variable length (so far),
      * so handling the variable length portion is open-coded here */
-    padded_value_len = ROUND_UP(mf->n_bytes, 8);
-    ofpbuf_put_uninit(openflow, padded_value_len);
+    oasf = ofputil_put_OFPAT12_SET_FIELD(openflow);
+    oasf->dst = htonl(mf->oxm_header);
     oasf->len = htons(ntohs(oasf->len) + padded_value_len);
-    memset(oasf + 1, 0, padded_value_len);
 
+    value = ofpbuf_put_zeros(openflow, padded_value_len);
     bitwise_copy(&load->subvalue, sizeof load->subvalue, load->dst.ofs,
-                 oasf + 1, mf->n_bytes, load->dst.ofs, load->dst.n_bits);
-    return;
+                 value, mf->n_bytes, load->dst.ofs, load->dst.n_bits);
 }
 
 void
@@ -1299,3 +1312,149 @@ nxm_reg_load(const struct mf_subfield *dst, uint64_t src_data,
                  sizeof src_data_be * 8);
     mf_write_subfield_flow(dst, &src_subvalue, flow);
 }
+\f
+/* nxm_parse_stack_action, works for both push() and pop(). */
+void
+nxm_parse_stack_action(struct ofpact_stack *stack_action, const char *s)
+{
+    s = mf_parse_subfield(&stack_action->subfield, s);
+    if (*s != '\0') {
+        ovs_fatal(0, "%s: trailing garbage following push or pop", s);
+    }
+}
+
+void
+nxm_format_stack_push(const struct ofpact_stack *push, struct ds *s)
+{
+    ds_put_cstr(s, "push:");
+    mf_format_subfield(&push->subfield, s);
+}
+
+void
+nxm_format_stack_pop(const struct ofpact_stack *pop, struct ds *s)
+{
+    ds_put_cstr(s, "pop:");
+    mf_format_subfield(&pop->subfield, s);
+}
+
+/* Common set for both push and pop actions. */
+static void
+stack_action_from_openflow__(const struct nx_action_stack *nasp,
+                                    struct ofpact_stack *stack_action)
+{
+    stack_action->subfield.field = mf_from_nxm_header(ntohl(nasp->field));
+    stack_action->subfield.ofs = ntohs(nasp->offset);
+    stack_action->subfield.n_bits = ntohs(nasp->n_bits);
+}
+
+static void
+nxm_stack_to_nxast__(const struct ofpact_stack *stack_action,
+                            struct nx_action_stack *nasp)
+{
+    nasp->offset = htons(stack_action->subfield.ofs);
+    nasp->n_bits = htons(stack_action->subfield.n_bits);
+    nasp->field = htonl(stack_action->subfield.field->nxm_header);
+}
+
+enum ofperr
+nxm_stack_push_from_openflow(const struct nx_action_stack *nasp,
+                             struct ofpbuf *ofpacts)
+{
+    struct ofpact_stack *push;
+
+    push = ofpact_put_STACK_PUSH(ofpacts);
+    stack_action_from_openflow__(nasp, push);
+
+    return nxm_stack_push_check(push, NULL);
+}
+
+enum ofperr
+nxm_stack_pop_from_openflow(const struct nx_action_stack *nasp,
+                             struct ofpbuf *ofpacts)
+{
+    struct ofpact_stack *pop;
+
+    pop = ofpact_put_STACK_POP(ofpacts);
+    stack_action_from_openflow__(nasp, pop);
+
+    return nxm_stack_pop_check(pop, NULL);
+}
+
+enum ofperr
+nxm_stack_push_check(const struct ofpact_stack *push,
+                     const struct flow *flow)
+{
+    return mf_check_src(&push->subfield, flow);
+}
+
+enum ofperr
+nxm_stack_pop_check(const struct ofpact_stack *pop,
+                    const struct flow *flow)
+{
+    return mf_check_dst(&pop->subfield, flow);
+}
+
+void
+nxm_stack_push_to_nxast(const struct ofpact_stack *stack,
+                        struct ofpbuf *openflow)
+{
+    nxm_stack_to_nxast__(stack, ofputil_put_NXAST_STACK_PUSH(openflow));
+}
+
+void
+nxm_stack_pop_to_nxast(const struct ofpact_stack *stack,
+                       struct ofpbuf *openflow)
+{
+    nxm_stack_to_nxast__(stack, ofputil_put_NXAST_STACK_POP(openflow));
+}
+
+/* nxm_execute_stack_push(), nxm_execute_stack_pop(). */
+static void
+nx_stack_push(struct ofpbuf *stack, union mf_subvalue *v)
+{
+    ofpbuf_put(stack, v, sizeof *v);
+}
+
+static union mf_subvalue *
+nx_stack_pop(struct ofpbuf *stack)
+{
+    union mf_subvalue *v = NULL;
+
+    if (stack->size) {
+        stack->size -= sizeof *v;
+        v = (union mf_subvalue *) ofpbuf_tail(stack);
+    }
+
+    return v;
+}
+
+void
+nxm_execute_stack_push(const struct ofpact_stack *push,
+                       const struct flow *flow, struct ofpbuf *stack)
+{
+    union mf_subvalue dst_value;
+
+    mf_read_subfield(&push->subfield, flow, &dst_value);
+    nx_stack_push(stack, &dst_value);
+}
+
+void
+nxm_execute_stack_pop(const struct ofpact_stack *pop,
+                      struct flow *flow, struct ofpbuf *stack)
+{
+    union mf_subvalue *src_value;
+
+    src_value = nx_stack_pop(stack);
+
+    /* Only pop if stack is not empty. Otherwise, give warning. */
+    if (src_value) {
+        mf_write_subfield_flow(&pop->subfield, src_value, flow);
+    } else {
+        if (!VLOG_DROP_WARN(&rl)) {
+            char *flow_str = flow_to_string(flow);
+            VLOG_WARN_RL(&rl, "Failed to pop from an empty stack. On flow \n"
+                           " %s", flow_str);
+            free(flow_str);
+        }
+    }
+}
index 6a57297..7d316d8 100644 (file)
@@ -29,10 +29,12 @@ struct match;
 struct mf_subfield;
 struct ofpact_reg_move;
 struct ofpact_reg_load;
+struct ofpact_stack;
 struct ofpbuf;
 struct nx_action_reg_load;
 struct nx_action_reg_move;
 
+
 /* Nicira Extended Match (NXM) flexible flow match helper functions.
  *
  * See include/openflow/nicira-ext.h for NXM specification.
@@ -83,6 +85,30 @@ void nxm_execute_reg_load(const struct ofpact_reg_load *, struct flow *);
 void nxm_reg_load(const struct mf_subfield *, uint64_t src_data,
                   struct flow *);
 
+void nxm_parse_stack_action(struct ofpact_stack *, const char *);
+
+void nxm_format_stack_push(const struct ofpact_stack *, struct ds *);
+void nxm_format_stack_pop(const struct ofpact_stack *, struct ds *);
+
+enum ofperr nxm_stack_push_from_openflow(const struct nx_action_stack *,
+                                       struct ofpbuf *ofpacts);
+enum ofperr nxm_stack_pop_from_openflow(const struct nx_action_stack *,
+                                       struct ofpbuf *ofpacts);
+enum ofperr nxm_stack_push_check(const struct ofpact_stack *,
+                                 const  struct flow *);
+enum ofperr nxm_stack_pop_check(const struct ofpact_stack *,
+                               const struct flow *);
+
+void nxm_stack_push_to_nxast(const struct ofpact_stack *,
+                           struct ofpbuf *openflow);
+void nxm_stack_pop_to_nxast(const struct ofpact_stack *,
+                           struct ofpbuf *openflow);
+
+void nxm_execute_stack_push(const struct ofpact_stack *,
+                            const struct flow *, struct ofpbuf *);
+void nxm_execute_stack_pop(const struct ofpact_stack *,
+                            struct flow *, struct ofpbuf *);
+
 int nxm_field_bytes(uint32_t header);
 int nxm_field_bits(uint32_t header);
 
index 7e48981..751c1c9 100644 (file)
@@ -73,6 +73,8 @@ odp_action_len(uint16_t type)
     case OVS_ACTION_ATTR_USERSPACE: return -2;
     case OVS_ACTION_ATTR_PUSH_VLAN: return sizeof(struct ovs_action_push_vlan);
     case OVS_ACTION_ATTR_POP_VLAN: return 0;
+    case OVS_ACTION_ATTR_PUSH_MPLS: return sizeof(struct ovs_action_push_mpls);
+    case OVS_ACTION_ATTR_POP_MPLS: return sizeof(ovs_be16);
     case OVS_ACTION_ATTR_SET: return -2;
     case OVS_ACTION_ATTR_SAMPLE: return -2;
 
@@ -94,7 +96,6 @@ ovs_key_attr_to_string(enum ovs_key_attr attr)
     case OVS_KEY_ATTR_ENCAP: return "encap";
     case OVS_KEY_ATTR_PRIORITY: return "skb_priority";
     case OVS_KEY_ATTR_SKB_MARK: return "skb_mark";
-    case OVS_KEY_ATTR_TUN_ID: return "tun_id";
     case OVS_KEY_ATTR_TUNNEL: return "tunnel";
     case OVS_KEY_ATTR_IN_PORT: return "in_port";
     case OVS_KEY_ATTR_ETHERNET: return "eth";
@@ -108,6 +109,7 @@ ovs_key_attr_to_string(enum ovs_key_attr attr)
     case OVS_KEY_ATTR_ICMPV6: return "icmpv6";
     case OVS_KEY_ATTR_ARP: return "arp";
     case OVS_KEY_ATTR_ND: return "nd";
+    case OVS_KEY_ATTR_MPLS: return "mpls";
 
     case __OVS_KEY_ATTR_MAX:
     default:
@@ -245,9 +247,11 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
 {
     static const struct nl_policy ovs_userspace_policy[] = {
         [OVS_USERSPACE_ATTR_PID] = { .type = NL_A_U32 },
-        [OVS_USERSPACE_ATTR_USERDATA] = { .type = NL_A_U64, .optional = true },
+        [OVS_USERSPACE_ATTR_USERDATA] = { .type = NL_A_UNSPEC,
+                                          .optional = true },
     };
     struct nlattr *a[ARRAY_SIZE(ovs_userspace_policy)];
+    const struct nlattr *userdata_attr;
 
     if (!nl_parse_nested(attr, ovs_userspace_policy, a, ARRAY_SIZE(a))) {
         ds_put_cstr(ds, "userspace(error)");
@@ -257,7 +261,8 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
     ds_put_format(ds, "userspace(pid=%"PRIu32,
                   nl_attr_get_u32(a[OVS_USERSPACE_ATTR_PID]));
 
-    if (a[OVS_USERSPACE_ATTR_USERDATA]) {
+    userdata_attr = a[OVS_USERSPACE_ATTR_USERDATA];
+    if (userdata_attr && nl_attr_get_size(userdata_attr) == sizeof(uint64_t)) {
         uint64_t userdata = nl_attr_get_u64(a[OVS_USERSPACE_ATTR_USERDATA]);
         union user_action_cookie cookie;
 
@@ -284,6 +289,16 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
             ds_put_format(ds, ",userdata=0x%"PRIx64, userdata);
             break;
         }
+    } else if (userdata_attr) {
+        const uint8_t *userdata = nl_attr_get(userdata_attr);
+        size_t len = nl_attr_get_size(userdata_attr);
+        size_t i;
+
+        ds_put_format(ds, ",userdata(");
+        for (i = 0; i < len; i++) {
+            ds_put_format(ds, "%02x", userdata[i]);
+        }
+        ds_put_char(ds, ')');
     }
 
     ds_put_char(ds, ')');
@@ -300,6 +315,16 @@ format_vlan_tci(struct ds *ds, ovs_be16 vlan_tci)
     }
 }
 
+static void
+format_mpls_lse(struct ds *ds, ovs_be32 mpls_lse)
+{
+    ds_put_format(ds, "label=%"PRIu32",tc=%d,ttl=%d,bos=%d",
+                  mpls_lse_to_label(mpls_lse),
+                  mpls_lse_to_tc(mpls_lse),
+                  mpls_lse_to_ttl(mpls_lse),
+                  mpls_lse_to_bos(mpls_lse));
+}
+
 static void
 format_odp_action(struct ds *ds, const struct nlattr *a)
 {
@@ -339,6 +364,18 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
     case OVS_ACTION_ATTR_POP_VLAN:
         ds_put_cstr(ds, "pop_vlan");
         break;
+    case OVS_ACTION_ATTR_PUSH_MPLS: {
+        const struct ovs_action_push_mpls *mpls = nl_attr_get(a);
+        ds_put_cstr(ds, "push_mpls(");
+        format_mpls_lse(ds, mpls->mpls_lse);
+        ds_put_format(ds, ",eth_type=0x%"PRIx16")", ntohs(mpls->mpls_ethertype));
+        break;
+    }
+    case OVS_ACTION_ATTR_POP_MPLS: {
+        ovs_be16 ethertype = nl_attr_get_be16(a);
+        ds_put_format(ds, "pop_mpls(eth_type=0x%"PRIx16")", ntohs(ethertype));
+        break;
+    }
     case OVS_ACTION_ATTR_SAMPLE:
         format_odp_sample_action(ds, a);
         break;
@@ -424,7 +461,7 @@ parse_odp_action(const char *s, const struct simap *port_names,
         int n = -1;
 
         if (sscanf(s, "userspace(pid=%lli)%n", &pid, &n) > 0 && n > 0) {
-            odp_put_userspace_action(pid, NULL, actions);
+            odp_put_userspace_action(pid, NULL, 0, actions);
             return n;
         } else if (sscanf(s, "userspace(pid=%lli,sFlow(vid=%i,"
                           "pcp=%i,output=%lli))%n",
@@ -440,7 +477,7 @@ parse_odp_action(const char *s, const struct simap *port_names,
             cookie.type = USER_ACTION_COOKIE_SFLOW;
             cookie.sflow.vlan_tci = htons(tci);
             cookie.sflow.output = output;
-            odp_put_userspace_action(pid, &cookie, actions);
+            odp_put_userspace_action(pid, &cookie, sizeof cookie, actions);
             return n;
         } else if (sscanf(s, "userspace(pid=%lli,slow_path%n", &pid, &n) > 0
                    && n > 0) {
@@ -462,18 +499,29 @@ parse_odp_action(const char *s, const struct simap *port_names,
             }
             n++;
 
-            odp_put_userspace_action(pid, &cookie, actions);
+            odp_put_userspace_action(pid, &cookie, sizeof cookie, actions);
             return n;
         } else if (sscanf(s, "userspace(pid=%lli,userdata="
                           "%31[x0123456789abcdefABCDEF])%n", &pid, userdata_s,
                           &n) > 0 && n > 0) {
-            union user_action_cookie cookie;
             uint64_t userdata;
 
             userdata = strtoull(userdata_s, NULL, 0);
-            memcpy(&cookie, &userdata, sizeof cookie);
-            odp_put_userspace_action(pid, &cookie, actions);
+            odp_put_userspace_action(pid, &userdata, sizeof(userdata),
+                                     actions);
             return n;
+        } else if (sscanf(s, "userspace(pid=%lli,userdata(%n", &pid, &n) > 0
+                   && n > 0) {
+            struct ofpbuf buf;
+            char *end;
+
+            ofpbuf_init(&buf, 16);
+            end = ofpbuf_put_hex(&buf, &s[n], NULL);
+            if (end[0] == ')' && end[1] == ')') {
+                odp_put_userspace_action(pid, buf.data, buf.size, actions);
+                ofpbuf_uninit(&buf);
+                return (end + 2) - s;
+            }
         }
     }
 
@@ -616,12 +664,12 @@ odp_flow_key_attr_len(uint16_t type)
     case OVS_KEY_ATTR_ENCAP: return -2;
     case OVS_KEY_ATTR_PRIORITY: return 4;
     case OVS_KEY_ATTR_SKB_MARK: return 4;
-    case OVS_KEY_ATTR_TUN_ID: return 8;
     case OVS_KEY_ATTR_TUNNEL: return -2;
     case OVS_KEY_ATTR_IN_PORT: return 4;
     case OVS_KEY_ATTR_ETHERNET: return sizeof(struct ovs_key_ethernet);
     case OVS_KEY_ATTR_VLAN: return sizeof(ovs_be16);
     case OVS_KEY_ATTR_ETHERTYPE: return 2;
+    case OVS_KEY_ATTR_MPLS: return sizeof(struct ovs_key_mpls);
     case OVS_KEY_ATTR_IPV4: return sizeof(struct ovs_key_ipv4);
     case OVS_KEY_ATTR_IPV6: return sizeof(struct ovs_key_ipv6);
     case OVS_KEY_ATTR_TCP: return sizeof(struct ovs_key_tcp);
@@ -820,10 +868,6 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
         ds_put_format(ds, "(%#"PRIx32")", nl_attr_get_u32(a));
         break;
 
-    case OVS_KEY_ATTR_TUN_ID:
-        ds_put_format(ds, "(%#"PRIx64")", ntohll(nl_attr_get_be64(a)));
-        break;
-
     case OVS_KEY_ATTR_TUNNEL:
         memset(&tun_key, 0, sizeof tun_key);
         if (tun_key_from_attr(a, &tun_key) == ODP_FIT_ERROR) {
@@ -859,6 +903,14 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
         ds_put_char(ds, ')');
         break;
 
+    case OVS_KEY_ATTR_MPLS: {
+        const struct ovs_key_mpls *mpls_key = nl_attr_get(a);
+        ds_put_char(ds, '(');
+        format_mpls_lse(ds, mpls_key->mpls_top_lse);
+        ds_put_char(ds, ')');
+        break;
+    }
+
     case OVS_KEY_ATTR_ETHERTYPE:
         ds_put_format(ds, "(0x%04"PRIx16")",
                       ntohs(nl_attr_get_be16(a)));
@@ -1019,6 +1071,15 @@ ovs_frag_type_from_string(const char *s, enum ovs_frag_type *type)
     return true;
 }
 
+static ovs_be32
+mpls_lse_from_components(int mpls_label, int mpls_tc, int mpls_ttl, int mpls_bos)
+{
+    return (htonl((mpls_label << MPLS_LABEL_SHIFT) |
+                  (mpls_tc << MPLS_TC_SHIFT)       |
+                  (mpls_ttl << MPLS_TTL_SHIFT)     |
+                  (mpls_bos << MPLS_BOS_SHIFT)));
+}
+
 static int
 parse_odp_key_attr(const char *s, const struct simap *port_names,
                    struct ofpbuf *key)
@@ -1053,18 +1114,6 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
         }
     }
 
-    {
-        char tun_id_s[32];
-        int n = -1;
-
-        if (sscanf(s, "tun_id(%31[x0123456789abcdefABCDEF])%n",
-                   tun_id_s, &n) > 0 && n > 0) {
-            uint64_t tun_id = strtoull(tun_id_s, NULL, 0);
-            nl_msg_put_be64(key, OVS_KEY_ATTR_TUN_ID, htonll(tun_id));
-            return n;
-        }
-    }
-
     {
         char tun_id_s[32];
         int tos, ttl;
@@ -1171,6 +1220,22 @@ parse_odp_key_attr(const char *s, const struct simap *port_names,
         }
     }
 
+    {
+        int label, tc, ttl, bos;
+        int n = -1;
+
+        if (sscanf(s, "mpls(label=%"SCNi32",tc=%i,ttl=%i,bos=%i)%n",
+                    &label, &tc, &ttl, &bos, &n) > 0 &&
+                    n > 0) {
+            struct ovs_key_mpls *mpls;
+
+            mpls = nl_msg_put_unspec_uninit(key, OVS_KEY_ATTR_MPLS,
+                                            sizeof *mpls);
+            mpls->mpls_top_lse = mpls_lse_from_components(label, tc, ttl, bos);
+            return n;
+        }
+    }
+
     {
         ovs_be32 ipv4_src;
         ovs_be32 ipv4_dst;
@@ -1455,8 +1520,6 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
 
     if (flow->tunnel.ip_dst) {
         tun_key_to_attr(buf, &flow->tunnel);
-    } else if (flow->tunnel.tun_id != htonll(0)) {
-        nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tunnel.tun_id);
     }
 
     if (flow->skb_mark) {
@@ -1526,6 +1589,14 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
         memcpy(arp_key->arp_tha, flow->arp_tha, ETH_ADDR_LEN);
     }
 
+    if (flow->mpls_depth) {
+        struct ovs_key_mpls *mpls_key;
+
+        mpls_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_MPLS,
+                                            sizeof *mpls_key);
+        mpls_key->mpls_top_lse = flow->mpls_lse;
+    }
+
     if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
         if (flow->nw_proto == IPPROTO_TCP) {
             struct ovs_key_tcp *tcp_key;
@@ -1643,6 +1714,7 @@ parse_flow_nlattrs(const struct nlattr *key, size_t key_len,
     uint64_t present_attrs;
     size_t left;
 
+    BUILD_ASSERT(OVS_KEY_ATTR_MAX < CHAR_BIT * sizeof present_attrs);
     present_attrs = 0;
     *out_of_range_attrp = 0;
     NL_ATTR_FOR_EACH (nla, left, key, key_len) {
@@ -1657,7 +1729,7 @@ parse_flow_nlattrs(const struct nlattr *key, size_t key_len,
             return false;
         }
 
-        if (type >= CHAR_BIT * sizeof present_attrs) {
+        if (type > OVS_KEY_ATTR_MAX) {
             *out_of_range_attrp = type;
         } else {
             if (present_attrs & (UINT64_C(1) << type)) {
@@ -1728,14 +1800,22 @@ parse_ethertype(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
 }
 
 static enum odp_key_fitness
-parse_l3_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
-                uint64_t present_attrs, int out_of_range_attr,
-                uint64_t expected_attrs, struct flow *flow,
-                const struct nlattr *key, size_t key_len)
+parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
+                  uint64_t present_attrs, int out_of_range_attr,
+                  uint64_t expected_attrs, struct flow *flow,
+                  const struct nlattr *key, size_t key_len)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
 
-    if (flow->dl_type == htons(ETH_TYPE_IP)) {
+    if (eth_type_mpls(flow->dl_type)) {
+        expected_attrs |= (UINT64_C(1) << OVS_KEY_ATTR_MPLS);
+
+        if (!(present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_MPLS))) {
+            return ODP_FIT_TOO_LITTLE;
+        }
+        flow->mpls_lse = nl_attr_get_be32(attrs[OVS_KEY_ATTR_MPLS]);
+        flow->mpls_depth++;
+    } else if (flow->dl_type == htons(ETH_TYPE_IP)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_IPV4;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV4)) {
             const struct ovs_key_ipv4 *ipv4_key;
@@ -1787,7 +1867,8 @@ parse_l3_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
     }
 
     if (flow->nw_proto == IPPROTO_TCP
-        && is_ip_any(flow)
+        && (flow->dl_type == htons(ETH_TYPE_IP) ||
+            flow->dl_type == htons(ETH_TYPE_IPV6))
         && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_TCP;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TCP)) {
@@ -1798,7 +1879,8 @@ parse_l3_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
             flow->tp_dst = tcp_key->tcp_dst;
         }
     } else if (flow->nw_proto == IPPROTO_UDP
-               && is_ip_any(flow)
+               && (flow->dl_type == htons(ETH_TYPE_IP) ||
+                   flow->dl_type == htons(ETH_TYPE_IPV6))
                && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_UDP;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_UDP)) {
@@ -1904,8 +1986,8 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
     if (!parse_ethertype(attrs, present_attrs, &expected_attrs, flow)) {
         return ODP_FIT_ERROR;
     }
-    encap_fitness = parse_l3_onward(attrs, present_attrs, out_of_range_attr,
-                                    expected_attrs, flow, key, key_len);
+    encap_fitness = parse_l2_5_onward(attrs, present_attrs, out_of_range_attr,
+                                      expected_attrs, flow, key, key_len);
 
     /* The overall fitness is the worse of the outer and inner attributes. */
     return MAX(fitness, encap_fitness);
@@ -1955,11 +2037,6 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_SKB_MARK;
     }
 
-    if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TUN_ID)) {
-        flow->tunnel.tun_id = nl_attr_get_be64(attrs[OVS_KEY_ATTR_TUN_ID]);
-        expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_TUN_ID;
-    }
-
     if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TUNNEL)) {
         enum odp_key_fitness res;
 
@@ -1997,8 +2074,8 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
         return parse_8021q_onward(attrs, present_attrs, out_of_range_attr,
                                   expected_attrs, flow, key, key_len);
     }
-    return parse_l3_onward(attrs, present_attrs, out_of_range_attr,
-                           expected_attrs, flow, key, key_len);
+    return parse_l2_5_onward(attrs, present_attrs, out_of_range_attr,
+                             expected_attrs, flow, key, key_len);
 }
 
 /* Returns 'fitness' as a string, for use in debug messages. */
@@ -2020,25 +2097,30 @@ odp_key_fitness_to_string(enum odp_key_fitness fitness)
 }
 
 /* Appends an OVS_ACTION_ATTR_USERSPACE action to 'odp_actions' that specifies
- * Netlink PID 'pid'.  If 'cookie' is nonnull, adds a userdata attribute whose
- * contents contains 'cookie' and returns the offset within 'odp_actions' of
- * the start of the cookie.  (If 'cookie' is null, then the return value is not
- * meaningful.) */
+ * Netlink PID 'pid'.  If 'userdata' is nonnull, adds a userdata attribute
+ * whose contents are the 'userdata_size' bytes at 'userdata' and returns the
+ * offset within 'odp_actions' of the start of the cookie.  (If 'userdata' is
+ * null, then the return value is not meaningful.) */
 size_t
-odp_put_userspace_action(uint32_t pid, const union user_action_cookie *cookie,
+odp_put_userspace_action(uint32_t pid,
+                         const void *userdata, size_t userdata_size,
                          struct ofpbuf *odp_actions)
 {
+    size_t userdata_ofs;
     size_t offset;
 
     offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_USERSPACE);
     nl_msg_put_u32(odp_actions, OVS_USERSPACE_ATTR_PID, pid);
-    if (cookie) {
+    if (userdata) {
+        userdata_ofs = odp_actions->size + NLA_HDRLEN;
         nl_msg_put_unspec(odp_actions, OVS_USERSPACE_ATTR_USERDATA,
-                          cookie, sizeof *cookie);
+                          userdata, userdata_size);
+    } else {
+        userdata_ofs = 0;
     }
     nl_msg_end_nested(odp_actions, offset);
 
-    return cookie ? odp_actions->size - NLA_ALIGN(sizeof *cookie) : 0;
+    return userdata_ofs;
 }
 
 void
@@ -2061,6 +2143,14 @@ commit_set_action(struct ofpbuf *odp_actions, enum ovs_key_attr key_type,
     nl_msg_end_nested(odp_actions, offset);
 }
 
+void
+odp_put_skb_mark_action(const uint32_t skb_mark,
+                        struct ofpbuf *odp_actions)
+{
+    commit_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK, &skb_mark,
+                      sizeof(skb_mark));
+}
+
 /* If any of the flow key data that ODP actions can modify are different in
  * 'base->tunnel' and 'flow->tunnel', appends a set_tunnel ODP action to
  * 'odp_actions' that change the flow tunneling information in key from
@@ -2079,9 +2169,6 @@ commit_odp_tunnel_action(const struct flow *flow, struct flow *base,
     /* A valid IPV4_TUNNEL must have non-zero ip_dst. */
     if (flow->tunnel.ip_dst) {
         odp_put_tunnel_action(&base->tunnel, odp_actions);
-    } else {
-        commit_set_action(odp_actions, OVS_KEY_ATTR_TUN_ID,
-                          &base->tunnel.tun_id, sizeof base->tunnel.tun_id);
     }
 }
 
@@ -2129,6 +2216,50 @@ commit_vlan_action(const struct flow *flow, struct flow *base,
     base->vlan_tci = flow->vlan_tci;
 }
 
+static void
+commit_mpls_action(const struct flow *flow, struct flow *base,
+                   struct ofpbuf *odp_actions)
+{
+    if (flow->mpls_lse == base->mpls_lse &&
+        flow->mpls_depth == base->mpls_depth) {
+        return;
+    }
+
+    if (flow->mpls_depth < base->mpls_depth) {
+        if (base->mpls_depth - flow->mpls_depth > 1) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10);
+            VLOG_WARN_RL(&rl, "Multiple mpls_pop actions reduced to "
+                         " a single mpls_pop action");
+        }
+
+        nl_msg_put_be16(odp_actions, OVS_ACTION_ATTR_POP_MPLS, flow->dl_type);
+    } else if (flow->mpls_depth > base->mpls_depth) {
+        struct ovs_action_push_mpls *mpls;
+
+        if (flow->mpls_depth - base->mpls_depth > 1) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(10, 10);
+            VLOG_WARN_RL(&rl, "Multiple mpls_push actions reduced to "
+                         " a single mpls_push action");
+        }
+
+        mpls = nl_msg_put_unspec_uninit(odp_actions, OVS_ACTION_ATTR_PUSH_MPLS,
+                                        sizeof *mpls);
+        memset(mpls, 0, sizeof *mpls);
+        mpls->mpls_ethertype = flow->dl_type;
+        mpls->mpls_lse = flow->mpls_lse;
+    } else {
+        struct ovs_key_mpls mpls_key;
+
+        mpls_key.mpls_top_lse = flow->mpls_lse;
+        commit_set_action(odp_actions, OVS_KEY_ATTR_MPLS,
+                          &mpls_key, sizeof(mpls_key));
+    }
+
+    base->dl_type = flow->dl_type;
+    base->mpls_lse = flow->mpls_lse;
+    base->mpls_depth = flow->mpls_depth;
+}
+
 static void
 commit_set_ipv4_action(const struct flow *flow, struct flow *base,
                      struct ofpbuf *odp_actions)
@@ -2204,7 +2335,7 @@ static void
 commit_set_port_action(const struct flow *flow, struct flow *base,
                        struct ofpbuf *odp_actions)
 {
-    if (!base->tp_src && !base->tp_dst) {
+    if (!is_ip_any(base) || (!base->tp_src && !base->tp_dst)) {
         return;
     }
 
@@ -2255,8 +2386,7 @@ commit_set_skb_mark_action(const struct flow *flow, struct flow *base,
     }
     base->skb_mark = flow->skb_mark;
 
-    commit_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK,
-                      &base->skb_mark, sizeof(base->skb_mark));
+    odp_put_skb_mark_action(base->skb_mark, odp_actions);
 }
 /* If any of the flow key data that ODP actions can modify are different in
  * 'base' and 'flow', appends ODP actions to 'odp_actions' that change the flow
@@ -2271,6 +2401,11 @@ commit_odp_actions(const struct flow *flow, struct flow *base,
     commit_vlan_action(flow, base, odp_actions);
     commit_set_nw_action(flow, base, odp_actions);
     commit_set_port_action(flow, base, odp_actions);
+    /* Commiting MPLS actions should occur after committing nw and port
+     * actions. This is because committing MPLS actions may alter a packet so
+     * that it is no longer IP and thus nw and port actions are no longer valid.
+     */
+    commit_mpls_action(flow, base, odp_actions);
     commit_set_priority_action(flow, base, odp_actions);
     commit_set_skb_mark_action(flow, base, odp_actions);
 }
index ccf6c2a..ad0fb30 100644 (file)
@@ -54,7 +54,6 @@ int odp_actions_from_string(const char *, const struct simap *port_names,
  *                                     struct  pad  nl hdr  total
  *                                     ------  ---  ------  -----
  *  OVS_KEY_ATTR_PRIORITY                4    --     4      8
- *  OVS_KEY_ATTR_TUN_ID                  8    --     4     12
  *  OVS_KEY_ATTR_TUNNEL                  0    --     4      4
  *  - OVS_TUNNEL_KEY_ATTR_ID             8    --     4     12
  *  - OVS_TUNNEL_KEY_ATTR_IPV4_SRC       4    --     4      8
@@ -74,7 +73,7 @@ int odp_actions_from_string(const char *, const struct simap *port_names,
  *  OVS_KEY_ATTR_ICMPV6                  2     2     4      8
  *  OVS_KEY_ATTR_ND                     28    --     4     32
  *  ----------------------------------------------------------
- *  total                                                 220
+ *  total                                                 208
  *
  * We include some slack space in case the calculation isn't quite right or we
  * add another field and forget to adjust this value.
@@ -152,10 +151,12 @@ union user_action_cookie {
 BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 8);
 
 size_t odp_put_userspace_action(uint32_t pid,
-                                const union user_action_cookie *,
+                                const void *userdata, size_t userdata_size,
                                 struct ofpbuf *odp_actions);
 void odp_put_tunnel_action(const struct flow_tnl *tunnel,
                            struct ofpbuf *odp_actions);
+void odp_put_skb_mark_action(const uint32_t skb_mark,
+                             struct ofpbuf *odp_actions);
 
 /* Reasons why a subfacet might not be fast-pathable. */
 enum slow_path_reason {
index a439d13..d405d2d 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <config.h>
 #include "ofp-actions.h"
-#include "autopath.h"
 #include "bundle.h"
 #include "byte-order.h"
 #include "compiler.h"
@@ -340,6 +339,16 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
             (const struct nx_action_reg_load *) a, out);
         break;
 
+    case OFPUTIL_NXAST_STACK_PUSH:
+        error = nxm_stack_push_from_openflow(
+            (const struct nx_action_stack *) a, out);
+        break;
+
+    case OFPUTIL_NXAST_STACK_POP:
+        error = nxm_stack_pop_from_openflow(
+            (const struct nx_action_stack *) a, out);
+        break;
+
     case OFPUTIL_NXAST_NOTE:
         nan = (const struct nx_action_note *) a;
         note_from_openflow(nan, out);
@@ -357,11 +366,6 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
                                         ofpact_put_MULTIPATH(out));
         break;
 
-    case OFPUTIL_NXAST_AUTOPATH__DEPRECATED:
-        error = autopath_from_openflow((const struct nx_action_autopath *) a,
-                                       ofpact_put_AUTOPATH(out));
-        break;
-
     case OFPUTIL_NXAST_BUNDLE:
     case OFPUTIL_NXAST_BUNDLE_LOAD:
         error = bundle_from_openflow((const struct nx_action_bundle *) a, out);
@@ -402,6 +406,34 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
     case OFPUTIL_NXAST_CONTROLLER:
         controller_from_openflow((const struct nx_action_controller *) a, out);
         break;
+
+    case OFPUTIL_NXAST_PUSH_MPLS: {
+        struct nx_action_push_mpls *nxapm = (struct nx_action_push_mpls *)a;
+        if (!eth_type_mpls(nxapm->ethertype)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_PUSH_MPLS(out)->ethertype = nxapm->ethertype;
+        break;
+    }
+
+    case OFPUTIL_NXAST_SET_MPLS_TTL: {
+        struct nx_action_mpls_ttl *nxamt = (struct nx_action_mpls_ttl *)a;
+        ofpact_put_SET_MPLS_TTL(out)->ttl = nxamt->ttl;
+        break;
+    }
+
+    case OFPUTIL_NXAST_DEC_MPLS_TTL:
+        ofpact_put_DEC_MPLS_TTL(out);
+        break;
+
+    case OFPUTIL_NXAST_POP_MPLS: {
+        struct nx_action_pop_mpls *nxapm = (struct nx_action_pop_mpls *)a;
+        if (eth_type_mpls(nxapm->ethertype)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_POP_MPLS(out)->ethertype = nxapm->ethertype;
+        break;
+    }
     }
 
     return error;
@@ -774,6 +806,34 @@ ofpact_from_openflow11(const union ofp_action *a, struct ofpbuf *out)
         return nxm_reg_load_from_openflow12_set_field(
             (const struct ofp12_action_set_field *)a, out);
 
+    case OFPUTIL_OFPAT11_SET_MPLS_TTL: {
+        struct ofp11_action_mpls_ttl *oamt = (struct ofp11_action_mpls_ttl *)a;
+        ofpact_put_SET_MPLS_TTL(out)->ttl = oamt->mpls_ttl;
+        break;
+    }
+
+    case OFPUTIL_OFPAT11_DEC_MPLS_TTL:
+        ofpact_put_DEC_MPLS_TTL(out);
+        break;
+
+    case OFPUTIL_OFPAT11_PUSH_MPLS: {
+        struct ofp11_action_push *oap = (struct ofp11_action_push *)a;
+        if (!eth_type_mpls(oap->ethertype)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_PUSH_MPLS(out)->ethertype = oap->ethertype;
+        break;
+    }
+
+    case OFPUTIL_OFPAT11_POP_MPLS: {
+        struct ofp11_action_pop_mpls *oapm = (struct ofp11_action_pop_mpls *)a;
+        if (eth_type_mpls(oapm->ethertype)) {
+            return OFPERR_OFPBAC_BAD_ARGUMENT;
+        }
+        ofpact_put_POP_MPLS(out)->ethertype = oapm->ethertype;
+        break;
+    }
+
 #define NXAST_ACTION(ENUM, STRUCT, EXTENSIBLE, NAME) case OFPUTIL_##ENUM:
 #include "ofp-util.def"
         return ofpact_from_nxast(a, code, out);
@@ -1053,7 +1113,8 @@ exit:
 }
 \f
 static enum ofperr
-ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
+ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
+               ovs_be16 *dl_type)
 {
     const struct ofpact_enqueue *enqueue;
 
@@ -1096,9 +1157,23 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
         return nxm_reg_move_check(ofpact_get_REG_MOVE(a), flow);
 
     case OFPACT_REG_LOAD:
-        return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow);
+        if (*dl_type != flow->dl_type) {
+            struct flow updated_flow = *flow;
+            updated_flow.dl_type = *dl_type;
+            return nxm_reg_load_check(ofpact_get_REG_LOAD(a), &updated_flow);
+        } else {
+            return nxm_reg_load_check(ofpact_get_REG_LOAD(a), flow);
+        }
+
+    case OFPACT_STACK_PUSH:
+        return nxm_stack_push_check(ofpact_get_STACK_PUSH(a), flow);
+
+    case OFPACT_STACK_POP:
+        return nxm_stack_pop_check(ofpact_get_STACK_POP(a), flow);
 
     case OFPACT_DEC_TTL:
+    case OFPACT_SET_MPLS_TTL:
+    case OFPACT_DEC_MPLS_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_SET_QUEUE:
     case OFPACT_POP_QUEUE:
@@ -1112,13 +1187,18 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports)
     case OFPACT_MULTIPATH:
         return multipath_check(ofpact_get_MULTIPATH(a), flow);
 
-    case OFPACT_AUTOPATH:
-        return autopath_check(ofpact_get_AUTOPATH(a), flow);
-
     case OFPACT_NOTE:
     case OFPACT_EXIT:
         return 0;
 
+    case OFPACT_PUSH_MPLS:
+        *dl_type = ofpact_get_PUSH_MPLS(a)->ethertype;
+        return 0;
+
+    case OFPACT_POP_MPLS:
+        *dl_type = ofpact_get_POP_MPLS(a)->ethertype;
+        return 0;
+
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_WRITE_METADATA:
     case OFPACT_GOTO_TABLE:
@@ -1137,9 +1217,10 @@ ofpacts_check(const struct ofpact ofpacts[], size_t ofpacts_len,
               const struct flow *flow, int max_ports)
 {
     const struct ofpact *a;
+    ovs_be16 dl_type = flow->dl_type;
 
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
-        enum ofperr error = ofpact_check__(a, flow, max_ports);
+        enum ofperr error = ofpact_check__(a, flow, max_ports, &dl_type);
         if (error) {
             return error;
         }
@@ -1336,10 +1417,27 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         nxm_reg_load_to_nxast(ofpact_get_REG_LOAD(a), out);
         break;
 
+    case OFPACT_STACK_PUSH:
+        nxm_stack_push_to_nxast(ofpact_get_STACK_PUSH(a), out);
+        break;
+
+    case OFPACT_STACK_POP:
+        nxm_stack_pop_to_nxast(ofpact_get_STACK_POP(a), out);
+        break;
+
     case OFPACT_DEC_TTL:
         ofpact_dec_ttl_to_nxast(ofpact_get_DEC_TTL(a), out);
         break;
 
+    case OFPACT_SET_MPLS_TTL:
+        ofputil_put_NXAST_SET_MPLS_TTL(out)->ttl
+            = ofpact_get_SET_MPLS_TTL(a)->ttl;
+        break;
+
+    case OFPACT_DEC_MPLS_TTL:
+        ofputil_put_NXAST_DEC_MPLS_TTL(out);
+        break;
+
     case OFPACT_SET_TUNNEL:
         ofpact_set_tunnel_to_nxast(ofpact_get_SET_TUNNEL(a), out);
         break;
@@ -1373,10 +1471,6 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         multipath_to_nxast(ofpact_get_MULTIPATH(a), out);
         break;
 
-    case OFPACT_AUTOPATH:
-        autopath_to_nxast(ofpact_get_AUTOPATH(a), out);
-        break;
-
     case OFPACT_NOTE:
         ofpact_note_to_nxast(ofpact_get_NOTE(a), out);
         break;
@@ -1385,6 +1479,16 @@ ofpact_to_nxast(const struct ofpact *a, struct ofpbuf *out)
         ofputil_put_NXAST_EXIT(out);
         break;
 
+    case OFPACT_PUSH_MPLS:
+        ofputil_put_NXAST_PUSH_MPLS(out)->ethertype =
+            ofpact_get_PUSH_MPLS(a)->ethertype;
+        break;
+
+    case OFPACT_POP_MPLS:
+        ofputil_put_NXAST_POP_MPLS(out)->ethertype =
+            ofpact_get_POP_MPLS(a)->ethertype;
+        break;
+
     case OFPACT_OUTPUT:
     case OFPACT_ENQUEUE:
     case OFPACT_SET_VLAN_VID:
@@ -1500,7 +1604,11 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_BUNDLE:
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
+    case OFPACT_STACK_PUSH:
+    case OFPACT_STACK_POP:
     case OFPACT_DEC_TTL:
+    case OFPACT_SET_MPLS_TTL:
+    case OFPACT_DEC_MPLS_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_WRITE_METADATA:
     case OFPACT_SET_QUEUE:
@@ -1509,9 +1617,10 @@ ofpact_to_openflow10(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_RESUBMIT:
     case OFPACT_LEARN:
     case OFPACT_MULTIPATH:
-    case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_PUSH_MPLS:
+    case OFPACT_POP_MPLS:
         ofpact_to_nxast(a, out);
         break;
     }
@@ -1632,10 +1741,30 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
         ofpact_dec_ttl_to_openflow11(ofpact_get_DEC_TTL(a), out);
         break;
 
+    case OFPACT_SET_MPLS_TTL:
+        ofputil_put_OFPAT11_SET_MPLS_TTL(out)->mpls_ttl
+            = ofpact_get_SET_MPLS_TTL(a)->ttl;
+        break;
+
+    case OFPACT_DEC_MPLS_TTL:
+        ofputil_put_OFPAT11_DEC_MPLS_TTL(out);
+        break;
+
     case OFPACT_WRITE_METADATA:
         /* OpenFlow 1.1 uses OFPIT_WRITE_METADATA to express this action. */
         break;
 
+    case OFPACT_PUSH_MPLS:
+        ofputil_put_OFPAT11_PUSH_MPLS(out)->ethertype =
+            ofpact_get_PUSH_MPLS(a)->ethertype;
+        break;
+
+    case OFPACT_POP_MPLS:
+        ofputil_put_OFPAT11_POP_MPLS(out)->ethertype =
+            ofpact_get_POP_MPLS(a)->ethertype;
+
+        break;
+
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_GOTO_TABLE:
         NOT_REACHED();
@@ -1645,13 +1774,14 @@ ofpact_to_openflow11(const struct ofpact *a, struct ofpbuf *out)
     case OFPACT_BUNDLE:
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
+    case OFPACT_STACK_PUSH:
+    case OFPACT_STACK_POP:
     case OFPACT_SET_TUNNEL:
     case OFPACT_POP_QUEUE:
     case OFPACT_FIN_TIMEOUT:
     case OFPACT_RESUBMIT:
     case OFPACT_LEARN:
     case OFPACT_MULTIPATH:
-    case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
         ofpact_to_nxast(a, out);
@@ -1765,7 +1895,11 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     case OFPACT_SET_L4_DST_PORT:
     case OFPACT_REG_MOVE:
     case OFPACT_REG_LOAD:
+    case OFPACT_STACK_PUSH:
+    case OFPACT_STACK_POP:
     case OFPACT_DEC_TTL:
+    case OFPACT_SET_MPLS_TTL:
+    case OFPACT_DEC_MPLS_TTL:
     case OFPACT_SET_TUNNEL:
     case OFPACT_WRITE_METADATA:
     case OFPACT_SET_QUEUE:
@@ -1774,9 +1908,10 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, uint16_t port)
     case OFPACT_RESUBMIT:
     case OFPACT_LEARN:
     case OFPACT_MULTIPATH:
-    case OFPACT_AUTOPATH:
     case OFPACT_NOTE:
     case OFPACT_EXIT:
+    case OFPACT_PUSH_MPLS:
+    case OFPACT_POP_MPLS:
     case OFPACT_CLEAR_ACTIONS:
     case OFPACT_GOTO_TABLE:
     default:
@@ -1865,7 +2000,6 @@ ofpact_format(const struct ofpact *a, struct ds *s)
 {
     const struct ofpact_enqueue *enqueue;
     const struct ofpact_resubmit *resubmit;
-    const struct ofpact_autopath *autopath;
     const struct ofpact_controller *controller;
     const struct ofpact_metadata *metadata;
     const struct ofpact_tunnel *tunnel;
@@ -1984,10 +2118,27 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         nxm_format_reg_load(ofpact_get_REG_LOAD(a), s);
         break;
 
+    case OFPACT_STACK_PUSH:
+        nxm_format_stack_push(ofpact_get_STACK_PUSH(a), s);
+        break;
+
+    case OFPACT_STACK_POP:
+        nxm_format_stack_pop(ofpact_get_STACK_POP(a), s);
+        break;
+
     case OFPACT_DEC_TTL:
         print_dec_ttl(ofpact_get_DEC_TTL(a), s);
         break;
 
+    case OFPACT_SET_MPLS_TTL:
+        ds_put_format(s, "set_mpls_ttl(%"PRIu8")",
+                      ofpact_get_SET_MPLS_TTL(a)->ttl);
+        break;
+
+    case OFPACT_DEC_MPLS_TTL:
+        ds_put_cstr(s, "dec_mpls_ttl");
+        break;
+
     case OFPACT_SET_TUNNEL:
         tunnel = ofpact_get_SET_TUNNEL(a);
         ds_put_format(s, "set_tunnel%s:%#"PRIx64,
@@ -2035,19 +2186,20 @@ ofpact_format(const struct ofpact *a, struct ds *s)
         multipath_format(ofpact_get_MULTIPATH(a), s);
         break;
 
-    case OFPACT_AUTOPATH:
-        autopath = ofpact_get_AUTOPATH(a);
-        ds_put_cstr(s, "autopath(");
-        ofputil_format_port(autopath->port, s);
-        ds_put_char(s, ',');
-        mf_format_subfield(&autopath->dst, s);
-        ds_put_char(s, ')');
-        break;
-
     case OFPACT_NOTE:
         print_note(ofpact_get_NOTE(a), s);
         break;
 
+    case OFPACT_PUSH_MPLS:
+        ds_put_format(s, "push_mpls:0x%04"PRIx16,
+                      ntohs(ofpact_get_PUSH_MPLS(a)->ethertype));
+        break;
+
+    case OFPACT_POP_MPLS:
+        ds_put_format(s, "pop_mpls:0x%04"PRIx16,
+                      ntohs(ofpact_get_POP_MPLS(a)->ethertype));
+        break;
+
     case OFPACT_EXIT:
         ds_put_cstr(s, "exit");
         break;
index e930986..0189c8a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Nicira, Inc.
+ * Copyright (c) 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
     DEFINE_OFPACT(SET_L4_DST_PORT, ofpact_l4_port,       ofpact)    \
     DEFINE_OFPACT(REG_MOVE,        ofpact_reg_move,      ofpact)    \
     DEFINE_OFPACT(REG_LOAD,        ofpact_reg_load,      ofpact)    \
+    DEFINE_OFPACT(STACK_PUSH,      ofpact_stack,         ofpact)    \
+    DEFINE_OFPACT(STACK_POP,       ofpact_stack,         ofpact)    \
     DEFINE_OFPACT(DEC_TTL,         ofpact_cnt_ids,       cnt_ids)   \
+    DEFINE_OFPACT(SET_MPLS_TTL,    ofpact_mpls_ttl,      ofpact)    \
+    DEFINE_OFPACT(DEC_MPLS_TTL,    ofpact_null,          ofpact)    \
+    DEFINE_OFPACT(PUSH_MPLS,       ofpact_push_mpls,     ofpact)    \
+    DEFINE_OFPACT(POP_MPLS,        ofpact_pop_mpls,      ofpact)    \
                                                                     \
     /* Metadata. */                                                 \
     DEFINE_OFPACT(SET_TUNNEL,      ofpact_tunnel,        ofpact)    \
@@ -84,7 +90,6 @@
                                                                     \
     /* Arithmetic. */                                               \
     DEFINE_OFPACT(MULTIPATH,       ofpact_multipath,     ofpact)    \
-    DEFINE_OFPACT(AUTOPATH,        ofpact_autopath,      ofpact)    \
                                                                     \
     /* Other. */                                                    \
     DEFINE_OFPACT(NOTE,            ofpact_note,          data)      \
@@ -301,6 +306,14 @@ struct ofpact_reg_move {
     struct mf_subfield dst;
 };
 
+/* OFPACT_STACK_PUSH.
+ *
+ * Used for NXAST_STACK_PUSH and NXAST_STACK_POP. */
+struct ofpact_stack {
+    struct ofpact ofpact;
+    struct mf_subfield subfield;
+};
+
 /* OFPACT_REG_LOAD.
  *
  * Used for NXAST_REG_LOAD, OFPAT12_SET_FIELD. */
@@ -310,6 +323,22 @@ struct ofpact_reg_load {
     union mf_subvalue subvalue; /* Least-significant bits are used. */
 };
 
+/* OFPACT_PUSH_VLAN/MPLS/PBB
+ *
+ * Used for NXAST_PUSH_MPLS, OFPAT11_PUSH_MPLS. */
+struct ofpact_push_mpls {
+    struct ofpact ofpact;
+    ovs_be16 ethertype;
+};
+
+/* OFPACT_POP_MPLS
+ *
+ * Used for NXAST_POP_MPLS, OFPAT11_POP_MPLS.. */
+struct ofpact_pop_mpls {
+    struct ofpact ofpact;
+    ovs_be16 ethertype;
+};
+
 /* OFPACT_SET_TUNNEL.
  *
  * Used for NXAST_SET_TUNNEL, NXAST_SET_TUNNEL64. */
@@ -403,15 +432,6 @@ struct ofpact_multipath {
     struct mf_subfield dst;
 };
 
-/* OFPACT_AUTOPATH.
- *
- * Used for NXAST_AUTOPATH. */
-struct ofpact_autopath {
-    struct ofpact ofpact;
-    struct mf_subfield dst;
-    uint32_t port;
-};
-
 /* OFPACT_NOTE.
  *
  * Used for NXAST_NOTE. */
@@ -432,6 +452,15 @@ struct ofpact_cnt_ids {
     uint16_t cnt_ids[];
 };
 
+/* OFPACT_SET_MPLS_TTL.
+ *
+ * Used for NXAST_SET_MPLS_TTL */
+struct ofpact_mpls_ttl {
+    struct ofpact ofpact;
+
+    uint8_t ttl;
+};
+
 /* OFPACT_GOTO_TABLE
  *
  * Used for OFPIT11_GOTO_TABLE */
index 47d7615..af4178e 100644 (file)
@@ -320,6 +320,23 @@ ofpraw_decode(enum ofpraw *raw, const struct ofp_header *oh)
     return ofpraw_pull(raw, &msg);
 }
 
+/* Does the same job as ofpraw_decode(), except that it assert-fails if
+ * ofpraw_decode() would have reported an error.  Thus, it's able to use the
+ * return value for the OFPRAW_* message type instead of an error code.
+ *
+ * (It only makes sense to use this function if you previously called
+ * ofpraw_decode() on the message and thus know that it's OK.) */
+enum ofpraw
+ofpraw_decode_assert(const struct ofp_header *oh)
+{
+    enum ofperr error;
+    enum ofpraw raw;
+
+    error = ofpraw_decode(&raw, oh);
+    ovs_assert(!error);
+    return raw;
+}
+
 /* Determines the OFPRAW_* type of the OpenFlow message in 'msg', which starts
  * at 'msg->data' and has length 'msg->size' bytes.  On success, returns 0 and
  * stores the type into '*rawp'.  On failure, returns an OFPERR_* error code
@@ -403,11 +420,11 @@ ofpraw_pull(enum ofpraw *rawp, struct ofpbuf *msg)
 }
 
 /* Does the same job as ofpraw_pull(), except that it assert-fails if
- * ofpbuf_pull() would have reported an error.  Thus, it's able to use the
+ * ofpraw_pull() would have reported an error.  Thus, it's able to use the
  * return value for the OFPRAW_* message type instead of an error code.
  *
  * (It only makes sense to use this function if you previously called
- * ofpbuf_decode() on the message and thus know that it's OK.) */
+ * ofpraw_decode() on the message and thus know that it's OK.) */
 enum ofpraw
 ofpraw_pull_assert(struct ofpbuf *msg)
 {
@@ -834,6 +851,8 @@ ofpmp_reserve(struct list *replies, size_t len)
 
         next = ofpbuf_new(MAX(1024, hdrs_len + len));
         ofpbuf_put(next, msg->data, hdrs_len);
+        next->l2 = next->data;
+        next->l3 = ofpbuf_tail(next);
         list_push_back(replies, &next->list_node);
 
         *ofpmp_flags__(msg->data) |= htons(OFPSF_REPLY_MORE);
index 2db4fc9..66ec448 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 Nicira, Inc.
+ * Copyright (c) 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -387,6 +387,7 @@ enum ofpraw {
 
 /* Decoding messages into OFPRAW_* values. */
 enum ofperr ofpraw_decode(enum ofpraw *, const struct ofp_header *);
+enum ofpraw ofpraw_decode_assert(const struct ofp_header *);
 enum ofperr ofpraw_pull(enum ofpraw *, struct ofpbuf *);
 enum ofpraw ofpraw_pull_assert(struct ofpbuf *);
 
index 6f35c12..e8abc9f 100644 (file)
@@ -22,7 +22,6 @@
 #include <errno.h>
 #include <stdlib.h>
 
-#include "autopath.h"
 #include "bundle.h"
 #include "byte-order.h"
 #include "dynamic-string.h"
@@ -318,6 +317,18 @@ parse_dec_ttl(struct ofpbuf *b, char *arg)
     }
 }
 
+static void
+parse_set_mpls_ttl(struct ofpbuf *b, const char *arg)
+{
+    struct ofpact_mpls_ttl *mpls_ttl = ofpact_put_SET_MPLS_TTL(b);
+
+    if (*arg == '\0') {
+        ovs_fatal(0, "parse_set_mpls_ttl: expected ttl.");
+    }
+
+    mpls_ttl->ttl = atoi(arg);
+}
+
 static void
 set_field_parse(const char *arg, struct ofpbuf *ofpacts)
 {
@@ -526,10 +537,6 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         multipath_parse(ofpact_put_MULTIPATH(ofpacts), arg);
         break;
 
-    case OFPUTIL_NXAST_AUTOPATH__DEPRECATED:
-        autopath_parse(ofpact_put_AUTOPATH(ofpacts), arg);
-        break;
-
     case OFPUTIL_NXAST_BUNDLE:
         bundle_parse(arg, ofpacts);
         break;
@@ -555,6 +562,16 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         parse_dec_ttl(ofpacts, arg);
         break;
 
+    case OFPUTIL_NXAST_SET_MPLS_TTL:
+    case OFPUTIL_OFPAT11_SET_MPLS_TTL:
+        parse_set_mpls_ttl(ofpacts, arg);
+        break;
+
+    case OFPUTIL_OFPAT11_DEC_MPLS_TTL:
+    case OFPUTIL_NXAST_DEC_MPLS_TTL:
+        ofpact_put_DEC_MPLS_TTL(ofpacts);
+        break;
+
     case OFPUTIL_NXAST_FIN_TIMEOUT:
         parse_fin_timeout(ofpacts, arg);
         break;
@@ -562,6 +579,24 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
     case OFPUTIL_NXAST_CONTROLLER:
         parse_controller(ofpacts, arg);
         break;
+
+    case OFPUTIL_OFPAT11_PUSH_MPLS:
+    case OFPUTIL_NXAST_PUSH_MPLS:
+        ofpact_put_PUSH_MPLS(ofpacts)->ethertype =
+            htons(str_to_u16(arg, "push_mpls"));
+        break;
+
+    case OFPUTIL_OFPAT11_POP_MPLS:
+    case OFPUTIL_NXAST_POP_MPLS:
+        ofpact_put_POP_MPLS(ofpacts)->ethertype =
+            htons(str_to_u16(arg, "pop_mpls"));
+        break;
+    case OFPUTIL_NXAST_STACK_PUSH:
+        nxm_parse_stack_action(ofpact_put_STACK_PUSH(ofpacts), arg);
+        break;
+    case OFPUTIL_NXAST_STACK_POP:
+        nxm_parse_stack_action(ofpact_put_STACK_POP(ofpacts), arg);
+        break;
     }
 }
 
@@ -726,7 +761,9 @@ parse_protocol(const char *name, const struct protocol **p_out)
         { "tcp6", ETH_TYPE_IPV6, IPPROTO_TCP },
         { "udp6", ETH_TYPE_IPV6, IPPROTO_UDP },
         { "rarp", ETH_TYPE_RARP, 0},
-};
+        { "mpls", ETH_TYPE_MPLS, 0 },
+        { "mplsm", ETH_TYPE_MPLS_MCAST, 0 },
+    };
     const struct protocol *p;
 
     for (p = protocols; p < &protocols[ARRAY_SIZE(protocols)]; p++) {
@@ -914,7 +951,9 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
                 parse_field(mf_from_name(name), value, &fm->match);
             } else if (!strcmp(name, "duration")
                        || !strcmp(name, "n_packets")
-                       || !strcmp(name, "n_bytes")) {
+                       || !strcmp(name, "n_bytes")
+                       || !strcmp(name, "idle_age")
+                       || !strcmp(name, "hard_age")) {
                 /* Ignore these, so that users can feed the output of
                  * "ovs-ofctl dump-flows" back into commands that parse
                  * flows. */
index b97180e..95d9b73 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -44,7 +44,6 @@
 #include "openflow/openflow.h"
 #include "openflow/nicira-ext.h"
 #include "packets.h"
-#include "pcap.h"
 #include "type-props.h"
 #include "unaligned.h"
 #include "util.h"
@@ -642,6 +641,10 @@ ofp10_match_to_string(const struct ofp10_match *om, int verbosity)
             ds_put_cstr(&f, "arp,");
         } else if (om->dl_type == htons(ETH_TYPE_RARP)){
             ds_put_cstr(&f, "rarp,");
+        } else if (om->dl_type == htons(ETH_TYPE_MPLS)) {
+            ds_put_cstr(&f, "mpls,");
+        } else if (om->dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+            ds_put_cstr(&f, "mplsm,");
         } else {
             skip_type = false;
         }
@@ -1546,19 +1549,18 @@ ofp_print_role_message(struct ds *string, const struct ofp_header *oh)
     }
 
     ds_put_cstr(string, " role=");
-    if (rr.request_current_role_only) {
-        ds_put_cstr(string, "nochange");
-        return;
-    }
 
     switch (rr.role) {
-    case NX_ROLE_OTHER:
+    case OFPCR12_ROLE_NOCHANGE:
+        ds_put_cstr(string, "nochange");
+        break;
+    case OFPCR12_ROLE_EQUAL:
         ds_put_cstr(string, "equal"); /* OF 1.2 wording */
         break;
-    case NX_ROLE_MASTER:
+    case OFPCR12_ROLE_MASTER:
         ds_put_cstr(string, "master");
         break;
-    case NX_ROLE_SLAVE:
+    case OFPCR12_ROLE_SLAVE:
         ds_put_cstr(string, "slave");
         break;
     default:
index c66cd40..6b78f84 100644 (file)
@@ -23,7 +23,6 @@
 #include <netinet/in.h>
 #include <netinet/icmp6.h>
 #include <stdlib.h>
-#include "autopath.h"
 #include "bundle.h"
 #include "byte-order.h"
 #include "classifier.h"
@@ -85,7 +84,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
 void
 ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
 {
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     /* Initialize most of wc. */
     flow_wildcards_init_catchall(wc);
@@ -440,8 +439,7 @@ ofputil_match_from_ofp11_match(const struct ofp11_match *ofmatch,
         }
     }
 
-    if (match->flow.dl_type == htons(ETH_TYPE_MPLS) ||
-        match->flow.dl_type == htons(ETH_TYPE_MPLS_MCAST)) {
+    if (eth_type_mpls(match->flow.dl_type)) {
         enum { OFPFW11_MPLS_ALL = OFPFW11_MPLS_LABEL | OFPFW11_MPLS_TC };
 
         if ((wc & OFPFW11_MPLS_ALL) != OFPFW11_MPLS_ALL) {
@@ -1060,7 +1058,7 @@ ofputil_usable_protocols(const struct match *match)
 {
     const struct flow_wildcards *wc = &match->wc;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     /* tunnel params other than tun_id can't be sent in a flow_mod */
     if (!tun_parms_fully_wildcarded(wc)) {
@@ -1152,6 +1150,26 @@ ofputil_usable_protocols(const struct match *match)
             | OFPUTIL_P_OF13_OXM;
     }
 
+    /* NXM and OF1.1+ support matching MPLS label */
+    if (wc->masks.mpls_lse & htonl(MPLS_LABEL_MASK)) {
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
+            | OFPUTIL_P_OF13_OXM;
+    }
+
+    /* NXM and OF1.1+ support matching MPLS TC */
+    if (wc->masks.mpls_lse & htonl(MPLS_TC_MASK)) {
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
+            | OFPUTIL_P_OF13_OXM;
+    }
+
+    /* NXM and OF1.3+ support matching MPLS stack flag */
+    /* Allow for OF1.2 as there doesn't seem to be a
+     * particularly good reason not to */
+    if (wc->masks.mpls_lse & htonl(MPLS_BOS_MASK)) {
+        return OFPUTIL_P_OF10_NXM_ANY | OFPUTIL_P_OF12_OXM
+            | OFPUTIL_P_OF13_OXM;
+    }
+
     /* Other formats can express this rule. */
     return OFPUTIL_P_ANY;
 }
@@ -2327,7 +2345,7 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
         fr->priority = ntohs(nfr->priority);
         fr->cookie = nfr->cookie;
         fr->reason = nfr->reason;
-        fr->table_id = 255;
+        fr->table_id = nfr->table_id ? nfr->table_id - 1 : 255;
         fr->duration_sec = ntohl(nfr->duration_sec);
         fr->duration_nsec = ntohl(nfr->duration_nsec);
         fr->idle_timeout = ntohs(nfr->idle_timeout);
@@ -2406,6 +2424,7 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
         nfr->cookie = fr->cookie;
         nfr->priority = htons(fr->priority);
         nfr->reason = fr->reason;
+        nfr->table_id = fr->table_id + 1;
         nfr->duration_sec = htonl(fr->duration_sec);
         nfr->duration_nsec = htonl(fr->duration_nsec);
         nfr->idle_timeout = htons(fr->idle_timeout);
@@ -3364,43 +3383,54 @@ enum ofperr
 ofputil_decode_role_message(const struct ofp_header *oh,
                             struct ofputil_role_request *rr)
 {
-    const struct ofp12_role_request *orr = ofpmsg_body(oh);
-    uint32_t role = ntohl(orr->role);
     struct ofpbuf b;
     enum ofpraw raw;
 
-    memset(rr, 0, sizeof *rr);
-
     ofpbuf_use_const(&b, oh, ntohs(oh->length));
     raw = ofpraw_pull_assert(&b);
 
-    if (raw == OFPRAW_OFPT12_ROLE_REQUEST
-        || raw == OFPRAW_OFPT12_ROLE_REPLY) {
+    if (raw == OFPRAW_OFPT12_ROLE_REQUEST ||
+        raw == OFPRAW_OFPT12_ROLE_REPLY) {
+        const struct ofp12_role_request *orr = b.l3;
 
-        if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
-            if (role == OFPCR12_ROLE_NOCHANGE) {
-                rr->request_current_role_only = true;
-                return 0;
-            }
-            if (role == OFPCR12_ROLE_MASTER || role == OFPCR12_ROLE_SLAVE) {
-                rr->generation_id = ntohll(orr->generation_id);
-                rr->have_generation_id = true;
-            }
+        if (orr->role != htonl(OFPCR12_ROLE_NOCHANGE) &&
+            orr->role != htonl(OFPCR12_ROLE_EQUAL) &&
+            orr->role != htonl(OFPCR12_ROLE_MASTER) &&
+            orr->role != htonl(OFPCR12_ROLE_SLAVE)) {
+            return OFPERR_OFPRRFC_BAD_ROLE;
         }
 
-        /* Map to enum nx_role */
-        role -= 1; /* OFPCR12_ROLE_MASTER -> NX_ROLE_MASTER etc. */
-    } else if (raw != OFPRAW_NXT_ROLE_REQUEST
-               && raw != OFPRAW_NXT_ROLE_REPLY) {
-        return OFPERR_OFPBRC_BAD_TYPE;
-    }
+        rr->role = ntohl(orr->role);
+        if (raw == OFPRAW_OFPT12_ROLE_REQUEST
+            ? orr->role == htonl(OFPCR12_ROLE_NOCHANGE)
+            : orr->generation_id == htonll(UINT64_MAX)) {
+            rr->have_generation_id = false;
+            rr->generation_id = 0;
+        } else {
+            rr->have_generation_id = true;
+            rr->generation_id = ntohll(orr->generation_id);
+        }
+    } else if (raw == OFPRAW_NXT_ROLE_REQUEST ||
+               raw == OFPRAW_NXT_ROLE_REPLY) {
+        const struct nx_role_request *nrr = b.l3;
+
+        BUILD_ASSERT(NX_ROLE_OTHER + 1 == OFPCR12_ROLE_EQUAL);
+        BUILD_ASSERT(NX_ROLE_MASTER + 1 == OFPCR12_ROLE_MASTER);
+        BUILD_ASSERT(NX_ROLE_SLAVE + 1 == OFPCR12_ROLE_SLAVE);
+
+        if (nrr->role != htonl(NX_ROLE_OTHER) &&
+            nrr->role != htonl(NX_ROLE_MASTER) &&
+            nrr->role != htonl(NX_ROLE_SLAVE)) {
+            return OFPERR_OFPRRFC_BAD_ROLE;
+        }
 
-    if (role != NX_ROLE_OTHER && role != NX_ROLE_MASTER
-        && role != NX_ROLE_SLAVE) {
-        return OFPERR_OFPRRFC_BAD_ROLE;
+        rr->role = ntohl(nrr->role) + 1;
+        rr->have_generation_id = false;
+        rr->generation_id = 0;
+    } else {
+        NOT_REACHED();
     }
 
-    rr->role = role;
     return 0;
 }
 
@@ -3408,47 +3438,35 @@ ofputil_decode_role_message(const struct ofp_header *oh,
  * buffer owned by the caller. */
 struct ofpbuf *
 ofputil_encode_role_reply(const struct ofp_header *request,
-                          enum nx_role role)
+                          const struct ofputil_role_request *rr)
 {
-    struct ofp12_role_request *reply;
     struct ofpbuf *buf;
-    size_t reply_size;
-
-    struct ofpbuf b;
     enum ofpraw raw;
 
-    ofpbuf_use_const(&b, request, ntohs(request->length));
-    raw = ofpraw_pull_assert(&b);
+    raw = ofpraw_decode_assert(request);
     if (raw == OFPRAW_OFPT12_ROLE_REQUEST) {
-        reply_size = sizeof (struct ofp12_role_request);
-        raw = OFPRAW_OFPT12_ROLE_REPLY;
-    }
-    else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
-        reply_size = sizeof (struct nx_role_request);
-        raw = OFPRAW_NXT_ROLE_REPLY;
-    } else {
-        NOT_REACHED();
-    }
+        struct ofp12_role_request *orr;
 
-    buf = ofpraw_alloc_reply(raw, request, 0);
-    reply = ofpbuf_put_zeros(buf, reply_size);
+        buf = ofpraw_alloc_reply(OFPRAW_OFPT12_ROLE_REPLY, request, 0);
+        orr = ofpbuf_put_zeros(buf, sizeof *orr);
 
-    if (raw == OFPRAW_OFPT12_ROLE_REPLY) {
-        /* Map to OpenFlow enum ofp12_controller_role */
-        role += 1; /* NX_ROLE_MASTER -> OFPCR12_ROLE_MASTER etc. */
-        /*
-         * OpenFlow specification does not specify use of generation_id field
-         * on reply messages.  Intuitively, it would seem a good idea to return
-         * the current value.  However, the current value is undefined
-         * initially, and there is no way to insert an undefined value in the
-         * message.  Therefore we leave the generation_id zeroed on reply
-         * messages.
-         *
-         * A request for clarification has been filed with the Open Networking
-         * Foundation as EXT-272.
-         */
+        orr->role = htonl(rr->role);
+        orr->generation_id = htonll(rr->have_generation_id
+                                    ? rr->generation_id
+                                    : UINT64_MAX);
+    } else if (raw == OFPRAW_NXT_ROLE_REQUEST) {
+        struct nx_role_request *nrr;
+
+        BUILD_ASSERT(NX_ROLE_OTHER == OFPCR12_ROLE_EQUAL - 1);
+        BUILD_ASSERT(NX_ROLE_MASTER == OFPCR12_ROLE_MASTER - 1);
+        BUILD_ASSERT(NX_ROLE_SLAVE == OFPCR12_ROLE_SLAVE - 1);
+
+        buf = ofpraw_alloc_reply(OFPRAW_NXT_ROLE_REPLY, request, 0);
+        nrr = ofpbuf_put_zeros(buf, sizeof *nrr);
+        nrr->role = htonl(rr->role - 1);
+    } else {
+        NOT_REACHED();
     }
-    reply->role = htonl(role);
 
     return buf;
 }
@@ -4115,14 +4133,14 @@ ofputil_port_from_string(const char *s, uint16_t *portp)
             *portp = port32;
             return true;
         } else if (port32 <= OFPP_LAST_RESV) {
-            struct ds s;
+            struct ds msg;
 
-            ds_init(&s);
-            ofputil_format_port(port32, &s);
+            ds_init(&msg);
+            ofputil_format_port(port32, &msg);
             VLOG_WARN_ONCE("referring to port %s as %u is deprecated for "
                            "compatibility with future versions of OpenFlow",
-                           ds_cstr(&s), port32);
-            ds_destroy(&s);
+                           ds_cstr(&msg), port32);
+            ds_destroy(&msg);
 
             *portp = port32;
             return true;
@@ -4307,7 +4325,8 @@ ofputil_normalize_match__(struct match *match, bool may_log)
         MAY_ARP_SHA     = 1 << 4, /* arp_sha */
         MAY_ARP_THA     = 1 << 5, /* arp_tha */
         MAY_IPV6        = 1 << 6, /* ipv6_src, ipv6_dst, ipv6_label */
-        MAY_ND_TARGET   = 1 << 7  /* nd_target */
+        MAY_ND_TARGET   = 1 << 7, /* nd_target */
+        MAY_MPLS        = 1 << 8, /* mpls label and tc */
     } may_match;
 
     struct flow_wildcards wc;
@@ -4336,6 +4355,8 @@ ofputil_normalize_match__(struct match *match, bool may_log)
     } else if (match->flow.dl_type == htons(ETH_TYPE_ARP) ||
                match->flow.dl_type == htons(ETH_TYPE_RARP)) {
         may_match = MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA;
+    } else if (eth_type_mpls(match->flow.dl_type)) {
+        may_match = MAY_MPLS;
     } else {
         may_match = 0;
     }
@@ -4368,6 +4389,10 @@ ofputil_normalize_match__(struct match *match, bool may_log)
     if (!(may_match & MAY_ND_TARGET)) {
         wc.masks.nd_target = in6addr_any;
     }
+    if (!(may_match & MAY_MPLS)) {
+        wc.masks.mpls_lse = htonl(0);
+        wc.masks.mpls_depth = 0;
+    }
 
     /* Log any changes. */
     if (!flow_wildcards_equal(&wc, &match->wc)) {
index 6d08d8a..b7dde48 100644 (file)
@@ -30,8 +30,12 @@ OFPAT11_ACTION(OFPAT11_SET_NW_TOS,   ofp_action_nw_tos,   0, "mod_nw_tos")
 //OFPAT11_ACTION(OFPAT11_SET_NW_ECN,   ofp11_action_nw_ecn, "0, mod_nw_ecn")
 OFPAT11_ACTION(OFPAT11_SET_TP_SRC,   ofp_action_tp_port,  0, "mod_tp_src")
 OFPAT11_ACTION(OFPAT11_SET_TP_DST,   ofp_action_tp_port,  0, "mod_tp_dst")
+OFPAT11_ACTION(OFPAT11_SET_MPLS_TTL, ofp11_action_mpls_ttl, 0, "set_mpls_ttl")
+OFPAT11_ACTION(OFPAT11_DEC_MPLS_TTL, ofp_action_header,   0, "dec_mpls_ttl")
 OFPAT11_ACTION(OFPAT11_PUSH_VLAN,    ofp11_action_push,   0, "push_vlan")
 OFPAT11_ACTION(OFPAT11_POP_VLAN,     ofp_action_header,   0, "pop_vlan")
+OFPAT11_ACTION(OFPAT11_PUSH_MPLS,    ofp11_action_push,   0, "push_mpls")
+OFPAT11_ACTION(OFPAT11_POP_MPLS,     ofp11_action_pop_mpls, 0, "pop_mpls")
 OFPAT11_ACTION(OFPAT11_SET_QUEUE,    ofp11_action_set_queue, 0, "set_queue")
 //OFPAT11_ACTION(OFPAT11_SET_NW_TTL,   ofp11_action_nw_ttl, 0, "set_nw_ttl")
 OFPAT11_ACTION(OFPAT11_DEC_NW_TTL,   ofp_action_header,   0, NULL)
@@ -46,10 +50,11 @@ NXAST_ACTION(NXAST_SET_QUEUE,       nx_action_set_queue,    0, "set_queue")
 NXAST_ACTION(NXAST_POP_QUEUE,       nx_action_pop_queue,    0, "pop_queue")
 NXAST_ACTION(NXAST_REG_MOVE,        nx_action_reg_move,     0, "move")
 NXAST_ACTION(NXAST_REG_LOAD,        nx_action_reg_load,     0, "load")
+NXAST_ACTION(NXAST_STACK_PUSH,      nx_action_stack,        0, "push")
+NXAST_ACTION(NXAST_STACK_POP,       nx_action_stack,        0, "pop")
 NXAST_ACTION(NXAST_NOTE,            nx_action_note,         1, "note")
 NXAST_ACTION(NXAST_SET_TUNNEL64,    nx_action_set_tunnel64, 0, "set_tunnel64")
 NXAST_ACTION(NXAST_MULTIPATH,       nx_action_multipath,    0, "multipath")
-NXAST_ACTION(NXAST_AUTOPATH__DEPRECATED,nx_action_autopath, 0, "autopath")
 NXAST_ACTION(NXAST_BUNDLE,          nx_action_bundle,       1, "bundle")
 NXAST_ACTION(NXAST_BUNDLE_LOAD,     nx_action_bundle,       1, "bundle_load")
 NXAST_ACTION(NXAST_RESUBMIT_TABLE,  nx_action_resubmit,     0, NULL)
@@ -62,6 +67,10 @@ NXAST_ACTION(NXAST_CONTROLLER,      nx_action_controller,   0, "controller")
 NXAST_ACTION(NXAST_DEC_TTL_CNT_IDS, nx_action_cnt_ids,      1, NULL)
 NXAST_ACTION(NXAST_WRITE_METADATA,  nx_action_write_metadata, 0,
              "write_metadata")
+NXAST_ACTION(NXAST_SET_MPLS_TTL,    nx_action_mpls_ttl,     0, "set_mpls_ttl")
+NXAST_ACTION(NXAST_DEC_MPLS_TTL,    nx_action_header,       0, "dec_mpls_ttl")
+NXAST_ACTION(NXAST_PUSH_MPLS,       nx_action_push_mpls,    0, "push_mpls")
+NXAST_ACTION(NXAST_POP_MPLS,        nx_action_pop_mpls,     0, "pop_mpls")
 
 #undef OFPAT10_ACTION
 #undef OFPAT11_ACTION
index 77162bf..db28c58 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -508,16 +508,15 @@ struct ofpbuf *ofputil_encode_port_mod(const struct ofputil_port_mod *,
 
 /* Abstract ofp_role_request and reply. */
 struct ofputil_role_request {
-    bool request_current_role_only; /* no role change */
+    enum ofp12_controller_role role;
     bool have_generation_id;
-    enum nx_role role;
     uint64_t generation_id;
 };
 
 enum ofperr ofputil_decode_role_message(const struct ofp_header *,
                                         struct ofputil_role_request *);
 struct ofpbuf *ofputil_encode_role_reply(const struct ofp_header *,
-                                         enum nx_role current_role);
+                                         const struct ofputil_role_request *);
 
 /* Abstract table stats.
  *
@@ -615,7 +614,6 @@ bool ofputil_frag_handling_from_string(const char *, enum ofp_config_flags *);
  * OFPUTIL_NXAST_NOTE
  * OFPUTIL_NXAST_SET_TUNNEL64
  * OFPUTIL_NXAST_MULTIPATH
- * OFPUTIL_NXAST_AUTOPATH
  * OFPUTIL_NXAST_BUNDLE
  * OFPUTIL_NXAST_BUNDLE_LOAD
  * OFPUTIL_NXAST_RESUBMIT_TABLE
@@ -688,8 +686,6 @@ union ofp_action *ofputil_actions_clone(const union ofp_action *, size_t n);
 /* Handy utility for parsing flows and actions. */
 bool ofputil_parse_key_value(char **stringp, char **keyp, char **valuep);
 
-struct ofpbuf *ofputlil_dump_ports(enum ofp_version ofp_version, int16_t port);
-
 struct ofputil_port_stats {
     uint16_t port_no;
     struct netdev_stats stats;
index 6484ab3..c960a7e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ ofpbuf_use__(struct ofpbuf *b, void *base, size_t allocated,
     b->allocated = allocated;
     b->source = source;
     b->size = 0;
-    b->l2 = b->l3 = b->l4 = b->l7 = NULL;
+    b->l2 = b->l2_5 = b->l3 = b->l4 = b->l7 = NULL;
     list_poison(&b->list_node);
     b->private_p = NULL;
 }
@@ -52,7 +52,7 @@ ofpbuf_use(struct ofpbuf *b, void *base, size_t allocated)
  *
  * 'base' should be appropriately aligned.  Using an array of uint32_t or
  * uint64_t for the buffer is a reasonable way to ensure appropriate alignment
- * for 32- or 64-bit data.  OFPBUF_STACK_BUFFER is a convenient way to do so.
+ * for 32- or 64-bit data.
  *
  * An ofpbuf operation that requires reallocating data will assert-fail if this
  * function was used to initialize it.  Thus, one need not call ofpbuf_uninit()
@@ -72,7 +72,7 @@ ofpbuf_use_stack(struct ofpbuf *b, void *base, size_t allocated)
  *
  * 'base' should be appropriately aligned.  Using an array of uint32_t or
  * uint64_t for the buffer is a reasonable way to ensure appropriate alignment
- * for 32- or 64-bit data.  OFPBUF_STACK_BUFFER is a convenient way to do so.
+ * for 32- or 64-bit data.
  *
  * An ofpbuf operation that requires reallocating data will copy the provided
  * buffer into a malloc()'d buffer.  Thus, it is wise to call ofpbuf_uninit()
@@ -176,6 +176,9 @@ ofpbuf_clone_with_headroom(const struct ofpbuf *buffer, size_t headroom)
     if (buffer->l2) {
         new_buffer->l2 = (char *) buffer->l2 + data_delta;
     }
+    if (buffer->l2_5) {
+        new_buffer->l2_5 = (char *) buffer->l2_5 + data_delta;
+    }
     if (buffer->l3) {
         new_buffer->l3 = (char *) buffer->l3 + data_delta;
     }
@@ -295,6 +298,9 @@ ofpbuf_resize__(struct ofpbuf *b, size_t new_headroom, size_t new_tailroom)
         if (b->l2) {
             b->l2 = (char *) b->l2 + data_delta;
         }
+        if (b->l2_5) {
+            b->l2_5 = (char *) b->l2_5 + data_delta;
+        }
         if (b->l3) {
             b->l3 = (char *) b->l3 + data_delta;
         }
index 520455d..8b03c7e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -43,6 +43,7 @@ struct ofpbuf {
     size_t size;                /* Number of bytes in use. */
 
     void *l2;                   /* Link-level header. */
+    void *l2_5;                 /* MPLS label stack */
     void *l3;                   /* Network-level header. */
     void *l4;                   /* Transport-level header. */
     void *l7;                   /* Application data. */
@@ -51,10 +52,6 @@ struct ofpbuf {
     void *private_p;            /* Private pointer for use by owner. */
 };
 
-/* Declares NAME as a SIZE-byte array aligned properly for storing any kind of
- * data.  For use with ofpbuf_use_stack(). */
-#define OFPBUF_STACK_BUFFER(NAME, SIZE) uint64_t NAME[DIV_ROUND_UP(SIZE, 8)]
-
 void ofpbuf_use(struct ofpbuf *, void *, size_t);
 void ofpbuf_use_stack(struct ofpbuf *, void *, size_t);
 void ofpbuf_use_stub(struct ofpbuf *, void *, size_t);
index 0afd03a..7ec7694 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -466,6 +466,47 @@ ovsdb_atom_to_json(const union ovsdb_atom *atom, enum ovsdb_atomic_type type)
     }
 }
 
+/* Returns strlen(json_to_string(ovsdb_atom_to_json(atom, type), 0)). */
+size_t
+ovsdb_atom_json_length(const union ovsdb_atom *atom,
+                       enum ovsdb_atomic_type type)
+{
+    struct json json;
+
+    switch (type) {
+    case OVSDB_TYPE_VOID:
+        NOT_REACHED();
+
+    case OVSDB_TYPE_INTEGER:
+        json.type = JSON_INTEGER;
+        json.u.integer = atom->integer;
+        break;
+
+    case OVSDB_TYPE_REAL:
+        json.type = JSON_REAL;
+        json.u.real = atom->real;
+        break;
+
+    case OVSDB_TYPE_BOOLEAN:
+        json.type = atom->boolean ? JSON_TRUE : JSON_FALSE;
+        break;
+
+    case OVSDB_TYPE_STRING:
+        json.type = JSON_STRING;
+        json.u.string = atom->string;
+        break;
+
+    case OVSDB_TYPE_UUID:
+        return strlen("[\"uuid\",\"00000000-0000-0000-0000-000000000000\"]");
+
+    case OVSDB_N_TYPES:
+    default:
+        NOT_REACHED();
+    }
+
+    return json_serialized_length(&json);
+}
+
 static char *
 ovsdb_atom_from_string__(union ovsdb_atom *atom,
                          const struct ovsdb_base_type *base, const char *s,
@@ -1307,6 +1348,56 @@ ovsdb_datum_to_json(const struct ovsdb_datum *datum,
     }
 }
 
+/* Returns strlen(json_to_string(ovsdb_datum_to_json(datum, type), 0)). */
+size_t
+ovsdb_datum_json_length(const struct ovsdb_datum *datum,
+                        const struct ovsdb_type *type)
+{
+    if (ovsdb_type_is_map(type)) {
+        size_t length;
+
+        /* ["map",[...]]. */
+        length = 10;
+        if (datum->n > 0) {
+            size_t i;
+
+            /* Commas between pairs in the inner [...] */
+            length += datum->n - 1;
+
+            /* [,] in each pair. */
+            length += datum->n * 3;
+
+            /* Data. */
+            for (i = 0; i < datum->n; i++) {
+                length += ovsdb_atom_json_length(&datum->keys[i],
+                                                 type->key.type);
+                length += ovsdb_atom_json_length(&datum->values[i],
+                                                 type->value.type);
+            }
+        }
+        return length;
+    } else if (datum->n == 1) {
+        return ovsdb_atom_json_length(&datum->keys[0], type->key.type);
+    } else {
+        size_t length;
+        size_t i;
+
+        /* ["set",[...]]. */
+        length = 10;
+        if (datum->n > 0) {
+            /* Commas between elements in the inner [...]. */
+            length += datum->n - 1;
+
+            /* Data. */
+            for (i = 0; i < datum->n; i++) {
+                length += ovsdb_atom_json_length(&datum->keys[i],
+                                                 type->key.type);
+            }
+        }
+        return length;
+    }
+}
+
 static const char *
 skip_spaces(const char *p)
 {
index 2e31cc5..ece1672 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -88,6 +88,8 @@ struct ovsdb_error *ovsdb_atom_from_json(union ovsdb_atom *,
     WARN_UNUSED_RESULT;
 struct json *ovsdb_atom_to_json(const union ovsdb_atom *,
                                 enum ovsdb_atomic_type);
+size_t ovsdb_atom_json_length(const union ovsdb_atom *,
+                              enum ovsdb_atomic_type);
 
 char *ovsdb_atom_from_string(union ovsdb_atom *,
                              const struct ovsdb_base_type *, const char *,
@@ -163,6 +165,8 @@ struct ovsdb_error *ovsdb_datum_from_json(struct ovsdb_datum *,
     WARN_UNUSED_RESULT;
 struct json *ovsdb_datum_to_json(const struct ovsdb_datum *,
                                  const struct ovsdb_type *);
+size_t ovsdb_datum_json_length(const struct ovsdb_datum *,
+                               const struct ovsdb_type *);
 
 char *ovsdb_datum_from_string(struct ovsdb_datum *,
                               const struct ovsdb_type *, const char *,
index 0cb0759..116aa86 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -157,6 +157,9 @@ static void ovsdb_idl_parse_lock_notify(struct ovsdb_idl *,
  * 'class'.  (Ordinarily 'class' is compiled from an OVSDB schema automatically
  * by ovsdb-idlc.)
  *
+ * Passes 'retry' to jsonrpc_session_open().  See that function for
+ * documentation.
+ *
  * If 'monitor_everything_by_default' is true, then everything in the remote
  * database will be replicated by default.  ovsdb_idl_omit() and
  * ovsdb_idl_omit_alert() may be used to selectively drop some columns from
@@ -168,7 +171,7 @@ static void ovsdb_idl_parse_lock_notify(struct ovsdb_idl *,
  */
 struct ovsdb_idl *
 ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
-                 bool monitor_everything_by_default)
+                 bool monitor_everything_by_default, bool retry)
 {
     struct ovsdb_idl *idl;
     uint8_t default_mode;
@@ -180,7 +183,7 @@ ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
 
     idl = xzalloc(sizeof *idl);
     idl->class = class;
-    idl->session = jsonrpc_session_open(remote);
+    idl->session = jsonrpc_session_open(remote, retry);
     shash_init(&idl->table_by_name);
     idl->tables = xmalloc(class->n_tables * sizeof *idl->tables);
     for (i = 0; i < class->n_tables; i++) {
@@ -412,6 +415,18 @@ ovsdb_idl_verify_write_only(struct ovsdb_idl *idl)
 {
     idl->verify_write_only = true;
 }
+
+bool
+ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
+{
+    return jsonrpc_session_is_alive(idl->session);
+}
+
+int
+ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
+{
+    return jsonrpc_session_get_last_error(idl->session);
+}
 \f
 static unsigned char *
 ovsdb_idl_get_mode(struct ovsdb_idl *idl,
@@ -1826,10 +1841,10 @@ ovsdb_idl_txn_complete(struct ovsdb_idl_txn *txn,
  * Takes ownership of what 'datum' points to (and in some cases destroys that
  * data before returning) but makes a copy of 'datum' itself.  (Commonly
  * 'datum' is on the caller's stack.) */
-void
-ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
-                    const struct ovsdb_idl_column *column,
-                    struct ovsdb_datum *datum)
+static void
+ovsdb_idl_txn_write__(const struct ovsdb_idl_row *row_,
+                      const struct ovsdb_idl_column *column,
+                      struct ovsdb_datum *datum, bool owns_datum)
 {
     struct ovsdb_idl_row *row = CONST_CAST(struct ovsdb_idl_row *, row_);
     const struct ovsdb_idl_table_class *class;
@@ -1837,8 +1852,7 @@ ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
     bool write_only;
 
     if (ovsdb_idl_row_is_synthetic(row)) {
-        ovsdb_datum_destroy(datum, &column->type);
-        return;
+        goto discard_datum;
     }
 
     class = row->table->class;
@@ -1853,8 +1867,7 @@ ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
     if (row->table->idl->verify_write_only && !write_only) {
         VLOG_ERR("Bug: Attempt to write to a read/write column (%s:%s) when"
                  " explicitly configured not to.", class->name, column->name);
-        ovsdb_datum_destroy(datum, &column->type);
-        return;
+        goto discard_datum;
     }
 
     /* If this is a write-only column and the datum being written is the same
@@ -1870,8 +1883,7 @@ ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
      * ovsdb_idl_txn_commit().) */
     if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
                                          datum, &column->type)) {
-        ovsdb_datum_destroy(datum, &column->type);
-        return;
+        goto discard_datum;
     }
 
     if (hmap_node_is_null(&row->txn_node)) {
@@ -1889,9 +1901,36 @@ ovsdb_idl_txn_write(const struct ovsdb_idl_row *row_,
     } else {
         bitmap_set1(row->written, column_idx);
     }
-    row->new[column_idx] = *datum;
+    if (owns_datum) {
+        row->new[column_idx] = *datum;
+    } else {
+        ovsdb_datum_clone(&row->new[column_idx], datum, &column->type);
+    }
     (column->unparse)(row);
     (column->parse)(row, &row->new[column_idx]);
+    return;
+
+discard_datum:
+    if (owns_datum) {
+        ovsdb_datum_destroy(datum, &column->type);
+    }
+}
+
+void
+ovsdb_idl_txn_write(const struct ovsdb_idl_row *row,
+                    const struct ovsdb_idl_column *column,
+                    struct ovsdb_datum *datum)
+{
+    ovsdb_idl_txn_write__(row, column, datum, true);
+}
+
+void
+ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *row,
+                          const struct ovsdb_idl_column *column,
+                          const struct ovsdb_datum *datum)
+{
+    ovsdb_idl_txn_write__(row, column,
+                          CONST_CAST(struct ovsdb_datum *, datum), false);
 }
 
 /* Causes the original contents of 'column' in 'row_' to be verified as a
@@ -2145,6 +2184,7 @@ ovsdb_idl_txn_process_insert_reply(struct ovsdb_idl_txn_insert *insert,
         VLOG_WARN_RL(&syntax_rl, "\"insert\" reply \"uuid\" is not a JSON "
                      "UUID: %s", s);
         free(s);
+        ovsdb_error_destroy(error);
         return false;
     }
 
index 27008b7..6b5e198 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -44,7 +44,8 @@ struct uuid;
 
 struct ovsdb_idl *ovsdb_idl_create(const char *remote,
                                    const struct ovsdb_idl_class *,
-                                   bool monitor_everything_by_default);
+                                   bool monitor_everything_by_default,
+                                   bool retry);
 void ovsdb_idl_destroy(struct ovsdb_idl *);
 
 void ovsdb_idl_run(struct ovsdb_idl *);
@@ -58,6 +59,9 @@ unsigned int ovsdb_idl_get_seqno(const struct ovsdb_idl *);
 bool ovsdb_idl_has_ever_connected(const struct ovsdb_idl *);
 void ovsdb_idl_force_reconnect(struct ovsdb_idl *);
 void ovsdb_idl_verify_write_only(struct ovsdb_idl *);
+
+bool ovsdb_idl_is_alive(const struct ovsdb_idl *);
+int ovsdb_idl_get_last_error(const struct ovsdb_idl *);
 \f
 /* Choosing columns and tables to replicate. */
 
@@ -202,6 +206,9 @@ const struct uuid *ovsdb_idl_txn_get_insert_uuid(const struct ovsdb_idl_txn *,
 void ovsdb_idl_txn_write(const struct ovsdb_idl_row *,
                          const struct ovsdb_idl_column *,
                          struct ovsdb_datum *);
+void ovsdb_idl_txn_write_clone(const struct ovsdb_idl_row *,
+                               const struct ovsdb_idl_column *,
+                               const struct ovsdb_datum *);
 void ovsdb_idl_txn_delete(const struct ovsdb_idl_row *);
 const struct ovsdb_idl_row *ovsdb_idl_txn_insert(
     struct ovsdb_idl_txn *, const struct ovsdb_idl_table_class *,
index fa73282..77aa7d3 100644 (file)
@@ -192,7 +192,8 @@ eth_push_vlan(struct ofpbuf *packet, ovs_be16 tci)
 
 /* Removes outermost VLAN header (if any is present) from 'packet'.
  *
- * 'packet->l2' must initially point to 'packet''s Ethernet header. */
+ * 'packet->l2_5' should initially point to 'packet''s outer-most MPLS header
+ * or may be NULL if there are no MPLS headers. */
 void
 eth_pop_vlan(struct ofpbuf *packet)
 {
@@ -211,6 +212,182 @@ eth_pop_vlan(struct ofpbuf *packet)
     }
 }
 
+/* Return depth of mpls stack.
+ *
+ * 'packet->l2_5' should initially point to 'packet''s outer-most MPLS header
+ * or may be NULL if there are no MPLS headers. */
+uint16_t
+eth_mpls_depth(const struct ofpbuf *packet)
+{
+    struct mpls_hdr *mh = packet->l2_5;
+    uint16_t depth;
+
+    if (!mh) {
+        return 0;
+    }
+
+    depth = 0;
+    while (packet->size >= ((char *)mh - (char *)packet->data) + sizeof *mh) {
+        depth++;
+        if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) {
+            break;
+        }
+        mh++;
+    }
+
+    return depth;
+}
+
+/* Set ethertype of the packet. */
+void
+set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type)
+{
+    struct eth_header *eh = packet->data;
+
+    if (eh->eth_type == htons(ETH_TYPE_VLAN)) {
+        ovs_be16 *p;
+        p = (ovs_be16 *)((char *)(packet->l2_5 ? packet->l2_5 : packet->l3) - 2);
+        *p = eth_type;
+    } else {
+        eh->eth_type = eth_type;
+    }
+}
+
+static bool is_mpls(struct ofpbuf *packet)
+{
+    return packet->l2_5 != NULL;
+}
+
+/* Set time to live (TTL) of an MPLS label stack entry (LSE). */
+void
+set_mpls_lse_ttl(ovs_be32 *lse, uint8_t ttl)
+{
+    *lse &= ~htonl(MPLS_TTL_MASK);
+    *lse |= htonl((ttl << MPLS_TTL_SHIFT) & MPLS_TTL_MASK);
+}
+
+/* Set traffic class (TC) of an MPLS label stack entry (LSE). */
+void
+set_mpls_lse_tc(ovs_be32 *lse, uint8_t tc)
+{
+    *lse &= ~htonl(MPLS_TC_MASK);
+    *lse |= htonl((tc << MPLS_TC_SHIFT) & MPLS_TC_MASK);
+}
+
+/* Set label of an MPLS label stack entry (LSE). */
+void
+set_mpls_lse_label(ovs_be32 *lse, ovs_be32 label)
+{
+    *lse &= ~htonl(MPLS_LABEL_MASK);
+    *lse |= htonl((ntohl(label) << MPLS_LABEL_SHIFT) & MPLS_LABEL_MASK);
+}
+
+/* Set bottom of stack (BoS) bit of an MPLS label stack entry (LSE). */
+void
+set_mpls_lse_bos(ovs_be32 *lse, uint8_t bos)
+{
+    *lse &= ~htonl(MPLS_BOS_MASK);
+    *lse |= htonl((bos << MPLS_BOS_SHIFT) & MPLS_BOS_MASK);
+}
+
+/* Compose an MPLS label stack entry (LSE) from its components:
+ * label, traffic class (TC), time to live (TTL) and
+ * bottom of stack (BoS) bit. */
+ovs_be32
+set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos, ovs_be32 label)
+{
+    ovs_be32 lse = htonl(0);
+    set_mpls_lse_ttl(&lse, ttl);
+    set_mpls_lse_tc(&lse, tc);
+    set_mpls_lse_bos(&lse, bos);
+    set_mpls_lse_label(&lse, label);
+    return lse;
+}
+
+/* Push an new MPLS stack entry onto the MPLS stack and adjust 'packet->l2' and
+ * 'packet->l2_5' accordingly.  The new entry will be the outermost entry on
+ * the stack.
+ *
+ * Previous to calling this function, 'packet->l2_5' must be set; if the MPLS
+ * label to be pushed will be the first label in 'packet', then it should be
+ * the same as 'packet->l3'. */
+static void
+push_mpls_lse(struct ofpbuf *packet, struct mpls_hdr *mh)
+{
+    char * header;
+    size_t len;
+    header = ofpbuf_push_uninit(packet, MPLS_HLEN);
+    len = (char *)packet->l2_5 - (char *)packet->l2;
+    memmove(header, packet->l2, len);
+    memcpy(header + len, mh, sizeof *mh);
+    packet->l2 = (char*)packet->l2 - MPLS_HLEN;
+    packet->l2_5 = (char*)packet->l2_5 - MPLS_HLEN;
+}
+
+/* Set MPLS label stack entry to outermost MPLS header.*/
+void
+set_mpls_lse(struct ofpbuf *packet, ovs_be32 mpls_lse)
+{
+    struct mpls_hdr *mh = packet->l2_5;
+
+    /* Packet type should be MPLS to set label stack entry. */
+    if (is_mpls(packet)) {
+        /* Update mpls label stack entry. */
+        mh->mpls_lse = mpls_lse;
+    }
+}
+
+/* Push MPLS label stack entry 'lse' onto 'packet' as the the outermost MPLS
+ * header.  If 'packet' does not already have any MPLS labels, then its
+ * Ethertype is changed to 'ethtype' (which must be an MPLS Ethertype). */
+void
+push_mpls(struct ofpbuf *packet, ovs_be16 ethtype, ovs_be32 lse)
+{
+    struct mpls_hdr mh;
+
+    if (!eth_type_mpls(ethtype)) {
+        return;
+    }
+
+    if (!is_mpls(packet)) {
+        /* Set ethtype and MPLS label stack entry. */
+        set_ethertype(packet, ethtype);
+        packet->l2_5 = packet->l3;
+    }
+
+    /* Push new MPLS shim header onto packet. */
+    mh.mpls_lse = lse;
+    push_mpls_lse(packet, &mh);
+}
+
+/* If 'packet' is an MPLS packet, removes its outermost MPLS label stack entry.
+ * If the label that was removed was the only MPLS label, changes 'packet''s
+ * Ethertype to 'ethtype' (which ordinarily should not be an MPLS
+ * Ethertype). */
+void
+pop_mpls(struct ofpbuf *packet, ovs_be16 ethtype)
+{
+    struct mpls_hdr *mh = NULL;
+
+    if (is_mpls(packet)) {
+        size_t len;
+        mh = packet->l2_5;
+        len = (char*)packet->l2_5 - (char*)packet->l2;
+        /* If bottom of the stack set ethertype. */
+        if (mh->mpls_lse & htonl(MPLS_BOS_MASK)) {
+            set_ethertype(packet, ethtype);
+            packet->l2_5 = NULL;
+        } else {
+            packet->l2_5 = (char*)packet->l2_5 + MPLS_HLEN;
+        }
+        /* Shift the l2 header forward. */
+        memmove((char*)packet->data + MPLS_HLEN, packet->data, len);
+        packet->size -= MPLS_HLEN;
+        packet->data = (char*)packet->data + MPLS_HLEN;
+        packet->l2 = (char*)packet->l2 + MPLS_HLEN;
+    }
+}
+
 /* Converts hex digits in 'hex' to an Ethernet packet in '*packetp'.  The
  * caller must free '*packetp'.  On success, returns NULL.  On failure, returns
  * an error message and stores NULL in '*packetp'. */
@@ -710,7 +887,8 @@ packet_set_udp_port(struct ofpbuf *packet, ovs_be16 src, ovs_be16 dst)
 uint8_t
 packet_get_tcp_flags(const struct ofpbuf *packet, const struct flow *flow)
 {
-    if (is_ip_any(flow) && flow->nw_proto == IPPROTO_TCP && packet->l7) {
+    if (dl_type_is_ip_any(flow->dl_type) &&
+        flow->nw_proto == IPPROTO_TCP && packet->l7) {
         const struct tcp_header *tcp = packet->l4;
         return TCP_FLAGS(tcp->tcp_ctl);
     } else {
index 8dd3ebf..b73ff63 100644 (file)
@@ -140,6 +140,10 @@ void compose_rarp(struct ofpbuf *, const uint8_t eth_src[ETH_ADDR_LEN]);
 void eth_push_vlan(struct ofpbuf *, ovs_be16 tci);
 void eth_pop_vlan(struct ofpbuf *);
 
+uint16_t eth_mpls_depth(const struct ofpbuf *packet);
+
+void set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type);
+
 const char *eth_from_hex(const char *hex, struct ofpbuf **packetp);
 void eth_format_masked(const uint8_t eth[ETH_ADDR_LEN],
                        const uint8_t mask[ETH_ADDR_LEN], struct ds *s);
@@ -147,6 +151,17 @@ void eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN],
                      const uint8_t mask[ETH_ADDR_LEN],
                      uint8_t dst[ETH_ADDR_LEN]);
 
+void set_mpls_lse(struct ofpbuf *, ovs_be32 label);
+void push_mpls(struct ofpbuf *packet, ovs_be16 ethtype, ovs_be32 lse);
+void pop_mpls(struct ofpbuf *, ovs_be16 ethtype);
+
+void set_mpls_lse_ttl(ovs_be32 *lse, uint8_t ttl);
+void set_mpls_lse_tc(ovs_be32 *lse, uint8_t tc);
+void set_mpls_lse_label(ovs_be32 *lse, ovs_be32 label);
+void set_mpls_lse_bos(ovs_be32 *lse, uint8_t bos);
+ovs_be32 set_mpls_lse_values(uint8_t ttl, uint8_t tc, uint8_t bos,
+                             ovs_be32 label);
+
 /* Example:
  *
  * uint8_t mac[ETH_ADDR_LEN];
@@ -186,6 +201,12 @@ void eth_addr_bitand(const uint8_t src[ETH_ADDR_LEN],
 #define ETH_TYPE_MPLS          0x8847
 #define ETH_TYPE_MPLS_MCAST    0x8848
 
+static inline bool eth_type_mpls(ovs_be16 eth_type)
+{
+    return eth_type == htons(ETH_TYPE_MPLS) ||
+        eth_type == htons(ETH_TYPE_MPLS_MCAST);
+}
+
 /* Minimum value for an Ethernet type.  Values below this are IEEE 802.2 frame
  * lengths. */
 #define ETH_TYPE_MIN           0x600
@@ -272,6 +293,66 @@ struct vlan_eth_header {
 } __attribute__((packed));
 BUILD_ASSERT_DECL(VLAN_ETH_HEADER_LEN == sizeof(struct vlan_eth_header));
 
+/* MPLS related definitions */
+#define MPLS_TTL_MASK       0x000000ff
+#define MPLS_TTL_SHIFT      0
+
+#define MPLS_BOS_MASK       0x00000100
+#define MPLS_BOS_SHIFT      8
+
+#define MPLS_TC_MASK        0x00000e00
+#define MPLS_TC_SHIFT       9
+
+#define MPLS_LABEL_MASK     0xfffff000
+#define MPLS_LABEL_SHIFT    12
+
+#define MPLS_HLEN           4
+
+struct mpls_hdr {
+    ovs_be32 mpls_lse;
+};
+BUILD_ASSERT_DECL(MPLS_HLEN == sizeof(struct mpls_hdr));
+
+/* Given a mpls label stack entry in network byte order
+ * return mpls label in host byte order */
+static inline uint32_t
+mpls_lse_to_label(ovs_be32 mpls_lse)
+{
+    return (ntohl(mpls_lse) & MPLS_LABEL_MASK) >> MPLS_LABEL_SHIFT;
+}
+
+/* Given a mpls label stack entry in network byte order
+ * return mpls tc */
+static inline uint8_t
+mpls_lse_to_tc(ovs_be32 mpls_lse)
+{
+    return (ntohl(mpls_lse) & MPLS_TC_MASK) >> MPLS_TC_SHIFT;
+}
+
+/* Given a mpls label stack entry in network byte order
+ * return mpls ttl */
+static inline uint8_t
+mpls_lse_to_ttl(ovs_be32 mpls_lse)
+{
+    return (ntohl(mpls_lse) & MPLS_TTL_MASK) >> MPLS_TTL_SHIFT;
+}
+
+/* Set TTL in mpls lse. */
+static inline void
+flow_set_mpls_lse_ttl(ovs_be32 *mpls_lse, uint8_t ttl)
+{
+    *mpls_lse &= ~htonl(MPLS_TTL_MASK);
+    *mpls_lse |= htonl(ttl << MPLS_TTL_SHIFT);
+}
+
+/* Given a mpls label stack entry in network byte order
+ * return mpls BoS bit  */
+static inline uint8_t
+mpls_lse_to_bos(ovs_be32 mpls_lse)
+{
+    return (mpls_lse & htonl(MPLS_BOS_MASK)) != 0;
+}
+
 #define IP_FMT "%"PRIu32".%"PRIu32".%"PRIu32".%"PRIu32
 #define IP_ARGS(ip)                             \
     ntohl(ip) >> 24,                            \
@@ -468,10 +549,15 @@ static inline bool ipv6_mask_is_exact(const struct in6_addr *mask) {
     return ipv6_addr_equals(mask, &in6addr_exact);
 }
 
+static inline bool dl_type_is_ip_any(ovs_be16 dl_type)
+{
+    return dl_type == htons(ETH_TYPE_IP)
+        || dl_type == htons(ETH_TYPE_IPV6);
+}
+
 static inline bool is_ip_any(const struct flow *flow)
 {
-    return flow->dl_type == htons(ETH_TYPE_IP)
-        || flow->dl_type == htons(ETH_TYPE_IPV6);
+    return dl_type_is_ip_any(flow->dl_type);
 }
 
 void format_ipv6_addr(char *addr_str, const struct in6_addr *addr);
similarity index 99%
rename from lib/pcap.c
rename to lib/pcap-file.c
index 1033ba9..d137be8 100644 (file)
@@ -15,7 +15,7 @@
  */
 
 #include <config.h>
-#include "pcap.h"
+#include "pcap-file.h"
 #include <errno.h>
 #include <inttypes.h>
 #include <string.h>
similarity index 92%
rename from lib/pcap.h
rename to lib/pcap-file.h
index 43a4306..46625c3 100644 (file)
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef PCAP_H
-#define PCAP_H 1
+#ifndef PCAP_FILE_H
+#define PCAP_FILE_H 1
 
 #include <stdio.h>
 
@@ -27,4 +27,4 @@ void pcap_write_header(FILE *);
 int pcap_read(FILE *, struct ofpbuf **);
 void pcap_write(FILE *, struct ofpbuf *);
 
-#endif /* dhcp.h */
+#endif /* pcap-file.h */
index fca1dfa..9855306 100644 (file)
@@ -165,8 +165,8 @@ log_wakeup(const char *where, const struct pollfd *pollfd, int timeout)
     cpu_usage = get_cpu_usage();
     if (VLOG_IS_DBG_ENABLED()) {
         level = VLL_DBG;
-    } else if (cpu_usage > 50 && !VLOG_DROP_WARN(&rl)) {
-        level = VLL_WARN;
+    } else if (cpu_usage > 50 && !VLOG_DROP_INFO(&rl)) {
+        level = VLL_INFO;
     } else {
         return;
     }
index 3fc2e18..795a136 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -408,14 +408,20 @@ struct stream {
 static int
 stream_open(struct stream *s, size_t max_size)
 {
+    int error;
+
     s->max_size = max_size;
     ds_init(&s->log);
     if (pipe(s->fds)) {
         VLOG_WARN("failed to create pipe: %s", strerror(errno));
         return errno;
     }
-    set_nonblocking(s->fds[0]);
-    return 0;
+    error = set_nonblocking(s->fds[0]);
+    if (error) {
+        close(s->fds[0]);
+        close(s->fds[1]);
+    }
+    return error;
 }
 
 static void
index 40cc7fc..b914ef6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -207,7 +207,8 @@ reconnect_get_max_tries(struct reconnect *fsm)
 
 /* Configures the backoff parameters for 'fsm'.  'min_backoff' is the minimum
  * number of milliseconds, and 'max_backoff' is the maximum, between connection
- * attempts.
+ * attempts.  The current backoff is also the duration that 'fsm' is willing to
+ * wait for a given connection to succeed or fail.
  *
  * 'min_backoff' must be at least 1000, and 'max_backoff' must be greater than
  * or equal to 'min_backoff'.
index cc8ddb8..9c30f68 100644 (file)
@@ -147,6 +147,19 @@ simap_delete(struct simap *simap, struct simap_node *node)
     free(node);
 }
 
+/* Searches for 'name' in 'simap'.  If found, deletes it and returns true.  If
+ * not found, returns false without modifying 'simap'. */
+bool
+simap_find_and_delete(struct simap *simap, const char *name)
+{
+    struct simap_node *node = simap_find(simap, name);
+    if (node) {
+        simap_delete(simap, node);
+        return true;
+    }
+    return false;
+}
+
 /* Searches 'simap' for a mapping with the given 'name'.  Returns it, if found,
  * or a null pointer if not. */
 struct simap_node *
@@ -172,6 +185,13 @@ simap_get(const struct simap *simap, const char *name)
     return node ? node->data : 0;
 }
 
+/* Returns true if 'simap' contains a copy of 'name', false otherwise. */
+bool
+simap_contains(const struct simap *simap, const char *name)
+{
+    return simap_find(simap, name) != NULL;
+}
+
 /* Returns an array that contains a pointer to each mapping in 'simap',
  * ordered alphabetically by name.  The returned array has simap_count(simap)
  * elements.
index e7bf80b..3e247fc 100644 (file)
@@ -58,8 +58,10 @@ unsigned int simap_get(const struct simap *, const char *);
 struct simap_node *simap_find(const struct simap *, const char *);
 struct simap_node *simap_find_len(const struct simap *,
                                   const char *, size_t len);
+bool simap_contains(const struct simap *, const char *);
 
 void simap_delete(struct simap *, struct simap_node *);
+bool simap_find_and_delete(struct simap *, const char *);
 
 const struct simap_node **simap_sort(const struct simap *);
 
index 3e3c67f..9fea7bd 100644 (file)
@@ -409,13 +409,8 @@ make_unix_socket(int style, bool nonblock,
      * it will only happen if style is SOCK_STREAM or SOCK_SEQPACKET, and only
      * if a backlog of un-accepted connections has built up in the kernel.)  */
     if (nonblock) {
-        int flags = fcntl(fd, F_GETFL, 0);
-        if (flags == -1) {
-            error = errno;
-            goto error;
-        }
-        if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
-            error = errno;
+        error = set_nonblocking(fd);
+        if (error) {
             goto error;
         }
     }
index 6ed7648..dbee135 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
 #include "packets.h"
 #include "poll-loop.h"
 #include "socket-util.h"
+#include "dirs.h"
 #include "util.h"
 #include "stream-provider.h"
 #include "stream-fd.h"
@@ -42,15 +43,19 @@ static int
 unix_open(const char *name, char *suffix, struct stream **streamp,
           uint8_t dscp OVS_UNUSED)
 {
-    const char *connect_path = suffix;
+    char *connect_path;
     int fd;
 
+    connect_path = abs_file_name(ovs_rundir(), suffix);
     fd = make_unix_socket(SOCK_STREAM, true, NULL, connect_path);
+
     if (fd < 0) {
         VLOG_DBG("%s: connection failed (%s)", connect_path, strerror(-fd));
+        free(connect_path);
         return -fd;
     }
 
+    free(connect_path);
     return new_fd_stream(name, fd, check_connection_completion(fd), streamp);
 }
 
@@ -76,11 +81,14 @@ static int
 punix_open(const char *name OVS_UNUSED, char *suffix,
            struct pstream **pstreamp, uint8_t dscp OVS_UNUSED)
 {
+    char *bind_path;
     int fd, error;
 
-    fd = make_unix_socket(SOCK_STREAM, true, suffix, NULL);
+    bind_path = abs_file_name(ovs_rundir(), suffix);
+    fd = make_unix_socket(SOCK_STREAM, true, bind_path, NULL);
     if (fd < 0) {
-        VLOG_ERR("%s: binding failed: %s", suffix, strerror(errno));
+        VLOG_ERR("%s: binding failed: %s", bind_path, strerror(errno));
+        free(bind_path);
         return errno;
     }
 
@@ -88,11 +96,11 @@ punix_open(const char *name OVS_UNUSED, char *suffix,
         error = errno;
         VLOG_ERR("%s: listen: %s", name, strerror(error));
         close(fd);
+        free(bind_path);
         return error;
     }
 
-    return new_fd_pstream(name, fd, punix_accept, NULL,
-                          xstrdup(suffix), pstreamp);
+    return new_fd_pstream(name, fd, punix_accept, NULL, bind_path, pstreamp);
 }
 
 static int
index d91305c..6e41514 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,9 +17,6 @@
 #include <config.h>
 #include "timeval.h"
 #include <errno.h>
-#if HAVE_EXECINFO_H
-#include <execinfo.h>
-#endif
 #include <poll.h>
 #include <signal.h>
 #include <stdlib.h>
 #include "util.h"
 #include "vlog.h"
 
+/* backtrace() from <execinfo.h> is really useful, but it is not signal safe
+ * everywhere, such as on x86-64.  */
+#if HAVE_EXECINFO_H && !defined __x86_64__
+#  define USE_BACKTRACE 1
+#  include <execinfo.h>
+#else
+#  define USE_BACKTRACE 0
+#endif
+
 VLOG_DEFINE_THIS_MODULE(timeval);
 
 /* The clock to use for measuring time intervals.  This is CLOCK_MONOTONIC by
@@ -93,9 +99,7 @@ static void timespec_add(struct timespec *sum,
                          const struct timespec *a, const struct timespec *b);
 static unixctl_cb_func backtrace_cb;
 
-#ifndef HAVE_EXECINFO_H
-#define HAVE_EXECINFO_H 0
-
+#if !USE_BACKTRACE
 static int
 backtrace(void **buffer OVS_UNUSED, int size OVS_UNUSED)
 {
@@ -107,7 +111,7 @@ backtrace_symbols(void *const *buffer OVS_UNUSED, int size OVS_UNUSED)
 {
     NOT_REACHED();
 }
-#endif
+#endif  /* !USE_BACKTRACE */
 
 /* Initializes the timetracking module, if not already initialized. */
 static void
@@ -124,7 +128,7 @@ time_init(void)
      * initialization which is not signal safe.  This can cause deadlocks if
      * run from the signal handler.  As a workaround, force the initialization
      * to happen here. */
-    if (HAVE_EXECINFO_H) {
+    if (USE_BACKTRACE) {
         void *bt[1];
 
         backtrace(bt, ARRAY_SIZE(bt));
@@ -132,7 +136,7 @@ time_init(void)
 
     memset(traces, 0, sizeof traces);
 
-    if (HAVE_EXECINFO_H && CACHE_TIME) {
+    if (USE_BACKTRACE && CACHE_TIME) {
         unixctl_command_register("backtrace", "", 0, 0, backtrace_cb, NULL);
     }
 
@@ -328,7 +332,7 @@ time_alarm(unsigned int secs)
     time_refresh();
 
     now = time_msec();
-    msecs = secs * 1000;
+    msecs = secs * 1000LL;
 
     block_sigalrm(&oldsigs);
     deadline = now < LLONG_MAX - msecs ? now + msecs : LLONG_MAX;
@@ -419,7 +423,7 @@ sigalrm_handler(int sig_nr OVS_UNUSED)
     wall_tick = true;
     monotonic_tick = true;
 
-    if (HAVE_EXECINFO_H && CACHE_TIME) {
+    if (USE_BACKTRACE && CACHE_TIME) {
         struct trace *trace = &traces[trace_head];
 
         trace->n_frames = backtrace(trace->backtrace,
@@ -516,7 +520,7 @@ log_poll_interval(long long int last_wakeup)
 {
     long long int interval = time_msec() - last_wakeup;
 
-    if (interval >= 1000) {
+    if (interval >= 1000 && !warp_offset.tv_sec && !warp_offset.tv_nsec) {
         const struct rusage *last_rusage = get_recent_rusage();
         struct rusage rusage;
 
@@ -633,7 +637,7 @@ format_backtraces(struct ds *ds, size_t min_count)
 {
     time_init();
 
-    if (HAVE_EXECINFO_H && CACHE_TIME) {
+    if (USE_BACKTRACE && CACHE_TIME) {
         struct hmap trace_map = HMAP_INITIALIZER(&trace_map);
         struct trace *trace, *next;
         sigset_t oldsigs;
@@ -730,7 +734,7 @@ backtrace_cb(struct unixctl_conn *conn,
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
 
-    ovs_assert(HAVE_EXECINFO_H && CACHE_TIME);
+    ovs_assert(USE_BACKTRACE && CACHE_TIME);
     format_backtraces(&ds, 0);
     unixctl_command_reply(conn, ds_cstr(&ds));
     ds_destroy(&ds);
index 5a7b6e2..72cf498 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -43,20 +43,14 @@ BUILD_ASSERT_DECL(TYPE_IS_SIGNED(time_t));
 /* Interval between updates to the reported time, in ms.  This should not be
  * adjusted much below 10 ms or so with the current implementation, or too
  * much time will be wasted in signal handlers and calls to clock_gettime(). */
-#define TIME_UPDATE_INTERVAL 100
+#define TIME_UPDATE_INTERVAL 25
 
-/* True on systems (particularly x86-64 Linux) where clock_gettime() is
- * inexpensive.  On these systems, we don't bother caching the current time.
- * Instead, we consult clock_gettime() directly when needed.
- *
- * False on systems where clock_gettime() is relatively expensive.  On these
- * systems, we cache the current time and set up a periodic SIGALRM to remind
- * us to update it.
- *
- * Also false on systems (e.g. ESX) that don't support setting up timers based
- * on a monotonically increasing clock. */
+/* True on systems that support a monotonic clock.  Compared to just getting
+ * the value of a variable, clock_gettime() is somewhat expensive, even on
+ * systems that try hard to optimize it (such as x86-64 Linux), so it's
+ * worthwhile to minimize calls via caching. */
 #ifndef CACHE_TIME
-#if defined ESX || (defined __x86_64__ && defined LINUX_DATAPATH)
+#if defined ESX
 #define CACHE_TIME 0
 #else
 #define CACHE_TIME 1
index e59056e..104a2d9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -462,7 +462,7 @@ unixctl_client_transact(struct jsonrpc *client, const char *command, int argc,
     error = jsonrpc_transact_block(client, request, &reply);
     if (error) {
         VLOG_WARN("error communicating with %s: %s", jsonrpc_get_name(client),
-                  strerror(error));
+                  ovs_retval_to_string(error));
         return error;
     }
 
index 83d3ff8..cbaffa7 100644 (file)
@@ -810,7 +810,7 @@ log_2_floor(uint32_t n)
 int
 log_2_ceil(uint32_t n)
 {
-    return log_2_floor(n) + !IS_POW2(n);
+    return log_2_floor(n) + !is_pow2(n);
 }
 
 /* Returns the number of trailing 0-bits in 'n'.  Undefined if 'n' == 0. */
index 7867b07..8bc9938 100644 (file)
@@ -431,6 +431,16 @@ exit:
     return msg;
 }
 
+/* Set debugging levels.  Abort with an error message if 's' is invalid. */
+void
+vlog_set_levels_from_string_assert(const char *s)
+{
+    char *error = vlog_set_levels_from_string(s);
+    if (error) {
+        ovs_fatal(0, "%s", error);
+    }
+}
+
 /* If 'arg' is null, configure maximum verbosity.  Otherwise, sets
  * configuration according to 'arg' (see vlog_set_levels_from_string()). */
 void
index 2595772..ab746c8 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -114,7 +114,8 @@ struct vlog_rate_limit {
 enum vlog_level vlog_get_level(const struct vlog_module *, enum vlog_facility);
 void vlog_set_levels(struct vlog_module *,
                      enum vlog_facility, enum vlog_level);
-char *vlog_set_levels_from_string(const char *);
+char *vlog_set_levels_from_string(const char *) WARN_UNUSED_RESULT;
+void vlog_set_levels_from_string_assert(const char *);
 char *vlog_get_levels(void);
 bool vlog_is_enabled(const struct vlog_module *, enum vlog_level);
 bool vlog_should_drop(const struct vlog_module *, enum vlog_level,
index b0f1a82..ce4a53b 100644 (file)
@@ -379,7 +379,7 @@ worker_main(int fd)
             /* Main process closed the IPC socket.  Exit cleanly. */
             break;
         } else if (error != EAGAIN) {
-            VLOG_FATAL("RPC receive failed (%s)", strerror(error));
+            VLOG_FATAL("RPC receive failed (%s)", ovs_retval_to_string(error));
         }
 
         poll_fd_wait(server_sock, POLLIN);
index f89fc17..a14f968 100644 (file)
@@ -227,6 +227,7 @@ ovsdb/remote-passive.man:
 vswitchd/ovs-vswitchd.8: \
        vswitchd/ovs-vswitchd.8.in \
        lib/common.man \
+       lib/coverage-unixctl.man \
        lib/daemon.man \
        lib/leak-checker.man \
        lib/memory-unixctl.man \
@@ -241,6 +242,7 @@ vswitchd/ovs-vswitchd.8: \
        ovsdb/remote-passive.man
 vswitchd/ovs-vswitchd.8.in:
 lib/common.man:
+lib/coverage-unixctl.man:
 lib/daemon.man:
 lib/leak-checker.man:
 lib/memory-unixctl.man:
index b94c337..b8cdfa5 100644 (file)
@@ -60,7 +60,7 @@ struct ofconn {
 /* State that should be cleared from one connection to the next. */
 
     /* OpenFlow state. */
-    enum nx_role role;           /* Role. */
+    enum ofp12_controller_role role;           /* Role. */
     enum ofputil_protocol protocol; /* Current protocol variant. */
     enum nx_packet_in_format packet_in_format; /* OFPT_PACKET_IN format. */
 
@@ -777,12 +777,13 @@ static int
 snoop_preference(const struct ofconn *ofconn)
 {
     switch (ofconn->role) {
-    case NX_ROLE_MASTER:
+    case OFPCR12_ROLE_MASTER:
         return 3;
-    case NX_ROLE_OTHER:
+    case OFPCR12_ROLE_EQUAL:
         return 2;
-    case NX_ROLE_SLAVE:
+    case OFPCR12_ROLE_SLAVE:
         return 1;
+    case OFPCR12_ROLE_NOCHANGE:
     default:
         /* Shouldn't happen. */
         return 0;
@@ -822,6 +823,17 @@ ofconn_get_type(const struct ofconn *ofconn)
     return ofconn->type;
 }
 
+/* If a master election id is defined, stores it into '*idp' and returns
+ * true.  Otherwise, stores UINT64_MAX into '*idp' and returns false. */
+bool
+ofconn_get_master_election_id(const struct ofconn *ofconn, uint64_t *idp)
+{
+    *idp = (ofconn->connmgr->master_election_id_defined
+            ? ofconn->connmgr->master_election_id
+            : UINT64_MAX);
+    return ofconn->connmgr->master_election_id_defined;
+}
+
 /* Sets the master election id.
  *
  * Returns true if successful, false if the id is stale
@@ -844,24 +856,24 @@ ofconn_set_master_election_id(struct ofconn *ofconn, uint64_t id)
 
 /* Returns the role configured for 'ofconn'.
  *
- * The default role, if no other role has been set, is NX_ROLE_OTHER. */
-enum nx_role
+ * The default role, if no other role has been set, is OFPCR12_ROLE_EQUAL. */
+enum ofp12_controller_role
 ofconn_get_role(const struct ofconn *ofconn)
 {
     return ofconn->role;
 }
 
-/* Changes 'ofconn''s role to 'role'.  If 'role' is NX_ROLE_MASTER then any
- * existing master is demoted to a slave. */
+/* Changes 'ofconn''s role to 'role'.  If 'role' is OFPCR12_ROLE_MASTER then
+ * any existing master is demoted to a slave. */
 void
-ofconn_set_role(struct ofconn *ofconn, enum nx_role role)
+ofconn_set_role(struct ofconn *ofconn, enum ofp12_controller_role role)
 {
-    if (role == NX_ROLE_MASTER) {
+    if (role == OFPCR12_ROLE_MASTER) {
         struct ofconn *other;
 
         HMAP_FOR_EACH (other, hmap_node, &ofconn->connmgr->controllers) {
-            if (other->role == NX_ROLE_MASTER) {
-                other->role = NX_ROLE_SLAVE;
+            if (other->role == OFPCR12_ROLE_MASTER) {
+                other->role = OFPCR12_ROLE_SLAVE;
             }
         }
     }
@@ -1092,7 +1104,7 @@ ofconn_flush(struct ofconn *ofconn)
     struct ofmonitor *monitor, *next_monitor;
     int i;
 
-    ofconn->role = NX_ROLE_OTHER;
+    ofconn->role = OFPCR12_ROLE_EQUAL;
     ofconn_set_protocol(ofconn, OFPUTIL_P_NONE);
     ofconn->packet_in_format = NXPIF_OPENFLOW10;
 
@@ -1177,6 +1189,7 @@ ofconn_destroy(struct ofconn *ofconn)
         hmap_remove(&ofconn->connmgr->controllers, &ofconn->hmap_node);
     }
 
+    hmap_destroy(&ofconn->monitors);
     list_remove(&ofconn->node);
     rconn_destroy(ofconn->rconn);
     rconn_packet_counter_destroy(ofconn->packet_in_counter);
@@ -1307,7 +1320,7 @@ ofconn_receives_async_msg(const struct ofconn *ofconn,
         return false;
     }
 
-    async_config = (ofconn->role == NX_ROLE_SLAVE
+    async_config = (ofconn->role == OFPCR12_ROLE_SLAVE
                     ? ofconn->slave_async_config
                     : ofconn->master_async_config);
     if (!(async_config[type] & (1u << reason))) {
index 6ce413e..48b8119 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -96,9 +96,10 @@ void connmgr_get_snoops(const struct connmgr *, struct sset *snoops);
 /* Individual connections to OpenFlow controllers. */
 enum ofconn_type ofconn_get_type(const struct ofconn *);
 
+bool ofconn_get_master_election_id(const struct ofconn *, uint64_t *idp);
 bool ofconn_set_master_election_id(struct ofconn *, uint64_t);
-enum nx_role ofconn_get_role(const struct ofconn *);
-void ofconn_set_role(struct ofconn *, enum nx_role);
+enum ofp12_controller_role ofconn_get_role(const struct ofconn *);
+void ofconn_set_role(struct ofconn *, enum ofp12_controller_role);
 
 enum ofputil_protocol ofconn_get_protocol(const struct ofconn *);
 void ofconn_set_protocol(struct ofconn *, enum ofputil_protocol);
index 3b98005..1a08fcc 100644 (file)
@@ -464,7 +464,7 @@ in_band_create(struct ofproto *ofproto, const char *local_name,
     int error;
 
     *in_bandp = NULL;
-    error = netdev_open(local_name, "system", &local_netdev);
+    error = netdev_open(local_name, "internal", &local_netdev);
     if (error) {
         VLOG_ERR("failed to initialize in-band control: cannot open "
                  "datapath local port %s (%s)", local_name, strerror(error));
index efd47b3..47830c1 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <errno.h>
 
-#include "autopath.h"
 #include "bond.h"
 #include "bundle.h"
 #include "byte-order.h"
@@ -79,6 +78,7 @@ BUILD_ASSERT_DECL(N_TABLES >= 2 && N_TABLES <= 255);
 struct ofport_dpif;
 struct ofproto_dpif;
 struct flow_miss;
+struct facet;
 
 struct rule_dpif {
     struct rule up;
@@ -119,8 +119,7 @@ static struct rule_dpif *rule_dpif_miss_rule(struct ofproto_dpif *ofproto,
 
 static void rule_credit_stats(struct rule_dpif *,
                               const struct dpif_flow_stats *);
-static void flow_push_stats(struct rule_dpif *, const struct flow *,
-                            const struct dpif_flow_stats *);
+static void flow_push_stats(struct facet *, const struct dpif_flow_stats *);
 static tag_type rule_calculate_tag(const struct flow *,
                                    const struct minimask *, uint32_t basis);
 static void rule_invalidate(const struct rule_dpif *);
@@ -217,6 +216,11 @@ struct action_xlate_ctx {
      * this flow when actions change header fields. */
     struct flow flow;
 
+    /* stack for the push and pop actions.
+     * Each stack element is of the type "union mf_subvalue". */
+    struct ofpbuf stack;
+    union mf_subvalue init_stack[1024 / sizeof(union mf_subvalue)];
+
     /* The packet corresponding to 'flow', or a null pointer if we are
      * revalidating without a packet to refer to. */
     const struct ofpbuf *packet;
@@ -284,12 +288,30 @@ struct action_xlate_ctx {
     uint32_t sflow_odp_port;    /* Output port for composing sFlow action. */
     uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */
     bool exit;                  /* No further actions should be processed. */
-    struct flow orig_flow;      /* Copy of original flow. */
+};
+
+/* Initial values of fields of the packet that may be changed during
+ * flow processing and needed later. */
+struct initial_vals {
+   /* This is the value of vlan_tci in the packet as actually received from
+    * dpif.  This is the same as the facet's flow.vlan_tci unless the packet
+    * was received via a VLAN splinter.  In that case, this value is 0
+    * (because the packet as actually received from the dpif had no 802.1Q
+    * tag) but the facet's flow.vlan_tci is set to the VLAN that the splinter
+    * represents.
+    *
+    * This member should be removed when the VLAN splinters feature is no
+    * longer needed. */
+    ovs_be16 vlan_tci;
+
+    /* If received on a tunnel, the IP TOS value of the tunnel. */
+    uint8_t tunnel_ip_tos;
 };
 
 static void action_xlate_ctx_init(struct action_xlate_ctx *,
                                   struct ofproto_dpif *, const struct flow *,
-                                  ovs_be16 initial_tci, struct rule_dpif *,
+                                  const struct initial_vals *initial_vals,
+                                  struct rule_dpif *,
                                   uint8_t tcp_flags, const struct ofpbuf *);
 static void xlate_actions(struct action_xlate_ctx *,
                           const struct ofpact *ofpacts, size_t ofpacts_len,
@@ -343,16 +365,12 @@ struct subfacet {
     struct list list_node;      /* In struct facet's 'facets' list. */
     struct facet *facet;        /* Owning facet. */
 
-    /* Key.
-     *
-     * To save memory in the common case, 'key' is NULL if 'key_fitness' is
-     * ODP_FIT_PERFECT, that is, odp_flow_key_from_flow() can accurately
-     * regenerate the ODP flow key from ->facet->flow. */
     enum odp_key_fitness key_fitness;
     struct nlattr *key;
     int key_len;
 
     long long int used;         /* Time last used; time created if not used. */
+    long long int created;      /* Time created. */
 
     uint64_t dp_packet_count;   /* Last known packet count in the datapath. */
     uint64_t dp_byte_count;     /* Last known byte count in the datapath. */
@@ -367,10 +385,8 @@ struct subfacet {
     enum slow_path_reason slow; /* 0 if fast path may be used. */
     enum subfacet_path path;    /* Installed in datapath? */
 
-    /* This value is normally the same as ->facet->flow.vlan_tci.  Only VLAN
-     * splinters can cause it to differ.  This value should be removed when
-     * the VLAN splinters feature is no longer needed.  */
-    ovs_be16 initial_tci;       /* Initial VLAN TCI value. */
+    /* Initial values of the packet that may be needed later. */
+    struct initial_vals initial_vals;
 
     /* Datapath port the packet arrived on.  This is needed to remove
      * flows for ports that are no longer part of the bridge.  Since the
@@ -386,14 +402,11 @@ static struct subfacet *subfacet_create(struct facet *, struct flow_miss *miss,
                                         long long int now);
 static struct subfacet *subfacet_find(struct ofproto_dpif *,
                                       const struct nlattr *key, size_t key_len,
-                                      uint32_t key_hash,
-                                      const struct flow *flow);
+                                      uint32_t key_hash);
 static void subfacet_destroy(struct subfacet *);
 static void subfacet_destroy__(struct subfacet *);
 static void subfacet_destroy_batch(struct ofproto_dpif *,
                                    struct subfacet **, int n);
-static void subfacet_get_key(struct subfacet *, struct odputil_keybuf *,
-                             struct ofpbuf *key);
 static void subfacet_reset_dp_stats(struct subfacet *,
                                     struct dpif_flow_stats *);
 static void subfacet_update_time(struct subfacet *, long long int used);
@@ -475,8 +488,12 @@ struct facet {
 
     /* Storage for a single subfacet, to reduce malloc() time and space
      * overhead.  (A facet always has at least one subfacet and in the common
-     * case has exactly one subfacet.) */
+     * case has exactly one subfacet.  However, 'one_subfacet' may not
+     * always be valid, since it could have been removed after newer
+     * subfacets were pushed onto the 'subfacets' list.) */
     struct subfacet one_subfacet;
+
+    long long int learn_rl;      /* Rate limiter for facet_learn(). */
 };
 
 static struct facet *facet_create(struct rule_dpif *,
@@ -498,6 +515,9 @@ static void facet_reset_counters(struct facet *);
 static void facet_push_stats(struct facet *);
 static void facet_learn(struct facet *);
 static void facet_account(struct facet *);
+static void push_all_stats(void);
+
+static struct subfacet *facet_get_subfacet(struct facet *);
 
 static bool facet_is_controller_flow(struct facet *);
 
@@ -510,7 +530,6 @@ struct ofport_dpif {
     struct list bundle_node;    /* In struct ofbundle's "ports" list. */
     struct cfm *cfm;            /* Connectivity Fault Management, if any. */
     tag_type tag;               /* Tag associated with this port. */
-    uint32_t bond_stable_id;    /* stable_id to use as bond slave, or 0. */
     bool may_enable;            /* May be enabled in bonds. */
     long long int carrier_seq;  /* Carrier status changes. */
     struct tnl_port *tnl_port;  /* Tunnel handle, or null. */
@@ -579,6 +598,7 @@ static void port_run_fast(struct ofport_dpif *);
 static void port_wait(struct ofport_dpif *);
 static int set_cfm(struct ofport *, const struct cfm_settings *);
 static void ofport_clear_priorities(struct ofport_dpif *);
+static void run_fast_rl(void);
 
 struct dpif_completion {
     struct list list_node;
@@ -634,7 +654,7 @@ struct dpif_backer {
     struct timer next_expiration;
     struct hmap odp_to_ofport_map; /* ODP port to ofport mapping. */
 
-    struct sset tnl_backers;       /* Set of dpif ports backing tunnels. */
+    struct simap tnl_backers;      /* Set of dpif ports backing tunnels. */
 
     /* Facet revalidation flags applying to facets which use this backer. */
     enum revalidate_reason need_revalidate; /* Revalidate every facet. */
@@ -650,6 +670,16 @@ static void drop_key_clear(struct dpif_backer *);
 static struct ofport_dpif *
 odp_port_to_ofport(const struct dpif_backer *, uint32_t odp_port);
 
+static void dpif_stats_update_hit_count(struct ofproto_dpif *ofproto,
+                                        uint64_t delta);
+struct avg_subfacet_rates {
+    double add_rate;     /* Moving average of new flows created per minute. */
+    double del_rate;     /* Moving average of flows deleted per minute. */
+};
+static void show_dp_rates(struct ds *ds, const char *heading,
+                          const struct avg_subfacet_rates *rates);
+static void exp_mavg(double *avg, int base, double new);
+
 struct ofproto_dpif {
     struct hmap_node all_ofproto_dpifs_node; /* In 'all_ofproto_dpifs'. */
     struct ofproto up;
@@ -675,6 +705,7 @@ struct ofproto_dpif {
     struct hmap facets;
     struct hmap subfacets;
     struct governor *governor;
+    long long int consistency_rl;
 
     /* Revalidation. */
     struct table_dpif tables[N_TABLES];
@@ -699,7 +730,52 @@ struct ofproto_dpif {
     struct sset ghost_ports;       /* Ports with no datapath port. */
     struct sset port_poll_set;     /* Queued names for port_poll() reply. */
     int port_poll_errno;           /* Last errno for port_poll() reply. */
+
+    /* Per ofproto's dpif stats. */
+    uint64_t n_hit;
+    uint64_t n_missed;
+
+    /* Subfacet statistics.
+     *
+     * These keep track of the total number of subfacets added and deleted and
+     * flow life span.  They are useful for computing the flow rates stats
+     * exposed via "ovs-appctl dpif/show".  The goal is to learn about
+     * traffic patterns in ways that we can use later to improve Open vSwitch
+     * performance in new situations.  */
+    long long int created;         /* Time when it is created. */
+    unsigned int max_n_subfacet;   /* Maximum number of flows */
+
+    /* The average number of subfacets... */
+    struct avg_subfacet_rates hourly; /* ...over the last hour. */
+    struct avg_subfacet_rates daily;  /* ...over the last day. */
+    long long int last_minute;        /* Last time 'hourly' was updated. */
+
+    /* Number of subfacets added or deleted since 'last_minute'. */
+    unsigned int subfacet_add_count;
+    unsigned int subfacet_del_count;
+
+    /* Number of subfacets added or deleted from 'created' to 'last_minute.' */
+    unsigned long long int total_subfacet_add_count;
+    unsigned long long int total_subfacet_del_count;
+
+    /* Sum of the number of milliseconds that each subfacet existed,
+     * over the subfacets that have been added and then later deleted. */
+    unsigned long long int total_subfacet_life_span;
+
+    /* Incremented by the number of currently existing subfacets, each
+     * time we pull statistics from the kernel. */
+    unsigned long long int total_subfacet_count;
+
+    /* Number of times we pull statistics from the kernel. */
+    unsigned long long int n_update_stats;
 };
+static unsigned long long int avg_subfacet_life_span(
+                                        const struct ofproto_dpif *);
+static double avg_subfacet_count(const struct ofproto_dpif *ofproto);
+static void update_moving_averages(struct ofproto_dpif *ofproto);
+static void dpif_stats_update_hit_count(struct ofproto_dpif *ofproto,
+                                        uint64_t delta);
+static void update_max_subfacet_count(struct ofproto_dpif *ofproto);
 
 /* Defer flow mod completion until "ovs-appctl ofproto/unclog"?  (Useful only
  * for debugging the asynchronous flow_mod implementation.) */
@@ -722,9 +798,8 @@ static struct ofport_dpif *get_ofp_port(const struct ofproto_dpif *,
 static struct ofport_dpif *get_odp_port(const struct ofproto_dpif *,
                                         uint32_t odp_port);
 static void ofproto_trace(struct ofproto_dpif *, const struct flow *,
-                          const struct ofpbuf *, ovs_be16 initial_tci,
-                          struct ds *);
-static bool may_dpif_port_del(struct ofport_dpif *);
+                          const struct ofpbuf *,
+                          const struct initial_vals *, struct ds *);
 
 /* Packet processing. */
 static void update_learning_table(struct ofproto_dpif *,
@@ -834,6 +909,7 @@ lookup_ofproto_dpif_by_port_name(const char *name)
 static int
 type_run(const char *type)
 {
+    static long long int push_timer = LLONG_MIN;
     struct dpif_backer *backer;
     char *devname;
     int error;
@@ -847,11 +923,73 @@ type_run(const char *type)
 
     dpif_run(backer->dpif);
 
+    /* The most natural place to push facet statistics is when they're pulled
+     * from the datapath.  However, when there are many flows in the datapath,
+     * this expensive operation can occur so frequently, that it reduces our
+     * ability to quickly set up flows.  To reduce the cost, we push statistics
+     * here instead. */
+    if (time_msec() > push_timer) {
+        push_timer = time_msec() + 2000;
+        push_all_stats();
+    }
+
     if (backer->need_revalidate
         || !tag_set_is_empty(&backer->revalidate_set)) {
         struct tag_set revalidate_set = backer->revalidate_set;
         bool need_revalidate = backer->need_revalidate;
         struct ofproto_dpif *ofproto;
+        struct simap_node *node;
+        struct simap tmp_backers;
+
+        /* Handle tunnel garbage collection. */
+        simap_init(&tmp_backers);
+        simap_swap(&backer->tnl_backers, &tmp_backers);
+
+        HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+            struct ofport_dpif *iter;
+
+            if (backer != ofproto->backer) {
+                continue;
+            }
+
+            HMAP_FOR_EACH (iter, up.hmap_node, &ofproto->up.ports) {
+                const char *dp_port;
+
+                if (!iter->tnl_port) {
+                    continue;
+                }
+
+                dp_port = netdev_vport_get_dpif_port(iter->up.netdev);
+                node = simap_find(&tmp_backers, dp_port);
+                if (node) {
+                    simap_put(&backer->tnl_backers, dp_port, node->data);
+                    simap_delete(&tmp_backers, node);
+                    node = simap_find(&backer->tnl_backers, dp_port);
+                } else {
+                    node = simap_find(&backer->tnl_backers, dp_port);
+                    if (!node) {
+                        uint32_t odp_port = UINT32_MAX;
+
+                        if (!dpif_port_add(backer->dpif, iter->up.netdev,
+                                           &odp_port)) {
+                            simap_put(&backer->tnl_backers, dp_port, odp_port);
+                            node = simap_find(&backer->tnl_backers, dp_port);
+                        }
+                    }
+                }
+
+                iter->odp_port = node ? node->data : OVSP_NONE;
+                if (tnl_port_reconfigure(&iter->up, iter->odp_port,
+                                         &iter->tnl_port)) {
+                    backer->need_revalidate = REV_RECONFIGURE;
+                }
+            }
+        }
+
+        SIMAP_FOR_EACH (node, &tmp_backers) {
+            dpif_port_del(backer->dpif, node->data);
+        }
+        simap_destroy(&tmp_backers);
 
         switch (backer->need_revalidate) {
         case REV_RECONFIGURE:   COVERAGE_INC(rev_reconfigure);   break;
@@ -867,21 +1005,22 @@ type_run(const char *type)
             drop_key_clear(backer);
         }
 
+        /* Clear the revalidation flags. */
+        tag_set_init(&backer->revalidate_set);
+        backer->need_revalidate = 0;
+
         HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
-            struct facet *facet;
+            struct facet *facet, *next;
 
             if (ofproto->backer != backer) {
                 continue;
             }
 
-            /* Clear the revalidation flags. */
-            tag_set_init(&backer->revalidate_set);
-            backer->need_revalidate = 0;
-
-            HMAP_FOR_EACH (facet, hmap_node, &ofproto->facets) {
+            HMAP_FOR_EACH_SAFE (facet, next, hmap_node, &ofproto->facets) {
                 if (need_revalidate
                     || tag_set_intersects(&revalidate_set, facet->tags)) {
                     facet_revalidate(facet);
+                    run_fast_rl();
                 }
             }
         }
@@ -904,7 +1043,7 @@ type_run(const char *type)
 
         HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node,
                        &all_ofproto_dpifs) {
-            if (sset_contains(&ofproto->backer->tnl_backers, devname)) {
+            if (simap_contains(&ofproto->backer->tnl_backers, devname)) {
                 goto next;
             }
         }
@@ -949,18 +1088,10 @@ type_run(const char *type)
 }
 
 static int
-type_run_fast(const char *type)
+dpif_backer_run_fast(struct dpif_backer *backer, int max_batch)
 {
-    struct dpif_backer *backer;
     unsigned int work;
 
-    backer = shash_find_data(&all_dpif_backers, type);
-    if (!backer) {
-        /* This is not necessarily a problem, since backers are only
-         * created on demand. */
-        return 0;
-    }
-
     /* Handle one or more batches of upcalls, until there's nothing left to do
      * or until we do a fixed total amount of work.
      *
@@ -971,8 +1102,8 @@ type_run_fast(const char *type)
      * optimizations can make major improvements on some benchmarks and
      * presumably for real traffic as well. */
     work = 0;
-    while (work < FLOW_MISS_MAX_BATCH) {
-        int retval = handle_upcalls(backer, FLOW_MISS_MAX_BATCH - work);
+    while (work < max_batch) {
+        int retval = handle_upcalls(backer, max_batch - work);
         if (retval <= 0) {
             return -retval;
         }
@@ -982,6 +1113,58 @@ type_run_fast(const char *type)
     return 0;
 }
 
+static int
+type_run_fast(const char *type)
+{
+    struct dpif_backer *backer;
+
+    backer = shash_find_data(&all_dpif_backers, type);
+    if (!backer) {
+        /* This is not necessarily a problem, since backers are only
+         * created on demand. */
+        return 0;
+    }
+
+    return dpif_backer_run_fast(backer, FLOW_MISS_MAX_BATCH);
+}
+
+static void
+run_fast_rl(void)
+{
+    static long long int port_rl = LLONG_MIN;
+    static unsigned int backer_rl = 0;
+
+    if (time_msec() >= port_rl) {
+        struct ofproto_dpif *ofproto;
+        struct ofport_dpif *ofport;
+
+        HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+
+            HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
+                port_run_fast(ofport);
+            }
+        }
+        port_rl = time_msec() + 200;
+    }
+
+    /* XXX: We have to be careful not to do too much work in this function.  If
+     * we call dpif_backer_run_fast() too often, or with too large a batch,
+     * performance improves signifcantly, but at a cost.  It's possible for the
+     * number of flows in the datapath to increase without bound, and for poll
+     * loops to take 10s of seconds.   The correct solution to this problem,
+     * long term, is to separate flow miss handling into it's own thread so it
+     * isn't affected by revalidations, and expirations.  Until then, this is
+     * the best we can do. */
+    if (++backer_rl >= 10) {
+        struct shash_node *node;
+
+        backer_rl = 0;
+        SHASH_FOR_EACH (node, &all_dpif_backers) {
+            dpif_backer_run_fast(node->data, 1);
+        }
+    }
+}
+
 static void
 type_wait(const char *type)
 {
@@ -1029,7 +1212,7 @@ close_dpif_backer(struct dpif_backer *backer)
     drop_key_clear(backer);
     hmap_destroy(&backer->drop_keys);
 
-    sset_destroy(&backer->tnl_backers);
+    simap_destroy(&backer->tnl_backers);
     hmap_destroy(&backer->odp_to_ofport_map);
     node = shash_find(&all_dpif_backers, backer->type);
     free(backer->type);
@@ -1106,7 +1289,7 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
     hmap_init(&backer->drop_keys);
     timer_set_duration(&backer->next_expiration, 1000);
     backer->need_revalidate = 0;
-    sset_init(&backer->tnl_backers);
+    simap_init(&backer->tnl_backers);
     tag_set_init(&backer->revalidate_set);
     *backerp = backer;
 
@@ -1177,6 +1360,7 @@ construct(struct ofproto *ofproto_)
     hmap_init(&ofproto->facets);
     hmap_init(&ofproto->subfacets);
     ofproto->governor = NULL;
+    ofproto->consistency_rl = LLONG_MIN;
 
     for (i = 0; i < N_TABLES; i++) {
         struct table_dpif *table = &ofproto->tables[i];
@@ -1225,6 +1409,22 @@ construct(struct ofproto *ofproto_)
     error = add_internal_flows(ofproto);
     ofproto->up.tables[TBL_INTERNAL].flags = OFTABLE_HIDDEN | OFTABLE_READONLY;
 
+    ofproto->n_hit = 0;
+    ofproto->n_missed = 0;
+
+    ofproto->max_n_subfacet = 0;
+    ofproto->created = time_msec();
+    ofproto->last_minute = ofproto->created;
+    memset(&ofproto->hourly, 0, sizeof ofproto->hourly);
+    memset(&ofproto->daily, 0, sizeof ofproto->daily);
+    ofproto->subfacet_add_count = 0;
+    ofproto->subfacet_del_count = 0;
+    ofproto->total_subfacet_add_count = 0;
+    ofproto->total_subfacet_del_count = 0;
+    ofproto->total_subfacet_life_span = 0;
+    ofproto->total_subfacet_count = 0;
+    ofproto->n_update_stats = 0;
+
     return error;
 }
 
@@ -1398,10 +1598,13 @@ run(struct ofproto *ofproto_)
     mac_learning_run(ofproto->ml, &ofproto->backer->revalidate_set);
 
     /* Check the consistency of a random facet, to aid debugging. */
-    if (!hmap_is_empty(&ofproto->facets)
+    if (time_msec() >= ofproto->consistency_rl
+        && !hmap_is_empty(&ofproto->facets)
         && !ofproto->backer->need_revalidate) {
         struct facet *facet;
 
+        ofproto->consistency_rl = time_msec() + 250;
+
         facet = CONTAINER_OF(hmap_random_node(&ofproto->facets),
                              struct facet, hmap_node);
         if (!tag_set_intersects(&ofproto->backer->revalidate_set,
@@ -1601,12 +1804,14 @@ port_construct(struct ofport *port_)
         if (odp_port_to_ofp_port(ofproto, port->odp_port) != OFPP_NONE) {
             VLOG_ERR("port %s already has an OpenFlow port number",
                      dpif_port.name);
+            dpif_port_destroy(&dpif_port);
             return EBUSY;
         }
 
         hmap_insert(&ofproto->backer->odp_to_ofport_map, &port->odp_port_node,
                     hash_int(port->odp_port, 0));
     }
+    dpif_port_destroy(&dpif_port);
 
     if (ofproto->sflow) {
         dpif_sflow_add_port(ofproto->sflow, port_, port->odp_port);
@@ -1623,14 +1828,15 @@ port_destruct(struct ofport *port_)
     const char *dp_port_name = netdev_vport_get_dpif_port(port->up.netdev);
     const char *devname = netdev_get_name(port->up.netdev);
 
-    if (dpif_port_exists(ofproto->backer->dpif, dp_port_name)
-        && may_dpif_port_del(port)) {
+    if (dpif_port_exists(ofproto->backer->dpif, dp_port_name)) {
         /* The underlying device is still there, so delete it.  This
          * happens when the ofproto is being destroyed, since the caller
          * assumes that removal of attached ports will happen as part of
          * destruction. */
-        dpif_port_del(ofproto->backer->dpif, port->odp_port);
-        sset_find_and_delete(&ofproto->backer->tnl_backers, dp_port_name);
+        if (!port->tnl_port) {
+            dpif_port_del(ofproto->backer->dpif, port->odp_port);
+        }
+        ofproto->backer->need_revalidate = REV_RECONFIGURE;
     }
 
     if (port->odp_port != OVSP_NONE && !port->tnl_port) {
@@ -1735,43 +1941,22 @@ set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
     return error;
 }
 
-static int
-get_cfm_fault(const struct ofport *ofport_)
-{
-    struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-
-    return ofport->cfm ? cfm_get_fault(ofport->cfm) : -1;
-}
-
-static int
-get_cfm_opup(const struct ofport *ofport_)
-{
-    struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-
-    return ofport->cfm ? cfm_get_opup(ofport->cfm) : -1;
-}
-
-static int
-get_cfm_remote_mpids(const struct ofport *ofport_, const uint64_t **rmps,
-                     size_t *n_rmps)
+static bool
+get_cfm_status(const struct ofport *ofport_,
+               struct ofproto_cfm_status *status)
 {
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
 
     if (ofport->cfm) {
-        cfm_get_remote_mpids(ofport->cfm, rmps, n_rmps);
-        return 0;
+        status->faults = cfm_get_fault(ofport->cfm);
+        status->remote_opstate = cfm_get_opup(ofport->cfm);
+        status->health = cfm_get_health(ofport->cfm);
+        cfm_get_remote_mpids(ofport->cfm, &status->rmps, &status->n_rmps);
+        return true;
     } else {
-        return -1;
+        return false;
     }
 }
-
-static int
-get_cfm_health(const struct ofport *ofport_)
-{
-    struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
-
-    return ofport->cfm ? cfm_get_health(ofport->cfm) : -1;
-}
 \f
 /* Spanning Tree. */
 
@@ -2213,8 +2398,7 @@ bundle_del_port(struct ofport_dpif *port)
 
 static bool
 bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port,
-                struct lacp_slave_settings *lacp,
-                uint32_t bond_stable_id)
+                struct lacp_slave_settings *lacp)
 {
     struct ofport_dpif *port;
 
@@ -2241,8 +2425,6 @@ bundle_add_port(struct ofbundle *bundle, uint32_t ofp_port,
         lacp_slave_register(bundle->lacp, port, lacp);
     }
 
-    port->bond_stable_id = bond_stable_id;
-
     return true;
 }
 
@@ -2350,8 +2532,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
     ok = true;
     for (i = 0; i < s->n_slaves; i++) {
         if (!bundle_add_port(bundle, s->slaves[i],
-                             s->lacp ? &s->lacp_slaves[i] : NULL,
-                             s->bond_stable_ids ? s->bond_stable_ids[i] : 0)) {
+                             s->lacp ? &s->lacp_slaves[i] : NULL)) {
             ok = false;
         }
     }
@@ -2451,8 +2632,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
         }
 
         LIST_FOR_EACH (port, bundle_node, &bundle->ports) {
-            bond_slave_register(bundle->bond, port, port->bond_stable_id,
-                                port->up.netdev);
+            bond_slave_register(bundle->bond, port, port->up.netdev);
         }
     } else {
         bond_destroy(bundle->bond);
@@ -2815,6 +2995,8 @@ mirror_get_stats(struct ofproto *ofproto_, void *aux,
         return 0;
     }
 
+    push_all_stats();
+
     *packets = mirror->packet_count;
     *bytes = mirror->byte_count;
 
@@ -3020,58 +3202,26 @@ port_add(struct ofproto *ofproto_, struct netdev *netdev)
     }
 
     if (!dpif_port_exists(ofproto->backer->dpif, dp_port_name)) {
-        int error = dpif_port_add(ofproto->backer->dpif, netdev, NULL);
+        uint32_t port_no = UINT32_MAX;
+        int error;
+
+        error = dpif_port_add(ofproto->backer->dpif, netdev, &port_no);
         if (error) {
             return error;
         }
+        if (netdev_get_tunnel_config(netdev)) {
+            simap_put(&ofproto->backer->tnl_backers, dp_port_name, port_no);
+        }
     }
 
     if (netdev_get_tunnel_config(netdev)) {
         sset_add(&ofproto->ghost_ports, devname);
-        sset_add(&ofproto->backer->tnl_backers, dp_port_name);
     } else {
         sset_add(&ofproto->ports, devname);
     }
     return 0;
 }
 
-/* Returns true if the odp_port backing 'ofport' may be deleted from the
- * datapath. In most cases, this function simply returns true. However, for
- * tunnels it's possible that multiple ofports use the same odp_port, in which
- * case we need to keep the odp_port backer around until the last ofport is
- * deleted. */
-static bool
-may_dpif_port_del(struct ofport_dpif *ofport)
-{
-    struct dpif_backer *backer = ofproto_dpif_cast(ofport->up.ofproto)->backer;
-    struct ofproto_dpif *ofproto_iter;
-
-    if (!ofport->tnl_port) {
-        return true;
-    }
-
-    HMAP_FOR_EACH (ofproto_iter, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
-        struct ofport_dpif *iter;
-
-        if (backer != ofproto_iter->backer) {
-            continue;
-        }
-
-        HMAP_FOR_EACH (iter, up.hmap_node, &ofproto_iter->up.ports) {
-            if (ofport == iter) {
-                continue;
-            }
-
-            if (!strcmp(netdev_vport_get_dpif_port(ofport->up.netdev),
-                        netdev_vport_get_dpif_port(iter->up.netdev))) {
-                return false;
-            }
-        }
-    }
-
-    return true;
-}
-
 static int
 port_del(struct ofproto *ofproto_, uint16_t ofp_port)
 {
@@ -3085,17 +3235,14 @@ port_del(struct ofproto *ofproto_, uint16_t ofp_port)
 
     sset_find_and_delete(&ofproto->ghost_ports,
                          netdev_get_name(ofport->up.netdev));
-    if (may_dpif_port_del(ofport)) {
+    ofproto->backer->need_revalidate = REV_RECONFIGURE;
+    if (!ofport->tnl_port) {
         error = dpif_port_del(ofproto->backer->dpif, ofport->odp_port);
         if (!error) {
-            const char *dpif_port;
-
             /* The caller is going to close ofport->up.netdev.  If this is a
              * bonded port, then the bond is using that netdev, so remove it
              * from the bond.  The client will need to reconfigure everything
              * after deleting ports, so then the slave will get re-added. */
-            dpif_port = netdev_vport_get_dpif_port(ofport->up.netdev);
-            sset_find_and_delete(&ofproto->backer->tnl_backers, dpif_port);
             bundle_remove(&ofport->up);
         }
     }
@@ -3108,6 +3255,8 @@ port_get_stats(const struct ofport *ofport_, struct netdev_stats *stats)
     struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
     int error;
 
+    push_all_stats();
+
     error = netdev_get_stats(ofport->up.netdev, stats);
 
     if (!error && ofport_->ofp_port == OFPP_LOCAL) {
@@ -3163,6 +3312,9 @@ struct port_dump_state {
     uint32_t bucket;
     uint32_t offset;
     bool ghost;
+
+    struct ofproto_port port;
+    bool has_port;
 };
 
 static int
@@ -3181,12 +3333,20 @@ port_dump_next(const struct ofproto *ofproto_, void *state_,
     const struct sset *sset;
     struct sset_node *node;
 
+    if (state->has_port) {
+        ofproto_port_destroy(&state->port);
+        state->has_port = false;
+    }
     sset = state->ghost ? &ofproto->ghost_ports : &ofproto->ports;
     while ((node = sset_at_position(sset, &state->bucket, &state->offset))) {
         int error;
 
-        error = port_query_by_name(ofproto_, node->name, port);
-        if (error != ENODEV) {
+        error = port_query_by_name(ofproto_, node->name, &state->port);
+        if (!error) {
+            *port = state->port;
+            state->has_port = true;
+            return 0;
+        } else if (error != ENODEV) {
             return error;
         }
     }
@@ -3206,6 +3366,9 @@ port_dump_done(const struct ofproto *ofproto_ OVS_UNUSED, void *state_)
 {
     struct port_dump_state *state = state_;
 
+    if (state->has_port) {
+        ofproto_port_destroy(&state->port);
+    }
     free(state);
     return 0;
 }
@@ -3263,7 +3426,7 @@ struct flow_miss {
     enum odp_key_fitness key_fitness;
     const struct nlattr *key;
     size_t key_len;
-    ovs_be16 initial_tci;
+    struct initial_vals initial_vals;
     struct list packets;
     enum dpif_upcall_type upcall_type;
     uint32_t odp_in_port;
@@ -3271,7 +3434,6 @@ struct flow_miss {
 
 struct flow_miss_op {
     struct dpif_op dpif_op;
-    struct subfacet *subfacet;  /* Subfacet  */
     void *garbage;              /* Pointer to pass to free(), NULL if none. */
     uint64_t stub[1024 / 8];    /* Temporary buffer. */
 };
@@ -3302,15 +3464,11 @@ send_packet_in_miss(struct ofproto_dpif *ofproto, const struct ofpbuf *packet,
 
 static enum slow_path_reason
 process_special(struct ofproto_dpif *ofproto, const struct flow *flow,
-                const struct ofpbuf *packet)
+                const struct ofport_dpif *ofport, const struct ofpbuf *packet)
 {
-    struct ofport_dpif *ofport = get_ofp_port(ofproto, flow->in_port);
-
     if (!ofport) {
         return 0;
-    }
-
-    if (ofport->cfm && cfm_should_process_flow(ofport->cfm, flow)) {
+    } else if (ofport->cfm && cfm_should_process_flow(ofport->cfm, flow)) {
         if (packet) {
             cfm_process_heartbeat(ofport->cfm, packet);
         }
@@ -3326,17 +3484,19 @@ process_special(struct ofproto_dpif *ofproto, const struct flow *flow,
             stp_process_packet(ofport, packet);
         }
         return SLOW_STP;
+    } else {
+        return 0;
     }
-    return 0;
 }
 
 static struct flow_miss *
-flow_miss_find(struct hmap *todo, const struct flow *flow, uint32_t hash)
+flow_miss_find(struct hmap *todo, const struct ofproto_dpif *ofproto,
+               const struct flow *flow, uint32_t hash)
 {
     struct flow_miss *miss;
 
     HMAP_FOR_EACH_WITH_HASH (miss, hmap_node, hash, todo) {
-        if (flow_equal(&miss->flow, flow)) {
+        if (miss->ofproto == ofproto && flow_equal(&miss->flow, flow)) {
             return miss;
         }
     }
@@ -3353,7 +3513,7 @@ static void
 init_flow_miss_execute_op(struct flow_miss *miss, struct ofpbuf *packet,
                           struct flow_miss_op *op)
 {
-    if (miss->flow.vlan_tci != miss->initial_tci) {
+    if (miss->flow.vlan_tci != miss->initial_vals.vlan_tci) {
         /* This packet was received on a VLAN splinter port.  We
          * added a VLAN to the packet to make the packet resemble
          * the flow, but the actions were composed assuming that
@@ -3363,7 +3523,6 @@ init_flow_miss_execute_op(struct flow_miss *miss, struct ofpbuf *packet,
         eth_pop_vlan(packet);
     }
 
-    op->subfacet = NULL;
     op->garbage = NULL;
     op->dpif_op.type = DPIF_OP_EXECUTE;
     op->dpif_op.u.execute.key = miss->key;
@@ -3446,8 +3605,8 @@ handle_flow_miss_without_facet(struct flow_miss *miss,
         dpif_flow_stats_extract(&miss->flow, packet, now, &stats);
         rule_credit_stats(rule, &stats);
 
-        action_xlate_ctx_init(&ctx, ofproto, &miss->flow, miss->initial_tci,
-                              rule, 0, packet);
+        action_xlate_ctx_init(&ctx, ofproto, &miss->flow,
+                              &miss->initial_vals, rule, 0, packet);
         ctx.resubmit_stats = &stats;
         xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len,
                       &odp_actions);
@@ -3507,7 +3666,6 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
             struct dpif_execute *execute = &op->dpif_op.u.execute;
 
             init_flow_miss_execute_op(miss, packet, op);
-            op->subfacet = subfacet;
             if (!subfacet->slow) {
                 execute->actions = subfacet->actions;
                 execute->actions_len = subfacet->actions_len;
@@ -3529,7 +3687,8 @@ handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
         struct flow_miss_op *op = &ops[(*n_ops)++];
         struct dpif_flow_put *put = &op->dpif_op.u.flow_put;
 
-        op->subfacet = subfacet;
+        subfacet->path = want_path;
+
         op->garbage = NULL;
         op->dpif_op.type = DPIF_OP_FLOW_PUT;
         put->flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
@@ -3637,10 +3796,12 @@ drop_key_clear(struct dpif_backer *backer)
  * flow->vlan_tci correctly for the VLAN of the VLAN splinter port, and pushes
  * a VLAN header onto 'packet' (if it is nonnull).
  *
- * Optionally, if nonnull, sets '*initial_tci' to the VLAN TCI with which the
- * packet was really received, that is, the actual VLAN TCI extracted by
- * odp_flow_key_to_flow().  (This differs from the value returned in
- * flow->vlan_tci only for packets received on VLAN splinters.)
+ * Optionally, if 'initial_vals' is nonnull, sets 'initial_vals->vlan_tci'
+ * to the VLAN TCI with which the packet was really received, that is, the
+ * actual VLAN TCI extracted by odp_flow_key_to_flow().  (This differs from
+ * the value returned in flow->vlan_tci only for packets received on
+ * VLAN splinters.)  Also, if received on an IP tunnel, sets
+ * 'initial_vals->tunnel_ip_tos' to the tunnel's IP TOS.
  *
  * Similarly, this function also includes some logic to help with tunnels.  It
  * may modify 'flow' as necessary to make the tunneling implementation
@@ -3653,7 +3814,7 @@ ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet,
                 const struct nlattr *key, size_t key_len,
                 struct flow *flow, enum odp_key_fitness *fitnessp,
                 struct ofproto_dpif **ofproto, uint32_t *odp_in_port,
-                ovs_be16 *initial_tci)
+                struct initial_vals *initial_vals)
 {
     const struct ofport_dpif *port;
     enum odp_key_fitness fitness;
@@ -3665,8 +3826,9 @@ ofproto_receive(const struct dpif_backer *backer, struct ofpbuf *packet,
         goto exit;
     }
 
-    if (initial_tci) {
-        *initial_tci = flow->vlan_tci;
+    if (initial_vals) {
+        initial_vals->vlan_tci = flow->vlan_tci;
+        initial_vals->tunnel_ip_tos = flow->tunnel.ip_tos;
     }
 
     if (odp_in_port) {
@@ -3770,7 +3932,7 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
 
         error = ofproto_receive(backer, upcall->packet, upcall->key,
                                 upcall->key_len, &flow, &miss->key_fitness,
-                                &ofproto, &odp_in_port, &miss->initial_tci);
+                                &ofproto, &odp_in_port, &miss->initial_vals);
         if (error == ENODEV) {
             struct drop_key *drop_key;
 
@@ -3799,12 +3961,14 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
         if (error) {
             continue;
         }
+
+        ofproto->n_missed++;
         flow_extract(upcall->packet, flow.skb_priority, flow.skb_mark,
                      &flow.tunnel, flow.in_port, &miss->flow);
 
         /* Add other packets to a to-do list. */
         hash = flow_hash(&miss->flow, 0);
-        existing_miss = flow_miss_find(&todo, &miss->flow, hash);
+        existing_miss = flow_miss_find(&todo, ofproto, &miss->flow, hash);
         if (!existing_miss) {
             hmap_insert(&todo, &miss->hmap_node, hash);
             miss->ofproto = ofproto;
@@ -3835,25 +3999,9 @@ handle_miss_upcalls(struct dpif_backer *backer, struct dpif_upcall *upcalls,
     }
     dpif_operate(backer->dpif, dpif_ops, n_ops);
 
-    /* Free memory and update facets. */
+    /* Free memory. */
     for (i = 0; i < n_ops; i++) {
-        struct flow_miss_op *op = &flow_miss_ops[i];
-
-        switch (op->dpif_op.type) {
-        case DPIF_OP_EXECUTE:
-            break;
-
-        case DPIF_OP_FLOW_PUT:
-            if (!op->dpif_op.error) {
-                op->subfacet->path = subfacet_want_path(op->subfacet->slow);
-            }
-            break;
-
-        case DPIF_OP_FLOW_DEL:
-            NOT_REACHED();
-        }
-
-        free(op->garbage);
+        free(flow_miss_ops[i].garbage);
     }
     hmap_destroy(&todo);
 }
@@ -3878,7 +4026,16 @@ classify_upcall(const struct dpif_upcall *upcall)
     }
 
     /* "action" upcalls need a closer look. */
-    memcpy(&cookie, &upcall->userdata, sizeof(cookie));
+    if (!upcall->userdata) {
+        VLOG_WARN_RL(&rl, "action upcall missing cookie");
+        return BAD_UPCALL;
+    }
+    if (nl_attr_get_size(upcall->userdata) != sizeof(cookie)) {
+        VLOG_WARN_RL(&rl, "action upcall cookie has unexpected size %zu",
+                     nl_attr_get_size(upcall->userdata));
+        return BAD_UPCALL;
+    }
+    memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie));
     switch (cookie.type) {
     case USER_ACTION_COOKIE_SFLOW:
         return SFLOW_UPCALL;
@@ -3888,7 +4045,8 @@ classify_upcall(const struct dpif_upcall *upcall)
 
     case USER_ACTION_COOKIE_UNSPEC:
     default:
-        VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64, upcall->userdata);
+        VLOG_WARN_RL(&rl, "invalid user cookie : 0x%"PRIx64,
+                     nl_attr_get_u64(upcall->userdata));
         return BAD_UPCALL;
     }
 }
@@ -3908,7 +4066,7 @@ handle_sflow_upcall(struct dpif_backer *backer,
         return;
     }
 
-    memcpy(&cookie, &upcall->userdata, sizeof(cookie));
+    memcpy(&cookie, nl_attr_get(upcall->userdata), sizeof(cookie));
     dpif_sflow_received(ofproto->sflow, upcall->packet, &flow,
                         odp_in_port, &cookie);
 }
@@ -3999,6 +4157,9 @@ expire(struct dpif_backer *backer)
             continue;
         }
 
+        /* Keep track of the max number of flows per ofproto_dpif. */
+        update_max_subfacet_count(ofproto);
+
         /* Expire subfacets that have been idle too long. */
         dp_max_idle = subfacet_max_idle(ofproto);
         expire_subfacets(ofproto, dp_max_idle);
@@ -4060,7 +4221,6 @@ update_subfacet_stats(struct subfacet *subfacet,
         facet_account(facet);
         facet->accounted_bytes = facet->byte_count;
     }
-    facet_push_stats(facet);
 }
 
 /* 'key' with length 'key_len' bytes is a flow in 'dpif' that we know nothing
@@ -4092,6 +4252,11 @@ delete_unexpected_flow(struct ofproto_dpif *ofproto,
  * avoided by calling update_stats() whenever rules are created or
  * deleted.  However, the performance impact of making so many calls to the
  * datapath do not justify the benefit of having perfectly accurate statistics.
+ *
+ * In addition, this function maintains per ofproto flow hit counts. The patch
+ * port is not treated specially. e.g. A packet ingress from br0 patched into
+ * br1 will increase the hit count of br0 by 1, however, does not affect
+ * the hit or miss counts of br1.
  */
 static void
 update_stats(struct dpif_backer *backer)
@@ -4114,15 +4279,25 @@ update_stats(struct dpif_backer *backer)
             continue;
         }
 
+        ofproto->total_subfacet_count += hmap_count(&ofproto->subfacets);
+        ofproto->n_update_stats++;
+        update_moving_averages(ofproto);
+
         ofport = get_ofp_port(ofproto, flow.in_port);
         if (ofport && ofport->tnl_port) {
             netdev_vport_inc_rx(ofport->up.netdev, stats);
         }
 
         key_hash = odp_flow_key_hash(key, key_len);
-        subfacet = subfacet_find(ofproto, key, key_len, key_hash, &flow);
+        subfacet = subfacet_find(ofproto, key, key_len, key_hash);
         switch (subfacet ? subfacet->path : SF_NOT_INSTALLED) {
         case SF_FAST_PATH:
+            /* Update ofproto_dpif's hit count. */
+            if (stats->n_packets > subfacet->dp_packet_count) {
+                uint64_t delta = stats->n_packets - subfacet->dp_packet_count;
+                dpif_stats_update_hit_count(ofproto, delta);
+            }
+
             update_subfacet_stats(subfacet, stats);
             break;
 
@@ -4135,6 +4310,7 @@ update_stats(struct dpif_backer *backer)
             delete_unexpected_flow(ofproto, key, key_len);
             break;
         }
+        run_fast_rl();
     }
     dpif_flow_dump_done(&dump);
 }
@@ -4333,6 +4509,8 @@ facet_create(struct rule_dpif *rule, const struct flow *flow, uint32_t hash)
     netflow_flow_init(&facet->nf_flow);
     netflow_flow_update_time(ofproto->netflow, &facet->nf_flow, facet->used);
 
+    facet->learn_rl = time_msec() + 500;
+
     return facet;
 }
 
@@ -4405,8 +4583,17 @@ static void
 facet_learn(struct facet *facet)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
+    struct subfacet *subfacet= CONTAINER_OF(list_front(&facet->subfacets),
+                                            struct subfacet, list_node);
+    long long int now = time_msec();
     struct action_xlate_ctx ctx;
 
+    if (!facet->has_fin_timeout && now < facet->learn_rl) {
+        return;
+    }
+
+    facet->learn_rl = now + 500;
+
     if (!facet->has_learn
         && !facet->has_normal
         && (!facet->has_fin_timeout
@@ -4415,7 +4602,7 @@ facet_learn(struct facet *facet)
     }
 
     action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
-                          facet->flow.vlan_tci,
+                          &subfacet->initial_vals,
                           facet->rule, facet->tcp_flags, NULL);
     ctx.may_learn = true;
     xlate_actions_for_side_effects(&ctx, facet->rule->up.ofpacts,
@@ -4426,7 +4613,7 @@ static void
 facet_account(struct facet *facet)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
-    struct subfacet *subfacet;
+    struct subfacet *subfacet = facet_get_subfacet(facet);
     const struct nlattr *a;
     unsigned int left;
     ovs_be16 vlan_tci;
@@ -4445,8 +4632,6 @@ facet_account(struct facet *facet)
      *
      * We use the actions from an arbitrary subfacet because they should all
      * be equally valid for our purpose. */
-    subfacet = CONTAINER_OF(list_front(&facet->subfacets),
-                            struct subfacet, list_node);
     vlan_tci = facet->flow.vlan_tci;
     NL_ATTR_FOR_EACH_UNSAFE (a, left,
                              subfacet->actions, subfacet->actions_len) {
@@ -4575,11 +4760,22 @@ facet_lookup_valid(struct ofproto_dpif *ofproto, const struct flow *flow,
             || tag_set_intersects(&ofproto->backer->revalidate_set,
                                   facet->tags))) {
         facet_revalidate(facet);
+
+        /* facet_revalidate() may have destroyed 'facet'. */
+        facet = facet_find(ofproto, flow, hash);
     }
 
     return facet;
 }
 
+/* Return a subfacet from 'facet'.  A facet consists of one or more
+ * subfacets, and this function returns one of them. */
+static struct subfacet *facet_get_subfacet(struct facet *facet)
+{
+    return CONTAINER_OF(list_front(&facet->subfacets), struct subfacet,
+                        list_node);
+}
+
 static const char *
 subfacet_path_to_string(enum subfacet_path path)
 {
@@ -4660,13 +4856,11 @@ facet_check_consistency(struct facet *facet)
     ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub);
     LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
         enum subfacet_path want_path;
-        struct odputil_keybuf keybuf;
         struct action_xlate_ctx ctx;
-        struct ofpbuf key;
         struct ds s;
 
         action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
-                              subfacet->initial_tci, rule, 0, NULL);
+                              &subfacet->initial_vals, rule, 0, NULL);
         xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len,
                       &odp_actions);
 
@@ -4698,8 +4892,7 @@ facet_check_consistency(struct facet *facet)
         }
 
         ds_init(&s);
-        subfacet_get_key(subfacet, &keybuf, &key);
-        odp_flow_key_format(key.data, key.size, &s);
+        odp_flow_key_format(subfacet->key, subfacet->key_len, &s);
 
         ds_put_cstr(&s, ": inconsistency in subfacet");
         if (want_path != subfacet->path) {
@@ -4737,7 +4930,10 @@ facet_check_consistency(struct facet *facet)
  *     'facet' to the new rule and recompiles its actions.
  *
  *   - If the rule found is the same as 'facet''s current rule, leaves 'facet'
- *     where it is and recompiles its actions anyway. */
+ *     where it is and recompiles its actions anyway.
+ *
+ *   - If any of 'facet''s subfacets correspond to a new flow according to
+ *     ofproto_receive(), 'facet' is removed. */
 static void
 facet_revalidate(struct facet *facet)
 {
@@ -4758,6 +4954,25 @@ facet_revalidate(struct facet *facet)
 
     COVERAGE_INC(facet_revalidate);
 
+    /* Check that child subfacets still correspond to this facet.  Tunnel
+     * configuration changes could cause a subfacet's OpenFlow in_port to
+     * change. */
+    LIST_FOR_EACH (subfacet, list_node, &facet->subfacets) {
+        struct ofproto_dpif *recv_ofproto;
+        struct flow recv_flow;
+        int error;
+
+        error = ofproto_receive(ofproto->backer, NULL, subfacet->key,
+                                subfacet->key_len, &recv_flow, NULL,
+                                &recv_ofproto, NULL, NULL);
+        if (error
+            || recv_ofproto != ofproto
+            || memcmp(&recv_flow, &facet->flow, sizeof recv_flow)) {
+            facet_remove(facet);
+            return;
+        }
+    }
+
     new_rule = rule_dpif_lookup(ofproto, &facet->flow);
 
     /* Calculate new datapath actions.
@@ -4776,7 +4991,7 @@ facet_revalidate(struct facet *facet)
         enum slow_path_reason slow;
 
         action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
-                              subfacet->initial_tci, new_rule, 0, NULL);
+                              &subfacet->initial_vals, new_rule, 0, NULL);
         xlate_actions(&ctx, new_rule->up.ofpacts, new_rule->up.ofpacts_len,
                       &odp_actions);
 
@@ -4878,13 +5093,35 @@ facet_push_stats(struct facet *facet)
         facet->prev_byte_count = facet->byte_count;
         facet->prev_used = facet->used;
 
-        flow_push_stats(facet->rule, &facet->flow, &stats);
+        flow_push_stats(facet, &stats);
 
         update_mirror_stats(ofproto_dpif_cast(facet->rule->up.ofproto),
                             facet->mirrors, stats.n_packets, stats.n_bytes);
     }
 }
 
+static void
+push_all_stats(void)
+{
+    static long long int rl = LLONG_MIN;
+    struct ofproto_dpif *ofproto;
+
+    if (time_msec() < rl) {
+        return;
+    }
+
+    HMAP_FOR_EACH (ofproto, all_ofproto_dpifs_node, &all_ofproto_dpifs) {
+        struct facet *facet;
+
+        HMAP_FOR_EACH (facet, hmap_node, &ofproto->facets) {
+            facet_push_stats(facet);
+            run_fast_rl();
+        }
+    }
+
+    rl = time_msec() + 100;
+}
+
 static void
 rule_credit_stats(struct rule_dpif *rule, const struct dpif_flow_stats *stats)
 {
@@ -4893,19 +5130,20 @@ rule_credit_stats(struct rule_dpif *rule, const struct dpif_flow_stats *stats)
     ofproto_rule_update_used(&rule->up, stats->used);
 }
 
-/* Pushes flow statistics to the rules which 'flow' resubmits into given
- * 'rule''s actions and mirrors. */
+/* Pushes flow statistics to the rules which 'facet->flow' resubmits
+ * into given 'facet->rule''s actions and mirrors. */
 static void
-flow_push_stats(struct rule_dpif *rule,
-                const struct flow *flow, const struct dpif_flow_stats *stats)
+flow_push_stats(struct facet *facet, const struct dpif_flow_stats *stats)
 {
+    struct rule_dpif *rule = facet->rule;
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
+    struct subfacet *subfacet = facet_get_subfacet(facet);
     struct action_xlate_ctx ctx;
 
     ofproto_rule_update_used(&rule->up, stats->used);
 
-    action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, rule,
-                          0, NULL);
+    action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
+                          &subfacet->initial_vals, rule, 0, NULL);
     ctx.resubmit_stats = stats;
     xlate_actions_for_side_effects(&ctx, rule->up.ofpacts,
                                    rule->up.ofpacts_len);
@@ -4915,17 +5153,14 @@ flow_push_stats(struct rule_dpif *rule,
 
 static struct subfacet *
 subfacet_find(struct ofproto_dpif *ofproto,
-              const struct nlattr *key, size_t key_len, uint32_t key_hash,
-              const struct flow *flow)
+              const struct nlattr *key, size_t key_len, uint32_t key_hash)
 {
     struct subfacet *subfacet;
 
     HMAP_FOR_EACH_WITH_HASH (subfacet, hmap_node, key_hash,
                              &ofproto->subfacets) {
-        if (subfacet->key
-            ? (subfacet->key_len == key_len
-               && !memcmp(key, subfacet->key, key_len))
-            : flow_equal(flow, &subfacet->facet->flow)) {
+        if (subfacet->key_len == key_len
+            && !memcmp(key, subfacet->key, key_len)) {
             return subfacet;
         }
     }
@@ -4957,8 +5192,7 @@ subfacet_create(struct facet *facet, struct flow_miss *miss,
     if (list_is_empty(&facet->subfacets)) {
         subfacet = &facet->one_subfacet;
     } else {
-        subfacet = subfacet_find(ofproto, key, key_len, key_hash,
-                                 &facet->flow);
+        subfacet = subfacet_find(ofproto, key, key_len, key_hash);
         if (subfacet) {
             if (subfacet->facet == facet) {
                 return subfacet;
@@ -4976,14 +5210,10 @@ subfacet_create(struct facet *facet, struct flow_miss *miss,
     list_push_back(&facet->subfacets, &subfacet->list_node);
     subfacet->facet = facet;
     subfacet->key_fitness = key_fitness;
-    if (key_fitness != ODP_FIT_PERFECT) {
-        subfacet->key = xmemdup(key, key_len);
-        subfacet->key_len = key_len;
-    } else {
-        subfacet->key = NULL;
-        subfacet->key_len = 0;
-    }
+    subfacet->key = xmemdup(key, key_len);
+    subfacet->key_len = key_len;
     subfacet->used = now;
+    subfacet->created = now;
     subfacet->dp_packet_count = 0;
     subfacet->dp_byte_count = 0;
     subfacet->actions_len = 0;
@@ -4992,9 +5222,10 @@ subfacet_create(struct facet *facet, struct flow_miss *miss,
                       ? SLOW_MATCH
                       : 0);
     subfacet->path = SF_NOT_INSTALLED;
-    subfacet->initial_tci = miss->initial_tci;
+    subfacet->initial_vals = miss->initial_vals;
     subfacet->odp_in_port = miss->odp_in_port;
 
+    ofproto->subfacet_add_count++;
     return subfacet;
 }
 
@@ -5006,6 +5237,10 @@ subfacet_destroy__(struct subfacet *subfacet)
     struct facet *facet = subfacet->facet;
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
 
+    /* Update ofproto stats before uninstall the subfacet. */
+    ofproto->subfacet_del_count++;
+    ofproto->total_subfacet_life_span += (time_msec() - subfacet->created);
+
     subfacet_uninstall(subfacet);
     hmap_remove(&ofproto->subfacets, &subfacet->hmap_node);
     list_remove(&subfacet->list_node);
@@ -5035,18 +5270,15 @@ static void
 subfacet_destroy_batch(struct ofproto_dpif *ofproto,
                        struct subfacet **subfacets, int n)
 {
-    struct odputil_keybuf keybufs[SUBFACET_DESTROY_MAX_BATCH];
     struct dpif_op ops[SUBFACET_DESTROY_MAX_BATCH];
     struct dpif_op *opsp[SUBFACET_DESTROY_MAX_BATCH];
-    struct ofpbuf keys[SUBFACET_DESTROY_MAX_BATCH];
     struct dpif_flow_stats stats[SUBFACET_DESTROY_MAX_BATCH];
     int i;
 
     for (i = 0; i < n; i++) {
         ops[i].type = DPIF_OP_FLOW_DEL;
-        subfacet_get_key(subfacets[i], &keybufs[i], &keys[i]);
-        ops[i].u.flow_del.key = keys[i].data;
-        ops[i].u.flow_del.key_len = keys[i].size;
+        ops[i].u.flow_del.key = subfacets[i]->key;
+        ops[i].u.flow_del.key_len = subfacets[i]->key_len;
         ops[i].u.flow_del.stats = &stats[i];
         opsp[i] = &ops[i];
     }
@@ -5056,24 +5288,7 @@ subfacet_destroy_batch(struct ofproto_dpif *ofproto,
         subfacet_reset_dp_stats(subfacets[i], &stats[i]);
         subfacets[i]->path = SF_NOT_INSTALLED;
         subfacet_destroy(subfacets[i]);
-    }
-}
-
-/* Initializes 'key' with the sequence of OVS_KEY_ATTR_* Netlink attributes
- * that can be used to refer to 'subfacet'.  The caller must provide 'keybuf'
- * for use as temporary storage. */
-static void
-subfacet_get_key(struct subfacet *subfacet, struct odputil_keybuf *keybuf,
-                 struct ofpbuf *key)
-{
-
-    if (!subfacet->key) {
-        struct flow *flow = &subfacet->facet->flow;
-
-        ofpbuf_use_stack(key, keybuf, sizeof *keybuf);
-        odp_flow_key_from_flow(key, flow, subfacet->odp_in_port);
-    } else {
-        ofpbuf_use_const(key, subfacet->key, subfacet->key_len);
+        run_fast_rl();
     }
 }
 
@@ -5090,8 +5305,8 @@ subfacet_make_actions(struct subfacet *subfacet, const struct ofpbuf *packet,
 
     struct action_xlate_ctx ctx;
 
-    action_xlate_ctx_init(&ctx, ofproto, &facet->flow, subfacet->initial_tci,
-                          rule, 0, packet);
+    action_xlate_ctx_init(&ctx, ofproto, &facet->flow,
+                          &subfacet->initial_vals, rule, 0, packet);
     xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len, odp_actions);
     facet->tags = ctx.tags;
     facet->has_learn = ctx.has_learn;
@@ -5125,9 +5340,7 @@ subfacet_install(struct subfacet *subfacet,
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
     enum subfacet_path path = subfacet_want_path(slow);
     uint64_t slow_path_stub[128 / 8];
-    struct odputil_keybuf keybuf;
     enum dpif_flow_put_flags flags;
-    struct ofpbuf key;
     int ret;
 
     flags = DPIF_FP_CREATE | DPIF_FP_MODIFY;
@@ -5141,9 +5354,8 @@ subfacet_install(struct subfacet *subfacet,
                           &actions, &actions_len);
     }
 
-    subfacet_get_key(subfacet, &keybuf, &key);
-    ret = dpif_flow_put(ofproto->backer->dpif, flags, key.data, key.size,
-                        actions, actions_len, stats);
+    ret = dpif_flow_put(ofproto->backer->dpif, flags, subfacet->key,
+                        subfacet->key_len, actions, actions_len, stats);
 
     if (stats) {
         subfacet_reset_dp_stats(subfacet, stats);
@@ -5169,14 +5381,11 @@ subfacet_uninstall(struct subfacet *subfacet)
     if (subfacet->path != SF_NOT_INSTALLED) {
         struct rule_dpif *rule = subfacet->facet->rule;
         struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
-        struct odputil_keybuf keybuf;
         struct dpif_flow_stats stats;
-        struct ofpbuf key;
         int error;
 
-        subfacet_get_key(subfacet, &keybuf, &key);
-        error = dpif_flow_del(ofproto->backer->dpif,
-                              key.data, key.size, &stats);
+        error = dpif_flow_del(ofproto->backer->dpif, subfacet->key,
+                              subfacet->key_len, &stats);
         subfacet_reset_dp_stats(subfacet, &stats);
         if (!error) {
             subfacet_update_stats(subfacet, &stats);
@@ -5236,7 +5445,6 @@ subfacet_update_stats(struct subfacet *subfacet,
         facet->packet_count += stats->n_packets;
         facet->byte_count += stats->n_bytes;
         facet->tcp_flags |= stats->tcp_flags;
-        facet_push_stats(facet);
         netflow_flow_update_flags(&facet->nf_flow, stats->tcp_flags);
     }
 }
@@ -5396,6 +5604,8 @@ rule_get_stats(struct rule *rule_, uint64_t *packets, uint64_t *bytes)
     struct rule_dpif *rule = rule_dpif_cast(rule_);
     struct facet *facet;
 
+    push_all_stats();
+
     /* Start from historical data for 'rule' itself that are no longer tracked
      * in facets.  This counts, for example, facets that have expired. */
     *packets = rule->packet_count;
@@ -5415,9 +5625,8 @@ rule_dpif_execute(struct rule_dpif *rule, const struct flow *flow,
                   struct ofpbuf *packet)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
-
+    struct initial_vals initial_vals;
     struct dpif_flow_stats stats;
-
     struct action_xlate_ctx ctx;
     uint64_t odp_actions_stub[1024 / 8];
     struct ofpbuf odp_actions;
@@ -5425,8 +5634,10 @@ rule_dpif_execute(struct rule_dpif *rule, const struct flow *flow,
     dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
     rule_credit_stats(rule, &stats);
 
+    initial_vals.vlan_tci = flow->vlan_tci;
+    initial_vals.tunnel_ip_tos = flow->tunnel.ip_tos;
     ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub);
-    action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci,
+    action_xlate_ctx_init(&ctx, ofproto, flow, &initial_vals,
                           rule, stats.tcp_flags, packet);
     ctx.resubmit_stats = &stats;
     xlate_actions(&ctx, rule->up.ofpacts, rule->up.ofpacts_len, &odp_actions);
@@ -5505,6 +5716,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
         dpif_flow_stats_extract(&flow, packet, time_msec(), &stats);
         netdev_vport_inc_tx(ofport->up.netdev, &stats);
         odp_put_tunnel_action(&flow.tunnel, &odp_actions);
+        odp_put_skb_mark_action(flow.skb_mark, &odp_actions);
     } else {
         odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port,
                                           flow.vlan_tci);
@@ -5537,6 +5749,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
 \f
 /* OpenFlow to datapath action translation. */
 
+static bool may_receive(const struct ofport_dpif *, struct action_xlate_ctx *);
 static void do_xlate_actions(const struct ofpact *, size_t ofpacts_len,
                              struct action_xlate_ctx *);
 static void xlate_normal(struct action_xlate_ctx *);
@@ -5567,7 +5780,7 @@ compose_slow_path(const struct ofproto_dpif *ofproto, const struct flow *flow,
     ofpbuf_use_stack(&buf, stub, stub_size);
     if (slow & (SLOW_CFM | SLOW_LACP | SLOW_STP)) {
         uint32_t pid = dpif_port_get_pid(ofproto->backer->dpif, UINT32_MAX);
-        odp_put_userspace_action(pid, &cookie, &buf);
+        odp_put_userspace_action(pid, &cookie, sizeof cookie, &buf);
     } else {
         put_userspace_action(ofproto, &buf, flow, &cookie);
     }
@@ -5586,7 +5799,7 @@ put_userspace_action(const struct ofproto_dpif *ofproto,
     pid = dpif_port_get_pid(ofproto->backer->dpif,
                             ofp_port_to_odp_port(ofproto, flow->in_port));
 
-    return odp_put_userspace_action(pid, cookie, odp_actions);
+    return odp_put_userspace_action(pid, cookie, sizeof *cookie, odp_actions);
 }
 
 static void
@@ -5700,7 +5913,7 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
 
     /* If 'struct flow' gets additional metadata, we'll need to zero it out
      * before traversing a patch port. */
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     if (!ofport) {
         xlate_report(ctx, "Nonexistent output port");
@@ -5717,6 +5930,8 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
         struct ofport_dpif *peer = ofport_get_peer(ofport);
         struct flow old_flow = ctx->flow;
         const struct ofproto_dpif *peer_ofproto;
+        enum slow_path_reason special;
+        struct ofport_dpif *in_port;
 
         if (!peer) {
             xlate_report(ctx, "Nonexistent patch port peer");
@@ -5734,7 +5949,26 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
         ctx->flow.metadata = htonll(0);
         memset(&ctx->flow.tunnel, 0, sizeof ctx->flow.tunnel);
         memset(ctx->flow.regs, 0, sizeof ctx->flow.regs);
-        xlate_table_action(ctx, ctx->flow.in_port, 0, true);
+
+        in_port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
+        special = process_special(ctx->ofproto, &ctx->flow, in_port,
+                                  ctx->packet);
+        if (special) {
+            ctx->slow |= special;
+        } else if (!in_port || may_receive(in_port, ctx)) {
+            if (!in_port || stp_forward_in_state(in_port->stp_state)) {
+                xlate_table_action(ctx, ctx->flow.in_port, 0, true);
+            } else {
+                /* Forwarding is disabled by STP.  Let OFPP_NORMAL and the
+                 * learning action look at the packet, then drop it. */
+                struct flow old_base_flow = ctx->base_flow;
+                size_t old_size = ctx->odp_actions->size;
+                xlate_table_action(ctx, ctx->flow.in_port, 0, true);
+                ctx->base_flow = old_base_flow;
+                ctx->odp_actions->size = old_size;
+            }
+        }
+
         ctx->flow = old_flow;
         ctx->ofproto = ofproto_dpif_cast(ofport->up.ofproto);
 
@@ -5752,7 +5986,6 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
         ctx->flow.nw_tos |= pdscp->dscp;
     }
 
-    odp_port = ofp_port_to_odp_port(ctx->ofproto, ofp_port);
     if (ofport->tnl_port) {
         odp_port = tnl_port_send(ofport->tnl_port, &ctx->flow);
         if (odp_port == OVSP_NONE) {
@@ -5767,11 +6000,13 @@ compose_output_action__(struct action_xlate_ctx *ctx, uint16_t ofp_port,
         commit_odp_tunnel_action(&ctx->flow, &ctx->base_flow,
                                  ctx->odp_actions);
     } else {
+        odp_port = ofport->odp_port;
         out_port = vsp_realdev_to_vlandev(ctx->ofproto, odp_port,
                                           ctx->flow.vlan_tci);
         if (out_port != odp_port) {
             ctx->flow.vlan_tci = htons(0);
         }
+        ctx->flow.skb_mark &= ~IPSEC_MARK;
     }
     commit_odp_actions(&ctx->flow, &ctx->base_flow, ctx->odp_actions);
     nl_msg_put_u32(ctx->odp_actions, OVS_ACTION_ATTR_OUTPUT, out_port);
@@ -5790,62 +6025,74 @@ compose_output_action(struct action_xlate_ctx *ctx, uint16_t ofp_port)
     compose_output_action__(ctx, ofp_port, true);
 }
 
+static void
+tag_the_flow(struct action_xlate_ctx *ctx, struct rule_dpif *rule)
+{
+    struct ofproto_dpif *ofproto = ctx->ofproto;
+    uint8_t table_id = ctx->table_id;
+
+    if (table_id > 0 && table_id < N_TABLES) {
+        struct table_dpif *table = &ofproto->tables[table_id];
+        if (table->other_table) {
+            ctx->tags |= (rule && rule->tag
+                          ? rule->tag
+                          : rule_calculate_tag(&ctx->flow,
+                                               &table->other_table->mask,
+                                               table->basis));
+        }
+    }
+}
+
+/* Common rule processing in one place to avoid duplicating code. */
+static struct rule_dpif *
+ctx_rule_hooks(struct action_xlate_ctx *ctx, struct rule_dpif *rule,
+               bool may_packet_in)
+{
+    if (ctx->resubmit_hook) {
+        ctx->resubmit_hook(ctx, rule);
+    }
+    if (rule == NULL && may_packet_in) {
+        /* XXX
+         * check if table configuration flags
+         * OFPTC_TABLE_MISS_CONTROLLER, default.
+         * OFPTC_TABLE_MISS_CONTINUE,
+         * OFPTC_TABLE_MISS_DROP
+         * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do?
+         */
+        rule = rule_dpif_miss_rule(ctx->ofproto, &ctx->flow);
+    }
+    if (rule && ctx->resubmit_stats) {
+        rule_credit_stats(rule, ctx->resubmit_stats);
+    }
+    return rule;
+}
+
 static void
 xlate_table_action(struct action_xlate_ctx *ctx,
                    uint16_t in_port, uint8_t table_id, bool may_packet_in)
 {
     if (ctx->recurse < MAX_RESUBMIT_RECURSION) {
-        struct ofproto_dpif *ofproto = ctx->ofproto;
         struct rule_dpif *rule;
-        uint16_t old_in_port;
-        uint8_t old_table_id;
+        uint16_t old_in_port = ctx->flow.in_port;
+        uint8_t old_table_id = ctx->table_id;
 
-        old_table_id = ctx->table_id;
         ctx->table_id = table_id;
 
         /* Look up a flow with 'in_port' as the input port. */
-        old_in_port = ctx->flow.in_port;
         ctx->flow.in_port = in_port;
-        rule = rule_dpif_lookup__(ofproto, &ctx->flow, table_id);
-
-        /* Tag the flow. */
-        if (table_id > 0 && table_id < N_TABLES) {
-            struct table_dpif *table = &ofproto->tables[table_id];
-            if (table->other_table) {
-                ctx->tags |= (rule && rule->tag
-                              ? rule->tag
-                              : rule_calculate_tag(&ctx->flow,
-                                                   &table->other_table->mask,
-                                                   table->basis));
-            }
-        }
+        rule = rule_dpif_lookup__(ctx->ofproto, &ctx->flow, table_id);
+
+        tag_the_flow(ctx, rule);
 
         /* Restore the original input port.  Otherwise OFPP_NORMAL and
          * OFPP_IN_PORT will have surprising behavior. */
         ctx->flow.in_port = old_in_port;
 
-        if (ctx->resubmit_hook) {
-            ctx->resubmit_hook(ctx, rule);
-        }
-
-        if (rule == NULL && may_packet_in) {
-            /* XXX
-             * check if table configuration flags
-             * OFPTC_TABLE_MISS_CONTROLLER, default.
-             * OFPTC_TABLE_MISS_CONTINUE,
-             * OFPTC_TABLE_MISS_DROP
-             * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do?
-             */
-            rule = rule_dpif_miss_rule(ofproto, &ctx->flow);
-        }
+        rule = ctx_rule_hooks(ctx, rule, may_packet_in);
 
         if (rule) {
             struct rule_dpif *old_rule = ctx->rule;
 
-            if (ctx->resubmit_stats) {
-                rule_credit_stats(rule, ctx->resubmit_stats);
-            }
-
             ctx->recurse++;
             ctx->rule = rule;
             do_xlate_actions(rule->up.ofpacts, rule->up.ofpacts_len, ctx);
@@ -5922,16 +6169,11 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len,
 
     if (packet->l2 && packet->l3) {
         struct eth_header *eh;
+        uint16_t mpls_depth;
 
         eth_pop_vlan(packet);
         eh = packet->l2;
 
-        /* If the Ethernet type is less than ETH_TYPE_MIN, it's likely an 802.2
-         * LLC frame.  Calculating the Ethernet type of these frames is more
-         * trouble than seems appropriate for a simple assertion. */
-        ovs_assert(ntohs(eh->eth_type) < ETH_TYPE_MIN
-                   || eh->eth_type == ctx->flow.dl_type);
-
         memcpy(eh->eth_src, ctx->flow.dl_src, sizeof eh->eth_src);
         memcpy(eh->eth_dst, ctx->flow.dl_dst, sizeof eh->eth_dst);
 
@@ -5939,6 +6181,16 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len,
             eth_push_vlan(packet, ctx->flow.vlan_tci);
         }
 
+        mpls_depth = eth_mpls_depth(packet);
+
+        if (mpls_depth < ctx->flow.mpls_depth) {
+            push_mpls(packet, ctx->flow.dl_type, ctx->flow.mpls_lse);
+        } else if (mpls_depth > ctx->flow.mpls_depth) {
+            pop_mpls(packet, ctx->flow.dl_type);
+        } else if (mpls_depth) {
+            set_mpls_lse(packet, ctx->flow.mpls_lse);
+        }
+
         if (packet->l4) {
             if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) {
                 packet_set_ipv4(packet, ctx->flow.nw_src, ctx->flow.nw_dst,
@@ -5971,6 +6223,46 @@ execute_controller_action(struct action_xlate_ctx *ctx, int len,
     ofpbuf_delete(packet);
 }
 
+static void
+execute_mpls_push_action(struct action_xlate_ctx *ctx, ovs_be16 eth_type)
+{
+    ovs_assert(eth_type_mpls(eth_type));
+
+    if (ctx->base_flow.mpls_depth) {
+        ctx->flow.mpls_lse &= ~htonl(MPLS_BOS_MASK);
+        ctx->flow.mpls_depth++;
+    } else {
+        ovs_be32 label;
+        uint8_t tc, ttl;
+
+        if (ctx->flow.dl_type == htons(ETH_TYPE_IPV6)) {
+            label = htonl(0x2); /* IPV6 Explicit Null. */
+        } else {
+            label = htonl(0x0); /* IPV4 Explicit Null. */
+        }
+        tc = (ctx->flow.nw_tos & IP_DSCP_MASK) >> 2;
+        ttl = ctx->flow.nw_ttl ? ctx->flow.nw_ttl : 0x40;
+        ctx->flow.mpls_lse = set_mpls_lse_values(ttl, tc, 1, label);
+        ctx->flow.mpls_depth = 1;
+    }
+    ctx->flow.dl_type = eth_type;
+}
+
+static void
+execute_mpls_pop_action(struct action_xlate_ctx *ctx, ovs_be16 eth_type)
+{
+    ovs_assert(eth_type_mpls(ctx->flow.dl_type));
+    ovs_assert(!eth_type_mpls(eth_type));
+
+    if (ctx->flow.mpls_depth) {
+        ctx->flow.mpls_depth--;
+        ctx->flow.mpls_lse = htonl(0);
+        if (!ctx->flow.mpls_depth) {
+            ctx->flow.dl_type = eth_type;
+        }
+    }
+}
+
 static bool
 compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
 {
@@ -5995,6 +6287,38 @@ compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
     }
 }
 
+static bool
+execute_set_mpls_ttl_action(struct action_xlate_ctx *ctx, uint8_t ttl)
+{
+    if (!eth_type_mpls(ctx->flow.dl_type)) {
+        return true;
+    }
+
+    set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl);
+    return false;
+}
+
+static bool
+execute_dec_mpls_ttl_action(struct action_xlate_ctx *ctx)
+{
+    uint8_t ttl = mpls_lse_to_ttl(ctx->flow.mpls_lse);
+
+    if (!eth_type_mpls(ctx->flow.dl_type)) {
+        return false;
+    }
+
+    if (ttl > 1) {
+        ttl--;
+        set_mpls_lse_ttl(&ctx->flow.mpls_lse, ttl);
+        return false;
+    } else {
+        execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0);
+
+        /* Stop processing for current table. */
+        return true;
+    }
+}
+
 static void
 xlate_output_action(struct action_xlate_ctx *ctx,
                     uint16_t port, uint16_t max_len, bool may_packet_in)
@@ -6112,26 +6436,6 @@ struct xlate_reg_state {
     ovs_be64 tun_id;
 };
 
-static void
-xlate_autopath(struct action_xlate_ctx *ctx,
-               const struct ofpact_autopath *ap)
-{
-    uint16_t ofp_port = ap->port;
-    struct ofport_dpif *port = get_ofp_port(ctx->ofproto, ofp_port);
-
-    if (!port || !port->bundle) {
-        ofp_port = OFPP_NONE;
-    } else if (port->bundle->bond) {
-        /* Autopath does not support VLAN hashing. */
-        struct ofport_dpif *slave = bond_choose_output_slave(
-            port->bundle->bond, &ctx->flow, 0, &ctx->tags);
-        if (slave) {
-            ofp_port = slave->up.ofp_port;
-        }
-    }
-    nxm_reg_load(&ap->dst, ofp_port, &ctx->flow);
-}
-
 static bool
 slave_enabled_cb(uint16_t ofp_port, void *ofproto_)
 {
@@ -6233,25 +6537,38 @@ may_receive(const struct ofport_dpif *port, struct action_xlate_ctx *ctx)
     return true;
 }
 
+static bool
+tunnel_ecn_ok(struct action_xlate_ctx *ctx)
+{
+    if (is_ip_any(&ctx->base_flow)
+        && (ctx->base_flow.tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE) {
+        if ((ctx->base_flow.nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) {
+            VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE"
+                         " but is not ECN capable");
+            return false;
+        } else {
+            /* Set the ECN CE value in the tunneled packet. */
+            ctx->flow.nw_tos |= IP_ECN_CE;
+        }
+    }
+
+    return true;
+}
+
 static void
 do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
                  struct action_xlate_ctx *ctx)
 {
-    const struct ofport_dpif *port;
     bool was_evictable = true;
     const struct ofpact *a;
 
-    port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
-    if (port && !may_receive(port, ctx)) {
-        /* Drop this flow. */
-        return;
-    }
-
     if (ctx->rule) {
         /* Don't let the rule we're working on get evicted underneath us. */
         was_evictable = ctx->rule->up.evictable;
         ctx->rule->up.evictable = false;
     }
+
+ do_xlate_actions_again:
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
         struct ofpact_controller *controller;
         const struct ofpact_metadata *metadata;
@@ -6310,11 +6627,15 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_SET_IPV4_SRC:
-            ctx->flow.nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4;
+            if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) {
+                ctx->flow.nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4;
+            }
             break;
 
         case OFPACT_SET_IPV4_DST:
-            ctx->flow.nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4;
+            if (ctx->flow.dl_type == htons(ETH_TYPE_IP)) {
+                ctx->flow.nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4;
+            }
             break;
 
         case OFPACT_SET_IPV4_DSCP:
@@ -6326,11 +6647,15 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_SET_L4_SRC_PORT:
-            ctx->flow.tp_src = htons(ofpact_get_SET_L4_SRC_PORT(a)->port);
+            if (is_ip_any(&ctx->flow)) {
+                ctx->flow.tp_src = htons(ofpact_get_SET_L4_SRC_PORT(a)->port);
+            }
             break;
 
         case OFPACT_SET_L4_DST_PORT:
-            ctx->flow.tp_dst = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
+            if (is_ip_any(&ctx->flow)) {
+                ctx->flow.tp_dst = htons(ofpact_get_SET_L4_DST_PORT(a)->port);
+            }
             break;
 
         case OFPACT_RESUBMIT:
@@ -6357,6 +6682,36 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             nxm_execute_reg_load(ofpact_get_REG_LOAD(a), &ctx->flow);
             break;
 
+        case OFPACT_STACK_PUSH:
+            nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), &ctx->flow,
+                                   &ctx->stack);
+            break;
+
+        case OFPACT_STACK_POP:
+            nxm_execute_stack_pop(ofpact_get_STACK_POP(a), &ctx->flow,
+                                  &ctx->stack);
+            break;
+
+        case OFPACT_PUSH_MPLS:
+            execute_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a)->ethertype);
+            break;
+
+        case OFPACT_POP_MPLS:
+            execute_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype);
+            break;
+
+        case OFPACT_SET_MPLS_TTL:
+            if (execute_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl)) {
+                goto out;
+            }
+            break;
+
+        case OFPACT_DEC_MPLS_TTL:
+            if (execute_dec_mpls_ttl_action(ctx)) {
+                goto out;
+            }
+            break;
+
         case OFPACT_DEC_TTL:
             if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
                 goto out;
@@ -6371,10 +6726,6 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             multipath_execute(ofpact_get_MULTIPATH(a), &ctx->flow);
             break;
 
-        case OFPACT_AUTOPATH:
-            xlate_autopath(ctx, ofpact_get_AUTOPATH(a));
-            break;
-
         case OFPACT_BUNDLE:
             ctx->ofproto->has_bundle_action = true;
             xlate_bundle_action(ctx, ofpact_get_BUNDLE(a));
@@ -6415,23 +6766,40 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             break;
 
         case OFPACT_GOTO_TABLE: {
-            /* XXX remove recursion */
-            /* It is assumed that goto-table is last action */
+            /* It is assumed that goto-table is the last action. */
             struct ofpact_goto_table *ogt = ofpact_get_GOTO_TABLE(a);
+            struct rule_dpif *rule;
+
             ovs_assert(ctx->table_id < ogt->table_id);
-            xlate_table_action(ctx, ctx->flow.in_port, ogt->table_id, true);
+
+            ctx->table_id = ogt->table_id;
+
+            /* Look up a flow from the new table. */
+            rule = rule_dpif_lookup__(ctx->ofproto, &ctx->flow, ctx->table_id);
+
+            tag_the_flow(ctx, rule);
+
+            rule = ctx_rule_hooks(ctx, rule, true);
+
+            if (rule) {
+                if (ctx->rule) {
+                    ctx->rule->up.evictable = was_evictable;
+                }
+                ctx->rule = rule;
+                was_evictable = rule->up.evictable;
+                rule->up.evictable = false;
+
+                /* Tail recursion removal. */
+                ofpacts = rule->up.ofpacts;
+                ofpacts_len = rule->up.ofpacts_len;
+                goto do_xlate_actions_again;
+            }
             break;
         }
         }
     }
 
 out:
-    /* We've let OFPP_NORMAL and the learning action look at the packet,
-     * so drop it now if forwarding is disabled. */
-    if (port && !stp_forward_in_state(port->stp_state)) {
-        ofpbuf_clear(ctx->odp_actions);
-        add_sflow_action(ctx);
-    }
     if (ctx->rule) {
         ctx->rule->up.evictable = was_evictable;
     }
@@ -6440,7 +6808,8 @@ out:
 static void
 action_xlate_ctx_init(struct action_xlate_ctx *ctx,
                       struct ofproto_dpif *ofproto, const struct flow *flow,
-                      ovs_be16 initial_tci, struct rule_dpif *rule,
+                      const struct initial_vals *initial_vals,
+                      struct rule_dpif *rule,
                       uint8_t tcp_flags, const struct ofpbuf *packet)
 {
     ovs_be64 initial_tun_id = flow->tunnel.tun_id;
@@ -6470,7 +6839,8 @@ action_xlate_ctx_init(struct action_xlate_ctx *ctx,
     ctx->flow = *flow;
     memset(&ctx->flow.tunnel, 0, sizeof ctx->flow.tunnel);
     ctx->base_flow = ctx->flow;
-    ctx->base_flow.vlan_tci = initial_tci;
+    ctx->base_flow.vlan_tci = initial_vals->vlan_tci;
+    ctx->base_flow.tunnel.ip_tos = initial_vals->tunnel_ip_tos;
     ctx->flow.tunnel.tun_id = initial_tun_id;
     ctx->rule = rule;
     ctx->packet = packet;
@@ -6494,6 +6864,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
     static bool hit_resubmit_limit;
 
     enum slow_path_reason special;
+    struct ofport_dpif *in_port;
+    struct flow orig_flow;
 
     COVERAGE_INC(ofproto_dpif_xlate);
 
@@ -6514,14 +6886,12 @@ xlate_actions(struct action_xlate_ctx *ctx,
     ctx->table_id = 0;
     ctx->exit = false;
 
+    ofpbuf_use_stub(&ctx->stack, ctx->init_stack, sizeof ctx->init_stack);
+
     if (ctx->ofproto->has_mirrors || hit_resubmit_limit) {
         /* Do this conditionally because the copy is expensive enough that it
-         * shows up in profiles.
-         *
-         * We keep orig_flow in 'ctx' only because I couldn't make GCC 4.4
-         * believe that I wasn't using it without initializing it if I kept it
-         * in a local variable. */
-        ctx->orig_flow = ctx->flow;
+         * shows up in profiles. */
+        orig_flow = ctx->flow;
     }
 
     if (ctx->flow.nw_frag & FLOW_NW_FRAG_ANY) {
@@ -6547,16 +6917,30 @@ xlate_actions(struct action_xlate_ctx *ctx,
         }
     }
 
-    special = process_special(ctx->ofproto, &ctx->flow, ctx->packet);
+    in_port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
+    special = process_special(ctx->ofproto, &ctx->flow, in_port, ctx->packet);
     if (special) {
         ctx->slow |= special;
     } else {
         static struct vlog_rate_limit trace_rl = VLOG_RATE_LIMIT_INIT(1, 1);
-        ovs_be16 initial_tci = ctx->base_flow.vlan_tci;
+        struct initial_vals initial_vals;
         uint32_t local_odp_port;
 
+        initial_vals.vlan_tci = ctx->base_flow.vlan_tci;
+        initial_vals.tunnel_ip_tos = ctx->base_flow.tunnel.ip_tos;
+
         add_sflow_action(ctx);
-        do_xlate_actions(ofpacts, ofpacts_len, ctx);
+
+        if (tunnel_ecn_ok(ctx) && (!in_port || may_receive(in_port, ctx))) {
+            do_xlate_actions(ofpacts, ofpacts_len, ctx);
+
+            /* We've let OFPP_NORMAL and the learning action look at the
+             * packet, so drop it now if forwarding is disabled. */
+            if (in_port && !stp_forward_in_state(in_port->stp_state)) {
+                ofpbuf_clear(ctx->odp_actions);
+                add_sflow_action(ctx);
+            }
+        }
 
         if (ctx->max_resubmit_trigger && !ctx->resubmit_hook) {
             if (!hit_resubmit_limit) {
@@ -6566,8 +6950,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
             } else if (!VLOG_DROP_ERR(&trace_rl)) {
                 struct ds ds = DS_EMPTY_INITIALIZER;
 
-                ofproto_trace(ctx->ofproto, &ctx->orig_flow, ctx->packet,
-                              initial_tci, &ds);
+                ofproto_trace(ctx->ofproto, &orig_flow, ctx->packet,
+                              &initial_vals, &ds);
                 VLOG_ERR("Trace triggered by excessive resubmit "
                          "recursion:\n%s", ds_cstr(&ds));
                 ds_destroy(&ds);
@@ -6587,10 +6971,12 @@ xlate_actions(struct action_xlate_ctx *ctx,
             }
         }
         if (ctx->ofproto->has_mirrors) {
-            add_mirror_actions(ctx, &ctx->orig_flow);
+            add_mirror_actions(ctx, &orig_flow);
         }
         fix_sflow_action(ctx);
     }
+
+    ofpbuf_uninit(&ctx->stack);
 }
 
 /* Translates the 'ofpacts_len' bytes of "struct ofpact"s starting at 'ofpacts'
@@ -7287,6 +7673,7 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
            const struct ofpact *ofpacts, size_t ofpacts_len)
 {
     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+    struct initial_vals initial_vals;
     struct odputil_keybuf keybuf;
     struct dpif_flow_stats stats;
 
@@ -7302,7 +7689,9 @@ packet_out(struct ofproto *ofproto_, struct ofpbuf *packet,
 
     dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
 
-    action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, NULL,
+    initial_vals.vlan_tci = flow->vlan_tci;
+    initial_vals.tunnel_ip_tos = 0;
+    action_xlate_ctx_init(&ctx, ofproto, flow, &initial_vals, NULL,
                           packet_get_tcp_flags(packet, flow), packet);
     ctx.resubmit_stats = &stats;
 
@@ -7542,7 +7931,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
     struct ofproto_dpif *ofproto;
     struct ofpbuf odp_key;
     struct ofpbuf *packet;
-    ovs_be16 initial_tci;
+    struct initial_vals initial_vals;
     struct ds result;
     struct flow flow;
     char *s;
@@ -7583,16 +7972,16 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
                 goto exit;
             }
 
-            /* XXX: Since we allow the user to specify an ofproto, it's
-             * possible they will specify a different ofproto than the one the
-             * port actually belongs too.  Ideally we should simply remove the
-             * ability to specify the ofproto. */
+            /* The user might have specified the wrong ofproto but within the
+             * same backer.  That's OK, ofproto_receive() can find the right
+             * one for us. */
             if (ofproto_receive(ofproto->backer, NULL, odp_key.data,
-                                odp_key.size, &flow, NULL, NULL, NULL,
-                                &initial_tci)) {
+                                odp_key.size, &flow, NULL, &ofproto, NULL,
+                                &initial_vals)) {
                 unixctl_command_reply_error(conn, "Invalid flow");
                 goto exit;
             }
+            ds_put_format(&result, "Bridge: %s\n", ofproto->up.name);
         } else {
             char *error_s;
 
@@ -7603,7 +7992,8 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
                 goto exit;
             }
 
-            initial_tci = flow.vlan_tci;
+            initial_vals.vlan_tci = flow.vlan_tci;
+            initial_vals.tunnel_ip_tos = flow.tunnel.ip_tos;
         }
 
         /* Generate a packet, if requested. */
@@ -7637,13 +8027,14 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
 
         flow_extract(packet, priority, mark, NULL, in_port, &flow);
         flow.tunnel.tun_id = tun_id;
-        initial_tci = flow.vlan_tci;
+        initial_vals.vlan_tci = flow.vlan_tci;
+        initial_vals.tunnel_ip_tos = flow.tunnel.ip_tos;
     } else {
         unixctl_command_reply_error(conn, "Bad command syntax");
         goto exit;
     }
 
-    ofproto_trace(ofproto, &flow, packet, initial_tci, &result);
+    ofproto_trace(ofproto, &flow, packet, &initial_vals, &result);
     unixctl_command_reply(conn, ds_cstr(&result));
 
 exit:
@@ -7654,8 +8045,8 @@ exit:
 
 static void
 ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
-              const struct ofpbuf *packet, ovs_be16 initial_tci,
-              struct ds *ds)
+              const struct ofpbuf *packet,
+              const struct initial_vals *initial_vals, struct ds *ds)
 {
     struct rule_dpif *rule;
 
@@ -7685,7 +8076,7 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow,
         trace.flow = *flow;
         ofpbuf_use_stub(&odp_actions,
                         odp_actions_stub, sizeof odp_actions_stub);
-        action_xlate_ctx_init(&trace.ctx, ofproto, flow, initial_tci,
+        action_xlate_ctx_init(&trace.ctx, ofproto, flow, initial_vals,
                               rule, tcp_flags, packet);
         trace.ctx.resubmit_hook = trace_resubmit;
         trace.ctx.report_hook = trace_report;
@@ -7856,21 +8247,42 @@ ofproto_unixctl_dpif_dump_dps(struct unixctl_conn *conn, int argc OVS_UNUSED,
 static void
 show_dp_format(const struct ofproto_dpif *ofproto, struct ds *ds)
 {
-    struct dpif_dp_stats s;
     const struct shash_node **ports;
     int i;
+    struct avg_subfacet_rates lifetime;
+    unsigned long long int minutes;
+    const int min_ms = 60 * 1000; /* milliseconds in one minute. */
 
-    dpif_get_dp_stats(ofproto->backer->dpif, &s);
+    minutes = (time_msec() - ofproto->created) / min_ms;
+
+    if (minutes > 0) {
+        lifetime.add_rate = (double)ofproto->total_subfacet_add_count
+                            / minutes;
+        lifetime.del_rate = (double)ofproto->total_subfacet_del_count
+                            / minutes;
+    }else {
+        lifetime.add_rate = 0.0;
+        lifetime.del_rate = 0.0;
+    }
 
     ds_put_format(ds, "%s (%s):\n", ofproto->up.name,
                   dpif_name(ofproto->backer->dpif));
-    /* xxx It would be better to show bridge-specific stats instead
-     * xxx of dp ones. */
     ds_put_format(ds,
-                  "\tlookups: hit:%"PRIu64" missed:%"PRIu64" lost:%"PRIu64"\n",
-                  s.n_hit, s.n_missed, s.n_lost);
-    ds_put_format(ds, "\tflows: %zu\n",
-                  hmap_count(&ofproto->subfacets));
+                  "\tlookups: hit:%"PRIu64" missed:%"PRIu64"\n",
+                  ofproto->n_hit, ofproto->n_missed);
+    ds_put_format(ds, "\tflows: cur: %zu, avg: %5.3f, max: %d,"
+                  " life span: %llu(ms)\n",
+                  hmap_count(&ofproto->subfacets),
+                  avg_subfacet_count(ofproto),
+                  ofproto->max_n_subfacet,
+                  avg_subfacet_life_span(ofproto));
+    if (minutes >= 60) {
+        show_dp_rates(ds, "\t\thourly avg:", &ofproto->hourly);
+    }
+    if (minutes >= 60 * 24) {
+        show_dp_rates(ds, "\t\tdaily avg:",  &ofproto->daily);
+    }
+    show_dp_rates(ds, "\t\toverall avg:",  &lifetime);
 
     ports = shash_sort(&ofproto->up.port_by_name);
     for (i = 0; i < shash_count(&ofproto->up.port_by_name); i++) {
@@ -7981,11 +8393,7 @@ ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn,
     update_stats(ofproto->backer);
 
     HMAP_FOR_EACH (subfacet, hmap_node, &ofproto->subfacets) {
-        struct odputil_keybuf keybuf;
-        struct ofpbuf key;
-
-        subfacet_get_key(subfacet, &keybuf, &key);
-        odp_flow_key_format(key.data, key.size, &ds);
+        odp_flow_key_format(subfacet->key, subfacet->key_len, &ds);
 
         ds_put_format(&ds, ", packets:%"PRIu64", bytes:%"PRIu64", used:",
                       subfacet->dp_packet_count, subfacet->dp_byte_count);
@@ -8001,7 +8409,18 @@ ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn,
         }
 
         ds_put_cstr(&ds, ", actions:");
-        format_odp_actions(&ds, subfacet->actions, subfacet->actions_len);
+        if (subfacet->slow) {
+            uint64_t slow_path_stub[128 / 8];
+            const struct nlattr *actions;
+            size_t actions_len;
+
+            compose_slow_path(ofproto, &subfacet->facet->flow, subfacet->slow,
+                              slow_path_stub, sizeof slow_path_stub,
+                              &actions, &actions_len);
+            format_odp_actions(&ds, actions, actions_len);
+        } else {
+            format_odp_actions(&ds, subfacet->actions, subfacet->actions_len);
+        }
         ds_put_char(&ds, '\n');
     }
 
@@ -8280,6 +8699,85 @@ odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port)
         return OFPP_NONE;
     }
 }
+static unsigned long long int
+avg_subfacet_life_span(const struct ofproto_dpif *ofproto)
+{
+    unsigned long long int dc;
+    unsigned long long int avg;
+
+    dc = ofproto->total_subfacet_del_count + ofproto->subfacet_del_count;
+    avg = dc ? ofproto->total_subfacet_life_span / dc : 0;
+
+    return avg;
+}
+
+static double
+avg_subfacet_count(const struct ofproto_dpif *ofproto)
+{
+    double avg_c = 0.0;
+
+    if (ofproto->n_update_stats) {
+        avg_c = (double)ofproto->total_subfacet_count
+                / ofproto->n_update_stats;
+    }
+
+    return avg_c;
+}
+
+static void
+show_dp_rates(struct ds *ds, const char *heading,
+              const struct avg_subfacet_rates *rates)
+{
+    ds_put_format(ds, "%s add rate: %5.3f/min, del rate: %5.3f/min\n",
+                  heading, rates->add_rate, rates->del_rate);
+}
+
+static void
+update_max_subfacet_count(struct ofproto_dpif *ofproto)
+{
+    ofproto->max_n_subfacet = MAX(ofproto->max_n_subfacet,
+                                  hmap_count(&ofproto->subfacets));
+}
+
+/* Compute exponentially weighted moving average, adding 'new' as the newest,
+ * most heavily weighted element.  'base' designates the rate of decay: after
+ * 'base' further updates, 'new''s weight in the EWMA decays to about 1/e
+ * (about .37). */
+static void
+exp_mavg(double *avg, int base, double new)
+{
+    *avg = (*avg * (base - 1) + new) / base;
+}
+
+static void
+update_moving_averages(struct ofproto_dpif *ofproto)
+{
+    const int min_ms = 60 * 1000; /* milliseconds in one minute. */
+
+    /* Update hourly averages on the minute boundaries. */
+    if (time_msec() - ofproto->last_minute >= min_ms) {
+        exp_mavg(&ofproto->hourly.add_rate, 60, ofproto->subfacet_add_count);
+        exp_mavg(&ofproto->hourly.del_rate, 60, ofproto->subfacet_del_count);
+
+        /* Update daily averages on the hour boundaries. */
+        if ((ofproto->last_minute - ofproto->created) / min_ms % 60 == 59) {
+            exp_mavg(&ofproto->daily.add_rate, 24, ofproto->hourly.add_rate);
+            exp_mavg(&ofproto->daily.del_rate, 24, ofproto->hourly.del_rate);
+        }
+
+        ofproto->total_subfacet_add_count += ofproto->subfacet_add_count;
+        ofproto->total_subfacet_del_count += ofproto->subfacet_del_count;
+        ofproto->subfacet_add_count = 0;
+        ofproto->subfacet_del_count = 0;
+        ofproto->last_minute += min_ms;
+    }
+}
+
+static void
+dpif_stats_update_hit_count(struct ofproto_dpif *ofproto, uint64_t delta)
+{
+    ofproto->n_hit += delta;
+}
 
 const struct ofproto_class ofproto_dpif_class = {
     init,
@@ -8331,10 +8829,7 @@ const struct ofproto_class ofproto_dpif_class = {
     get_netflow_ids,
     set_sflow,
     set_cfm,
-    get_cfm_fault,
-    get_cfm_opup,
-    get_cfm_remote_mpids,
-    get_cfm_health,
+    get_cfm_status,
     set_stp,
     get_stp_status,
     set_stp_port,
index 95bda33..d8db3ae 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -1120,44 +1120,15 @@ struct ofproto_class {
      * support CFM, as does a null pointer. */
     int (*set_cfm)(struct ofport *ofport, const struct cfm_settings *s);
 
-    /* Checks the fault status of CFM configured on 'ofport'.  Returns a
-     * bitmask of 'cfm_fault_reason's to indicate a CFM fault (generally
-     * indicating a connectivity problem).  Returns zero if CFM is not faulted,
-     * and -1 if CFM is not enabled on 'port'.
+    /* Checks the status of CFM configured on 'ofport'.  Returns true if the
+     * port's CFM status was successfully stored into '*status'.  Returns false
+     * if the port did not have CFM configured, in which case '*status' is
+     * indeterminate.
      *
-     * This function may be a null pointer if the ofproto implementation does
-     * not support CFM. */
-    int (*get_cfm_fault)(const struct ofport *ofport);
-
-    /* Check the operational status reported by the remote CFM endpoint of
-     * 'ofp_port'  Returns 1 if operationally up, 0 if operationally down, and
-     * -1 if CFM is not enabled on 'ofp_port' or does not support operational
-     * status.
-     *
-     * This function may be a null pointer if the ofproto implementation does
-     * not support CFM. */
-    int (*get_cfm_opup)(const struct ofport *ofport);
-
-    /* Gets the MPIDs of the remote maintenance points broadcasting to
-     * 'ofport'.  Populates 'rmps' with a provider owned array of MPIDs, and
-     * 'n_rmps' with the number of MPIDs in 'rmps'. Returns a number less than
-     * 0 if CFM is not enabled of 'ofport'.
-     *
-     * This function may be a null pointer if the ofproto implementation does
-     * not support CFM. */
-    int (*get_cfm_remote_mpids)(const struct ofport *ofport,
-                                const uint64_t **rmps, size_t *n_rmps);
-
-    /* Checks the health of CFM configured on 'ofport'.  Returns an integer
-     * to indicate the health percentage of the 'ofport' which is an average of
-     * the health of all the remote_mps.  Returns an integer between 0 and 100
-     * where 0 means that the 'ofport' is very unhealthy and 100 means the
-     * 'ofport' is perfectly healthy.  Returns -1 if CFM is not enabled on
-     * 'port' or if the number of remote_mpids is > 1.
-     *
-     * This function may be a null pointer if the ofproto implementation does
-     * not support CFM. */
-    int (*get_cfm_health)(const struct ofport *ofport);
+     * The caller must provide and owns '*status', but it does not own and must
+     * not modify or free the array returned in 'status->rmps'. */
+    bool (*get_cfm_status)(const struct ofport *ofport,
+                           struct ofproto_cfm_status *status);
 
     /* Configures spanning tree protocol (STP) on 'ofproto' using the
      * settings defined in 's'.
index c0d94f7..03ca59b 100644 (file)
@@ -2238,7 +2238,7 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_header *oh)
     uint16_t flags = ntohs(osc->flags);
 
     if (ofconn_get_type(ofconn) != OFCONN_PRIMARY
-        || ofconn_get_role(ofconn) != NX_ROLE_SLAVE) {
+        || ofconn_get_role(ofconn) != OFPCR12_ROLE_SLAVE) {
         enum ofp_config_flags cur = ofproto->frag_handling;
         enum ofp_config_flags next = flags & OFPC_FRAG_MASK;
 
@@ -2272,7 +2272,7 @@ static enum ofperr
 reject_slave_controller(struct ofconn *ofconn)
 {
     if (ofconn_get_type(ofconn) == OFCONN_PRIMARY
-        && ofconn_get_role(ofconn) == NX_ROLE_SLAVE) {
+        && ofconn_get_role(ofconn) == OFPCR12_ROLE_SLAVE) {
         return OFPERR_OFPBRC_EPERM;
     } else {
         return 0;
@@ -2843,62 +2843,21 @@ ofproto_get_netflow_ids(const struct ofproto *ofproto,
     ofproto->ofproto_class->get_netflow_ids(ofproto, engine_type, engine_id);
 }
 
-/* Checks the fault status of CFM for 'ofp_port' within 'ofproto'.  Returns a
- * bitmask of 'cfm_fault_reason's to indicate a CFM fault (generally
- * indicating a connectivity problem).  Returns zero if CFM is not faulted,
- * and -1 if CFM is not enabled on 'ofp_port'. */
-int
-ofproto_port_get_cfm_fault(const struct ofproto *ofproto, uint16_t ofp_port)
-{
-    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
-    return (ofport && ofproto->ofproto_class->get_cfm_fault
-            ? ofproto->ofproto_class->get_cfm_fault(ofport)
-            : -1);
-}
-
-/* Checks the operational status reported by the remote CFM endpoint of
- * 'ofp_port'  Returns 1 if operationally up, 0 if operationally down, and -1
- * if CFM is not enabled on 'ofp_port' or does not support operational status.
- */
-int
-ofproto_port_get_cfm_opup(const struct ofproto *ofproto, uint16_t ofp_port)
-{
-    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
-    return (ofport && ofproto->ofproto_class->get_cfm_opup
-            ? ofproto->ofproto_class->get_cfm_opup(ofport)
-            : -1);
-}
-
-/* Gets the MPIDs of the remote maintenance points broadcasting to 'ofp_port'
- * within 'ofproto'.  Populates 'rmps' with an array of MPIDs owned by
- * 'ofproto', and 'n_rmps' with the number of MPIDs in 'rmps'.  Returns a
- * number less than 0 if CFM is not enabled on 'ofp_port'. */
-int
-ofproto_port_get_cfm_remote_mpids(const struct ofproto *ofproto,
-                                  uint16_t ofp_port, const uint64_t **rmps,
-                                  size_t *n_rmps)
-{
-    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
-
-    *rmps = NULL;
-    *n_rmps = 0;
-    return (ofport && ofproto->ofproto_class->get_cfm_remote_mpids
-            ? ofproto->ofproto_class->get_cfm_remote_mpids(ofport, rmps,
-                                                           n_rmps)
-            : -1);
-}
-
-/* Checks the health of the CFM for 'ofp_port' within 'ofproto'.  Returns an
- * integer value between 0 and 100 to indicate the health of the port as a
- * percentage which is the average of cfm health of all the remote_mpids or
- * returns -1 if CFM is not enabled on 'ofport'. */
-int
-ofproto_port_get_cfm_health(const struct ofproto *ofproto, uint16_t ofp_port)
+/* Checks the status of CFM configured on 'ofp_port' within 'ofproto'.  Returns
+ * true if the port's CFM status was successfully stored into '*status'.
+ * Returns false if the port did not have CFM configured, in which case
+ * '*status' is indeterminate.
+ *
+ * The caller must provide and owns '*status', but it does not own and must not
+ * modify or free the array returned in 'status->rmps'. */
+bool
+ofproto_port_get_cfm_status(const struct ofproto *ofproto, uint16_t ofp_port,
+                            struct ofproto_cfm_status *status)
 {
     struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
-    return (ofport && ofproto->ofproto_class->get_cfm_health
-            ? ofproto->ofproto_class->get_cfm_health(ofport)
-            : -1);
+    return (ofport
+            && ofproto->ofproto_class->get_cfm_status
+            && ofproto->ofproto_class->get_cfm_status(ofport, status));
 }
 
 static enum ofperr
@@ -3576,38 +3535,34 @@ handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn,
 static enum ofperr
 handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
 {
-    struct ofputil_role_request rr;
+    struct ofputil_role_request request;
+    struct ofputil_role_request reply;
     struct ofpbuf *buf;
-    uint32_t role;
     enum ofperr error;
 
-    error = ofputil_decode_role_message(oh, &rr);
+    error = ofputil_decode_role_message(oh, &request);
     if (error) {
         return error;
     }
 
-    if (rr.request_current_role_only) {
-        role = ofconn_get_role(ofconn); /* NX_ROLE_* */
-        goto reply;
-    }
-
-    role = rr.role;
-
-    if (ofconn_get_role(ofconn) != role
-        && ofconn_has_pending_opgroups(ofconn)) {
-        return OFPROTO_POSTPONE;
-    }
+    if (request.role != OFPCR12_ROLE_NOCHANGE) {
+        if (ofconn_get_role(ofconn) != request.role
+            && ofconn_has_pending_opgroups(ofconn)) {
+            return OFPROTO_POSTPONE;
+        }
 
-    if (rr.have_generation_id) {
-        if (!ofconn_set_master_election_id(ofconn, rr.generation_id)) {
-            return OFPERR_OFPRRFC_STALE;
+        if (request.have_generation_id
+            && !ofconn_set_master_election_id(ofconn, request.generation_id)) {
+                return OFPERR_OFPRRFC_STALE;
         }
-    }
 
-    ofconn_set_role(ofconn, role);
+        ofconn_set_role(ofconn, request.role);
+    }
 
-reply:
-    buf = ofputil_encode_role_reply(oh, role);
+    reply.role = ofconn_get_role(ofconn);
+    reply.have_generation_id = ofconn_get_master_election_id(
+        ofconn, &reply.generation_id);
+    buf = ofputil_encode_role_reply(oh, &reply);
     ofconn_send_reply(ofconn, buf);
 
     return 0;
index 413472a..b3a55a4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@
 extern "C" {
 #endif
 
-struct cfm_settings;
 struct cls_rule;
 struct netdev;
 struct ofproto;
@@ -44,7 +43,7 @@ struct netdev_stats;
 
 struct ofproto_controller_info {
     bool is_connected;
-    enum nx_role role;
+    enum ofp12_controller_role role;
     struct {
         const char *keys[4];
         const char *values[4];
@@ -198,7 +197,7 @@ int ofproto_port_dump_done(struct ofproto_port_dump *);
           : (ofproto_port_dump_done(DUMP), false));         \
         )
 
-#define OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT  1000
+#define OFPROTO_FLOW_EVICTION_THRESHOLD_DEFAULT  2500
 #define OFPROTO_FLOW_EVICTION_THRESHOLD_MIN 100
 
 const char *ofproto_port_open_type(const char *datapath_type,
@@ -282,7 +281,6 @@ struct ofproto_bundle_settings {
     bool use_priority_tags;     /* Use 802.1p tag for frames in VLAN 0? */
 
     struct bond_settings *bond; /* Must be nonnull iff if n_slaves > 1. */
-    uint32_t *bond_stable_ids;  /* Array of n_slaves elements. */
 
     struct lacp_settings *lacp;              /* Nonnull to enable LACP. */
     struct lacp_slave_settings *lacp_slaves; /* Array of n_slaves elements. */
@@ -357,15 +355,33 @@ void ofproto_get_snoops(const struct ofproto *, struct sset *);
 void ofproto_get_all_flows(struct ofproto *p, struct ds *);
 void ofproto_get_netflow_ids(const struct ofproto *,
                              uint8_t *engine_type, uint8_t *engine_id);
-int ofproto_port_get_cfm_fault(const struct ofproto *, uint16_t ofp_port);
-int ofproto_port_get_cfm_opup(const struct ofproto *, uint16_t ofp_port);
-int ofproto_port_get_cfm_remote_mpids(const struct ofproto *,
-                                      uint16_t ofp_port, const uint64_t **rmps,
-                                      size_t *n_rmps);
-int ofproto_port_get_cfm_health(const struct ofproto *ofproto,
-                                uint16_t ofp_port);
+
 void ofproto_get_ofproto_controller_info(const struct ofproto *, struct shash *);
 void ofproto_free_ofproto_controller_info(struct shash *);
+
+/* CFM status query. */
+struct ofproto_cfm_status {
+    /* 0 if not faulted, otherwise a combination of one or more reasons. */
+    enum cfm_fault_reason faults;
+
+    /* 0 if the remote CFM endpoint is operationally down,
+     * 1 if the remote CFM endpoint is operationally up,
+     * -1 if we don't know because the remote CFM endpoint is not in extended
+     * mode. */
+    int remote_opstate;
+
+    /* Ordinarily a "health status" in the range 0...100 inclusive, with 0
+     * being worst and 100 being best, or -1 if the health status is not
+     * well-defined. */
+    int health;
+
+    /* MPIDs of remote maintenance points whose CCMs have been received. */
+    const uint64_t *rmps;
+    size_t n_rmps;
+};
+
+bool ofproto_port_get_cfm_status(const struct ofproto *, uint16_t ofp_port,
+                                 struct ofproto_cfm_status *);
 \f
 /* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
  *
index ddfeeda..8aa7fbe 100644 (file)
 
 /* XXX:
  *
- * Ability to generate actions on input for ECN
  * Ability to generate metadata for packet-outs
- * IPsec using skb mark.
- * VXLAN.
- * Multicast group management (possibly).
  * Disallow netdevs with names like "gre64_system" to prevent collisions. */
 
 VLOG_DEFINE_THIS_MODULE(tunnel);
@@ -46,7 +42,7 @@ struct tnl_match {
     ovs_be32 ip_src;
     ovs_be32 ip_dst;
     uint32_t odp_port;
-    bool in_key_present;
+    uint32_t skb_mark;
     bool in_key_flow;
 };
 
@@ -95,7 +91,7 @@ tnl_port_add__(const struct ofport *ofport, uint32_t odp_port,
     tnl_port->match.in_key = cfg->in_key;
     tnl_port->match.ip_src = cfg->ip_src;
     tnl_port->match.ip_dst = cfg->ip_dst;
-    tnl_port->match.in_key_present = cfg->in_key_present;
+    tnl_port->match.skb_mark = cfg->ipsec ? IPSEC_MARK : 0;
     tnl_port->match.in_key_flow = cfg->in_key_flow;
     tnl_port->match.odp_port = odp_port;
 
@@ -185,7 +181,7 @@ tnl_port_receive(struct flow *flow)
     match.ip_src = flow->tunnel.ip_dst;
     match.ip_dst = flow->tunnel.ip_src;
     match.in_key = flow->tunnel.tun_id;
-    match.in_key_present = flow->tunnel.flags & FLOW_TNL_F_KEY;
+    match.skb_mark = flow->skb_mark;
 
     tnl_port = tnl_find(&match);
     if (!tnl_port) {
@@ -197,14 +193,6 @@ tnl_port_receive(struct flow *flow)
         return NULL;
     }
 
-    if (is_ip_any(flow)
-        && ((flow->tunnel.ip_tos & IP_ECN_MASK) == IP_ECN_CE)
-        && (flow->nw_tos & IP_ECN_MASK) == IP_ECN_NOT_ECT) {
-        VLOG_WARN_RL(&rl, "dropping tunnel packet marked ECN CE but is not ECN"
-                     " capable");
-        return NULL;
-    }
-
     if (!VLOG_DROP_DBG(&dbg_rl)) {
         pre_flow_str = flow_to_string(flow);
     }
@@ -251,6 +239,7 @@ tnl_port_send(const struct tnl_port *tnl_port, struct flow *flow)
 
     flow->tunnel.ip_src = tnl_port->match.ip_src;
     flow->tunnel.ip_dst = tnl_port->match.ip_dst;
+    flow->skb_mark = tnl_port->match.skb_mark;
 
     if (!cfg->out_key_flow) {
         flow->tunnel.tun_id = cfg->out_key;
@@ -319,15 +308,12 @@ static struct tnl_port *
 tnl_find(struct tnl_match *match_)
 {
     struct tnl_match match = *match_;
-    bool is_multicast = ip_is_multicast(match.ip_src);
     struct tnl_port *tnl_port;
 
     /* remote_ip, local_ip, in_key */
-    if (!is_multicast) {
-        tnl_port = tnl_find_exact(&match);
-        if (tnl_port) {
-            return tnl_port;
-        }
+    tnl_port = tnl_find_exact(&match);
+    if (tnl_port) {
+        return tnl_port;
     }
 
     /* remote_ip, in_key */
@@ -339,47 +325,20 @@ tnl_find(struct tnl_match *match_)
     match.ip_src = match_->ip_src;
 
     /* remote_ip, local_ip */
-    if (!is_multicast) {
-        match.in_key = 0;
-        match.in_key_flow = true;
-        tnl_port = tnl_find_exact(&match);
-        if (tnl_port) {
-            return tnl_port;
-        }
-        match.in_key = match_->in_key;
-        match.in_key_flow = false;
+    match.in_key = 0;
+    match.in_key_flow = true;
+    tnl_port = tnl_find_exact(&match);
+    if (tnl_port) {
+        return tnl_port;
     }
 
     /* remote_ip */
     match.ip_src = 0;
-    match.in_key = 0;
-    match.in_key_flow = true;
     tnl_port = tnl_find_exact(&match);
     if (tnl_port) {
         return tnl_port;
     }
-    match.ip_src = match_->ip_src;
-    match.in_key = match_->in_key;
-    match.in_key_flow = false;
-
-    if (is_multicast) {
-        match.ip_src = 0;
-        match.ip_dst = match_->ip_src;
-
-        /* multicast remote_ip, in_key */
-        tnl_port = tnl_find_exact(&match);
-        if (tnl_port) {
-            return tnl_port;
-        }
 
-        /* multicast remote_ip */
-        match.in_key = 0;
-        match.in_key_flow = true;
-        tnl_port = tnl_find_exact(&match);
-        if (tnl_port) {
-            return tnl_port;
-        }
-    }
     return NULL;
 }
 
@@ -389,15 +348,14 @@ tnl_match_fmt(const struct tnl_match *match, struct ds *ds)
     ds_put_format(ds, IP_FMT"->"IP_FMT, IP_ARGS(match->ip_src),
                   IP_ARGS(match->ip_dst));
 
-    if (match->in_key_present) {
-        if (match->in_key_flow) {
-            ds_put_cstr(ds, ", key=flow");
-        } else {
-            ds_put_format(ds, ", key=%#"PRIx64, ntohll(match->in_key));
-        }
+    if (match->in_key_flow) {
+        ds_put_cstr(ds, ", key=flow");
+    } else {
+        ds_put_format(ds, ", key=%#"PRIx64, ntohll(match->in_key));
     }
 
     ds_put_format(ds, ", dp port=%"PRIu32, match->odp_port);
+    ds_put_format(ds, ", skb mark=%"PRIu32, match->skb_mark);
 }
 
 static void
@@ -407,8 +365,8 @@ tnl_port_mod_log(const struct tnl_port *tnl_port, const char *action)
         struct ds ds = DS_EMPTY_INITIALIZER;
 
         tnl_match_fmt(&tnl_port->match, &ds);
-        VLOG_DBG("%s tunnel port %s (%s)", action, tnl_port_get_name(tnl_port),
-                 ds_cstr(&ds));
+        VLOG_INFO("%s tunnel port %s (%s)", action,
+                  tnl_port_get_name(tnl_port), ds_cstr(&ds));
         ds_destroy(&ds);
     }
 }
index acb69a8..1b055ae 100644 (file)
@@ -20,6 +20,9 @@
 #include <stdint.h>
 #include "flow.h"
 
+/* skb mark used for IPsec tunnel packets */
+#define IPSEC_MARK 1
+
 /* Tunnel port emulation layer.
  *
  * These functions emulate tunnel virtual ports based on the outer
index fd646f0..b02d5a3 100644 (file)
@@ -598,8 +598,8 @@ ovsdb_file_commit(struct ovsdb_replica *replica,
     }
     file->n_transactions++;
 
-    /* If it has been at least COMPACT_MIN_MSEC millseconds since the last time
-     * we compacted (or at least COMPACT_RETRY_MSEC since the last time we
+    /* If it has been at least COMPACT_MIN_MSEC ms since the last time we
+     * compacted (or at least COMPACT_RETRY_MSEC ms since the last time we
      * tried), and if there are at least 100 transactions in the database, and
      * if the database is at least 10 MB, then compact the database. */
     if (time_msec() >= file->next_compact
index 6d07c45..febc351 100644 (file)
@@ -82,6 +82,8 @@ static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_cancel(
     struct json_array *params,
     const struct json *request_id);
 static void ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *);
+static size_t ovsdb_jsonrpc_monitor_json_length_all(
+    struct ovsdb_jsonrpc_session *);
 \f
 /* JSON-RPC database server. */
 
@@ -210,7 +212,7 @@ ovsdb_jsonrpc_server_add_remote(struct ovsdb_jsonrpc_server *svr,
     shash_add(&svr->remotes, name, remote);
 
     if (!listener) {
-        ovsdb_jsonrpc_session_create(remote, jsonrpc_session_open(name));
+        ovsdb_jsonrpc_session_create(remote, jsonrpc_session_open(name, true));
     }
     return remote;
 }
@@ -335,6 +337,8 @@ struct ovsdb_jsonrpc_session {
     struct list node;           /* Element in remote's sessions list. */
     struct ovsdb_session up;
     struct ovsdb_jsonrpc_remote *remote;
+    size_t backlog_threshold;   /* See ovsdb_jsonrpc_session_run(). */
+    size_t reply_backlog;
 
     /* Triggers. */
     struct hmap triggers;       /* Hmap of "struct ovsdb_jsonrpc_trigger"s. */
@@ -371,6 +375,8 @@ ovsdb_jsonrpc_session_create(struct ovsdb_jsonrpc_remote *remote,
     list_push_back(&remote->sessions, &s->node);
     hmap_init(&s->triggers);
     hmap_init(&s->monitors);
+    s->reply_backlog = 0;
+    s->backlog_threshold = 1024 * 1024;
     s->js = js;
     s->js_seqno = jsonrpc_session_get_seqno(js);
 
@@ -384,6 +390,11 @@ ovsdb_jsonrpc_session_close(struct ovsdb_jsonrpc_session *s)
 {
     ovsdb_jsonrpc_monitor_remove_all(s);
     ovsdb_jsonrpc_session_unlock_all(s);
+    ovsdb_jsonrpc_trigger_complete_all(s);
+
+    hmap_destroy(&s->monitors);
+    hmap_destroy(&s->triggers);
+
     jsonrpc_session_close(s->js);
     list_remove(&s->node);
     s->remote->server->n_sessions--;
@@ -394,6 +405,8 @@ ovsdb_jsonrpc_session_close(struct ovsdb_jsonrpc_session *s)
 static int
 ovsdb_jsonrpc_session_run(struct ovsdb_jsonrpc_session *s)
 {
+    size_t backlog;
+
     jsonrpc_session_run(s->js);
     if (s->js_seqno != jsonrpc_session_get_seqno(s->js)) {
         s->js_seqno = jsonrpc_session_get_seqno(s->js);
@@ -404,7 +417,8 @@ ovsdb_jsonrpc_session_run(struct ovsdb_jsonrpc_session *s)
 
     ovsdb_jsonrpc_trigger_complete_done(s);
 
-    if (!jsonrpc_session_get_backlog(s->js)) {
+    backlog = jsonrpc_session_get_backlog(s->js);
+    if (!backlog) {
         struct jsonrpc_msg *msg = jsonrpc_session_recv(s->js);
         if (msg) {
             if (msg->type == JSONRPC_REQUEST) {
@@ -419,6 +433,39 @@ ovsdb_jsonrpc_session_run(struct ovsdb_jsonrpc_session *s)
                 jsonrpc_msg_destroy(msg);
             }
         }
+        s->reply_backlog = jsonrpc_session_get_backlog(s->js);
+    } else if (backlog > s->reply_backlog + s->backlog_threshold) {
+        /* We have a lot of data queued to send to the client.  The data is
+         * likely to be mostly monitor updates.  It is unlikely that the
+         * monitor updates are due to transactions by 's', because we will not
+         * let 's' make any more transactions until it drains its backlog to 0
+         * (see previous 'if' case).  So the monitor updates are probably due
+         * to transactions made by database clients other than 's'.  We can't
+         * fix that by preventing 's' from executing more transactions.  We
+         * could fix it by preventing every client from executing transactions,
+         * but then one slow or hung client could prevent other clients from
+         * doing useful work.
+         *
+         * Our solution is to cap the maximum backlog to O(1) in the amount of
+         * data in the database.  If the backlog exceeds that amount, then we
+         * disconnect the client.  When it reconnects, it can fetch the entire
+         * contents of the database using less data than was previously
+         * backlogged. */
+        size_t monitor_length;
+
+        monitor_length = ovsdb_jsonrpc_monitor_json_length_all(s);
+        if (backlog > s->reply_backlog + monitor_length * 2) {
+            VLOG_INFO("%s: %zu bytes backlogged but a complete replica "
+                      "would only take %zu bytes, disconnecting",
+                      jsonrpc_session_get_name(s->js),
+                      backlog - s->reply_backlog, monitor_length);
+            jsonrpc_session_force_reconnect(s->js);
+        } else {
+            /* The backlog is not unreasonably big.  Only check again after it
+             * becomes much bigger. */
+            s->backlog_threshold = 2 * MAX(s->backlog_threshold * 2,
+                                           monitor_length);
+        }
     }
     return jsonrpc_session_is_alive(s->js) ? 0 : ETIMEDOUT;
 }
@@ -1018,6 +1065,8 @@ struct ovsdb_jsonrpc_monitor *ovsdb_jsonrpc_monitor_find(
 static void ovsdb_jsonrpc_monitor_destroy(struct ovsdb_replica *);
 static struct json *ovsdb_jsonrpc_monitor_get_initial(
     const struct ovsdb_jsonrpc_monitor *);
+static size_t ovsdb_jsonrpc_monitor_json_length(
+    const struct ovsdb_jsonrpc_monitor *);
 
 static bool
 parse_bool(struct ovsdb_parser *parser, const char *name, bool default_value)
@@ -1287,6 +1336,22 @@ ovsdb_jsonrpc_monitor_remove_all(struct ovsdb_jsonrpc_session *s)
     }
 }
 
+/* Returns an overestimate of the number of bytes of JSON data required to
+ * report the current contents of the database over all the monitors currently
+ * configured in 's'.  */
+static size_t
+ovsdb_jsonrpc_monitor_json_length_all(struct ovsdb_jsonrpc_session *s)
+{
+    struct ovsdb_jsonrpc_monitor *m;
+    size_t length;
+
+    length = 0;
+    HMAP_FOR_EACH (m, node, &s->monitors) {
+        length += ovsdb_jsonrpc_monitor_json_length(m);
+    }
+    return length;
+}
+
 static struct ovsdb_jsonrpc_monitor *
 ovsdb_jsonrpc_monitor_cast(struct ovsdb_replica *replica)
 {
@@ -1422,6 +1487,52 @@ ovsdb_jsonrpc_monitor_change_cb(const struct ovsdb_row *old,
     return true;
 }
 
+/* Returns an overestimate of the number of bytes of JSON data required to
+ * report the current contents of the database over monitor 'm'. */
+static size_t
+ovsdb_jsonrpc_monitor_json_length(const struct ovsdb_jsonrpc_monitor *m)
+{
+    const struct shash_node *node;
+    size_t length;
+
+    /* Top-level overhead of monitor JSON. */
+    length = 256;
+
+    SHASH_FOR_EACH (node, &m->tables) {
+        const struct ovsdb_jsonrpc_monitor_table *mt = node->data;
+        const struct ovsdb_table *table = mt->table;
+        const struct ovsdb_row *row;
+        size_t i;
+
+        /* Per-table JSON overhead: "<table>":{...}. */
+        length += strlen(table->schema->name) + 32;
+
+        /* Per-row JSON overhead: ,"<uuid>":{"old":{...},"new":{...}} */
+        length += hmap_count(&table->rows) * (UUID_LEN + 32);
+
+        /* Per-row, per-column JSON overhead: ,"<column>": */
+        for (i = 0; i < mt->n_columns; i++) {
+            const struct ovsdb_jsonrpc_monitor_column *c = &mt->columns[i];
+            const struct ovsdb_column *column = c->column;
+
+            length += hmap_count(&table->rows) * (8 + strlen(column->name));
+        }
+
+        /* Data. */
+        HMAP_FOR_EACH (row, hmap_node, &table->rows) {
+            for (i = 0; i < mt->n_columns; i++) {
+                const struct ovsdb_jsonrpc_monitor_column *c = &mt->columns[i];
+                const struct ovsdb_column *column = c->column;
+
+                length += ovsdb_datum_json_length(&row->fields[column->index],
+                                                  &column->type);
+            }
+        }
+    }
+
+    return length;
+}
+
 static void
 ovsdb_jsonrpc_monitor_init_aux(struct ovsdb_jsonrpc_monitor_aux *aux,
                                const struct ovsdb_jsonrpc_monitor *m,
index 440e8d0..ea3c3f3 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -48,7 +48,7 @@ struct ovsdb_log {
     struct lockfile *lockfile;
     FILE *stream;
     struct ovsdb_error *read_error;
-    struct ovsdb_error *write_error;
+    bool write_error;
     enum ovsdb_log_mode mode;
 };
 
@@ -133,7 +133,7 @@ ovsdb_log_open(const char *name, enum ovsdb_log_open_mode open_mode,
     file->prev_offset = 0;
     file->offset = 0;
     file->read_error = NULL;
-    file->write_error = NULL;
+    file->write_error = false;
     file->mode = OVSDB_LOG_READ;
     *filep = file;
     return NULL;
@@ -154,7 +154,6 @@ ovsdb_log_close(struct ovsdb_log *file)
         fclose(file->stream);
         lockfile_unlock(file->lockfile);
         ovsdb_error_destroy(file->read_error);
-        ovsdb_error_destroy(file->write_error);
         free(file);
     }
 }
@@ -332,10 +331,9 @@ ovsdb_log_write(struct ovsdb_log *file, struct json *json)
 
     json_string = NULL;
 
-    if (file->write_error) {
-        return ovsdb_error_clone(file->write_error);
-    } else if (file->mode == OVSDB_LOG_READ) {
+    if (file->mode == OVSDB_LOG_READ || file->write_error) {
         file->mode = OVSDB_LOG_WRITE;
+        file->write_error = false;
         if (fseeko(file->stream, file->offset, SEEK_SET)) {
             error = ovsdb_io_error(errno, "%s: cannot seek to offset %lld",
                                    file->name, (long long int) file->offset);
@@ -383,7 +381,7 @@ ovsdb_log_write(struct ovsdb_log *file, struct json *json)
     return NULL;
 
 error:
-    file->write_error = ovsdb_error_clone(error);
+    file->write_error = true;
     free(json_string);
     return error;
 }
index dc0839e..1f21950 100755 (executable)
@@ -517,34 +517,54 @@ void
             print "{"
             print "    struct ovsdb_datum datum;"
             if type.n_min == 1 and type.n_max == 1:
+                print "    union ovsdb_atom key;"
+                if type.value:
+                    print "    union ovsdb_atom value;"
                 print
                 print "    ovs_assert(inited);"
                 print "    datum.n = 1;"
-                print "    datum.keys = xmalloc(sizeof *datum.keys);"
-                print "    " + type.key.copyCValue("datum.keys[0].%s" % type.key.type.to_string(), keyVar)
+                print "    datum.keys = &key;"
+                print "    " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
                 if type.value:
-                    print "    datum.values = xmalloc(sizeof *datum.values);"
-                    print "    "+ type.value.copyCValue("datum.values[0].%s" % type.value.type.to_string(), valueVar)
+                    print "    datum.values = &value;"
+                    print "    "+ type.value.assign_c_value_casting_away_const("value.%s" % type.value.type.to_string(), valueVar)
                 else:
                     print "    datum.values = NULL;"
+                txn_write_func = "ovsdb_idl_txn_write_clone"
             elif type.is_optional_pointer():
+                print "    union ovsdb_atom key;"
                 print
                 print "    ovs_assert(inited);"
                 print "    if (%s) {" % keyVar
                 print "        datum.n = 1;"
-                print "        datum.keys = xmalloc(sizeof *datum.keys);"
-                print "        " + type.key.copyCValue("datum.keys[0].%s" % type.key.type.to_string(), keyVar)
+                print "        datum.keys = &key;"
+                print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), keyVar)
+                print "    } else {"
+                print "        datum.n = 0;"
+                print "        datum.keys = NULL;"
+                print "    }"
+                print "    datum.values = NULL;"
+                txn_write_func = "ovsdb_idl_txn_write_clone"
+            elif type.n_max == 1:
+                print "    union ovsdb_atom key;"
+                print
+                print "    ovs_assert(inited);"
+                print "    if (%s) {" % nVar
+                print "        datum.n = 1;"
+                print "        datum.keys = &key;"
+                print "        " + type.key.assign_c_value_casting_away_const("key.%s" % type.key.type.to_string(), "*" + keyVar)
                 print "    } else {"
                 print "        datum.n = 0;"
                 print "        datum.keys = NULL;"
                 print "    }"
                 print "    datum.values = NULL;"
+                txn_write_func = "ovsdb_idl_txn_write_clone"
             else:
                 print "    size_t i;"
                 print
                 print "    ovs_assert(inited);"
                 print "    datum.n = %s;" % nVar
-                print "    datum.keys = xmalloc(%s * sizeof *datum.keys);" % nVar
+                print "    datum.keys = %s ? xmalloc(%s * sizeof *datum.keys) : NULL;" % (nVar, nVar)
                 if type.value:
                     print "    datum.values = xmalloc(%s * sizeof *datum.values);" % nVar
                 else:
@@ -560,8 +580,10 @@ void
                     valueType = "OVSDB_TYPE_VOID"
                 print "    ovsdb_datum_sort_unique(&datum, %s, %s);" % (
                     type.key.toAtomicType(), valueType)
-            print "    ovsdb_idl_txn_write(&row->header_, &%(s)s_columns[%(S)s_COL_%(C)s], &datum);" \
-                % {'s': structName,
+                txn_write_func = "ovsdb_idl_txn_write"
+            print "    %(f)s(&row->header_, &%(s)s_columns[%(S)s_COL_%(C)s], &datum);" \
+                % {'f': txn_write_func,
+                   's': structName,
                    'S': structName.upper(),
                    'C': columnName.upper()}
             print "}"
index 6b75f49..b50b39b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -435,8 +435,8 @@ print_db_changes(struct shash *tables, struct shash *names,
                              ? shash_find_data(&table_schema->columns, column)
                              : NULL);
                         if (column_schema) {
-                            const struct ovsdb_error *error;
                             const struct ovsdb_type *type;
+                            struct ovsdb_error *error;
                             struct ovsdb_datum datum;
 
                             type = &column_schema->type;
@@ -448,6 +448,8 @@ print_db_changes(struct shash *tables, struct shash *names,
                                 ds_init(&s);
                                 ovsdb_datum_to_string(&datum, type, &s);
                                 value_string = ds_steal_cstr(&s);
+                            } else {
+                                ovsdb_error_destroy(error);
                             }
                         }
                         if (!value_string) {
index 6e4ff79..e976d3b 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -69,10 +69,6 @@ void ovsdb_destroy(struct ovsdb *);
 
 void ovsdb_get_memory_usage(const struct ovsdb *, struct simap *usage);
 
-struct ovsdb_error *ovsdb_from_json(const struct json *, struct ovsdb **)
-    WARN_UNUSED_RESULT;
-struct json *ovsdb_to_json(const struct ovsdb *);
-
 struct ovsdb_table *ovsdb_get_table(const struct ovsdb *, const char *);
 
 struct json *ovsdb_execute(struct ovsdb *, const struct ovsdb_session *,
index e13374f..3ab2709 100644 (file)
@@ -510,3 +510,36 @@ help:
 +%: varname=$(subst +,,$@)
 +%:
        @echo "$($(varname))"
+
+# external nodes and links
+#
+ALL_LINKS := $(LINKS) $(patsubst L/%,%,$(filter L/%,$(MAKECMDGOALS)))
+EXTERNAL_LINKS := $(filter $(foreach host,$(EXTERNAL_HOSTS),%-$(host)),$(ALL_LINKS))
+
+$(foreach host,$(EXTERNAL_HOSTS),sshcheck-$(host)): ;
+$(foreach host,$(EXTERNAL_HOSTS),ovsversion-$(host)): ;
+$(foreach host,$(EXTERNAL_HOSTS),showdpid-$(host)): ;
+$(foreach host,$(EXTERNAL_HOSTS),showmac-$(host)): ;
+$(foreach host,$(EXTERNAL_HOSTS),showports-$(host)): ;
+$(foreach host,$(EXTERNAL_HOSTS),update-$(host)): ;
+$(foreach host,$(EXTERNAL_HOSTS),del-controller-$(host)): ;
+$(foreach host,$(EXTERNAL_HOSTS),cache/status.$(host)): ;
+$(foreach host,$(EXTERNAL_HOSTS),cache/db.$(host)): ;
+$(foreach host,$(EXTERNAL_HOSTS),cache/bridge.$(host)): ;
+$(foreach host,$(EXTERNAL_HOSTS),cache/switch.$(host)): ;
+$(foreach host,$(EXTERNAL_HOSTS),cache/controller.$(host)): ;
+$(foreach link,$(EXTERNAL_LINKS),cache/iface.$(link)@2): ;
+$(foreach link,$(EXTERNAL_LINKS),cache/port.$(link)@2): ;
+$(foreach link,$(EXTERNAL_LINKS),del-iface.$(link)@2): ;
+
+# we assume that a program called tunproxy is available on the
+# external nodes.  
+
+.SECONDEXPANSION:
+$(foreach link,$(EXTERNAL_LINKS),cache/endpoint.$(link)@2): cache/endpoint.%@2: cache/port.%@1 cache/host.$$(call leftnode,%)
+       @#echo $* [$<] [$^] $(call rightnode,$*)
+       @echo $(call default,EXTERNAL_PORT,$(call rightnode,$*)) > $@
+       @echo "===>" $(call rightnode,$*): \
+          ./tunproxy -t $$(cat cache/host.$(call leftnode,$*)):$$(cat cache/port.$*@1) \
+           -p $(call default,EXTERNAL_PORT,$(call rightnode,$*)) -e -d
+
diff --git a/planetlab/exp-tool/tunproxy.c b/planetlab/exp-tool/tunproxy.c
new file mode 100644 (file)
index 0000000..024d886
--- /dev/null
@@ -0,0 +1,141 @@
+/*\r
+ * tunproxy.c --- small demo program for tunneling over UDP with tun/tap\r
+ *\r
+ * Copyright (C) 2003  Philippe Biondi <phil@secdev.org>\r
+ * Copyright (C) 2013  Felician Nemeth <nemethf@tmit.bme.hu>\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify it\r
+ * under the terms of the GNU Lesser General Public License as published by\r
+ * the Free Software Foundation.\r
+ *\r
+ * This program is distributed in the hope that it will be useful, but\r
+ * WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+ * http://www.secdev.org/projects/tuntap_udp/files/tunproxy.c\r
+ */\r
+\r
+#include <stdlib.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <unistd.h>\r
+#include <sys/stat.h>\r
+#include <fcntl.h>\r
+#include <sys/types.h>\r
+#include <sys/socket.h>\r
+#include <netinet/in.h>\r
+#include <arpa/inet.h>\r
+#include <string.h>\r
+#include <net/if.h>\r
+#include <linux/if_tun.h>\r
+#include <getopt.h>\r
+#include <sys/ioctl.h>\r
+#include <errno.h>\r
+\r
+#define PERROR(x) do { perror(x); exit(1); } while (0)\r
+#define ERROR(x, args ...) do { fprintf(stderr,"ERROR:" x, ## args); exit(1); } while (0)\r
+\r
+extern void exit(int);\r
+\r
+void usage()\r
+{\r
+       fprintf(stderr, "Usage: tunproxy -t target_ip:port [-p local_port] [-e]\n");\r
+       exit(0);\r
+}\r
+\r
+int main(int argc, char *argv[])\r
+{\r
+       struct sockaddr_in sin, sout, remote;\r
+       struct ifreq ifr;\r
+       int fd, s, remote_len, remote_port, local_port, l;\r
+       unsigned int soutlen;\r
+       char c, *p, *remote_ip = 0;\r
+       char buf[2000];\r
+       fd_set fdset;\r
+\r
+       int TUNMODE = IFF_TUN, DEBUG = 0;\r
+\r
+       while ((c = getopt(argc, argv, "t:p:ehd")) != -1) {\r
+               switch (c) {\r
+               case 'h':\r
+                       usage();\r
+               case 'd':\r
+                       DEBUG++;\r
+                       break;\r
+               case 'p':\r
+                       local_port = atoi(optarg);\r
+                       break;\r
+               case 't':\r
+                       p = memchr(optarg,':',16);\r
+                       if (!p) ERROR("invalid argument : [%s]\n",optarg);\r
+                       *p = 0;\r
+                       remote_ip = optarg;\r
+                       remote_port = atoi(p+1);\r
+                       break;\r
+               case 'e':\r
+                       TUNMODE = IFF_TAP;\r
+                       break;\r
+               default:\r
+                       usage();\r
+               }\r
+       }\r
+       if (remote_ip == 0) usage();\r
+\r
+       if ( (fd = open("/dev/net/tun",O_RDWR)) < 0) PERROR("open");\r
+\r
+       memset(&ifr, 0, sizeof(ifr));\r
+       ifr.ifr_flags = TUNMODE | IFF_NO_PI;\r
+       strncpy(ifr.ifr_name, "toto%d", IFNAMSIZ);\r
+       if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) PERROR("ioctl");\r
+\r
+       printf("Allocated interface %s. Configure and use it\n", ifr.ifr_name);\r
+       \r
+       s = socket(PF_INET, SOCK_DGRAM, 0);\r
+       sin.sin_family = AF_INET;\r
+       sin.sin_addr.s_addr = htonl(INADDR_ANY);\r
+       sin.sin_port = htons(local_port);\r
+\r
+       if ( bind(s,(struct sockaddr *)&sin, sizeof(sin)) < 0)\r
+         PERROR("bind");\r
+\r
+       remote_len = sizeof(remote);\r
+       memset(&remote, 0, remote_len);\r
+       remote.sin_family = AF_INET;\r
+       remote.sin_port = htons(remote_port);\r
+       remote.sin_addr.s_addr=inet_addr(remote_ip);\r
+\r
+       while (1) {\r
+               FD_ZERO(&fdset);\r
+               FD_SET(fd, &fdset);\r
+               FD_SET(s, &fdset);\r
+               if (select(fd+s+1, &fdset,NULL,NULL,NULL) < 0) PERROR("select");\r
+               if (FD_ISSET(fd, &fdset)) {\r
+                       if (DEBUG)\r
+                         if (write(1,">", 1) < 0) PERROR("write");\r
+                       l = read(fd, buf, sizeof(buf));\r
+                       if (l < 0) \r
+                         PERROR("read");\r
+                       if (sendto(s, buf, l, 0, (struct sockaddr *)&remote, remote_len) < 0)\r
+                         PERROR("sendto");\r
+               }\r
+               if (FD_ISSET(s, &fdset)) {\r
+                       if (DEBUG) \r
+                         if (write(1,"<", 1) < 0) PERROR("write");\r
+                       soutlen = sizeof(sout);\r
+                       l = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&sout, &soutlen);\r
+                       if (l == -1) {\r
+                         if (write(1,"(", 1) < 0) PERROR("write");\r
+                         fprintf(stderr, "[%s,%d]", strerror(errno), l);\r
+                         continue;\r
+                       }\r
+                       if ((sout.sin_addr.s_addr != remote.sin_addr.s_addr) ||\r
+                           (sout.sin_port != remote.sin_port)) {\r
+                         printf("Got packet from  %s:%u instead of %s:%u\n", \r
+                                inet_ntoa(sout.sin_addr), ntohs(sout.sin_port),\r
+                                inet_ntoa(remote.sin_addr), ntohs(remote.sin_port));\r
+                       }\r
+                       if (write(fd, buf, l) < 0) PERROR("write");\r
+               }\r
+       }\r
+}\r
index 1a63bf0..d72be72 100755 (executable)
@@ -306,6 +306,15 @@ function get_local_links () {
     ovs-vsctl --db=unix:$DB_SOCKET list-ifaces "$bridge"
 }
 
+function get_mac () {
+
+    get_params "bridge" "$@"
+
+    set -e
+    local tap=$(ovs-appctl netdev-pltap/get-tapname "$bridge")
+    ifconfig "$tap" | awk '/HWaddr/ { print $5 }'
+}
+
 ### for demos - connect to an ndnmap deployment to visualize links bandwidth
 # this expects 3 arguments
 # an interface name, L<id1>-<id2> based on your ids in conf.mk
@@ -353,32 +362,13 @@ function gmap_probe () {
     echo $! > $pid_file
 }
 
-####################
-# xxx tmp for a demo 
-# there *must* be a better way to do that
-# the thing is the slice sees several tap devices at this point, which is odd...
-# for now I'm searching the tapname based on some hint - the vnet ip range
-VNET=10.0.16
-function show_mac () {
-    ifnames=$(grep : /proc/net/dev | cut -d: -f1 | awk '{print $1;}')
-    tapname=""
-    for ifname in $ifnames; do
-       ifconfig $ifname | grep -q "$VNET" && tapname=$ifname
-    done
-    if [ -z "$tapname" ] ; then
-       echo "no-tap-found-for$VNET"
-       exit 1
-    fi
-    ifconfig $tapname | grep -i hwaddr | awk '{print $5;}'
-}
-
 ####################
 SUPPORTED_SUBCOMMANDS="start stop status 
 start_db stop_db start_switch stop_switch
 create_bridge create_port del_bridge del_port
 show get_local_endpoint set_remote_endpoint
 set_controller del_controller gmap_probe
-get_local_ip get_local_links show_mac"
+get_local_ip get_local_links get_mac"
 
 function main () {
        message="Usage: $COMMAND <subcommand> ...
index 5865acd..c858471 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+# Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -287,7 +287,9 @@ class BaseType(object):
         if self.enum:
             literals = [value.toEnglish(escapeLiteral)
                         for value in self.enum.values]
-            if len(literals) == 2:
+            if len(literals) == 1:
+                english = 'must be %s' % (literals[0])
+            elif len(literals) == 2:
                 english = 'either %s or %s' % (literals[0], literals[1])
             else:
                 english = 'one of %s, %s, or %s' % (literals[0],
@@ -351,6 +353,15 @@ class BaseType(object):
         else:
             return "%(dst)s = %(src)s;" % args
 
+    def assign_c_value_casting_away_const(self, dst, src):
+        args = {'dst': dst, 'src': src}
+        if self.ref_table_name:
+            return ("%(dst)s = %(src)s->header_.uuid;") % args
+        elif self.type == StringType:
+            return "%(dst)s = CONST_CAST(char *, %(src)s);" % args
+        else:
+            return "%(dst)s = %(src)s;" % args
+
     def initCDefault(self, var, is_optional):
         if self.ref_table_name:
             return "%s = NULL;" % var
index c640ebf..fb083ee 100644 (file)
@@ -107,6 +107,8 @@ class Stream(object):
             return errno.EAFNOSUPPORT, None
 
         suffix = name.split(":", 1)[1]
+        if name.startswith("unix:"):
+            suffix = ovs.util.abs_file_name(ovs.dirs.RUNDIR, suffix)
         error, sock = cls._open(suffix, dscp)
         if error:
             return error, None
@@ -282,6 +284,8 @@ class PassiveStream(object):
             return errno.EAFNOSUPPORT, None
 
         bind_path = name[6:]
+        if name.startswith("punix:"):
+            bind_path = ovs.util.abs_file_name(ovs.dirs.RUNDIR, bind_path)
         error, sock = ovs.socket_util.make_unix_socket(socket.SOCK_STREAM,
                                                        True, bind_path, None)
         if error:
index f7ace66..7cfa415 100644 (file)
@@ -61,8 +61,8 @@ class Vlog:
             return
 
         now = datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
-        message = ("%s|%s|%s|%s|%s"
-                   % (now, Vlog.__msg_num, self.name, level, message))
+        syslog_message = ("%s|%s|%s|%s"
+                           % (Vlog.__msg_num, self.name, level, message))
 
         level = LEVELS.get(level.lower(), logging.DEBUG)
         Vlog.__msg_num += 1
@@ -70,6 +70,10 @@ class Vlog:
         for f, f_level in Vlog.__mfl[self.name].iteritems():
             f_level = LEVELS.get(f_level, logging.CRITICAL)
             if level >= f_level:
+                if f == "syslog":
+                    message = syslog_message
+                else:
+                    message = "%s|%s" % (now, syslog_message)
                 logging.getLogger(f).log(level, message, **kwargs)
 
     def emer(self, message, **kwargs):
index d9b68e4..ba2774a 100644 (file)
@@ -42,11 +42,15 @@ assignments.  The following OVS-specific variable names are supported:
 Note
 ----
 
-"ifdown" on a bridge will not bring individual ports on the bridge
+"ifdown" on a bridge will not bring individual ports on the bridge
 down.  "ifup" on a bridge will not add ports to the bridge.  This
 behavior should be compatible with standard bridges (with
 TYPE=Bridge).
 
+* If 'ifup' on an interface is called multiple times, one can see
+"RTNETLINK answers: File exists" printed on the console. This comes from
+ifup-eth trying to add zeroconf route multiple times and is harmless.
+
 Examples
 --------
 
index 3bdc4ce..7bc8520 100644 (file)
@@ -17,6 +17,7 @@ EXTRA_DIST += \
        rhel/openvswitch-kmod-rhel5.spec.in \
        rhel/openvswitch-kmod-rhel6.spec \
        rhel/openvswitch-kmod-rhel6.spec.in \
+       rhel/openvswitch-kmod.files \
        rhel/openvswitch-kmod-fedora.spec \
        rhel/openvswitch-kmod-fedora.spec.in \
        rhel/openvswitch.spec \
index a25e624..55a13a7 100755 (executable)
@@ -31,7 +31,7 @@
 test -e /etc/sysconfig/openvswitch && . /etc/sysconfig/openvswitch
 
 start () {
-    set $ovs_ctl ${1-start}
+    set ovs_ctl ${1-start}
     set "$@" --system-id=random
     if test X"$FORCE_COREFILES" != X; then
        set "$@" --force-corefiles="$FORCE_COREFILES"
@@ -48,13 +48,13 @@ start () {
     set "$@" $OVS_CTL_OPTS
     "$@"
 
-    $ovs_ctl --protocol=gre enable-protocol
+    ovs_ctl --protocol=gre enable-protocol
 
     touch /var/lock/subsys/openvswitch
 }
 
 stop () {
-    $ovs_ctl stop
+    ovs_ctl stop
     rm -f /var/lock/subsys/openvswitch
 }
 
@@ -67,7 +67,6 @@ restart () {
     fi
 }
 
-ovs_ctl=/usr/share/openvswitch/scripts/ovs-ctl
 case $1 in
     start)
         start
@@ -83,10 +82,10 @@ case $1 in
         # Nothing to do.
         ;;
     status)
-        $ovs_ctl status
+        ovs_ctl status
         ;;
     version)
-        $ovs_ctl version
+        ovs_ctl version
         ;;
     force-reload-kmod)
         start force-reload-kmod
index 46b94b9..73751d4 100644 (file)
@@ -6,6 +6,8 @@
 # without warranty of any kind.
 
 /var/log/openvswitch/*.log {
+       daily
+       compress
        sharedscripts
        missingok
        postrotate
index 3538721..8904c59 100755 (executable)
@@ -34,7 +34,7 @@ if [ ! -x ${OTHERSCRIPT} ]; then
        OTHERSCRIPT="/etc/sysconfig/network-scripts/ifup-eth"
 fi
 
-check_recursion()
+check_recursion ()
 {
        [ -n "${UPPEDSTACK}" ] && for _r in ${UPPEDSTACK}; do
                [ "$_r" = "$1" ] && return 1
@@ -43,6 +43,13 @@ check_recursion()
        return 0
 }
 
+ifup_ovs_bridge ()
+{
+       if ovs-vsctl br-exists "${OVS_BRIDGE}"; then :; else
+               /sbin/ifup "${OVS_BRIDGE}"
+       fi
+}
+
 if [ -z "${UPPEDSTACK}" ]; then
        UPPEDSTACK="${DEVICE}"
 fi
@@ -57,7 +64,23 @@ done
 
 case "$TYPE" in
        OVSBridge)
-               ovs-vsctl -t ${TIMEOUT} -- --may-exist add-br "$DEVICE" $OVS_OPTIONS ${OVS_EXTRA+-- $OVS_EXTRA}
+               # If bridge already exists and is up, it has been configured through
+               # other cases like OVSPort, OVSIntPort and OVSBond. If it is down or
+               # it does not exist, create it. It is possible for a bridge to exist
+               # because it remained in the OVSDB for some reason, but it won't be up.
+               if check_device_down "${DEVICE}"; then
+                       ovs-vsctl -t ${TIMEOUT} -- --may-exist add-br "$DEVICE" $OVS_OPTIONS \
+                       ${OVS_EXTRA+-- $OVS_EXTRA} \
+                       ${STP+-- set bridge "$DEVICE" stp_enable="${STP}"}
+               else
+                       OVSBRIDGECONFIGURED="yes"
+               fi
+
+               # When dhcp is enabled, the assumption is that there will be a port to
+               # attach (otherwise, we can't reach out for dhcp). So, we do not
+               # configure the bridge through rhel's ifup infrastructure unless
+               # it is being configured after the port has been configured.
+               # The "OVSINTF" is set only after the port is configured.
                if [ "${OVSBOOTPROTO}" = "dhcp" ] && [ -n "${OVSINTF}" ]; then
                        case " ${OVSDHCPINTERFACES} " in
                                *" ${OVSINTF} "*)
@@ -65,24 +88,28 @@ case "$TYPE" in
                                ;;
                        esac
                fi
-               if [ "${OVSBOOTPROTO}" != "dhcp" ] && [ -z "${OVSINTF}" ]; then
+
+               # When dhcp is not enabled, it is possible that someone may want
+               # a standalone bridge (i.e it may not have any ports). Configure it.
+               if [ "${OVSBOOTPROTO}" != "dhcp" ] && [ -z "${OVSINTF}" ] && \
+                       [ "${OVSBRIDGECONFIGURED}" != "yes" ]; then
                        ${OTHERSCRIPT} ${CONFIG}
                fi
-               [ -n "${STP}" ] && ovs-vsctl --no-wait set bridge "${DEVICE}" stp_enable="${STP}"
+               exit 0
                ;;
        OVSPort)
-               /sbin/ifup "$OVS_BRIDGE"
+               ifup_ovs_bridge
                ${OTHERSCRIPT} ${CONFIG} ${2}
                ovs-vsctl -t ${TIMEOUT} -- --may-exist add-port "$OVS_BRIDGE" "$DEVICE" $OVS_OPTIONS ${OVS_EXTRA+-- $OVS_EXTRA}
                OVSINTF=${DEVICE} /sbin/ifup "$OVS_BRIDGE"
                ;;
        OVSIntPort)
-               /sbin/ifup "$OVS_BRIDGE"
+               ifup_ovs_bridge
                ovs-vsctl -t ${TIMEOUT} -- --may-exist add-port "$OVS_BRIDGE" "$DEVICE" $OVS_OPTIONS -- set Interface "$DEVICE" type=internal ${OVS_EXTRA+-- $OVS_EXTRA}
                ${OTHERSCRIPT} ${CONFIG} ${2}
                ;;
        OVSBond)
-               /sbin/ifup "$OVS_BRIDGE"
+               ifup_ovs_bridge
                for _iface in $BOND_IFACES; do
                        /sbin/ifup ${_iface}
                done
index d9aeff0..6dbb377 100644 (file)
@@ -19,6 +19,7 @@ Group:          System/Kernel
 License:        GPLv2
 URL:            http://openvswitch.org/
 Source0:        %{oname}-%{version}.tar.gz
+Source1:        %{oname}-kmod.files
 BuildRoot:      %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 BuildRequires:  %kernel_module_package_buildreqs
 
@@ -34,7 +35,7 @@ BuildRequires:  %kernel_module_package_buildreqs
 # specified kernel variants.
 %{!?kflavors:%define kflavors default}
 
-%kernel_module_package -n %{oname} %kflavors
+%kernel_module_package -n %{oname} -f %{SOURCE1} %kflavors
 
 %description
 Open vSwitch Linux kernel module.
@@ -42,6 +43,10 @@ Open vSwitch Linux kernel module.
 %prep
 
 %setup -n %{oname}-%{version}
+cat > %{oname}.conf << EOF
+override %{oname} * extra/%{oname}
+override %{oname} * weak-updates/%{oname}
+EOF
 
 %build
 for flavor in %flavors_to_build; do
@@ -57,6 +62,8 @@ for flavor in %flavors_to_build ; do
          make -C %{kernel_source $flavor} modules_install \
                  M="`pwd`"/_$flavor/datapath/linux
 done
+install -d %{buildroot}%{_sysconfdir}/depmod.d/
+install -m 644 %{oname}.conf %{buildroot}%{_sysconfdir}/depmod.d/
 
 %clean
 rm -rf $RPM_BUILD_ROOT
diff --git a/rhel/openvswitch-kmod.files b/rhel/openvswitch-kmod.files
new file mode 100644 (file)
index 0000000..357c2e8
--- /dev/null
@@ -0,0 +1,3 @@
+%defattr(644,root,root,755)
+/lib/modules/%2-%1
+/etc/depmod.d/openvswitch.conf
index c736df4..3db626c 100644 (file)
@@ -1,6 +1,7 @@
 # -*- shell-script -*-
 HAVE_OPENSSL='@HAVE_OPENSSL@'
 HAVE_PYTHON='@HAVE_PYTHON@'
+EGREP='@EGREP@'
 PERL='@PERL@'
 
 if test x"$PYTHON" = x; then
index 1ebdf85..275ff53 100644 (file)
@@ -21,7 +21,6 @@ TESTSUITE_AT = \
        tests/ovs-ofctl.at \
        tests/odp.at \
        tests/multipath.at \
-       tests/autopath.at \
        tests/lacp.at \
        tests/learn.at \
        tests/vconn.at \
@@ -233,6 +232,10 @@ noinst_PROGRAMS += tests/test-stp
 tests_test_stp_SOURCES = tests/test-stp.c
 tests_test_stp_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
 
+noinst_PROGRAMS += tests/test-sflow
+tests_test_sflow_SOURCES = tests/test-sflow.c
+tests_test_sflow_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
+
 noinst_PROGRAMS += tests/test-netflow
 tests_test_netflow_SOURCES = tests/test-netflow.c
 tests_test_netflow_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
@@ -308,6 +311,7 @@ CHECK_PYFILES = \
        tests/test-ovsdb.py \
        tests/test-reconnect.py \
        tests/MockXenAPI.py \
+       tests/test-unix-socket.py \
        tests/test-unixctl.py \
        tests/test-vlog.py
 EXTRA_DIST += $(CHECK_PYFILES)
diff --git a/tests/autopath.at b/tests/autopath.at
deleted file mode 100644 (file)
index 557c92c..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-AT_BANNER([autopath link selection])
-
-AT_SETUP([autopath basic])
-AT_CHECK([ovs-ofctl parse-flow 'actions=autopath(1, NXM_NX_REG0[[]])'], [0],
-  [usable protocols: any
-chosen protocol: OpenFlow10-table_id
-OFPT_FLOW_MOD (xid=0x1): ADD actions=autopath(1,NXM_NX_REG0[[]])
-], [stderr])
-AT_CHECK([ovs-ofctl parse-flow 'actions=autopath(2, NXM_NX_REG0[[2..30]])'], [0],
-  [usable protocols: any
-chosen protocol: OpenFlow10-table_id
-OFPT_FLOW_MOD (xid=0x1): ADD actions=autopath(2,NXM_NX_REG0[[2..30]])
-], [stderr])
-AT_CHECK([[sed 's/^[^|]*|[^|]*|//' stderr]], [0], [dnl
-autopath|WARN|The autopath action is deprecated and may be removed in February 2013.  Please email dev@openvswitch.org with concerns.
-])
-AT_CLEANUP
-
-AT_SETUP([autopath action missing argument])
-AT_CHECK([ovs-ofctl parse-flow actions=autopath], [1], [],
-  [ovs-ofctl: : not enough arguments to autopath action
-])
-AT_CLEANUP
-
-AT_SETUP([autopath action bad port])
-AT_CHECK([ovs-ofctl parse-flow 'actions=autopath(bad, NXM_NX_REG0[[]])'], [1], [],
-  [ovs-ofctl: bad, NXM_NX_REG0[[]]: bad port number
-])
-AT_CLEANUP
-
-AT_SETUP([autopath action destination too narrow])
-AT_CHECK([ovs-ofctl parse-flow 'actions=autopath(1,NXM_NX_REG0[[0..7]])'], [1], [],
-  [ovs-ofctl: 1,NXM_NX_REG0[[0..7]]: 8-bit destination field has 256 possible values, less than required 65536
-])
-AT_CLEANUP
-
index 59507ff..fdfe12e 100644 (file)
@@ -709,7 +709,7 @@ configure_datapath: bridge      - xenbr2
 configure_datapath: physical    - [u'eth2']
 configure_datapath: extra ports - []
 configure_datapath: extra bonds - []
-/usr/bin/ovs-vsctl --timeout=5 -vconsole:off get-fail-mode xenbr2
+/usr/bin/ovs-vsctl -vconsole:off get-fail-mode xenbr2
 Applying changes to /etc/sysconfig/network-scripts/route-xenbr2 configuration
 Applying changes to /etc/sysconfig/network configuration
 Applying changes to /etc/sysconfig/network-scripts/ifcfg-xenbr2 configuration
@@ -724,7 +724,7 @@ Applying changes to /etc/sysconfig/network-scripts/ifcfg-xenbr2 configuration
     set Bridge xenbr2 fail_mode=secure
     remove Bridge xenbr2 other_config disable-in-band
     br-set-external-id xenbr2 xs-network-uuids d08c8749-0c8f-9e8d-ce25-fd364661ee99
-/usr/bin/ovs-vsctl --timeout=5 -vconsole:off get interface eth2 ofport
+/usr/bin/ovs-vsctl -vconsole:off get interface eth2 ofport
 /usr/bin/ovs-ofctl add-flow xenbr2 idle_timeout=0,priority=0,in_port=5,arp,nw_proto=1,actions=local
 /usr/bin/ovs-ofctl add-flow xenbr2 idle_timeout=0,priority=0,in_port=local,arp,dl_src=00:15:17:a0:29:80,actions=5
 /usr/bin/ovs-ofctl add-flow xenbr2 idle_timeout=0,priority=0,in_port=5,dl_dst=00:15:17:a0:29:80,actions=local
index 3d3bd3b..026d49a 100644 (file)
@@ -2,6 +2,7 @@ AT_BANNER([JSON-RPC - Python])
 
 AT_SETUP([JSON-RPC request and successful reply - Python])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([$PYTHON $srcdir/test-jsonrpc.py --detach --pidfile=`pwd`/pid listen punix:socket])
 AT_CHECK([test -s pid])
 AT_CHECK([kill -0 `cat pid`])
@@ -14,6 +15,7 @@ AT_CLEANUP
 
 AT_SETUP([JSON-RPC request and error reply - Python])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([$PYTHON $srcdir/test-jsonrpc.py --detach --pidfile=`pwd`/pid listen punix:socket])
 AT_CHECK([test -s pid])
 AT_CHECK([kill -0 `cat pid`])
@@ -26,6 +28,7 @@ AT_CLEANUP
 
 AT_SETUP([JSON-RPC notification - Python])
 AT_SKIP_IF([test $HAVE_PYTHON = no])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([$PYTHON $srcdir/test-jsonrpc.py --detach --pidfile=`pwd`/pid listen punix:socket])
 AT_CHECK([test -s pid])
 # When a daemon dies it deletes its pidfile, so make a copy.
index 2a7f91b..664debe 100644 (file)
@@ -1,6 +1,7 @@
 AT_BANNER([JSON-RPC - C])
 
 AT_SETUP([JSON-RPC request and successful reply])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
 AT_CHECK([test -s pid])
 AT_CHECK([kill -0 `cat pid`])
@@ -12,6 +13,7 @@ AT_CHECK([kill `cat pid`])
 AT_CLEANUP
 
 AT_SETUP([JSON-RPC request and error reply])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
 AT_CHECK([test -s pid])
 AT_CHECK([kill -0 `cat pid`])
@@ -23,6 +25,7 @@ AT_CHECK([kill `cat pid`])
 AT_CLEANUP
 
 AT_SETUP([JSON-RPC notification])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_CHECK([test-jsonrpc --detach --no-chdir --pidfile="`pwd`"/pid listen punix:socket])
 AT_CHECK([test -s pid])
 # When a daemon dies it deletes its pidfile, so make a copy.
index 408b1ec..0bcd4b3 100644 (file)
@@ -40,7 +40,7 @@ AT_CLEANUP
 AT_SETUP([lacp - multi port config])
 OVS_VSWITCHD_START([dnl
         add-bond br0 bond p1 p2 --\
-        set Port bond lacp=active \
+        set Port bond lacp=active bond-mode=active-backup \
             other_config:lacp-time="fast" \
             other_config:lacp-system-id=11:22:33:44:55:66 \
             other_config:lacp-system-priority=54321 --\
@@ -141,6 +141,8 @@ OVS_VSWITCHD_START(
 AT_CHECK([ovs-appctl netdev-dummy/set-admin-state up], 0, [OK
 ])
 
+ovs-appctl time/stop
+
 # Wait for up to 5 (simulated) seconds, until LACP negotiation finishes.
 i=0
 while :; do
@@ -290,7 +292,7 @@ AT_CHECK([grep 'active slave' stdout], [0], [dnl
 ])
 
 # Redirect the patch link between p0 and p2 so that no packets get
-# back and forth across them anymore.  Then wait 4 simulated
+# back and forth across them anymore.  Then wait 2.5 simulated
 # seconds.  The LACP state should become "expired" for p0 and p2.
 AT_CHECK([ovs-vsctl \
 -- add-port br0 null0 -- set int null0 type=patch options:peer=p2 -- set int p2 options:peer=null0 \
index 800dc14..8f59b63 100644 (file)
@@ -252,6 +252,41 @@ NXST_FLOW reply:
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+# In this use of a learn action, the first packet in the flow creates
+# a new flow that changes the behavior of subsequent packets in the
+# flow.
+AT_SETUP([learning action - self-modifying flow])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], 1, 2, 3)
+
+# Set up flow table for TCPv4 port learning.
+AT_CHECK([[ovs-ofctl add-flow br0 'actions=load:3->NXM_NX_REG0[0..15],learn(table=0,priority=65535,NXM_OF_ETH_SRC[],NXM_OF_VLAN_TCI[0..11],output:NXM_NX_REG0[0..15]),output:2']])
+
+# Trace some packets arriving.  The particular packets don't matter.
+for i in 1 2 3 4 5 6 7 8 9 10; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'
+done
+
+# Check for the learning entry.
+AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0],
+[[ n_packets=1, n_bytes=60, actions=load:0x3->NXM_NX_REG0[0..15],learn(table=0,priority=65535,NXM_OF_ETH_SRC[],NXM_OF_VLAN_TCI[0..11],output:NXM_NX_REG0[0..15]),output:2
+ priority=65535,vlan_tci=0x0000/0x0fff,dl_src=50:54:00:00:00:05 actions=output:3
+NXST_FLOW reply:
+]])
+
+# Check that the first packet went out port 2 and the rest out port 3.
+AT_CHECK(
+  [(ovs-ofctl dump-ports br0 2; ovs-ofctl dump-ports br0 3) | STRIP_XIDS], [0],
+  [OFPST_PORT reply: 1 ports
+  port  2: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
+           tx pkts=1, bytes=60, drop=0, errs=0, coll=0
+OFPST_PORT reply: 1 ports
+  port  3: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0
+           tx pkts=9, bytes=540, drop=0, errs=0, coll=0
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([learning action - fin_timeout feature])
 # This is a totally artificial use of the "learn" action.  The only purpose
 # is to check that specifying fin_idle_timeout or fin_hard_timeout causes
index 55adcfb..650fef3 100644 (file)
@@ -114,7 +114,7 @@ m4_foreach(
    AT_CHECK([test-util testname], [0], [], [])
    AT_CLEANUP])
 
-AT_SETUP([test unix socket -- short pathname])
+AT_SETUP([test unix socket, short pathname - C])
 AT_CHECK([test-unix-socket x])
 AT_CLEANUP
 
@@ -123,22 +123,33 @@ dnl go in a fixed-length field in struct sockaddr_un.  Generally the limit
 dnl is about 100 bytes.  On Linux, we work around this by indirecting through
 dnl a directory fd using /proc/self/fd/<dirfd>.  We do not have a workaround
 dnl for other platforms, so we skip the test there.
-AT_SETUP([test unix socket -- long pathname])
-AT_CHECK([dnl
-    case `uname` in dnl (
-      *[[lL]]inux*)
-        exit 0
-        ;; dnl (
-      *)
-        dnl Magic exit code to tell Autotest to skip this test.
-        exit 77
-        ;;
-    esac
-])
+AT_SETUP([test unix socket, long pathname - C])
+AT_SKIP_IF([test ! -d /proc/self/fd])
+dnl Linux has a 108 byte limit; this is 150 bytes long.
+longname=012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+mkdir $longname
+cd $longname
+AT_CHECK([test-unix-socket ../$longname/socket socket])
+AT_CLEANUP
+
+AT_SETUP([test unix socket, short pathname - Python])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+AT_CHECK([$PYTHON $srcdir/test-unix-socket.py x])
+AT_CLEANUP
+
+dnl Unix sockets with long names are problematic because the name has to
+dnl go in a fixed-length field in struct sockaddr_un.  Generally the limit
+dnl is about 100 bytes.  On Linux, we work around this by indirecting through
+dnl a directory fd using /proc/self/fd/<dirfd>.  We do not have a workaround
+dnl for other platforms, so we skip the test there.
+AT_SETUP([test unix socket, long pathname - Python])
+AT_SKIP_IF([test $HAVE_PYTHON = no])
+AT_SKIP_IF([test ! -d /proc/self/fd])
 dnl Linux has a 108 byte limit; this is 150 bytes long.
-mkdir 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
-cd 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
-AT_CHECK([test-unix-socket ../012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789/socket socket])
+longname=012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+mkdir $longname
+cd $longname
+AT_CHECK([$PYTHON $abs_srcdir/test-unix-socket.py ../$longname/socket socket])
 AT_CLEANUP
 
 AT_SETUP([ovs_assert])
index 687f9c9..95cfba8 100644 (file)
@@ -25,6 +25,11 @@ in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv
 in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
 in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0806),arp(sip=1.2.3.4,tip=5.6.7.8,op=1,sha=00:0f:10:11:12:13,tha=00:14:15:16:17:18)
 skb_mark(0x1234),in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847),mpls(label=100,tc=3,ttl=64,bos=1)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847),mpls(label=100,tc=7,ttl=100,bos=1)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847),mpls(label=100,tc=7,ttl=100,bos=0)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8848),mpls(label=1000,tc=4,ttl=200,bos=1)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8848),mpls(label=1000,tc=4,ttl=200,bos=0)
 ])
 
 (echo '# Valid forms without tun_id or VLAN header.'
@@ -39,6 +44,14 @@ skb_mark(0x1234),in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth
  sed 's/\(eth([[^)]]*)\),*/\1,eth_type(0x8100),vlan(vid=99,pcp=7),encap(/
 s/$/)/' odp-base.txt
 
+ echo
+ echo '# Valid forms with MPLS header.'
+ sed 's/\(eth([[^)]]*),?\)/\1,eth_type(0x8847),mpls(label=100,tc=7,ttl=64,bos=1)/' odp-base.txt
+
+ echo
+ echo '# Valid forms with MPLS multicast header.'
+ sed 's/\(eth([[^)]]*),?\)/\1,eth_type(0x8848),mpls(label=100,tc=7,ttl=64,bos=1)/' odp-base.txt
+
  echo
  echo '# Valid forms with QoS priority.'
  sed 's/^/skb_priority(0x1234),/' odp-base.txt
@@ -76,7 +89,7 @@ userspace(pid=9765,slow_path())
 userspace(pid=9765,slow_path(cfm))
 userspace(pid=9765,slow_path(cfm,match))
 userspace(pid=9123,userdata=0x815309)
-set(tun_id(0x7f10354))
+userspace(pid=1234567,userdata(0102030405060708090a0b0c0d0e0f))
 set(in_port(2))
 set(eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15))
 set(eth_type(0x1234))
index aa51e08..8a40eb4 100644 (file)
@@ -78,10 +78,6 @@ ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffff0000ffff0000
 # actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[])
 ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
 
-# actions=autopath(2,NXM_NX_REG0[2..30])
-& autopath|WARN|The autopath action is deprecated and may be removed in February 2013.  Please email dev@openvswitch.org with concerns.
-ffff 0018 00002320 000b 009c 00010004 00000002 00000000
-
 # actions=bundle(eth_src,0,hrw,ofport,slaves:4,8)
 ffff 0028 00002320 000c 0001 0000 0000 00000002 0002 0000 00000000 00000000 dnl
 0004 0008 00000000
@@ -252,10 +248,6 @@ ffff 0020 00002320 0016 000000000000 fedcba9876543210 ffffffffffffffff ffff 0010
 # actions=multipath(eth_src,50,modulo_n,1,0,NXM_NX_REG0[])
 ffff 0020 00002320 000a 0000 0032 0000 0000 0000 0000 0000 0000 001f 00010004
 
-# actions=autopath(2,NXM_NX_REG0[2..30])
-& autopath|WARN|The autopath action is deprecated and may be removed in February 2013.  Please email dev@openvswitch.org with concerns.
-ffff 0018 00002320 000b 009c 00010004 00000002 00000000
-
 # actions=bundle(eth_src,0,hrw,ofport,slaves:4,8)
 ffff 0028 00002320 000c 0001 0000 0000 00000002 0002 0000 00000000 00000000 dnl
 0004 0008 00000000
index 4021291..35f599c 100644 (file)
@@ -1549,9 +1549,9 @@ AT_SETUP([OFPT_ROLE_REPLY - OF1.2])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
 03 19 00 18 00 00 00 02 00 00 00 03 00 00 00 00 \
-00 00 00 00 00 00 00 00 \
+12 34 56 78 ab cd ef 90 \
 "], [0], [dnl
-OFPT_ROLE_REPLY (OF1.2) (xid=0x2): role=slave
+OFPT_ROLE_REPLY (OF1.2) (xid=0x2): role=slave generation_id=1311768467750121360
 ])
 AT_CLEANUP
 
@@ -1699,7 +1699,7 @@ AT_SETUP([NXT_FLOW_REMOVED])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
 01 04 00 78 00 00 00 00 00 00 23 20 00 00 00 0e \
-00 00 00 00 00 00 00 00 ff ff 00 00 00 00 00 06 \
+00 00 00 00 00 00 00 00 ff ff 00 02 00 00 00 06 \
 01 6e 36 00 00 05 00 3c 00 00 00 00 00 00 00 01 \
 00 00 00 00 00 00 00 3c 00 00 00 02 00 03 00 00 \
 02 06 50 54 00 00 00 06 00 00 04 06 50 54 00 00 \
@@ -1707,7 +1707,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
 1e 02 00 02 00 00 20 04 c0 a8 00 01 00 00 22 04 \
 c0 a8 00 02 00 00 00 00 \
 "], [0], [dnl
-NXT_FLOW_REMOVED (xid=0x0): priority=65535,arp,in_port=3,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2 reason=idle duration6.024s idle5 pkts1 bytes60
+NXT_FLOW_REMOVED (xid=0x0): priority=65535,arp,in_port=3,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2 reason=idle table_id=1 duration6.024s idle5 pkts1 bytes60
 ])
 AT_CLEANUP
 
index 3eec947..06ebf23 100644 (file)
@@ -20,6 +20,20 @@ AT_CHECK([tail -1 stdout], [0],
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - goto table])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1], [10], [11])
+echo "table=0 in_port=1 actions=output(10),goto_table(1)" > flows.txt
+for i in `seq 1 252`; do echo "table=$i actions=goto_table($(($i+1)))"; done >> flows.txt
+echo "table=253 actions=output(11)" >> flows.txt
+AT_CHECK([ovs-ofctl -O OpenFlow12 add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: 10,11
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - registers])
 OVS_VSWITCHD_START
 ADD_OF_PORTS([br0], [20], [21], [22], [33], [90])
@@ -45,6 +59,7 @@ in_port=12 actions=load:0x10->NXM_NX_REG0[[]],load:0x11->NXM_NX_REG1[[]],load:0x
 in_port=13 actions=load:0x13->NXM_NX_REG3[[]],load:0x14->NXM_NX_REG4[[]],load:0x15->NXM_NX_REG5[[]]
 in_port=14 actions=load:0x16->NXM_NX_REG6[[]],load:0x17->NXM_NX_REG7[[]]
 in_port=15,reg0=0x10,reg1=0x11,reg2=0x12,reg3=0x13,reg4=0x14,reg5=0x15,reg6=0x16,reg7=0x17 actions=output:33
+
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
@@ -54,6 +69,25 @@ AT_CHECK([tail -1 stdout], [0],
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - push-pop])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [20], [21], [22], [33], [90])
+AT_DATA([flows.txt], [dnl
+in_port=90           actions=load:20->NXM_NX_REG0[[0..7]],load:21->NXM_NX_REG1[[0..7]],load:22->NXM_NX_REG2[[0..7]], load:33->NXM_NX_REG3[[0..7]], push:NXM_NX_REG0[[]], push:NXM_NX_REG1[[0..7]],push:NXM_NX_REG2[[0..15]], push:NXM_NX_REG3[[]], resubmit:2, resubmit:3, resubmit:4, resubmit:5
+in_port=2            actions=pop:NXM_NX_REG0[[0..7]],output:NXM_NX_REG0[[]]
+in_port=3            actions=pop:NXM_NX_REG1[[0..7]],output:NXM_NX_REG1[[]]
+in_port=4            actions=pop:NXM_NX_REG2[[0..15]],output:NXM_NX_REG2[[]]
+in_port=5            actions=pop:NXM_NX_REG3[[]],output:NXM_NX_REG3[[]]
+
+])
+AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: 33,22,21,20
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - output])
 OVS_VSWITCHD_START
 ADD_OF_PORTS([br0], [1], [9], [10], [11], [55], [66], [77], [88])
@@ -230,6 +264,16 @@ cookie=0x6 table=4 in_port=83 actions=load:4->NXM_NX_REG3[[]],mod_nw_src:83.83.8
 cookie=0x7 table=5 in_port=84 actions=load:5->NXM_NX_REG4[[]],load:6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,controller,resubmit(85,6)
 cookie=0x8 table=6 in_port=85 actions=mod_tp_src:85,controller,resubmit(86,7)
 cookie=0x9 table=7 in_port=86 actions=mod_tp_dst:86,controller,controller
+cookie=0xa dl_src=40:44:44:44:44:42 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],controller
+cookie=0xa dl_src=40:44:44:44:44:43 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],controller
+cookie=0xa dl_src=40:44:44:44:44:44 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],controller
+cookie=0xa dl_src=40:44:44:44:44:45 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],dec_mpls_ttl,controller
+cookie=0xa dl_src=40:44:44:44:44:46 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],set_mpls_ttl(10),controller
+cookie=0xa dl_src=40:44:44:44:44:47 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],dec_mpls_ttl,set_mpls_ttl(10),controller
+cookie=0xa dl_src=40:44:44:44:44:48 actions=push_mpls:0x8847,load:10->OXM_OF_MPLS_LABEL[[]],load:3->OXM_OF_MPLS_TC[[]],set_mpls_ttl(10),dec_mpls_ttl,controller
+cookie=0xb dl_src=50:55:55:55:55:55 dl_type=0x8847 actions=load:1000->OXM_OF_MPLS_LABEL[[]],controller
+cookie=0xd dl_src=60:66:66:66:66:66 actions=pop_mpls:0x0800,controller
+cookie=0xc dl_src=70:77:77:77:77:77 actions=push_mpls:0x8848,load:1000->OXM_OF_MPLS_LABEL[[]],load:7->OXM_OF_MPLS_TC[[]],controller
 ])
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
@@ -290,6 +334,206 @@ OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuf
 tcp,metadata=0,in_port=0,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10 tcp_csum:0
 ])
 
+dnl Modified MPLS controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:42,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+dnl in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847),mpls(label=100,tc=3,ttl=64,bos=1)
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:43,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=11,tc=3,ttl=64,bos=1)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:0),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:0),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:0),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:44,dst=50:54:00:00:00:07),eth_type(0x8100),vlan(vid=99,pcp=7),encap(eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no))'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:64,bos:1),metadata=0,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:45,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:63,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:63,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:63,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:46,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:47,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:10,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=40:44:44:44:44:48,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:9,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:9,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mpls(label:10,tc:3,ttl:9,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS actions.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:55:55:55:55:55,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=100,tc=7,ttl=64,bos=1),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
+mpls(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
+mpls(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
+mpls(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07
+])
+
+dnl Modified MPLS ipv6 controller action.
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=70:77:77:77:77:77,dst=50:54:00:00:00:07),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'
+done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mplsm(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mplsm(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
+mplsm(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07
+])
+
+
+dnl Modified MPLS pop action.
+dnl The input is a frame with two MPLS headers which tcpdump -vve shows as:
+dnl 60:66:66:66:66:66 > 50:54:00:00:00:07, ethertype MPLS multicast (0x8847), length 66: MPLS (label 20, exp 0, ttl 32)
+dnl             (tos 0x0, ttl 64, id 0, offset 0, flags [none], proto TCP (6), length 44)
+
+AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor.log])
+
+for i in 1 2 3; do
+    ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 60 66 66 66 66 66 88 47 00 01 41 20 45 00 00 2c 00 00 00 00 40 06 3b 78 c0 a8 00 01 c0 a8 00 02 00 50 00 00 00 00 00 2a 00 00 00 2a 50 00 27 10 77 44 00 00 48 4f 47 45'
+done
+#for i in 2 3; do
+#    ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=60:66:66:66:66:66,dst=50:54:00:00:00:07),eth_type(0x8847),mpls(label=10,tc=3,ttl=100,bos=1)'
+#done
+
+OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
+AT_CHECK([cat ofctl_monitor.log], [0], [dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0 tcp_csum:7744
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0 tcp_csum:7744
+dnl
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0 tcp_csum:7744
+])
+
 dnl Checksum TCP.
 AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --no-chdir --pidfile 2> ofctl_monitor.log])
 
@@ -364,6 +608,7 @@ NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6
 udp,metadata=0,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1
 ])
 
+AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
  cookie=0x1, n_packets=2, n_bytes=120, dl_src=20:22:22:22:22:22 actions=CONTROLLER:65535,resubmit(80,1)
  cookie=0x2, n_packets=3, n_bytes=180, dl_src=30:33:33:33:33:33 actions=mod_vlan_vid:15,CONTROLLER:65535
@@ -374,6 +619,16 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
  cookie=0x7, table=5, n_packets=2, n_bytes=120, in_port=84 actions=load:0x5->NXM_NX_REG4[[]],load:0x6->NXM_NX_TUN_ID[[]],mod_nw_dst:84.84.84.84,CONTROLLER:65535,resubmit(85,6)
  cookie=0x8, table=6, n_packets=2, n_bytes=120, in_port=85 actions=mod_tp_src:85,CONTROLLER:65535,resubmit(86,7)
  cookie=0x9, table=7, n_packets=2, n_bytes=120, in_port=86 actions=mod_tp_dst:86,CONTROLLER:65535,CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:42 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:43 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:44 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:45 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],dec_mpls_ttl,CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:46 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],set_mpls_ttl(10),CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:47 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],dec_mpls_ttl,set_mpls_ttl(10),CONTROLLER:65535
+ cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:48 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],set_mpls_ttl(10),dec_mpls_ttl,CONTROLLER:65535
+ cookie=0xb, n_packets=3, n_bytes=180, dl_src=50:55:55:55:55:55,dl_type=0x8847 actions=load:0x3e8->OXM_OF_MPLS_LABEL[[]],CONTROLLER:65535
+ cookie=0xc, n_packets=3, n_bytes=180, dl_src=70:77:77:77:77:77 actions=push_mpls:0x8848,load:0x3e8->OXM_OF_MPLS_LABEL[[]],load:0x7->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
+ cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:66:66 actions=pop_mpls:0x0800,CONTROLLER:65535
  n_packets=3, n_bytes=180, dl_src=10:11:11:11:11:11 actions=CONTROLLER:65535
 NXST_FLOW reply:
 ])
@@ -951,6 +1206,297 @@ AT_CHECK_UNQUOTED([ovs-appctl fdb/show br0 | sed 's/[[0-9]]\{1,\}$/?/' | sort],
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+dnl Test that sFlow samples packets correctly.
+AT_SETUP([ofproto-dpif - sFlow packet sampling])
+AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout])
+SFLOW_PORT=`cat stdout`
+OVS_VSWITCHD_START([set Bridge br0 fail-mode=standalone])
+
+ovs-appctl time/stop
+
+ADD_OF_PORTS([br0], 1, 2)
+ovs-vsctl \
+   set Interface br0 options:ifindex=1002 -- \
+   set Interface p1 options:ifindex=1004 -- \
+   set Interface p2 options:ifindex=1003 -- \
+   set Bridge br0 sflow=@sf -- \
+   --id=@sf create sflow targets=\"127.0.0.1:$SFLOW_PORT\" \
+     header=128 sampling=1 polling=1
+ON_EXIT([kill `cat test-sflow.pid`])
+AT_CHECK([test-sflow --detach --no-chdir --pidfile $SFLOW_PORT:127.0.0.1 > sflow.log])
+AT_CAPTURE_FILE([sflow.log])
+
+dnl open with ARP packets to seed the bridge-learning.  The output
+dnl ifIndex numbers should be reported predictably after that.
+dnl Since we set sampling=1 we should see all of these packets
+dnl reported. Sorting the output by data-source and seqNo makes
+dnl it deterministic. Ensuring that we send at least two packets
+dnl into each port means we get to check the seq nos are
+dnl incrementing correctly.
+
+ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.2,tip=192.168.0.1,op=1,sha=50:54:00:00:00:05,tha=00:00:00:00:00:00)'
+ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=FF:FF:FF:FF:FF:FF),eth_type(0x0806),arp(sip=192.168.0.1,tip=192.168.0.2,op=1,sha=50:54:00:00:00:07,tha=00:00:00:00:00:00)'
+ovs-appctl netdev-dummy/receive p1 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
+ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0)'
+ovs-appctl netdev-dummy/receive p2 'in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x86dd),ipv6(src=fe80::1,dst=fe80::2,label=0,proto=10,tclass=0x70,hlimit=128,frag=no)'
+
+dnl sleep long enough to get more than one counter sample
+dnl from each datasource so we can check sequence numbers
+for i in `seq 1 30`; do
+    ovs-appctl time/warp 100
+done
+OVS_VSWITCHD_STOP
+ovs-appctl -t test-sflow exit
+
+AT_CHECK([[sort sflow.log | $EGREP 'HEADER|ERROR' | sed 's/ /\
+       /g']], [0], [dnl
+HEADER
+       dgramSeqNo=1
+       ds=127.0.0.1>0:1003
+       fsSeqNo=1
+       in_vlan=0
+       in_priority=0
+       out_vlan=0
+       out_priority=0
+       meanSkip=1
+       samplePool=1
+       dropEvents=0
+       in_ifindex=1003
+       in_format=0
+       out_ifindex=2
+       out_format=2
+       hdr_prot=1
+       pkt_len=64
+       stripped=4
+       hdr_len=60
+       hdr=FF-FF-FF-FF-FF-FF-50-54-00-00-00-07-08-06-00-01-08-00-06-04-00-01-50-54-00-00-00-07-C0-A8-00-01-00-00-00-00-00-00-C0-A8-00-02-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
+HEADER
+       dgramSeqNo=1
+       ds=127.0.0.1>0:1003
+       fsSeqNo=2
+       in_vlan=0
+       in_priority=0
+       out_vlan=0
+       out_priority=0
+       meanSkip=1
+       samplePool=2
+       dropEvents=0
+       in_ifindex=1003
+       in_format=0
+       out_ifindex=1004
+       out_format=0
+       hdr_prot=1
+       pkt_len=64
+       stripped=4
+       hdr_len=60
+       hdr=50-54-00-00-00-05-50-54-00-00-00-07-08-00-45-00-00-1C-00-00-00-00-40-01-F9-8D-C0-A8-00-02-C0-A8-00-01-00-00-FF-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
+HEADER
+       dgramSeqNo=1
+       ds=127.0.0.1>0:1003
+       fsSeqNo=3
+       in_vlan=0
+       in_priority=0
+       out_vlan=0
+       out_priority=0
+       meanSkip=1
+       samplePool=3
+       dropEvents=0
+       in_ifindex=1003
+       in_format=0
+       out_ifindex=1004
+       out_format=0
+       hdr_prot=1
+       pkt_len=64
+       stripped=4
+       hdr_len=60
+       hdr=50-54-00-00-00-05-50-54-00-00-00-07-86-DD-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
+HEADER
+       dgramSeqNo=1
+       ds=127.0.0.1>0:1004
+       fsSeqNo=1
+       in_vlan=0
+       in_priority=0
+       out_vlan=0
+       out_priority=0
+       meanSkip=1
+       samplePool=1
+       dropEvents=0
+       in_ifindex=1004
+       in_format=0
+       out_ifindex=2
+       out_format=2
+       hdr_prot=1
+       pkt_len=64
+       stripped=4
+       hdr_len=60
+       hdr=FF-FF-FF-FF-FF-FF-50-54-00-00-00-05-08-06-00-01-08-00-06-04-00-01-50-54-00-00-00-05-C0-A8-00-02-00-00-00-00-00-00-C0-A8-00-01-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
+HEADER
+       dgramSeqNo=1
+       ds=127.0.0.1>0:1004
+       fsSeqNo=2
+       in_vlan=0
+       in_priority=0
+       out_vlan=0
+       out_priority=0
+       meanSkip=1
+       samplePool=2
+       dropEvents=0
+       in_ifindex=1004
+       in_format=0
+       out_ifindex=1003
+       out_format=0
+       hdr_prot=1
+       pkt_len=64
+       stripped=4
+       hdr_len=60
+       hdr=50-54-00-00-00-07-50-54-00-00-00-05-08-00-45-00-00-1C-00-00-00-00-40-01-F9-8D-C0-A8-00-01-C0-A8-00-02-08-00-F7-FF-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
+])
+
+AT_CHECK([[sort sflow.log | $EGREP 'IFCOUNTERS|ERROR' | head -6 | sed 's/ /\
+       /g']], [0], [dnl
+IFCOUNTERS
+       dgramSeqNo=2
+       ds=127.0.0.1>0:1002
+       csSeqNo=1
+       ifindex=1002
+       type=6
+       ifspeed=100000000
+       direction=0
+       status=3
+       in_octets=0
+       in_unicasts=0
+       in_multicasts=0
+       in_broadcasts=4294967295
+       in_discards=0
+       in_errors=0
+       in_unknownprotos=4294967295
+       out_octets=120
+       out_unicasts=2
+       out_multicasts=4294967295
+       out_broadcasts=4294967295
+       out_discards=0
+       out_errors=0
+       promiscuous=0
+IFCOUNTERS
+       dgramSeqNo=2
+       ds=127.0.0.1>0:1003
+       csSeqNo=1
+       ifindex=1003
+       type=6
+       ifspeed=100000000
+       direction=0
+       status=0
+       in_octets=98
+       in_unicasts=3
+       in_multicasts=0
+       in_broadcasts=4294967295
+       in_discards=0
+       in_errors=0
+       in_unknownprotos=4294967295
+       out_octets=120
+       out_unicasts=2
+       out_multicasts=4294967295
+       out_broadcasts=4294967295
+       out_discards=0
+       out_errors=0
+       promiscuous=0
+IFCOUNTERS
+       dgramSeqNo=2
+       ds=127.0.0.1>0:1004
+       csSeqNo=1
+       ifindex=1004
+       type=6
+       ifspeed=100000000
+       direction=0
+       status=0
+       in_octets=84
+       in_unicasts=2
+       in_multicasts=0
+       in_broadcasts=4294967295
+       in_discards=0
+       in_errors=0
+       in_unknownprotos=4294967295
+       out_octets=180
+       out_unicasts=3
+       out_multicasts=4294967295
+       out_broadcasts=4294967295
+       out_discards=0
+       out_errors=0
+       promiscuous=0
+IFCOUNTERS
+       dgramSeqNo=3
+       ds=127.0.0.1>0:1002
+       csSeqNo=2
+       ifindex=1002
+       type=6
+       ifspeed=100000000
+       direction=0
+       status=3
+       in_octets=0
+       in_unicasts=0
+       in_multicasts=0
+       in_broadcasts=4294967295
+       in_discards=0
+       in_errors=0
+       in_unknownprotos=4294967295
+       out_octets=120
+       out_unicasts=2
+       out_multicasts=4294967295
+       out_broadcasts=4294967295
+       out_discards=0
+       out_errors=0
+       promiscuous=0
+IFCOUNTERS
+       dgramSeqNo=3
+       ds=127.0.0.1>0:1003
+       csSeqNo=2
+       ifindex=1003
+       type=6
+       ifspeed=100000000
+       direction=0
+       status=0
+       in_octets=98
+       in_unicasts=3
+       in_multicasts=0
+       in_broadcasts=4294967295
+       in_discards=0
+       in_errors=0
+       in_unknownprotos=4294967295
+       out_octets=120
+       out_unicasts=2
+       out_multicasts=4294967295
+       out_broadcasts=4294967295
+       out_discards=0
+       out_errors=0
+       promiscuous=0
+IFCOUNTERS
+       dgramSeqNo=3
+       ds=127.0.0.1>0:1004
+       csSeqNo=2
+       ifindex=1004
+       type=6
+       ifspeed=100000000
+       direction=0
+       status=0
+       in_octets=84
+       in_unicasts=2
+       in_multicasts=0
+       in_broadcasts=4294967295
+       in_discards=0
+       in_errors=0
+       in_unknownprotos=4294967295
+       out_octets=180
+       out_unicasts=3
+       out_multicasts=4294967295
+       out_broadcasts=4294967295
+       out_discards=0
+       out_errors=0
+       promiscuous=0
+])
+AT_CLEANUP
+
+
+
 dnl Test that basic NetFlow reports flow statistics correctly:
 dnl - The initial packet of a flow are correctly accounted.
 dnl - Later packets within a flow are correctly accounted.
@@ -1010,7 +1556,7 @@ ovs-vsctl \
    --id=@nf create NetFlow targets=\"127.0.0.1:$NETFLOW_PORT\" \
      engine_id=1 engine_type=2 active_timeout=10 add-id-to-interface=false
 
-ON_EXIT([kill `test-netflow.pid`])
+ON_EXIT([kill `cat test-netflow.pid`])
 AT_CHECK([test-netflow --detach --no-chdir --pidfile $NETFLOW_PORT:127.0.0.1 > netflow.log])AT_CAPTURE_FILE([netflow.log])
 
 AT_CHECK([ovs-appctl time/stop])
@@ -1225,22 +1771,25 @@ ADD_OF_PORTS([br1], [3])
 
 AT_CHECK([ovs-appctl dpif/show], [0], [dnl
 br0 (dummy@ovs-dummy):
-       lookups: hit:0 missed:0 lost:0
-       flows: 0
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br0 65534/100: (dummy)
        p1 1/1: (dummy)
        p2 2/2: (dummy)
 br1 (dummy@ovs-dummy):
-       lookups: hit:0 missed:0 lost:0
-       flows: 0
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br1 65534/101: (dummy)
        p3 3/3: (dummy)
 ])
 
 AT_CHECK([ovs-appctl dpif/show br0], [0], [dnl
 br0 (dummy@ovs-dummy):
-       lookups: hit:0 missed:0 lost:0
-       flows: 0
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br0 65534/100: (dummy)
        p1 1/1: (dummy)
        p2 2/2: (dummy)
@@ -1262,12 +1811,12 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows br0 | sort | STRIP_USED], [0], [dnl
-in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:drop
-in_port(2),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:userspace(pid=0,slow_path(controller))
+in_port(2),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0), packets:0, bytes:0, used:0.0s, actions:userspace(pid=0,slow_path(controller))
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows br1 | sort | STRIP_USED], [0], [dnl
-in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:userspace(pid=0,slow_path(controller))
 ])
 
 OVS_VSWITCHD_STOP
@@ -1287,12 +1836,12 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows br0 | sort | STRIP_USED], [0], [dnl
-in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:drop
-in_port(2),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:userspace(pid=0,slow_path(controller))
+in_port(2),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=0,code=0), packets:0, bytes:0, used:0.0s, actions:userspace(pid=0,slow_path(controller))
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows br1 | sort | STRIP_USED], [0], [dnl
-in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:userspace(pid=0,slow_path(controller))
 ])
 
 AT_CHECK([ovs-appctl dpif/del-flows br0])
@@ -1300,7 +1849,7 @@ AT_CHECK([ovs-appctl dpif/dump-flows br0 | sort | STRIP_USED], [0], [dnl
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows br1 | sort | STRIP_USED], [0], [dnl
-in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:drop
+in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:0, bytes:0, used:0.0s, actions:userspace(pid=0,slow_path(controller))
 ])
 
 OVS_VSWITCHD_STOP
@@ -1326,16 +1875,22 @@ for i in $(seq 1 5); do
     ovs-appctl netdev-dummy/receive br1 'in_port(101),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
 done
 
+AT_CHECK([ovs-appctl time/warp 1000 && ovs-appctl time/warp 1000], [0], [warped
+warped
+])
+
 AT_CHECK([ovs-appctl dpif/show], [0], [dnl
 br0 (dummy@ovs-dummy):
-       lookups: hit:13 missed:2 lost:0
-       flows: 1
+       lookups: hit:9 missed:1
+       flows: cur: 1, avg: 1.000, max: 1, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br0 65534/100: (dummy)
        p2 2/2: (dummy)
        pbr0 1/none: (patch: peer=pbr1)
 br1 (dummy@ovs-dummy):
-       lookups: hit:13 missed:2 lost:0
-       flows: 1
+       lookups: hit:4 missed:1
+       flows: cur: 1, avg: 1.000, max: 1, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br1 65534/101: (dummy)
        p3 3/3: (dummy)
        pbr1 1/none: (patch: peer=pbr0)
@@ -1362,3 +1917,32 @@ OFPST_PORT reply (xid=0x4): 1 ports
 
 OVS_VSWITCHD_STOP
 AT_CLEANUP
+
+AT_SETUP([ofproto-dpif - ovs-appctl dpif/show rates])
+OVS_VSWITCHD_START([set Bridge br0 fail-mode=secure])
+ADD_OF_PORTS([br0], 1, 2)
+
+AT_CHECK([ovs-ofctl add-flow br0 actions=LOCAL,output:1,output:2])
+
+for i in $(seq 1 61); do
+    ovs-appctl netdev-dummy/receive br0 'in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
+    ovs-appctl time/warp 10000
+    ovs-appctl time/warp 50000
+done
+
+AT_CHECK([ovs-appctl time/warp 10000], [0], [warped
+])
+
+AT_CHECK([ovs-appctl dpif/show | sed 's/ 10[[0-9]]\{3\}(ms)$/ 10000(ms)/'], [0], [dnl
+br0 (dummy@ovs-dummy):
+       lookups: hit:0 missed:61
+       flows: cur: 0, avg: 1.000, max: 1, life span: 10000(ms)
+               hourly avg: add rate: 0.641/min, del rate: 0.635/min
+               overall avg: add rate: 1.000/min, del rate: 0.984/min
+       br0 65534/100: (dummy)
+       p1 1/1: (dummy)
+       p2 2/2: (dummy)
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
index b9356d3..9a6d5ab 100644 (file)
@@ -64,8 +64,26 @@ m4_define([OVS_VSWITCHD_START],
    AT_CHECK([ovs-vsctl -- add-br br0 -- set bridge br0 datapath-type=dummy other-config:datapath-id=fedcba9876543210 other-config:hwaddr=aa:55:aa:55:00:00 protocols=[[OpenFlow10,OpenFlow12,OpenFlow13]] fail-mode=secure -- $1 m4_if([$2], [], [], [| perl $srcdir/uuidfilt.pl])], [0], [$2])
 ])
 
+m4_divert_push([PREPARE_TESTS])
+check_logs () {
+    sed -n "$1
+/|WARN|/p
+/|ERR|/p
+/|EMER|/p" ovs-vswitchd.log ovsdb-server.log
+}
+m4_divert_pop([PREPARE_TESTS])
+
+# OVS_VSWITCHD_STOP([WHITELIST])
+#
+# Gracefully stops ovs-vswitchd and ovsdb-server, checking their log files
+# for messages with severity WARN or higher and signaling an error if any
+# is present.  The optional WHITELIST may contain shell-quoted "sed"
+# commands to delete any warnings that are actually expected, e.g.:
+#
+#   OVS_VSWITCHD_STOP(["/expected error/d"])
 m4_define([OVS_VSWITCHD_STOP],
-  [AT_CHECK([ovs-appctl -t ovs-vswitchd exit])
+  [AT_CHECK([check_logs $1])
+   AT_CHECK([ovs-appctl -t ovs-vswitchd exit])
    AT_CHECK([ovs-appctl -t ovsdb-server exit])])
 
 # ADD_OF_PORTS(BRIDGE, OF_PORT[, OF_PORT...])
index 45aa549..f41bfc3 100644 (file)
@@ -1332,7 +1332,7 @@ echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x2): role=equal"
 # Become slave (generation_id is initially undefined, so 2^63+2 should not be stale)
 ovs-appctl -t ovs-ofctl ofctl/send 031800180000000300000003000000008000000000000002
 echo >>expout "send: OFPT_ROLE_REQUEST (OF1.2) (xid=0x3): role=slave generation_id=9223372036854775810"
-echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x3): role=slave"
+echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x3): role=slave generation_id=9223372036854775810"
 
 # Try to become the master using a stale generation ID
 ovs-appctl -t ovs-ofctl ofctl/send 031800180000000400000002000000000000000000000002
@@ -1343,7 +1343,7 @@ echo >>expout "OFPT_ROLE_REQUEST (OF1.2) (xid=0x4): role=master generation_id=2"
 # Become master using a valid generation ID
 ovs-appctl -t ovs-ofctl ofctl/send 031800180000000500000002000000000000000000000001
 echo >>expout "send: OFPT_ROLE_REQUEST (OF1.2) (xid=0x5): role=master generation_id=1"
-echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x5): role=master"
+echo >>expout "OFPT_ROLE_REPLY (OF1.2) (xid=0x5): role=master generation_id=1"
 ovs-appctl -t ovs-ofctl ofctl/barrier
 echo >>expout "OFPT_BARRIER_REPLY (OF1.2) (xid=0x3):"
 
index e66c943..bd150cf 100644 (file)
@@ -33,7 +33,7 @@ chmod +x usr/sbin/setkey
 touch etc/racoon/certs/ovs-stale.pem
 
 ovs_vsctl () {
-    ovs-vsctl --timeout=5 --no-wait -vreconnect:emer --db=unix:socket "$@"
+    ovs-vsctl --no-wait -vreconnect:emer --db=unix:socket "$@"
 }
 trim () {  # Removes blank lines and lines starting with # from input.
     sed -e '/^#/d' -e '/^[       ]*$/d' "$@"
index ca68226..075f2e4 100644 (file)
@@ -243,7 +243,7 @@ tun_id=0x1234,cookie=0x5678,actions=flood
 actions=drop
 reg0=123,actions=move:NXM_NX_REG0[0..5]->NXM_NX_REG1[26..31],load:55->NXM_NX_REG2[0..31],move:NXM_NX_REG0[0..31]->NXM_NX_TUN_ID[0..31],move:NXM_NX_REG0[0..15]->NXM_OF_VLAN_TCI[]
 actions=move:OXM_OF_ETH_DST[]->OXM_OF_ETH_SRC[]
-actions=autopath(5,NXM_NX_REG0[])
+actions=push:NXM_NX_REG0[0..31],pop:NXM_NX_REG0[]
 vlan_tci=0x1123/0x1fff,actions=drop
 ]])
 AT_CHECK([ovs-ofctl -F nxm -mmm parse-flows flows.txt], [0], [stdout], [stderr])
@@ -272,12 +272,9 @@ NXT_FLOW_MOD: ADD NXM_NX_TUN_ID(0000000000001234) cookie:0x5678 actions=FLOOD
 NXT_FLOW_MOD: ADD <any> actions=drop
 NXT_FLOW_MOD: ADD NXM_NX_REG0(0000007b) actions=move:NXM_NX_REG0[0..5]->NXM_NX_REG1[26..31],load:0x37->NXM_NX_REG2[],move:NXM_NX_REG0[]->NXM_NX_TUN_ID[0..31],move:NXM_NX_REG0[0..15]->NXM_OF_VLAN_TCI[]
 NXT_FLOW_MOD: ADD <any> actions=move:NXM_OF_ETH_DST[]->NXM_OF_ETH_SRC[]
-NXT_FLOW_MOD: ADD <any> actions=autopath(5,NXM_NX_REG0[])
+NXT_FLOW_MOD: ADD <any> actions=push:NXM_NX_REG0[],pop:NXM_NX_REG0[]
 NXT_FLOW_MOD: ADD NXM_OF_VLAN_TCI_W(1123/1fff) actions=drop
 ]])
-AT_CHECK([[sed 's/^[^|]*|[^|]*|//' stderr]], [0], [dnl
-autopath|WARN|The autopath action is deprecated and may be removed in February 2013.  Please email dev@openvswitch.org with concerns.
-])
 AT_CLEANUP
 
 AT_SETUP([ovs-ofctl parse-nx-match])
index 326d5a4..c5c3f47 100644 (file)
@@ -15,17 +15,17 @@ dnl RUN_OVS_VSCTL(COMMAND, ...)
 dnl
 dnl Executes each ovs-vsctl COMMAND.
 m4_define([RUN_OVS_VSCTL],
-  [m4_foreach([command], [$@], [ovs-vsctl --timeout=5 --no-wait -vreconnect:emer --db=unix:socket command
+  [m4_foreach([command], [$@], [ovs-vsctl --no-wait -vreconnect:emer --db=unix:socket command
 ])])
 m4_define([RUN_OVS_VSCTL_ONELINE],
-  [m4_foreach([command], [$@], [ovs-vsctl --timeout=5 --no-wait -vreconnect:emer --db=unix:socket --oneline -- command
+  [m4_foreach([command], [$@], [ovs-vsctl --no-wait -vreconnect:emer --db=unix:socket --oneline -- command
 ])])
 
 dnl RUN_OVS_VSCTL_TOGETHER(COMMAND, ...)
 dnl
 dnl Executes each ovs-vsctl COMMAND in a single run of ovs-vsctl.
 m4_define([RUN_OVS_VSCTL_TOGETHER],
-  [ovs-vsctl --timeout=5 --no-wait -vreconnect:emer --db=unix:socket --oneline dnl
+  [ovs-vsctl --no-wait -vreconnect:emer --db=unix:socket --oneline dnl
 m4_foreach([command], [$@], [ -- command])])
 
 dnl CHECK_BRIDGES([BRIDGE, PARENT, VLAN], ...)
@@ -139,6 +139,40 @@ m4_define([CHECK_IFACES],
 ],
                [], [OVS_VSCTL_CLEANUP])])])
 
+dnl ----------------------------------------------------------------------
+AT_BANNER([ovs-vsctl unit tests])
+
+AT_SETUP([ovs-vsctl connection retry])
+OVS_RUNDIR=$PWD; export OVS_RUNDIR
+
+dnl Without --retry, there should be no retry for active connections.
+AT_CHECK([ovs-vsctl --db=unix:foo --timeout=10 -vreconnect:emer -- init],
+  [1], [], [stderr])
+AT_CHECK([[sed 's/([^()]*)/(...reason...)/' stderr]], [0],
+  [ovs-vsctl: unix:foo: database connection failed (...reason...)
+])
+
+dnl With --retry, we should retry for active connections.
+AT_CHECK(
+  [ovs-vsctl --db=unix:foo --timeout=1 --retry -vreconnect:emer -vPATTERN:console:'%c|%p|%m' -- init
+   echo $? > status],
+  [0], [], [stderr])
+AT_CHECK([grep -c 'terminating with signal' stderr], [0], [1
+])
+AT_CHECK([kill -l `cat status`], [0], [ALRM
+])
+
+dnl Without --retry, we should retry for passive connections.
+AT_CHECK(
+  [ovs-vsctl --db=punix:foo --timeout=1 -vreconnect:emer -vPATTERN:console:'%c|%p|%m' -- init
+   echo $? > status],
+  [0], [], [stderr])
+AT_CHECK([grep -c 'terminating with signal' stderr], [0], [1
+])
+AT_CHECK([kill -l `cat status`], [0], [ALRM
+])
+AT_CLEANUP
+
 dnl ----------------------------------------------------------------------
 AT_BANNER([ovs-vsctl unit tests -- real bridges])
 
@@ -833,7 +867,7 @@ AT_CHECK(
 
 ])
 m4_define([VSCTL_CHECK_FIND],
-  [AT_CHECK([echo `ovs-vsctl --bare --timeout=5 --no-wait -vreconnect:emer --db=unix:socket -- --columns=name find bridge '$1' | sort`], [0], [$2
+  [AT_CHECK([echo `ovs-vsctl --bare --no-wait -vreconnect:emer --db=unix:socket -- --columns=name find bridge '$1' | sort`], [0], [$2
 ])])
 
 # Arithmetic relational operators without keys.
@@ -1044,19 +1078,19 @@ AT_SETUP([unreferenced record warnings])
 AT_KEYWORDS([ovs-vsctl])
 OVS_VSCTL_SETUP
 AT_CHECK(
-  [ovs-vsctl -vPATTERN:console:'%c|%p|%m' --timeout=5 --no-wait -vreconnect:emer --db=unix:socket \
+  [ovs-vsctl -vPATTERN:console:'%c|%p|%m' --no-wait -vreconnect:emer --db=unix:socket \
      -- create Bridge name=br0 | $srcdir/uuidfilt.pl],
   [0], [<0>
 ], [vsctl|WARN|applying "create" command to table Bridge without --id option will have no effect
 ], [OVS_VSCTL_CLEANUP])
 AT_CHECK(
-  [ovs-vsctl -vPATTERN:console:'%c|%p|%m' --timeout=5 --no-wait -vreconnect:emer --db=unix:socket \
+  [ovs-vsctl -vPATTERN:console:'%c|%p|%m' --no-wait -vreconnect:emer --db=unix:socket \
      -- --id=@br0 create Bridge name=br0 | $srcdir/uuidfilt.pl],
   [0], [<0>
 ], [vsctl|WARN|row id "@br0" was created but no reference to it was inserted, so it will not actually appear in the database
 ], [OVS_VSCTL_CLEANUP])
 AT_CHECK(
-  [ovs-vsctl -vPATTERN:console:'%c|%p|%m' --timeout=5 --no-wait -vreconnect:emer --db=unix:socket \
+  [ovs-vsctl -vPATTERN:console:'%c|%p|%m' --no-wait -vreconnect:emer --db=unix:socket \
      -- --id=@eth0_iface create Interface name=eth0 \
      -- --id=@eth0 create Port name=eth0 interfaces=@eth0_iface \
      -- --id=@m0 create Mirror name=m0 output_port=@eth0 \
index 29d4737..b55eecd 100644 (file)
@@ -22,7 +22,7 @@ mkdir var var/run
 touch var/run/xapi_init_complete.cookie
 
 ovs_vsctl () {
-    ovs-vsctl --timeout=5 --no-wait -vreconnect:emer --db=unix:socket "$@"
+    ovs-vsctl --no-wait -vreconnect:emer --db=unix:socket "$@"
 }
 
 # Start ovsdb-server.
index 6a3b5d1..eec2a04 100644 (file)
@@ -138,6 +138,7 @@ m4_divert_pop([PREPARE_TESTS])
 m4_define([OVSDB_CHECK_EXECUTION],
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb execute execution positive $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    AT_CHECK([test-ovsdb execute "`$2`" m4_foreach([txn], [$3], [ 'txn'])],
      [0], [stdout], [])
    AT_CHECK([perl $srcdir/uuidfilt.pl stdout], [0], [$4])
index ce22010..3c32e2f 100644 (file)
@@ -1,5 +1,6 @@
 AT_BANNER([OVSDB -- interface description language (IDL)])
 
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 # OVSDB_CHECK_IDL_C(TITLE, [PRE-IDL-TXN], TRANSACTIONS, OUTPUT, [KEYWORDS],
 #                   [FILTER])
 #
@@ -19,6 +20,7 @@ AT_BANNER([OVSDB -- interface description language (IDL)])
 m4_define([OVSDB_CHECK_IDL_C],
   [AT_SETUP([$1 - C])
    AT_KEYWORDS([ovsdb server idl positive $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest.ovsschema],
                   [0], [stdout], [ignore])
    AT_CHECK([ovsdb-server '-vPATTERN:console:ovsdb-server|%c|%m' --detach --no-chdir --pidfile="`pwd`"/pid --remote=punix:socket --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
@@ -36,6 +38,7 @@ m4_define([OVSDB_CHECK_IDL_PY],
   [AT_SETUP([$1 - Python])
    AT_SKIP_IF([test $HAVE_PYTHON = no])
    AT_KEYWORDS([ovsdb server idl positive Python $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest.ovsschema],
                   [0], [stdout], [ignore])
    AT_CHECK([ovsdb-server '-vPATTERN:console:ovsdb-server|%c|%m' --detach --no-chdir --pidfile="`pwd`"/pid --remote=punix:socket --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
@@ -53,6 +56,7 @@ m4_define([OVSDB_CHECK_IDL_TCP_PY],
   [AT_SETUP([$1 - Python tcp])
    AT_SKIP_IF([test $HAVE_PYTHON = no])
    AT_KEYWORDS([ovsdb server idl positive Python with tcp socket $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest.ovsschema],
                   [0], [stdout], [ignore])
    AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout])
index c1aa619..2aa752b 100644 (file)
@@ -2,7 +2,8 @@ dnl OVSDB_INIT([$1])
 dnl
 dnl Creates an empty database named $1.
 m4_define([OVSDB_INIT],
-  [AT_CHECK(
+  [OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+   AT_CHECK(
      [ovsdb-tool create $1 $abs_top_srcdir/vswitchd/vswitch.ovsschema],
      [0], [stdout], [ignore])
    AT_CHECK(
index 167b44c..aff5854 100644 (file)
@@ -19,6 +19,7 @@ AT_BANNER([OVSDB -- ovsdb-server monitors])
 m4_define([OVSDB_CHECK_MONITOR], 
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb server monitor positive $9])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    $2 > schema
    AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
    m4_foreach([txn], [$3],
index 6dcf2f5..62eae38 100644 (file)
@@ -21,6 +21,7 @@ m4_define([OVSDB_SERVER_SHUTDOWN],
 # TITLE is provided to AT_SETUP and KEYWORDS to AT_KEYWORDS.
 m4_define([OVSDB_CHECK_EXECUTION], 
   [AT_SETUP([$1])
+  OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    AT_KEYWORDS([ovsdb server positive unix $5])
    $2 > schema
    AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
@@ -39,6 +40,7 @@ EXECUTION_EXAMPLES
 \f
 AT_SETUP([truncating corrupted database log])
 AT_KEYWORDS([ovsdb server positive unix])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
 dnl Do one transaction and save the output.
@@ -85,6 +87,7 @@ AT_CLEANUP
 
 AT_SETUP([truncating database log with bad transaction])
 AT_KEYWORDS([ovsdb server positive unix])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
 dnl Do one transaction and save the output.
@@ -132,6 +135,7 @@ AT_CLEANUP
 
 AT_SETUP([ovsdb-client get-schema-version])
 AT_KEYWORDS([ovsdb server positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 AT_CHECK([ovsdb-tool create db schema], [0], [ignore], [ignore])
 AT_CHECK([ovsdb-server --detach --no-chdir --pidfile="`pwd`"/pid --unixctl="`pwd`"/unixctl --remote=punix:socket db], [0], [ignore], [ignore])
@@ -142,6 +146,7 @@ AT_CLEANUP
 
 AT_SETUP([database multiplexing implementation])
 AT_KEYWORDS([ovsdb server positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema1
 constraint_schema > schema2
 AT_CHECK([ovsdb-tool create db1 schema1], [0], [ignore], [ignore])
@@ -280,6 +285,7 @@ AT_CLEANUP
 
 AT_SETUP([compacting online])
 AT_KEYWORDS([ovsdb server compact])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 dnl Make sure that "ovsdb-tool create" works with a dangling symlink for
 dnl the database and the lockfile, creating the target of each symlink rather
@@ -430,6 +436,7 @@ m4_define([OVSDB_CHECK_EXECUTION],
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb server positive ssl $5])
    AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    $2 > schema
    AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout])
    SSL_PORT=`cat stdout`
@@ -479,6 +486,7 @@ AT_CLEANUP])
 m4_define([OVSDB_CHECK_EXECUTION],
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb server positive tcp $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    $2 > schema
    AT_CHECK([perl $srcdir/choose-port.pl], [0], [stdout])
    TCP_PORT=`cat stdout`
@@ -519,6 +527,7 @@ AT_BANNER([OVSDB -- transactions on transient ovsdb-server])
 m4_define([OVSDB_CHECK_EXECUTION], 
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb server positive transient $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    $2 > schema
    AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
    m4_foreach([txn], [$3], 
index e4f4a29..286d700 100644 (file)
@@ -16,6 +16,7 @@ AT_BANNER([OVSDB -- ovsdb-tool])
 m4_define([OVSDB_CHECK_EXECUTION], 
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb file positive $5])
+   OVS_RUNDIR=`pwd`; export OVS_RUNDIR
    $2 > schema
    touch .db.~lock~
    AT_CHECK([ovsdb-tool create db schema], [0], [stdout], [ignore])
@@ -48,6 +49,7 @@ AT_CLEANUP
 
 AT_SETUP([ovsdb-tool compact])
 AT_KEYWORDS([ovsdb file positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 dnl Make sure that "ovsdb-tool create" works with a dangling symlink,
 dnl creating the target of the symlink rather than replacing the symlink
@@ -155,6 +157,7 @@ AT_CLEANUP
 
 AT_SETUP([ovsdb-tool convert -- removing a column])
 AT_KEYWORDS([ovsdb file positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 ordinal_schema > schema
 AT_DATA([new-schema], 
   [[{"name": "ordinals",
@@ -218,6 +221,7 @@ AT_CLEANUP
 
 AT_SETUP([ovsdb-tool convert -- adding a column])
 AT_KEYWORDS([ovsdb file positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
 AT_DATA([schema], 
   [[{"name": "ordinals",
      "tables": {
index aa8b6f0..f5b24b4 100644 (file)
@@ -137,6 +137,7 @@ main(int argc, char *argv[])
     for (i = 0; i < N_FLOWS; i++) {
         random_bytes(&flows[i], sizeof flows[i]);
         memset(flows[i].zeros, 0, sizeof flows[i].zeros);
+        flows[i].mpls_depth = 0;
         flows[i].regs[0] = OFPP_NONE;
     }
 
index b1461ff..18dee86 100644 (file)
@@ -463,6 +463,8 @@ check_tables(const struct classifier *cls,
 
     HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
         const struct cls_rule *head;
+        unsigned int max_priority = 0;
+        unsigned int max_count = 0;
 
         assert(!hmap_is_empty(&table->rules));
 
@@ -471,15 +473,26 @@ check_tables(const struct classifier *cls,
             unsigned int prev_priority = UINT_MAX;
             const struct cls_rule *rule;
 
+            if (head->priority > max_priority) {
+                max_priority = head->priority;
+                max_count = 1;
+            } else if (head->priority == max_priority) {
+                ++max_count;
+            }
+
             found_rules++;
             LIST_FOR_EACH (rule, list, &head->list) {
                 assert(rule->priority < prev_priority);
+                assert(rule->priority <= table->max_priority);
+
                 prev_priority = rule->priority;
                 found_rules++;
                 found_dups++;
                 assert(classifier_find_rule_exactly(cls, rule) == rule);
             }
         }
+        assert(table->max_priority == max_priority);
+        assert(table->max_count == max_count);
     }
 
     assert(found_tables == hmap_count(&cls->tables));
index b4dedee..c77372f 100644 (file)
@@ -25,7 +25,7 @@
 #include "ofpbuf.h"
 #include "ofp-print.h"
 #include "ofp-util.h"
-#include "pcap.h"
+#include "pcap-file.h"
 #include "util.h"
 #include "vlog.h"
 
index c7c01c8..24bc745 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@ print_and_free_json(struct json *json)
         ok = false;
     } else {
         char *s = json_to_string(json, JSSF_SORT | (pretty ? JSSF_PRETTY : 0));
+        ovs_assert(pretty || json_serialized_length(json) == strlen(s));
         puts(s);
         free(s);
         ok = true;
index b990c13..8442bc2 100644 (file)
@@ -61,6 +61,7 @@ main(int argc, char *argv[])
 
             random_bytes(&flow, sizeof flow);
             memset(flow.zeros, 0, sizeof flow.zeros);
+            flow.mpls_depth = 0;
 
             mp.max_link = n - 1;
             multipath_execute(&mp, &flow);
index 5ed31a9..268a105 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@ parse_keys(void)
     struct ds in;
 
     ds_init(&in);
-    vlog_set_levels_from_string("odp_util:console:dbg");
+    vlog_set_levels_from_string_assert("odp_util:console:dbg");
     while (!ds_get_test_line(&in, stdin)) {
         enum odp_key_fitness fitness;
         struct ofpbuf odp_key;
@@ -98,7 +98,7 @@ parse_actions(void)
     struct ds in;
 
     ds_init(&in);
-    vlog_set_levels_from_string("odp_util:console:dbg");
+    vlog_set_levels_from_string_assert("odp_util:console:dbg");
     while (!ds_get_test_line(&in, stdin)) {
         struct ofpbuf odp_actions;
         struct ds out;
index d448109..658259e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -218,13 +218,16 @@ unbox_json(struct json *json)
     }
 }
 
-static void
+static size_t
 print_and_free_json(struct json *json)
 {
     char *string = json_to_string(json, JSSF_SORT);
+    size_t length = strlen(string);
     json_destroy(json);
     puts(string);
     free(string);
+
+    return length;
 }
 
 static void
@@ -442,7 +445,10 @@ do_parse_atoms(int argc, char *argv[])
         if (error) {
             print_and_free_ovsdb_error(error);
         } else {
-            print_and_free_json(ovsdb_atom_to_json(&atom, base.type));
+            size_t length;
+
+            length = print_and_free_json(ovsdb_atom_to_json(&atom, base.type));
+            ovs_assert(length == ovsdb_atom_json_length(&atom, base.type));
             ovsdb_atom_destroy(&atom, base.type);
         }
     }
@@ -494,12 +500,14 @@ do_parse_data__(int argc, char *argv[],
 
     for (i = 2; i < argc; i++) {
         struct ovsdb_datum datum;
+        size_t length;
 
         json = unbox_json(parse_json(argv[i]));
         check_ovsdb_error(parse(&datum, &type, json, NULL));
         json_destroy(json);
 
-        print_and_free_json(ovsdb_datum_to_json(&datum, &type));
+        length = print_and_free_json(ovsdb_datum_to_json(&datum, &type));
+        ovs_assert(length == ovsdb_datum_json_length(&datum, &type));
 
         ovsdb_datum_destroy(&datum, &type);
     }
@@ -1880,7 +1888,7 @@ do_idl(int argc, char *argv[])
 
     idltest_init();
 
-    idl = ovsdb_idl_create(argv[1], &idltest_idl_class, true);
+    idl = ovsdb_idl_create(argv[1], &idltest_idl_class, true, true);
     if (argc > 2) {
         struct stream *stream;
 
diff --git a/tests/test-sflow.c b/tests/test-sflow.c
new file mode 100644 (file)
index 0000000..3eb93c5
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * Copyright (c) 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2013 InMon Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <setjmp.h>
+
+#include "command-line.h"
+#include "daemon.h"
+#include "dynamic-string.h"
+#include "netflow.h"
+#include "ofpbuf.h"
+#include "packets.h"
+#include "poll-loop.h"
+#include "socket-util.h"
+#include "unixctl.h"
+#include "util.h"
+#include "vlog.h"
+
+static void usage(void) NO_RETURN;
+static void parse_options(int argc, char *argv[]);
+
+static unixctl_cb_func test_sflow_exit;
+
+/* Datagram. */
+#define SFLOW_VERSION_5 5
+#define SFLOW_MIN_LEN 36
+#define SFLOW_MAX_AGENTIP_STRLEN 64
+
+/* Sample tag numbers. */
+#define SFLOW_FLOW_SAMPLE 1
+#define SFLOW_COUNTERS_SAMPLE 2
+#define SFLOW_FLOW_SAMPLE_EXPANDED 3
+#define SFLOW_COUNTERS_SAMPLE_EXPANDED 4
+
+/* Structure element tag numbers. */
+#define SFLOW_TAG_CTR_IFCOUNTERS 1
+#define SFLOW_TAG_PKT_HEADER 1
+#define SFLOW_TAG_PKT_SWITCH 1001
+
+struct sflow_addr {
+    enum {
+        SFLOW_ADDRTYPE_undefined = 0,
+        SFLOW_ADDRTYPE_IP4,
+        SFLOW_ADDRTYPE_IP6
+    } type;
+
+    union {
+        ovs_be32 ip4;
+        ovs_be32 ip6[4];
+    } a;
+};
+
+struct sflow_xdr {
+    /* Exceptions. */
+    jmp_buf env;
+    int errline;
+
+    /* Cursor. */
+    ovs_be32 *datap;
+    uint32_t i;
+    uint32_t quads;
+
+    /* Agent. */
+    struct sflow_addr agentAddr;
+    char agentIPStr[SFLOW_MAX_AGENTIP_STRLEN];
+    uint32_t subAgentId;
+    uint32_t uptime_mS;
+
+    /* Datasource. */
+    uint32_t dsClass;
+    uint32_t dsIndex;
+
+    /* Sequence numbers. */
+    uint32_t dgramSeqNo;
+    uint32_t fsSeqNo;
+    uint32_t csSeqNo;
+
+    /* Structure offsets. */
+    struct {
+        uint32_t HEADER;
+        uint32_t SWITCH;
+        uint32_t IFCOUNTERS;
+    } offset;
+
+    /* Flow sample fields. */
+    uint32_t meanSkipCount;
+    uint32_t samplePool;
+    uint32_t dropEvents;
+    uint32_t inputPortFormat;
+    uint32_t inputPort;
+    uint32_t outputPortFormat;
+    uint32_t outputPort;
+};
+
+#define SFLOWXDR_try(x) ((x->errline = setjmp(x->env)) == 0)
+#define SFLOWXDR_throw(x) longjmp(x->env, __LINE__)
+#define SFLOWXDR_assert(x, t) if (!(t)) SFLOWXDR_throw(x)
+
+static void
+sflowxdr_init(struct sflow_xdr *x, void *buf, size_t len)
+{
+    x->datap = buf;
+    x->quads = len >> 2;
+}
+
+static uint32_t
+sflowxdr_next(struct sflow_xdr *x)
+{
+    return ntohl(x->datap[x->i++]);
+}
+
+static ovs_be32
+sflowxdr_next_n(struct sflow_xdr *x)
+{
+    return x->datap[x->i++];
+}
+
+static bool
+sflowxdr_more(const struct sflow_xdr *x, uint32_t q)
+{
+    return q + x->i <= x->quads;
+}
+
+static void
+sflowxdr_skip(struct sflow_xdr *x, uint32_t q)
+{
+    x->i += q;
+}
+
+static uint32_t
+sflowxdr_mark(const struct sflow_xdr *x, uint32_t q)
+{
+    return x->i + q;
+}
+
+static bool
+sflowxdr_mark_ok(const struct sflow_xdr *x, uint32_t m)
+{
+    return m == x->i;
+}
+
+static void
+sflowxdr_mark_unique(struct sflow_xdr *x, uint32_t *pi)
+{
+    if (*pi) {
+        SFLOWXDR_throw(x);
+    }
+    *pi = x->i;
+}
+
+static void
+sflowxdr_setc(struct sflow_xdr *x, uint32_t j)
+{
+    x->i = j;
+}
+
+static const char *
+sflowxdr_str(const struct sflow_xdr *x)
+{
+    return (const char *) (x->datap + x->i);
+}
+
+static uint64_t
+sflowxdr_next_int64(struct sflow_xdr *x)
+{
+    uint64_t scratch;
+    scratch = sflowxdr_next(x);
+    scratch <<= 32;
+    scratch += sflowxdr_next(x);
+    return scratch;
+}
+
+static void
+process_counter_sample(struct sflow_xdr *x)
+{
+    if (x->offset.IFCOUNTERS) {
+        sflowxdr_setc(x, x->offset.IFCOUNTERS);
+        printf("IFCOUNTERS");
+        printf(" dgramSeqNo=%"PRIu32, x->dgramSeqNo);
+        printf(" ds=%s>%"PRIu32":%"PRIu32,
+               x->agentIPStr, x->dsClass, x->dsIndex);
+        printf(" csSeqNo=%"PRIu32, x->csSeqNo);
+        printf(" ifindex=%"PRIu32, sflowxdr_next(x));
+        printf(" type=%"PRIu32, sflowxdr_next(x));
+        printf(" ifspeed=%"PRIu64, sflowxdr_next_int64(x));
+        printf(" direction=%"PRIu32, sflowxdr_next(x));
+        printf(" status=%"PRIu32, sflowxdr_next(x));
+        printf(" in_octets=%"PRIu64, sflowxdr_next_int64(x));
+        printf(" in_unicasts=%"PRIu32, sflowxdr_next(x));
+        printf(" in_multicasts=%"PRIu32, sflowxdr_next(x));
+        printf(" in_broadcasts=%"PRIu32, sflowxdr_next(x));
+        printf(" in_discards=%"PRIu32, sflowxdr_next(x));
+        printf(" in_errors=%"PRIu32, sflowxdr_next(x));
+        printf(" in_unknownprotos=%"PRIu32, sflowxdr_next(x));
+        printf(" out_octets=%"PRIu64, sflowxdr_next_int64(x));
+        printf(" out_unicasts=%"PRIu32, sflowxdr_next(x));
+        printf(" out_multicasts=%"PRIu32, sflowxdr_next(x));
+        printf(" out_broadcasts=%"PRIu32, sflowxdr_next(x));
+        printf(" out_discards=%"PRIu32, sflowxdr_next(x));
+        printf(" out_errors=%"PRIu32, sflowxdr_next(x));
+        printf(" promiscuous=%"PRIu32, sflowxdr_next(x));
+        printf("\n");
+    }
+}
+
+static char
+bin_to_hex(int hexit)
+{
+    return "0123456789ABCDEF"[hexit];
+}
+
+static int
+print_hex(const char *a, int len, char *buf, int bufLen)
+{
+    unsigned char nextByte;
+    int b = 0;
+    int i;
+
+    for (i = 0; i < len; i++) {
+        if (b > bufLen - 10) {
+            break;
+        }
+        nextByte = a[i];
+        buf[b++] = bin_to_hex(nextByte >> 4);
+        buf[b++] = bin_to_hex(nextByte & 0x0f);
+        if (i < len - 1) {
+            buf[b++] = '-';
+        }
+    }
+    buf[b] = '\0';
+    return b;
+}
+
+#define SFLOW_HEX_SCRATCH 1024
+
+static void
+process_flow_sample(struct sflow_xdr *x)
+{
+    if (x->offset.HEADER) {
+        uint32_t headerLen;
+        char scratch[SFLOW_HEX_SCRATCH];
+
+        printf("HEADER");
+        printf(" dgramSeqNo=%"PRIu32, x->dgramSeqNo);
+        printf(" ds=%s>%"PRIu32":%"PRIu32,
+               x->agentIPStr, x->dsClass, x->dsIndex);
+        printf(" fsSeqNo=%"PRIu32, x->fsSeqNo);
+
+        if (x->offset.SWITCH) {
+            sflowxdr_setc(x, x->offset.SWITCH);
+            printf(" in_vlan=%"PRIu32, sflowxdr_next(x));
+            printf(" in_priority=%"PRIu32, sflowxdr_next(x));
+            printf(" out_vlan=%"PRIu32, sflowxdr_next(x));
+            printf(" out_priority=%"PRIu32, sflowxdr_next(x));
+        }
+
+        sflowxdr_setc(x, x->offset.HEADER);
+        printf(" meanSkip=%"PRIu32, x->meanSkipCount);
+        printf(" samplePool=%"PRIu32, x->samplePool);
+        printf(" dropEvents=%"PRIu32, x->dropEvents);
+        printf(" in_ifindex=%"PRIu32, x->inputPort);
+        printf(" in_format=%"PRIu32, x->inputPortFormat);
+        printf(" out_ifindex=%"PRIu32, x->outputPort);
+        printf(" out_format=%"PRIu32, x->outputPortFormat);
+        printf(" hdr_prot=%"PRIu32, sflowxdr_next(x));
+        printf(" pkt_len=%"PRIu32, sflowxdr_next(x));
+        printf(" stripped=%"PRIu32, sflowxdr_next(x));
+        headerLen = sflowxdr_next(x);
+        printf(" hdr_len=%"PRIu32, headerLen);
+        print_hex(sflowxdr_str(x), headerLen, scratch, SFLOW_HEX_SCRATCH);
+        printf(" hdr=%s", scratch);
+        printf("\n");
+    }
+}
+
+static void
+process_datagram(struct sflow_xdr *x)
+{
+    uint32_t samples, s;
+
+    SFLOWXDR_assert(x, (sflowxdr_next(x) == SFLOW_VERSION_5));
+
+    /* Read the sFlow header. */
+    x->agentAddr.type = sflowxdr_next(x);
+    switch (x->agentAddr.type) {
+    case SFLOW_ADDRTYPE_IP4:
+        x->agentAddr.a.ip4 = sflowxdr_next_n(x);
+        break;
+
+    case SFLOW_ADDRTYPE_IP6:
+        x->agentAddr.a.ip6[0] = sflowxdr_next_n(x);
+        x->agentAddr.a.ip6[1] = sflowxdr_next_n(x);
+        x->agentAddr.a.ip6[2] = sflowxdr_next_n(x);
+        x->agentAddr.a.ip6[3] = sflowxdr_next_n(x);
+        break;
+
+    case SFLOW_ADDRTYPE_undefined:
+    default:
+        SFLOWXDR_throw(x);
+        break;
+    }
+    x->subAgentId = sflowxdr_next(x);
+    x->dgramSeqNo = sflowxdr_next(x);
+    x->uptime_mS = sflowxdr_next(x);
+
+    /* Store the agent address as a string. */
+    if (x->agentAddr.type == SFLOW_ADDRTYPE_IP6) {
+        snprintf(x->agentIPStr, SFLOW_MAX_AGENTIP_STRLEN,
+                 "%04x:%04x:%04x:%04x",
+                 x->agentAddr.a.ip6[0],
+                 x->agentAddr.a.ip6[1],
+                 x->agentAddr.a.ip6[2],
+                 x->agentAddr.a.ip6[3]);
+    } else {
+        snprintf(x->agentIPStr, SFLOW_MAX_AGENTIP_STRLEN,
+                 IP_FMT, IP_ARGS(x->agentAddr.a.ip4));
+    }
+
+    /* Array of flow/counter samples. */
+    samples = sflowxdr_next(x);
+    for (s = 0; s < samples; s++) {
+        uint32_t sType = sflowxdr_next(x);
+        uint32_t sQuads = sflowxdr_next(x) >> 2;
+        uint32_t sMark = sflowxdr_mark(x, sQuads);
+        SFLOWXDR_assert(x, sflowxdr_more(x, sQuads));
+
+        switch (sType) {
+        case SFLOW_COUNTERS_SAMPLE_EXPANDED:
+        case SFLOW_COUNTERS_SAMPLE:
+        {
+            uint32_t csElements, e;
+            uint32_t ceTag, ceQuads, ceMark, csEnd;
+
+            x->csSeqNo = sflowxdr_next(x);
+            if (sType == SFLOW_COUNTERS_SAMPLE_EXPANDED) {
+                x->dsClass = sflowxdr_next(x);
+                x->dsIndex = sflowxdr_next(x);
+            } else {
+                uint32_t dsCombined = sflowxdr_next(x);
+                x->dsClass = dsCombined >> 24;
+                x->dsIndex = dsCombined & 0x00FFFFFF;
+            }
+
+            csElements = sflowxdr_next(x);
+            for (e = 0; e < csElements; e++) {
+                SFLOWXDR_assert(x, sflowxdr_more(x,2));
+                ceTag = sflowxdr_next(x);
+                ceQuads = sflowxdr_next(x) >> 2;
+                ceMark = sflowxdr_mark(x, ceQuads);
+                SFLOWXDR_assert(x, sflowxdr_more(x,ceQuads));
+                /* Only care about selected structures.  Just record their
+                 * offsets here. We'll read the fields out later. */
+                switch (ceTag) {
+                case SFLOW_TAG_CTR_IFCOUNTERS:
+                    sflowxdr_mark_unique(x, &x->offset.IFCOUNTERS);
+                    break;
+
+                    /* Add others here... */
+                }
+
+                sflowxdr_skip(x, ceQuads);
+                SFLOWXDR_assert(x, sflowxdr_mark_ok(x, ceMark));
+            }
+
+            csEnd = sflowxdr_mark(x, 0);
+            process_counter_sample(x);
+            /* Make sure we pick up the decoding where we left off. */
+            sflowxdr_setc(x, csEnd);
+
+            /* Clear the offsets for the next sample. */
+            memset(&x->offset, 0, sizeof x->offset);
+        }
+        break;
+
+        case SFLOW_FLOW_SAMPLE:
+        case SFLOW_FLOW_SAMPLE_EXPANDED:
+        {
+            uint32_t fsElements, e;
+            uint32_t feTag, feQuads, feMark, fsEnd;
+            x->fsSeqNo = sflowxdr_next(x);
+            if (sType == SFLOW_FLOW_SAMPLE_EXPANDED) {
+                x->dsClass = sflowxdr_next(x);
+                x->dsIndex = sflowxdr_next(x);
+            } else {
+                uint32_t dsCombined = sflowxdr_next(x);
+                x->dsClass = dsCombined >> 24;
+                x->dsIndex = dsCombined & 0x00FFFFFF;
+            }
+            x->meanSkipCount = sflowxdr_next(x);
+            x->samplePool = sflowxdr_next(x);
+            x->dropEvents = sflowxdr_next(x);
+            if (sType == SFLOW_FLOW_SAMPLE_EXPANDED) {
+                x->inputPortFormat = sflowxdr_next(x);
+                x->inputPort = sflowxdr_next(x);
+                x->outputPortFormat = sflowxdr_next(x);
+                x->outputPort = sflowxdr_next(x);
+            } else {
+                uint32_t inp, outp;
+
+                inp = sflowxdr_next(x);
+                outp = sflowxdr_next(x);
+                x->inputPortFormat = inp >> 30;
+                x->inputPort = inp & 0x3fffffff;
+                x->outputPortFormat = outp >> 30;
+                x->outputPort = outp & 0x3fffffff;
+            }
+            fsElements = sflowxdr_next(x);
+            for (e = 0; e < fsElements; e++) {
+                SFLOWXDR_assert(x, sflowxdr_more(x,2));
+                feTag = sflowxdr_next(x);
+                feQuads = sflowxdr_next(x) >> 2;
+                feMark = sflowxdr_mark(x, feQuads);
+                SFLOWXDR_assert(x, sflowxdr_more(x,feQuads));
+                /* Only care about selected structures.  Just record their
+                 * offsets here. We'll read the fields out below. */
+                switch (feTag) {
+                case SFLOW_TAG_PKT_HEADER:
+                    sflowxdr_mark_unique(x, &x->offset.HEADER);
+                    break;
+
+                case SFLOW_TAG_PKT_SWITCH:
+                    sflowxdr_mark_unique(x, &x->offset.SWITCH);
+                    break;
+
+                    /* Add others here... */
+                }
+
+                sflowxdr_skip(x, feQuads);
+                SFLOWXDR_assert(x, sflowxdr_mark_ok(x, feMark));
+            }
+
+            fsEnd = sflowxdr_mark(x, 0);
+            process_flow_sample(x);
+            /* Make sure we pick up the decoding where we left off. */
+            sflowxdr_setc(x, fsEnd);
+
+            /* Clear the offsets for the next counter/flow sample. */
+            memset(&x->offset, 0, sizeof x->offset);
+        }
+        break;
+
+        default:
+            /* Skip other sample types. */
+            sflowxdr_skip(x, sQuads);
+        }
+        SFLOWXDR_assert(x, sflowxdr_mark_ok(x, sMark));
+    }
+}
+
+static void
+print_sflow(struct ofpbuf *buf)
+{
+    char *dgram_buf;
+    int dgram_len = buf->size;
+    struct sflow_xdr xdrDatagram;
+    struct sflow_xdr *x = &xdrDatagram;
+
+    memset(x, 0, sizeof *x);
+    if (SFLOWXDR_try(x)) {
+        SFLOWXDR_assert(x, (dgram_buf = ofpbuf_try_pull(buf, buf->size)));
+        sflowxdr_init(x, dgram_buf, dgram_len);
+        SFLOWXDR_assert(x, dgram_len >= SFLOW_MIN_LEN);
+        process_datagram(x);
+    } else {
+        // CATCH
+        printf("\n>>>>> ERROR in " __FILE__ " at line %u\n", x->errline);
+    }
+}
+
+int
+main(int argc, char *argv[])
+{
+    struct unixctl_server *server;
+    enum { MAX_RECV = 1500 };
+    const char *target;
+    struct ofpbuf buf;
+    bool exiting = false;
+    int error;
+    int sock;
+
+    proctitle_init(argc, argv);
+    set_program_name(argv[0]);
+    parse_options(argc, argv);
+
+    if (argc - optind != 1) {
+        ovs_fatal(0, "exactly one non-option argument required "
+                  "(use --help for help)");
+    }
+    target = argv[optind];
+
+    sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0);
+    if (sock < 0) {
+        ovs_fatal(0, "%s: failed to open (%s)", argv[1], strerror(-sock));
+    }
+
+    daemon_save_fd(STDOUT_FILENO);
+    daemonize_start();
+
+    error = unixctl_server_create(NULL, &server);
+    if (error) {
+        ovs_fatal(error, "failed to create unixctl server");
+    }
+    unixctl_command_register("exit", "", 0, 0, test_sflow_exit, &exiting);
+
+    daemonize_complete();
+
+    ofpbuf_init(&buf, MAX_RECV);
+    for (;;) {
+        int retval;
+
+        unixctl_server_run(server);
+
+        ofpbuf_clear(&buf);
+        do {
+            retval = read(sock, buf.data, buf.allocated);
+        } while (retval < 0 && errno == EINTR);
+        if (retval > 0) {
+            ofpbuf_put_uninit(&buf, retval);
+            print_sflow(&buf);
+            fflush(stdout);
+        }
+
+        if (exiting) {
+            break;
+        }
+
+        poll_fd_wait(sock, POLLIN);
+        unixctl_server_wait(server);
+        poll_block();
+    }
+
+    return 0;
+}
+
+static void
+parse_options(int argc, char *argv[])
+{
+    enum {
+        DAEMON_OPTION_ENUMS
+    };
+    static struct option long_options[] = {
+        {"verbose", optional_argument, NULL, 'v'},
+        {"help", no_argument, NULL, 'h'},
+        DAEMON_LONG_OPTIONS,
+        {NULL, 0, NULL, 0},
+    };
+    char *short_options = long_options_to_short_options(long_options);
+
+    for (;;) {
+        int c = getopt_long(argc, argv, short_options, long_options, NULL);
+        if (c == -1) {
+            break;
+        }
+
+        switch (c) {
+        case 'h':
+            usage();
+
+        case 'v':
+            vlog_set_verbosity(optarg);
+            break;
+
+            DAEMON_OPTION_HANDLERS
+
+        case '?':
+            exit(EXIT_FAILURE);
+
+        default:
+            abort();
+        }
+    }
+    free(short_options);
+}
+
+static void
+usage(void)
+{
+    printf("%s: sflow collector test utility\n"
+           "usage: %s [OPTIONS] PORT[:IP]\n"
+           "where PORT is the UDP port to listen on and IP is optionally\n"
+           "the IP address to listen on.\n",
+           program_name, program_name);
+    daemon_usage();
+    vlog_usage();
+    printf("\nOther options:\n"
+           "  -h, --help                  display this help message\n");
+    exit(EXIT_SUCCESS);
+}
+
+static void
+test_sflow_exit(struct unixctl_conn *conn,
+                int argc OVS_UNUSED, const char *argv[] OVS_UNUSED,
+                void *exiting_)
+{
+    bool *exiting = exiting_;
+    *exiting = true;
+    unixctl_command_reply(conn, NULL);
+}
diff --git a/tests/test-unix-socket.py b/tests/test-unix-socket.py
new file mode 100644 (file)
index 0000000..5a3f3c0
--- /dev/null
@@ -0,0 +1,54 @@
+#
+# Copyright (c) 2010, 2012, 2013 Nicira, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import os
+import signal
+import socket
+import sys
+
+import ovs.socket_util
+
+def main(argv):
+    if len(argv) not in (2, 3):
+        sys.stderr.write("usage: %s SOCKETNAME1 [SOCKETNAME2]", argv[0])
+        sys.exit(1)
+
+    sockname1 = argv[1]
+    if len(argv) > 2:
+        sockname2 = argv[2]
+    else:
+        sockname2 = sockname1
+
+    signal.signal(signal.SIGALRM, signal.SIG_DFL)
+    signal.alarm(5)
+
+    # Create a listening socket under name 'sockname1'.
+    error, sock1 = ovs.socket_util.make_unix_socket(socket.SOCK_STREAM, False,
+                                                    sockname1, None)
+    if error:
+        sys.stderr.write("%s: bind failed (%s)" % (sockname1,
+                                                   os.strerror(error)))
+    sock1.listen(1)
+
+    # Connect to 'sockname2' (which should be the same file, perhaps under a
+    # different name).
+    error, sock2 = ovs.socket_util.make_unix_socket(socket.SOCK_STREAM, False,
+                                                    None, sockname2)
+    if error:
+        sys.stderr.write("%s: connect failed (%s)" % (sockname2,
+                                                      os.strerror(error)))
+
+if __name__ == '__main__':
+    main(sys.argv)
index fa80c4d..97bc247 100644 (file)
@@ -82,7 +82,6 @@ m4_include([tests/ofp-errors.at])
 m4_include([tests/ovs-ofctl.at])
 m4_include([tests/odp.at])
 m4_include([tests/multipath.at])
-m4_include([tests/autopath.at])
 m4_include([tests/learn.at])
 m4_include([tests/vconn.at])
 m4_include([tests/file_name.at])
index c708b30..78e43f5 100644 (file)
@@ -16,8 +16,9 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
 AT_CHECK([ovs-appctl dpif/show], [0], [dnl
 br0 (dummy@ovs-dummy):
-       lookups: hit:0 missed:0 lost:0
-       flows: 0
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br0 65534/100: (dummy)
        p1 1/1: (gre: remote_ip=1.1.1.1)
        p2 2/1: (gre: local_ip=2.2.2.2, remote_ip=1.1.1.1)
@@ -42,8 +43,9 @@ AT_CHECK([ovs-vsctl set Interface p2 type=gre options:local_ip=2.2.2.3 \
           -- set Interface p3 type=gre64])
 AT_CHECK([ovs-appctl dpif/show], [0], [dnl
 br0 (dummy@ovs-dummy):
-       lookups: hit:0 missed:0 lost:0
-       flows: 0
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br0 65534/100: (dummy)
        p1 1/1: (gre: remote_ip=1.1.1.1)
        p2 2/1: (gre: csum=true, df_default=false, local_ip=2.2.2.3, remote_ip=1.1.1.1, ttl=1)
@@ -64,7 +66,7 @@ Invalid flow
 ovs-appctl: ovs-vswitchd: server returned an error
 ])
 
-OVS_VSWITCHD_STOP
+OVS_VSWITCHD_STOP(["/receive tunnel port not found/d"])
 AT_CLEANUP
 
 AT_SETUP([tunnel - ECN decapsulation])
@@ -80,18 +82,38 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
 AT_CHECK([ovs-appctl dpif/show], [0], [dnl
 br0 (dummy@ovs-dummy):
-       lookups: hit:0 missed:0 lost:0
-       flows: 0
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br0 65534/100: (dummy)
        p1 1/1: (gre: remote_ip=1.1.1.1)
        p2 2/2: (dummy)
 ])
 
-AT_CHECK([ovs-appctl ofproto/trace br0 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=1,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+dnl Tunnel CE and encapsulated packet CE
+AT_CHECK([ovs-appctl ofproto/trace br0 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=3,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: 2
 ])
-OVS_VSWITCHD_STOP
+
+dnl Tunnel CE and encapsulated packet ECT(1)
+AT_CHECK([ovs-appctl ofproto/trace br0 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=1,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0x3,ttl=64,frag=no)),2
+])
+
+dnl Tunnel CE and encapsulated packet ECT(2)
+AT_CHECK([ovs-appctl ofproto/trace br0 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=2,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: set(ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0x3,ttl=64,frag=no)),2
+])
+
+dnl Tunnel CE and encapsulated packet Non-ECT
+AT_CHECK([ovs-appctl ofproto/trace br0 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+  [Datapath actions: drop
+])
+OVS_VSWITCHD_STOP(["/dropping tunnel packet marked ECN CE but is not ECN capable/d"])
 AT_CLEANUP
 
 AT_SETUP([tunnel - output])
@@ -108,8 +130,9 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
 AT_CHECK([ovs-appctl dpif/show], [0], [dnl
 br0 (dummy@ovs-dummy):
-       lookups: hit:0 missed:0 lost:0
-       flows: 0
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br0 65534/100: (dummy)
        p1 1/1: (gre: key=5, local_ip=2.2.2.2, remote_ip=1.1.1.1)
        p2 2/2: (dummy)
@@ -143,8 +166,9 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
 AT_CHECK([ovs-appctl dpif/show], [0], [dnl
 br0 (dummy@ovs-dummy):
-       lookups: hit:0 missed:0 lost:0
-       flows: 0
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br0 65534/100: (dummy)
        p1 1/1: (gre: remote_ip=1.1.1.1, tos=inherit, ttl=inherit)
        p2 2/2: (dummy)
@@ -188,8 +212,9 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
 AT_CHECK([ovs-appctl dpif/show], [0], [dnl
 br0 (dummy@ovs-dummy):
-       lookups: hit:0 missed:0 lost:0
-       flows: 0
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br0 65534/100: (dummy)
        p1 1/1: (gre: key=flow, remote_ip=1.1.1.1)
        p2 2/1: (gre: key=flow, remote_ip=2.2.2.2)
@@ -223,8 +248,9 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
 AT_CHECK([ovs-appctl dpif/show], [0], [dnl
 br0 (dummy@ovs-dummy):
-       lookups: hit:0 missed:0 lost:0
-       flows: 0
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br0 65534/100: (dummy)
        p1 1/1: (gre: key=1, remote_ip=1.1.1.1)
        p2 2/1: (gre: in_key=2, out_key=3, remote_ip=1.1.1.1)
@@ -256,7 +282,7 @@ AT_CHECK([ovs-appctl ofproto/trace br0 'tunnel(tun_id=0xf,src=1.1.1.1,dst=2.2.2.
 Invalid flow
 ovs-appctl: ovs-vswitchd: server returned an error
 ])
-OVS_VSWITCHD_STOP
+OVS_VSWITCHD_STOP(["/receive tunnel port not found/d"])
 AT_CLEANUP
 
 AT_SETUP([tunnel - key match])
@@ -278,8 +304,9 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
 AT_CHECK([ovs-appctl dpif/show], [0], [dnl
 br0 (dummy@ovs-dummy):
-       lookups: hit:0 missed:0 lost:0
-       flows: 0
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
        br0 65534/100: (dummy)
        p1 1/1: (gre: key=flow, remote_ip=1.1.1.1)
        p2 2/1: (gre: key=3, remote_ip=3.3.3.3)
@@ -310,3 +337,77 @@ AT_CHECK([tail -1 stdout], [0], [dnl
 
 OVS_VSWITCHD_STOP
 AT_CLEANUP
+
+AT_SETUP([tunnel - VXLAN])
+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
+                    options:remote_ip=1.1.1.1 ofport_request=1])
+
+AT_CHECK([ovs-appctl dpif/show], [0], [dnl
+br0 (dummy@ovs-dummy):
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
+       br0 65534/100: (dummy)
+       p1 1/1: (vxlan: remote_ip=1.1.1.1)
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([tunnel - LISP])
+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=lisp \
+                    options:remote_ip=1.1.1.1 ofport_request=1])
+
+AT_CHECK([ovs-appctl dpif/show], [0], [dnl
+br0 (dummy@ovs-dummy):
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
+       br0 65534/100: (dummy)
+       p1 1/1: (lisp: remote_ip=1.1.1.1)
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([tunnel - different VXLAN UDP port])
+OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=vxlan \
+                    options:remote_ip=1.1.1.1 ofport_request=1 options:dst_port=4341])
+
+AT_CHECK([ovs-appctl dpif/show], [0], [dnl
+br0 (dummy@ovs-dummy):
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
+       br0 65534/100: (dummy)
+       p1 1/1: (vxlan: dst_port=4341, remote_ip=1.1.1.1)
+])
+
+dnl change UDP port
+
+AT_CHECK([ovs-vsctl -- set Interface p1 options:dst_port=5000])
+
+AT_CHECK([ovs-appctl dpif/show], [0], [dnl
+br0 (dummy@ovs-dummy):
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
+       br0 65534/100: (dummy)
+       p1 1/2: (vxlan: dst_port=5000, remote_ip=1.1.1.1)
+])
+
+dnl change UDP port to default
+
+AT_CHECK([ovs-vsctl -- set Interface p1 options:dst_port=8472])
+
+AT_CHECK([ovs-appctl dpif/show], [0], [dnl
+br0 (dummy@ovs-dummy):
+       lookups: hit:0 missed:0
+       flows: cur: 0, avg: 0.000, max: 0, life span: 0(ms)
+               overall avg: add rate: 0.000/min, del rate: 0.000/min
+       br0 65534/100: (dummy)
+       p1 1/1: (vxlan: remote_ip=1.1.1.1)
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
index ae095b0..359f97a 100644 (file)
@@ -11,6 +11,7 @@ m4_define([TEST_VCONN_CLASS],
       [send-short-hello],
       [send-invalid-version-hello]],
      [AT_SETUP([$1 vconn - m4_bpatsubst(testname, [-], [ ])])
+     OVS_RUNDIR=`pwd`; export OVS_RUNDIR
       m4_if([$1], [ssl], [
         AT_SKIP_IF([test "$HAVE_OPENSSL" = no])
         AT_CHECK([cp $abs_top_builddir/tests/testpki*.pem .])])
index 88f905a..9d1ff66 100644 (file)
@@ -22,6 +22,9 @@ bugtool_scripts = \
        utilities/bugtool/ovs-bugtool-vsctl-show \
        utilities/bugtool/ovs-bugtool-ovsdb-dump \
        utilities/bugtool/ovs-bugtool-daemons-ver \
+       utilities/bugtool/ovs-bugtool-ovs-ofctl-show \
+       utilities/bugtool/ovs-bugtool-ovs-ofctl-dump-flows \
+       utilities/bugtool/ovs-bugtool-ovs-appctl-dpif \
        utilities/bugtool/ovs-bugtool-bond-show
 scripts_SCRIPTS += $(bugtool_scripts)
 
diff --git a/utilities/bugtool/ovs-bugtool-ovs-appctl-dpif b/utilities/bugtool/ovs-bugtool-ovs-appctl-dpif
new file mode 100755 (executable)
index 0000000..3560ef0
--- /dev/null
@@ -0,0 +1,26 @@
+#! /bin/sh
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General
+# Public License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+# Copyright (C) 2013 Nicira, Inc.
+
+for bridge in `ovs-vsctl -- --real list-br`
+do
+    echo "ovs-appctl dpif/show ${bridge}"
+    ovs-appctl dpif/show "${bridge}"
+    echo "ovs-appctl dpif/dump-flows ${bridge}"
+    ovs-appctl dpif/dump-flows "$bridge"
+    echo ""
+done
diff --git a/utilities/bugtool/ovs-bugtool-ovs-ofctl-dump-flows b/utilities/bugtool/ovs-bugtool-ovs-ofctl-dump-flows
new file mode 100755 (executable)
index 0000000..61fb841
--- /dev/null
@@ -0,0 +1,24 @@
+#! /bin/sh
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General
+# Public License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+# Copyright (C) 2013 Nicira, Inc.
+
+for bridge in `ovs-vsctl list-br`
+do
+    echo "ovs-ofctl dump-flows ${bridge}"
+    ovs-ofctl dump-flows "$bridge"
+    echo ""
+done
diff --git a/utilities/bugtool/ovs-bugtool-ovs-ofctl-show b/utilities/bugtool/ovs-bugtool-ovs-ofctl-show
new file mode 100755 (executable)
index 0000000..2843395
--- /dev/null
@@ -0,0 +1,24 @@
+#! /bin/sh
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General
+# Public License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+# Copyright (C) 2013 Nicira, Inc.
+
+for bridge in `ovs-vsctl list-br`
+do
+    echo "ovs-ofctl show ${bridge}"
+    ovs-ofctl show "$bridge"
+    echo ""
+done
index fe433d8..26e46e5 100755 (executable)
@@ -14,6 +14,6 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 # USA
 #
-# Copyright (C) 2012 Nicira, Inc.
+# Copyright (C) 2012, 2013 Nicira, Inc.
 
-ovs-vsctl --timeout=5 show
+ovs-vsctl show
index a1e653b..b528dba 100644 (file)
@@ -23,9 +23,6 @@ system and places it in \fB/var/log/ovs-bugtool\fR.
 .IP "\fB\-\-all\fR"
 Use all available capabilities.
 .
-.IP "\fB\-\-ovs\fR"
-Use only Open vSwitch relevant capabilities.
-.
 .IP "\fB\-\-capabilities\fR"
 List \fBovs\-bugtool\fR capabilities.
 .
@@ -35,10 +32,18 @@ Print verbose debugging output.
 .IP "\fB\-\-entries=\fIlist\fR"
 Use the capabilities specified in a comma-separated list.
 .
+.IP "\fB\-\-log\-days=\fIdays\fR"
+Include the logs rotated in the previous \fIdays\fR days in the debug bundle.
+The number of log files included has a big impact on the eventual bundle size.
+The default value is 20 days.
+.
 .IP "\fB\-\-output=\fIfiletype\fR"
 Generate a debug bundle with the specified file type.  Options include
 \fBtar\fR, \fBtar.gz\fR, \fBtar.bz2\fR, and \fBzip\fR.
 .
+.IP "\fB\-\-ovs\fR"
+Use only Open vSwitch relevant capabilities.
+.
 .IP "\fB\-\-silent\fR"
 Suppress output.
 .
index f91a3b3..ffaf753 100755 (executable)
@@ -76,8 +76,6 @@ FSTAB = '/etc/fstab'
 PROC_MOUNTS = '/proc/mounts'
 ISCSI_CONF = '/etc/iscsi/iscsid.conf'
 ISCSI_INITIATOR = '/etc/iscsi/initiatorname.iscsi'
-LVM_CACHE = '/etc/lvm/cache/.cache'
-LVM_CONFIG = '/etc/lvm/lvm.conf'
 PROC_CPUINFO = '/proc/cpuinfo'
 PROC_MEMINFO = '/proc/meminfo'
 PROC_IOPORTS = '/proc/ioports'
@@ -90,7 +88,6 @@ PROC_FILESYSTEMS = '/proc/filesystems'
 PROC_CMDLINE = '/proc/cmdline'
 PROC_CONFIG = '/proc/config.gz'
 PROC_USB_DEV = '/proc/bus/usb/devices'
-PROC_XEN_BALLOON = '/proc/xen/balloon'
 PROC_NET_BONDING_DIR = '/proc/net/bonding'
 IFCFG_RE = re.compile(r'^.*/ifcfg-.*')
 ROUTE_RE = re.compile(r'^.*/route-.*')
@@ -117,17 +114,10 @@ OPENVSWITCH_SYSCONFIG_SWITCH = '/etc/sysconfig/openvswitch'    # RHEL
 OPENVSWITCH_DEFAULT_CONTROLLER = '/etc/default/openvswitch-controller'
 OPENVSWITCH_CONF_DB = '@DBDIR@/conf.db'
 OPENVSWITCH_VSWITCHD_PID = '@RUNDIR@/ovs-vswitchd.pid'
-COLLECTD_LOGS_DIR = '/var/lib/collectd/rrd'
 VAR_LOG_DIR = '/var/log/'
 VAR_LOG_CORE_DIR = '/var/log/core'
-X11_LOGS_DIR = VAR_LOG_DIR
-X11_LOGS_RE = re.compile(r'.*/Xorg\..*$')
-X11_AUTH_DIR = '/root/'
-X11_AUTH_RE = re.compile(r'.*/\.((Xauthority)|(serverauth\.[0-9]*))$')
 YUM_LOG = '/var/log/yum.log'
 YUM_REPOS_DIR = '/etc/yum.repos.d'
-PAM_DIR = '/etc/pam.d'
-KRB5_CONF = '/etc/krb5.conf'
 
 #
 # External programs
@@ -145,15 +135,12 @@ DPKG_QUERY = 'dpkg-query'
 ETHTOOL = 'ethtool'
 FDISK = 'fdisk'
 FIND = 'find'
-HDPARM = 'hdparm'
 IFCONFIG = 'ifconfig'
 IPTABLES = 'iptables'
 ISCSIADM = 'iscsiadm'
 LOSETUP = 'losetup'
 LS = 'ls'
 LSPCI = 'lspci'
-LVDISPLAY = 'lvdisplay'
-LVS = 'lvs'
 MD5SUM = 'md5sum'
 MODINFO = 'modinfo'
 MPPUTIL = 'mppUtil'
@@ -164,15 +151,12 @@ OVS_OFCTL = 'ovs-ofctl'
 OVS_VSCTL = 'ovs-vsctl'
 OVS_APPCTL = 'ovs-appctl'
 PS = 'ps'
-PVS = 'pvs'
 ROUTE = 'route'
 RPM = 'rpm'
 SG_MAP = 'sg_map'
 SYSCTL = 'sysctl'
 TC = 'tc'
 UPTIME = 'uptime'
-VGS = 'vgs'
-VGSCAN = 'vgscan'
 ZCAT = 'zcat'
 
 #
@@ -214,29 +198,18 @@ CAP_XML_ROOT = "system-status-capabilities"
 CAP_XML_ELEMENT = 'capability'
 
 
-CAP_BLOBS                = 'blobs'
 CAP_BOOT_LOADER          = 'boot-loader'
-CAP_COLLECTD_LOGS        = 'collectd-logs'
 CAP_DISK_INFO            = 'disk-info'
-CAP_FIRSTBOOT            = 'firstboot'
 CAP_HARDWARE_INFO        = 'hardware-info'
-CAP_HDPARM_T             = 'hdparm-t'
-CAP_HIGH_AVAILABILITY    = 'high-availability'
 CAP_KERNEL_INFO          = 'kernel-info'
 CAP_LOSETUP_A            = 'loopback-devices'
 CAP_MULTIPATH            = 'multipath'
 CAP_NETWORK_CONFIG       = 'network-config'
 CAP_NETWORK_STATUS       = 'network-status'
-CAP_OEM                  = 'oem'
-CAP_PAM                  = 'pam'
+CAP_OPENVSWITCH_LOGS    = 'ovs-system-logs'
 CAP_PROCESS_LIST         = 'process-list'
-CAP_PERSISTENT_STATS     = 'persistent-stats'
 CAP_SYSTEM_LOGS          = 'system-logs'
 CAP_SYSTEM_SERVICES      = 'system-services'
-CAP_VNCTERM              = 'vncterm'
-CAP_WLB                  = 'wlb'
-CAP_X11_LOGS             = 'X11'
-CAP_X11_AUTH             = 'X11-auth'
 CAP_YUM                  = 'yum'
 
 KB = 1024
@@ -246,6 +219,8 @@ caps = {}
 cap_sizes = {}
 unlimited_data = False
 dbg = False
+# Default value for the number of rotated logs.
+log_days = 20
 
 def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
         max_time=-1, mime=MIME_TEXT, checked=True, hidden=False):
@@ -254,19 +229,12 @@ def cap(key, pii=PII_MAYBE, min_size=-1, max_size=-1, min_time=-1,
     cap_sizes[key] = 0
 
 
-cap(CAP_BLOBS,               PII_NO,                    max_size=5*MB)
 cap(CAP_BOOT_LOADER,         PII_NO,                    max_size=3*KB,
     max_time=5)
-cap(CAP_COLLECTD_LOGS,       PII_MAYBE,                 max_size=50*MB,
-    max_time=5)
 cap(CAP_DISK_INFO,           PII_MAYBE,                 max_size=50*KB,
     max_time=20)
-cap(CAP_FIRSTBOOT,           PII_YES,   min_size=60*KB, max_size=80*KB)
 cap(CAP_HARDWARE_INFO,       PII_MAYBE,                 max_size=30*KB,
     max_time=20)
-cap(CAP_HDPARM_T,            PII_NO,    min_size=0,     max_size=5*KB,
-    min_time=20, max_time=90, checked=False, hidden=True)
-cap(CAP_HIGH_AVAILABILITY,   PII_MAYBE,                 max_size=5*MB)
 cap(CAP_KERNEL_INFO,         PII_MAYBE,                 max_size=120*KB,
     max_time=5)
 cap(CAP_LOSETUP_A,           PII_MAYBE,                 max_size=KB, max_time=5)
@@ -274,22 +242,16 @@ cap(CAP_MULTIPATH,           PII_MAYBE,                 max_size=20*KB,
     max_time=10)
 cap(CAP_NETWORK_CONFIG,      PII_IF_CUSTOMIZED,
                                         min_size=0,     max_size=40*KB)
-cap(CAP_NETWORK_STATUS,      PII_YES,                   max_size=50*KB,
+cap(CAP_NETWORK_STATUS,      PII_YES,                   max_size=50*MB,
     max_time=30)
-cap(CAP_PAM,                 PII_NO,                    max_size=50*KB)
-cap(CAP_PERSISTENT_STATS,    PII_MAYBE,                 max_size=50*MB,
-    max_time=60)
+cap(CAP_OPENVSWITCH_LOGS,    PII_MAYBE,                 max_size=-1,
+    max_time=5)
 cap(CAP_PROCESS_LIST,        PII_YES,                   max_size=30*KB,
     max_time=20)
-cap(CAP_SYSTEM_LOGS,         PII_MAYBE,                 max_size=50*MB,
+cap(CAP_SYSTEM_LOGS,         PII_MAYBE,                 max_size=200*MB,
     max_time=5)
 cap(CAP_SYSTEM_SERVICES,     PII_NO,                    max_size=5*KB,
     max_time=20)
-cap(CAP_VNCTERM,             PII_MAYBE, checked = False)
-cap(CAP_WLB,                 PII_NO,                    max_size=3*MB,
-    max_time=20)
-cap(CAP_X11_LOGS,            PII_NO,                    max_size=100*KB)
-cap(CAP_X11_AUTH,            PII_NO,                    max_size=100*KB)
 cap(CAP_YUM,                 PII_IF_CUSTOMIZED,         max_size=10*KB,
     max_time=30)
 
@@ -307,7 +269,7 @@ def output(x):
 def output_ts(x):
     output("[%s]  %s" % (time.strftime("%x %X %Z"), x))
 
-def cmd_output(cap, args, label=None, filter=None):
+def cmd_output(cap, args, label=None, filter=None, binary=False):
     if cap in entries:
         if not label:
             if isinstance(args, list):
@@ -316,7 +278,8 @@ def cmd_output(cap, args, label=None, filter=None):
                 label = ' '.join(a)
             else:
                 label = args
-        data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter}
+        data[label] = {'cap': cap, 'cmd_args': args, 'filter': filter,
+                       'binary': binary}
 
 def file_output(cap, path_list, newest_first=False):
     """
@@ -360,6 +323,16 @@ def func_output(cap, label, func):
         t = str(func).split()
         data[label] = {'cap': cap, 'func': func}
 
+def log_output(cap, logs, newest_first=False):
+    global log_days
+    file_output(cap, logs)
+    file_output(cap,
+        ['%s.%d' % (f, n) for n in range(1, log_days+1) for f in logs], \
+        newest_first=newest_first)
+    file_output(cap,
+        ['%s.%d.gz' % (f, n) for n in range(1, log_days+1) for f in logs], \
+        newest_first=newest_first)
+
 def collect_data():
     process_lists = {}
 
@@ -369,7 +342,9 @@ def collect_data():
             v['output'] = StringIOmtime()
             if not process_lists.has_key(cap):
                 process_lists[cap] = []
-            process_lists[cap].append(ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'], v['filter']))
+            process_lists[cap].append(
+                ProcOutput(v['cmd_args'], caps[cap][MAX_TIME], v['output'],
+                           v['filter'], v['binary']))
         elif v.has_key('filename') and v['filename'].startswith('/proc/'):
             # proc files must be read into memory
             try:
@@ -401,7 +376,7 @@ def collect_data():
 
 def main(argv=None):
     global ANSWER_YES_TO_ALL, SILENT_MODE
-    global entries, data, dbg, unlimited_data
+    global entries, data, dbg, unlimited_data, log_days
 
     # Filter flags
     only_ovs_info = False
@@ -413,7 +388,7 @@ def main(argv=None):
         return 1
 
     output_file = None
-    output_type = 'tar.bz2'
+    output_type = 'tar.gz'
     output_fd = -1
 
     if argv is None:
@@ -423,7 +398,7 @@ def main(argv=None):
         (options, params) = getopt.gnu_getopt(
             argv, 'sy', ['capabilities', 'silent', 'yestoall', 'entries=',
                          'output=', 'outfd=', 'outfile=', 'all', 'unlimited',
-                         'debug', 'ovs'])
+                         'debug', 'ovs', 'log-days='])
     except getopt.GetoptError, opterr:
         print >>sys.stderr, opterr
         return 2
@@ -485,6 +460,9 @@ def main(argv=None):
             only_ovs_info = True
             collect_all_info = False
 
+        if k == '--log-days':
+            log_days = int(v)
+
     if len(params) != 1:
         print >>sys.stderr, "Invalid additional arguments", str(params)
         return 2
@@ -520,27 +498,18 @@ exclude those logs from the archive.
     cmd_output(CAP_BOOT_LOADER, [LS, '-lR', '/boot'])
     cmd_output(CAP_BOOT_LOADER, [MD5SUM, BOOT_KERNEL, BOOT_INITRD], label='vmlinuz-initrd.md5sum')
 
-    tree_output(CAP_COLLECTD_LOGS, COLLECTD_LOGS_DIR)
     cmd_output(CAP_DISK_INFO, [FDISK, '-l'])
     file_output(CAP_DISK_INFO, [PROC_PARTITIONS, PROC_MOUNTS])
     file_output(CAP_DISK_INFO, [FSTAB, ISCSI_CONF, ISCSI_INITIATOR])
     cmd_output(CAP_DISK_INFO, [DF, '-alT'])
     cmd_output(CAP_DISK_INFO, [DF, '-alTi'])
-    for d in disk_list():
-        cmd_output(CAP_DISK_INFO, [HDPARM, '-I', '/dev/%s' % d])
     if len(pidof('iscsid')) != 0:
         cmd_output(CAP_DISK_INFO, [ISCSIADM, '-m', 'node'])
-    cmd_output(CAP_DISK_INFO, [VGSCAN])
-    cmd_output(CAP_DISK_INFO, [PVS])
-    cmd_output(CAP_DISK_INFO, [VGS])
-    cmd_output(CAP_DISK_INFO, [LVS])
-    file_output(CAP_DISK_INFO, [LVM_CACHE, LVM_CONFIG])
     cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_host'])
     cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/scsi_disk'])
     cmd_output(CAP_DISK_INFO, [LS, '-R', '/sys/class/fc_transport'])
     cmd_output(CAP_DISK_INFO, [SG_MAP, '-x'])
     func_output(CAP_DISK_INFO, 'scsi-hosts', dump_scsi_hosts)
-    cmd_output(CAP_DISK_INFO, [LVDISPLAY, '--map'])
 
     file_output(CAP_HARDWARE_INFO, [PROC_CPUINFO, PROC_MEMINFO, PROC_IOPORTS, PROC_INTERRUPTS])
     cmd_output(CAP_HARDWARE_INFO, [DMIDECODE])
@@ -549,10 +518,7 @@ exclude those logs from the archive.
     file_output(CAP_HARDWARE_INFO, [PROC_USB_DEV, PROC_SCSI])
     file_output(CAP_HARDWARE_INFO, [SYSCONFIG_HWCONF])
     cmd_output(CAP_HARDWARE_INFO, [LS, '-lR', '/dev'])
-    # FIXME IDE?
 
-    for d in disk_list():
-        cmd_output(CAP_HDPARM_T, [HDPARM, '-tT', '/dev/%s' % d])
 
     file_output(CAP_KERNEL_INFO, [PROC_VERSION, PROC_MODULES, PROC_DEVICES,
                                   PROC_FILESYSTEMS, PROC_CMDLINE])
@@ -583,7 +549,8 @@ exclude those logs from the archive.
     cmd_output(CAP_NETWORK_STATUS, [NETSTAT, '-an'])
     for dir in DHCP_LEASE_DIR:
         tree_output(CAP_NETWORK_STATUS, dir)
-    cmd_output(CAP_NETWORK_STATUS, [IPTABLES, '-nL'])
+    for table in ['filter', 'nat', 'mangle', 'raw', 'security']:
+        cmd_output(CAP_NETWORK_STATUS, [IPTABLES, '-t', table, '-nL'])
     for p in os.listdir('/sys/class/net/'):
         try:
             f = open('/sys/class/net/%s/type' % p, 'r')
@@ -591,11 +558,12 @@ exclude those logs from the archive.
             f.close()
             if os.path.islink('/sys/class/net/%s/device' % p) and int(t) == 1:
                 # ARPHRD_ETHER
-                cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
                 cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-S', p])
-                cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
-                cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
-                cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
+                if not p.startswith('vif') and not p.startswith('tap'):
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, p])
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-k', p])
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-i', p])
+                    cmd_output(CAP_NETWORK_STATUS, [ETHTOOL, '-c', p])
             if int(t) == 1:
                 cmd_output(CAP_NETWORK_STATUS,
                            [TC, '-s', '-d', 'class', 'show', 'dev', p])
@@ -608,8 +576,6 @@ exclude those logs from the archive.
     if os.path.exists(OPENVSWITCH_VSWITCHD_PID):
         cmd_output(CAP_NETWORK_STATUS, [OVS_DPCTL, 'show', '-s'])
         for d in dp_list():
-            cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'show', d])
-            cmd_output(CAP_NETWORK_STATUS, [OVS_OFCTL, 'dump-flows', d])
             cmd_output(CAP_NETWORK_STATUS, [OVS_DPCTL, 'dump-flows', d])
         try:
             vspidfile = open(OPENVSWITCH_VSWITCHD_PID)
@@ -622,31 +588,23 @@ exclude those logs from the archive.
         except e:
             pass
 
-    tree_output(CAP_PAM, PAM_DIR)
-    file_output(CAP_PAM, [KRB5_CONF])
-
     cmd_output(CAP_PROCESS_LIST, [PS, 'wwwaxf', '-eo', 'pid,tty,stat,time,nice,psr,pcpu,pmem,nwchan,wchan:25,args'], label='process-tree')
     func_output(CAP_PROCESS_LIST, 'fd_usage', fd_usage)
 
-    logs = ([ VAR_LOG_DIR + x for x in
-             [ 'crit.log', 'kern.log', 'daemon.log', 'user.log',
-             'syslog', 'messages', 'secure', 'debug', 'dmesg', 'boot' ]]
-            + [ OPENVSWITCH_LOG_DIR + x for x in
-                [ 'ovs-vswitchd.log', 'ovsdb-server.log',
-                  'ovs-xapi-sync.log', 'ovs-monitor-ipsec.log' ]])
-    file_output(CAP_SYSTEM_LOGS, logs)
-    file_output(CAP_SYSTEM_LOGS,
-                [ '%s.%d' % (f, n) for n in range(20) for f in logs ])
-    file_output(CAP_SYSTEM_LOGS,
-                [ '%s.%d.gz' % (f, n) for n in range(20) for f in logs ])
+    system_logs = ([ VAR_LOG_DIR + x for x in
+        ['crit.log', 'kern.log', 'daemon.log', 'user.log',
+        'syslog', 'messages', 'secure', 'debug', 'dmesg', 'boot']])
+    ovs_logs = ([ OPENVSWITCH_LOG_DIR + x for x in
+        ['ovs-vswitchd.log', 'ovsdb-server.log',
+        'ovs-xapi-sync.log', 'ovs-monitor-ipsec.log', 'ovs-ctl.log']])
+    log_output(CAP_SYSTEM_LOGS, system_logs)
+    log_output(CAP_OPENVSWITCH_LOGS, ovs_logs)
 
     if not os.path.exists('/var/log/dmesg') and not os.path.exists('/var/log/boot'):
         cmd_output(CAP_SYSTEM_LOGS, [DMESG])
 
     cmd_output(CAP_SYSTEM_SERVICES, [CHKCONFIG, '--list'])
 
-    tree_output(CAP_X11_LOGS, X11_LOGS_DIR, X11_LOGS_RE)
-    tree_output(CAP_X11_AUTH, X11_AUTH_DIR, X11_AUTH_RE)
     tree_output(CAP_SYSTEM_LOGS, VAR_LOG_CORE_DIR)
 
     file_output(CAP_YUM, [YUM_LOG])
@@ -724,8 +682,6 @@ exclude those logs from the archive.
     else:
         make_zip(subdir, output_file)
 
-    clean_tapdisk_logs()
-
     if dbg:
         print >>sys.stderr, "Category sizes (max, actual):\n"
         for c in caps.keys():
@@ -733,39 +689,6 @@ exclude those logs from the archive.
                                                      cap_sizes[c])
     return 0
 
-def find_tapdisk_logs():
-    return glob.glob('/var/log/blktap/*.log*')
-
-def generate_tapdisk_logs():
-    for pid in pidof('tapdisk'):
-       try:
-           os.kill(pid, SIGUSR1)
-            output_ts("Including logs for tapdisk process %d" % pid)
-        except :
-            pass
-    # give processes a second to write their logs
-    time.sleep(1)
-
-def clean_tapdisk_logs():
-    for filename in find_tapdisk_logs():
-        try:
-            os.remove(filename)
-        except :
-            pass
-
-def filter_db_pii(str, state):
-    if 'in_secret_table' not in state:
-        state['in_secret_table'] = False
-
-    if str.startswith('<table ') and 'name="secret"' in str:
-        state['in_secret_table'] = True
-    elif str.startswith('</table>'):
-        state['in_secret_table'] = False
-
-    if state['in_secret_table'] and str.startswith("<row"): # match only on DB rows
-        str = re.sub(r'(value=")[^"]+(")', r'\1REMOVED\2', str)
-    return str
-
 def dump_scsi_hosts(cap):
     output = ''
     l = os.listdir('/sys/class/scsi_host')
@@ -932,8 +855,12 @@ def load_plugins(just_capabilities=False, filter=None):
                     continue
                 if el.tagName == "files":
                     newest_first = getBoolAttr(el, 'newest_first')
-                    file_output(dir, getText(el.childNodes).split(),
-                                newest_first=newest_first)
+                    if el.getAttribute("type") == "logs":
+                        log_output(dir, getText(el.childNodes).split(),
+                                    newest_first=newest_first)
+                    else:
+                        file_output(dir, getText(el.childNodes).split(),
+                                    newest_first=newest_first)
                 elif el.tagName == "directory":
                     pattern = el.getAttribute("pattern")
                     if pattern == '': pattern = None
@@ -945,7 +872,8 @@ def load_plugins(just_capabilities=False, filter=None):
                 elif el.tagName == "command":
                     label = el.getAttribute("label")
                     if label == '': label = None
-                    cmd_output(dir, getText(el.childNodes), label)
+                    binary = getBoolAttr(el, 'binary')
+                    cmd_output(dir, getText(el.childNodes), label, binary=binary)
 
 def make_tar(subdir, suffix, output_fd, output_file):
     global SILENT_MODE, data
@@ -1183,7 +1111,7 @@ def disk_list():
 class ProcOutput:
     debug = False
 
-    def __init__(self, command, max_time, inst=None, filter=None):
+    def __init__(self, command, max_time, inst=None, filter=None, binary=False):
         self.command = command
         self.max_time = max_time
         self.inst = inst
@@ -1194,6 +1122,10 @@ class ProcOutput:
         self.timeout = int(time.time()) + self.max_time
         self.filter = filter
         self.filter_state = {}
+        if binary:
+            self.bufsize = 1048576  # 1MB buffer
+        else:
+            self.bufsize = 1        # line buffered
 
     def __del__(self):
         self.terminate()
@@ -1206,7 +1138,9 @@ class ProcOutput:
         try:
             if ProcOutput.debug:
                 output_ts("Starting '%s'" % self.cmdAsStr())
-            self.proc = Popen(self.command, bufsize=1, stdin=dev_null, stdout=PIPE, stderr=dev_null, shell=isinstance(self.command, str))
+            self.proc = Popen(self.command, bufsize=self.bufsize,
+                              stdin=dev_null, stdout=PIPE, stderr=dev_null,
+                              shell=isinstance(self.command, str))
             old = fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_GETFD)
             fcntl.fcntl(self.proc.stdout.fileno(), fcntl.F_SETFD, old | fcntl.FD_CLOEXEC)
             self.running = True
@@ -1229,7 +1163,10 @@ class ProcOutput:
 
     def read_line(self):
         assert self.running
-        line = self.proc.stdout.readline()
+        if self.bufsize == 1:
+            line = self.proc.stdout.readline()
+        else:
+            line = self.proc.stdout.read(self.bufsize)
         if line == '':
             # process exited
             self.proc.stdout.close()
index 9539f7c..d79b4f3 100644 (file)
@@ -25,4 +25,7 @@
   <command label="ovs-appctl-coverage-show" filters="ovs">/usr/share/openvswitch/scripts/ovs-bugtool-coverage-show</command>
   <command label="ovs-appctl-bond-show" filters="ovs">/usr/share/openvswitch/scripts/ovs-bugtool-bond-show</command>
   <command label="ovs-appctl-memory-show" filters="ovs">/usr/share/openvswitch/scripts/ovs-bugtool-memory-show</command>
+  <command label="ovs-ofctl-show" filters="ovs">/usr/share/openvswitch/scripts/ovs-bugtool-ovs-ofctl-show</command>
+  <command label="ovs-ofctl-dump-flows" filters="ovs">/usr/share/openvswitch/scripts/ovs-bugtool-ovs-ofctl-dump-flows</command>
+  <command label="ovs-appctl-dpif" filters="ovs">/usr/share/openvswitch/scripts/ovs-bugtool-ovs-appctl-dpif</command>
 </collect>
index 78f67a3..5ad5f26 100755 (executable)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# Copyright (C) 2009, 2010, 2011, 2012 Nicira, Inc.
+# Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@ insert_mod_if_required () {
 }
 
 ovs_vsctl () {
-    ovs-vsctl --no-wait --timeout=5 "$@"
+    ovs-vsctl --no-wait "$@"
 }
 
 ovsdb_tool () {
@@ -157,7 +157,7 @@ set_system_ids () {
 
 check_force_cores () {
     if test X"$FORCE_COREFILES" = Xyes; then
-        ulimit -Sc 67108864
+        ulimit -c 67108864
     fi
 }
 
@@ -216,8 +216,9 @@ start_forwarding () {
         log_success_msg "ovs-vswitchd is already running"
     else
         # Increase the limit on the number of open file descriptors.
-        # ovs-vswitchd needs 16 per datapath, plus a few extra, so this
-        # should allow for 256 (or more) bridges.
+        # On Linux, ovs-vswitchd needs about one file descriptor per
+        # switch port, so this allows a very large number of switch
+        # ports.
         ulimit -n 5000
 
            # Start ovs-vswitchd.
@@ -274,7 +275,6 @@ ovs_save () {
         chmod +x "$2"
         return 0
     fi
-    eval $3=""
     [ -z "${bridges}" ] && return 0
 }
 
@@ -283,9 +283,7 @@ save_ofports_if_required () {
     case `ovs-appctl version | sed 1q` in
         "ovs-vswitchd (Open vSwitch) 1."[0-9].*)
             action "Saving ofport values" ovs_save save-ofports \
-                "${script_ofports}" script_ofports
-            ;;
-        *)
+                "${script_ofports}"
             ;;
     esac
 }
@@ -296,25 +294,43 @@ save_interfaces () {
 }
 
 restore_ofports () {
-    [ -n "${script_ofports}" ] && \
+    [ -x "${script_ofports}" ] && \
         action "Restoring ofport values" "${script_ofports}"
 }
 
 restore_flows () {
-    [ -n "${script_flows}" ] && \
+    [ -x "${script_flows}" ] && \
         action "Restoring saved flows" "${script_flows}"
 }
 
-force_reload_kmod () {
-    ifaces=`internal_interfaces`
-    action "Detected internal interfaces: $ifaces" true
+restore_interfaces () {
+    [ ! -x "${script_interfaces}" ] && return 0
+    action "Restoring interface configuration" "${script_interfaces}"
+    rc=$?
+    if test $rc = 0; then
+        level=debug
+    else
+        level=err
+    fi
+    log="logger -p daemon.$level -t ovs-save"
+    $log "interface restore script exited with status $rc:"
+    $log -f "$script_interfaces"
+}
 
+init_restore_scripts () {
     script_interfaces=`mktemp`
     script_flows=`mktemp`
     script_ofports=`mktemp`
     trap 'rm -f "${script_interfaces}" "${script_flows}" "${script_ofports}"' 0
+}
+
+force_reload_kmod () {
+    ifaces=`internal_interfaces`
+    action "Detected internal interfaces: $ifaces" true
+
+    init_restore_scripts
 
-    action "Saving flows" ovs_save save-flows "${script_flows}" script_flows
+    action "Saving flows" ovs_save save-flows "${script_flows}"
 
     save_ofports_if_required
 
@@ -352,16 +368,7 @@ force_reload_kmod () {
 
     restore_flows
 
-    action "Restoring interface configuration" "$script_interfaces"
-    rc=$?
-    if test $rc = 0; then
-        level=debug
-    else
-        level=err
-    fi
-    log="logger -p daemon.$level -t ovs-save"
-    $log "force-reload-kmod interface restore script exited with status $rc:"
-    $log -f "$script_interfaces"
+    restore_interfaces
 
     "$datadir/scripts/ovs-check-dead-ifs"
 }
@@ -370,13 +377,25 @@ force_reload_kmod () {
 ## restart ##
 ## ------- ##
 
+save_interfaces_if_required () {
+    # Save interfaces if we are upgrading from a pre-1.10 branch.
+    case `ovs-appctl version | sed 1q` in
+        "ovs-vswitchd (Open vSwitch) 1."[0-9].*)
+            ifaces=`internal_interfaces`
+            action "Detected internal interfaces: $ifaces" true
+            if action "Saving interface configuration" save_interfaces; then
+                chmod +x "$script_interfaces"
+            fi
+            ;;
+    esac
+}
+
 restart () {
     if daemon_is_running ovsdb-server && daemon_is_running ovs-vswitchd; then
-        script_flows=`mktemp`
-        trap 'rm -f "${script_flows}"' 0
-
-        action "Saving flows" ovs_save save-flows "${script_flows}" \
-            script_flows
+        init_restore_scripts
+        save_interfaces_if_required
+        action "Saving flows" ovs_save save-flows "${script_flows}"
+        save_ofports_if_required
     fi
 
     # Restart the database first, since a large database may take a
@@ -384,11 +403,18 @@ restart () {
     stop_ovsdb
     start_ovsdb
 
+    # Restore of ofports, if required, should happen before vswitchd is
+    # restarted.
+    restore_ofports
+
     stop_forwarding
     start_forwarding
 
-    # Restore the saved flows. Do not return error if restore fails.
-    restore_flows || true
+    # Restore the saved flows.
+    restore_flows
+
+    # Restore the interfaces if required. Return true even if restore fails.
+    restore_interfaces || true
 }
 
 ## --------------- ##
index b1b2570..2b0036c 100644 (file)
@@ -104,27 +104,54 @@ port.
 If one or more datapaths are specified, information on only those
 datapaths are displayed.  Otherwise, \fBovs\-dpctl\fR displays information
 about all configured datapaths.
+.SS "DEBUGGING COMMANDS"
+The following commands are primarily useful for debugging Open
+vSwitch.  The flow table entries (both matches and actions) that they
+work with are not OpenFlow flow entries.  Instead, they are different
+and considerably simpler flows maintained by the Open vSwitch kernel
+module.  Use \fBovs\-ofctl\fR(8), instead, to work with OpenFlow flow
+entries.
+.
+.PP
+The \fIdp\fR argument to each of these commands is optional when
+exactly one datapath exists, in which case that datapath is the
+default.  When multiple datapaths exist, then a datapath name is
+required.
 .
 .IP "\fBdump\-flows\fR [\fIdp\fR]"
 Prints to the console all flow entries in datapath \fIdp\fR's
-flow table.  If \fIdp\fR is not specified and exactly one datapath
-exists, the flows for that datapath will be printed.
+flow table.
+.
+.IP "\fBadd\-flow\fR [\fIdp\fR] \fIflow actions\fR"
+.IQ "[\fB\-\-clear\fR] [\fB\-\-may-create\fR] [\fB\-s\fR | \fB\-\-statistics\fR] \fBmod\-flow\fR [\fIdp\fR] \fIflow actions\fR"
+Adds or modifies a flow in \fIdp\fR's flow table that, when a packet
+matching \fIflow\fR arrives, causes \fIactions\fR to be executed.
+.IP
+The \fBadd\-flow\fR command succeeds only if \fIflow\fR does not
+already exist in \fIdp\fR.  Contrariwise, \fBmod\-flow\fR without
+\fB\-\-may\-create\fR only modifies the actions for an existing flow.
+With \fB\-\-may\-create\fR, \fBmod\-flow\fR will add a new flow or
+modify an existing one.
 .IP
-This command is primarily useful for debugging Open vSwitch.  The flow
-table entries that it displays are not
-OpenFlow flow entries.  Instead, they are different and considerably
-simpler flows maintained by the Open vSwitch kernel module.  If you wish
-to see the OpenFlow flow entries, use \fBovs\-ofctl dump\-flows\fR.
+If \fB\-s\fR or \fB\-\-statistics\fR is specified, then
+\fBmod\-flows\fR prints the modified flow's statistics.  A flow's
+statistics are the number of packets and bytes that have passed
+through the flow, the elapsed time since the flow last processed a
+packet (if ever), and (for TCP flows) the union of the TCP flags
+processed through the flow.
+.IP
+With \fB\-\-clear\fR, \fBmod\-flows\fR zeros out the flow's
+statistics.  The statistics printed if \fB\-s\fR or
+\fB\-\-statistics\fR is also specified are those from just before
+clearing the statistics.
+.
+.IP "[\fB\-s\fR | \fB\-\-statistics\fR] \fBdel\-flow\fR [\fIdp\fR] \fIflow\fR"
+Deletes the flow from \fIdp\fR's flow table that matches \fIflow\fR.
+If \fB\-s\fR or \fB\-\-statistics\fR is specified, then
+\fBmod\-flows\fR prints the deleted flow's statistics.
 .
 .IP "\fBdel\-flows\fR [\fIdp\fR]"
-Deletes all flow entries from datapath \fIdp\fR's flow table.  If
-\fIdp\fR is not specified and exactly one datapath exists, the flows for
-that datapath will be deleted.
-.IP
-This command is primarily useful for debugging Open vSwitch.  As
-discussed in \fBdump\-flows\fR, these entries are
-not OpenFlow flow entries.  By deleting them, the process that set them
-up may be confused about their disappearance.
+Deletes all flow entries from datapath \fIdp\fR's flow table.
 .
 .SH OPTIONS
 .IP "\fB\-s\fR"
index b48b349..3b6e6a5 100644 (file)
 
 VLOG_DEFINE_THIS_MODULE(dpctl);
 
-/* -s, --statistics: Print port statistics? */
+/* -s, --statistics: Print port/flow statistics? */
 static bool print_statistics;
 
+/* --clear: Reset existing statistics to zero when modifying a flow? */
+static bool zero_statistics;
+
+/* --may-create: Allow mod-flows command to create a new flow? */
+static bool may_create;
+
 /* -m, --more: Output verbosity.
  *
  * So far only undocumented commands honor this option, so we don't document
@@ -79,11 +85,14 @@ static void
 parse_options(int argc, char *argv[])
 {
     enum {
-        OPT_DUMMY = UCHAR_MAX + 1,
+        OPT_CLEAR = UCHAR_MAX + 1,
+        OPT_MAY_CREATE,
         VLOG_OPTION_ENUMS
     };
     static struct option long_options[] = {
         {"statistics", no_argument, NULL, 's'},
+        {"clear", no_argument, NULL, OPT_CLEAR},
+        {"may-create", no_argument, NULL, OPT_MAY_CREATE},
         {"more", no_argument, NULL, 'm'},
         {"timeout", required_argument, NULL, 't'},
         {"help", no_argument, NULL, 'h'},
@@ -107,6 +116,14 @@ parse_options(int argc, char *argv[])
             print_statistics = true;
             break;
 
+        case OPT_CLEAR:
+            zero_statistics = true;
+            break;
+
+        case OPT_MAY_CREATE:
+            may_create = true;
+            break;
+
         case 'm':
             verbosity++;
             break;
@@ -154,14 +171,20 @@ usage(void)
            "  show                     show basic info on all datapaths\n"
            "  show DP...               show basic info on each DP\n"
            "  dump-flows DP            display flows in DP\n"
+           "  add-flow DP FLOW ACTIONS add FLOW with ACTIONS to DP\n"
+           "  mod-flow DP FLOW ACTIONS change FLOW actions to ACTIONS in DP\n"
+           "  del-flow DP FLOW         delete FLOW from DP\n"
            "  del-flows DP             delete all flows from DP\n"
            "Each IFACE on add-dp, add-if, and set-if may be followed by\n"
            "comma-separated options.  See ovs-dpctl(8) for syntax, or the\n"
            "Interface table in ovs-vswitchd.conf.db(5) for an options list.\n",
            program_name, program_name);
     vlog_usage();
-    printf("\nOptions for show:\n"
-           "  -s,  --statistics           print port statistics\n"
+    printf("\nOptions for show and mod-flow:\n"
+           "  -s,  --statistics           print statistics for port or flow\n"
+           "\nOptions for mod-flow:\n"
+           "  --may-create                create flow if it doesn't exist\n"
+           "  --clear                     reset existing stats to zero\n"
            "\nOther options:\n"
            "  -t, --timeout=SECS          give up after SECS seconds\n"
            "  -h, --help                  display this help message\n"
@@ -747,6 +770,100 @@ dpctl_dump_flows(int argc, char *argv[])
     dpif_close(dpif);
 }
 
+static void
+dpctl_put_flow(int argc, char *argv[], enum dpif_flow_put_flags flags)
+{
+    const char *key_s = argv[argc - 2];
+    const char *actions_s = argv[argc - 1];
+    struct dpif_flow_stats stats;
+    struct ofpbuf actions;
+    struct ofpbuf key;
+    struct dpif *dpif;
+    char *dp_name;
+
+    ofpbuf_init(&key, 0);
+    run(odp_flow_key_from_string(key_s, NULL, &key), "parsing flow key");
+
+    ofpbuf_init(&actions, 0);
+    run(odp_actions_from_string(actions_s, NULL, &actions), "parsing actions");
+
+    dp_name = argc == 3 ? xstrdup(argv[1]) : get_one_dp();
+    run(parsed_dpif_open(dp_name, false, &dpif), "opening datapath");
+    free(dp_name);
+
+    run(dpif_flow_put(dpif, flags,
+                      key.data, key.size,
+                      actions.data, actions.size,
+                      print_statistics ? &stats : NULL),
+        "updating flow table");
+
+    ofpbuf_uninit(&key);
+    ofpbuf_uninit(&actions);
+
+    if (print_statistics) {
+        struct ds s;
+
+        ds_init(&s);
+        dpif_flow_stats_format(&stats, &s);
+        puts(ds_cstr(&s));
+        ds_destroy(&s);
+    }
+}
+
+static void
+dpctl_add_flow(int argc, char *argv[])
+{
+    dpctl_put_flow(argc, argv, DPIF_FP_CREATE);
+}
+
+static void
+dpctl_mod_flow(int argc OVS_UNUSED, char *argv[])
+{
+    enum dpif_flow_put_flags flags;
+
+    flags = DPIF_FP_MODIFY;
+    if (may_create) {
+        flags |= DPIF_FP_CREATE;
+    }
+    if (zero_statistics) {
+        flags |= DPIF_FP_ZERO_STATS;
+    }
+
+    dpctl_put_flow(argc, argv, flags);
+}
+
+static void
+dpctl_del_flow(int argc, char *argv[])
+{
+    const char *key_s = argv[argc - 1];
+    struct dpif_flow_stats stats;
+    struct ofpbuf key;
+    struct dpif *dpif;
+    char *dp_name;
+
+    ofpbuf_init(&key, 0);
+    run(odp_flow_key_from_string(key_s, NULL, &key), "parsing flow key");
+
+    dp_name = argc == 2 ? xstrdup(argv[1]) : get_one_dp();
+    run(parsed_dpif_open(dp_name, false, &dpif), "opening datapath");
+    free(dp_name);
+
+    run(dpif_flow_del(dpif,
+                      key.data, key.size,
+                      print_statistics ? &stats : NULL), "deleting flow");
+
+    ofpbuf_uninit(&key);
+
+    if (print_statistics) {
+        struct ds s;
+
+        ds_init(&s);
+        dpif_flow_stats_format(&stats, &s);
+        puts(ds_cstr(&s));
+        ds_destroy(&s);
+    }
+}
+
 static void
 dpctl_del_flows(int argc, char *argv[])
 {
@@ -939,14 +1056,13 @@ dpctl_normalize_actions(int argc, char *argv[])
 
     hmap_init(&actions_per_flow);
     NL_ATTR_FOR_EACH (a, left, odp_actions.data, odp_actions.size) {
-        if (nl_attr_type(a) == OVS_ACTION_ATTR_POP_VLAN) {
+        const struct ovs_action_push_vlan *push;
+        switch(nl_attr_type(a)) {
+        case OVS_ACTION_ATTR_POP_VLAN:
             flow.vlan_tci = htons(0);
             continue;
-        }
-
-        if (nl_attr_type(a) == OVS_ACTION_ATTR_PUSH_VLAN) {
-            const struct ovs_action_push_vlan *push;
 
+        case OVS_ACTION_ATTR_PUSH_VLAN:
             push = nl_attr_get_unspec(a, sizeof *push);
             flow.vlan_tci = push->vlan_tci;
             continue;
@@ -980,6 +1096,15 @@ dpctl_normalize_actions(int argc, char *argv[])
             printf("no vlan: ");
         }
 
+        if (af->flow.mpls_depth) {
+            printf("mpls(label=%"PRIu32",tc=%d,ttl=%d): ",
+                   mpls_lse_to_label(af->flow.mpls_lse),
+                   mpls_lse_to_tc(af->flow.mpls_lse),
+                   mpls_lse_to_ttl(af->flow.mpls_lse));
+        } else {
+            printf("no mpls: ");
+        }
+
         ds_clear(&s);
         format_odp_actions(&s, af->actions.data, af->actions.size);
         puts(ds_cstr(&s));
@@ -996,6 +1121,9 @@ static const struct command all_commands[] = {
     { "dump-dps", 0, 0, dpctl_dump_dps },
     { "show", 0, INT_MAX, dpctl_show },
     { "dump-flows", 0, 1, dpctl_dump_flows },
+    { "add-flow", 2, 3, dpctl_add_flow },
+    { "mod-flow", 2, 3, dpctl_mod_flow },
+    { "del-flow", 1, 2, dpctl_del_flow },
     { "del-flows", 0, 1, dpctl_del_flows },
     { "help", 0, INT_MAX, dpctl_help },
 
index b787b1c..a441c3d 100644 (file)
@@ -37,6 +37,11 @@ else
     dbdir='@DBDIR@'
 fi
 
+ovs_ctl () {
+    echo "`date -u`:$@" >> "${logdir}/ovs-ctl.log"
+    "${datadir}/scripts/ovs-ctl" "$@" 2>&1 | tee -a "${logdir}/ovs-ctl.log"
+}
+
 VERSION='@VERSION@'
 
 DAEMON_CWD=/
@@ -167,7 +172,10 @@ start_daemon () {
 stop_daemon () {
     if test -e "$rundir/$1.pid"; then
         if pid=`cat "$rundir/$1.pid"`; then
-            for action in TERM .1 .25 .65 1 1 1 1 KILL 1 1 1 1 FAIL; do
+            for action in TERM .1 .25 .65 1 1 1 1 KILL 1 1 1 2 10 15 30 FAIL; do
+                if pid_exists "$pid" >/dev/null 2>&1; then :; else
+                    return 0
+                fi
                 case $action in
                     TERM)
                         action "Killing $1 ($pid)" kill $pid
@@ -180,11 +188,7 @@ stop_daemon () {
                         return 1
                         ;;
                     *)
-                        if pid_exists $pid >/dev/null 2>&1; then
-                            sleep $action
-                        else
-                            return 0
-                        fi
+                        sleep $action
                         ;;
                 esac
             done
index c48645a..3cc618d 100644 (file)
@@ -915,6 +915,34 @@ for the tag. Only ethertype 0x8100 should be used. (0x88a8 which the spec
 allows isn't supported at the moment.)
 A priority of zero and the tag of zero are used for the new tag.
 .
+.IP \fBpush_mpls\fR:\fIethertype\fR
+If the packet does not already contain any MPLS labels, changes the
+packet's Ethertype to \fIethertype\fR, which must be either the MPLS
+unicast Ethertype \fB0x8847\fR or the MPLS multicast Ethertype
+\fB0x8848\fR, and then pushes an initial label stack entry.  The label
+stack entry's default label is 2 if the packet contains IPv6 and 0
+otherwise, its default traffic control value is the low 3 bits of the
+packet's DSCP value (0 if the packet is not IP), and its TTL is copied
+from the IP TTL (64 if the packet is not IP).
+.IP
+If the packet does already contain an MPLS label, pushes a new
+outermost label as a copy of the existing outermost label.
+.IP
+There are some limitations in the implementation.  \fBpush_mpls\fR
+followed by another \fBpush_mpls\fR will result in the first
+\fBpush_mpls\fR being discarded.
+.
+.IP \fBpop_mpls\fR:\fIethertype\fR
+Strips the outermost MPLS label stack entry.  If the MPLS label
+stripped was the only one, changes the ethertype of a packet to
+\fIethertype\fR, which should not ordinarily be an MPLS Ethertype.
+.
+.IP
+There are some limitations in the implementation.  \fBpop_mpls\fR
+followed by another \fBpush_mpls\fR without an intermediate
+\fBpush_mpls\fR will result in the first \fBpush_mpls\fR being
+discarded.
+.
 .IP \fBmod_dl_src\fB:\fImac\fR
 Sets the source Ethernet address to \fImac\fR.
 .
@@ -934,9 +962,9 @@ Sets the TCP or UDP source port to \fIport\fR.
 Sets the TCP or UDP destination port to \fIport\fR.
 .
 .IP \fBmod_nw_tos\fB:\fItos\fR
-Sets the IPv4 ToS/DSCP field to \fItos\fR.  Valid values are between 0 and
-255, inclusive.  Note that the two lower reserved bits are never
-modified.
+Sets the IPv4 ToS/DSCP field to \fItos\fR, which must be a multiple of
+4 between 0 and 255.  This action does not modify the two least
+significant bits of the ToS field (the ECN bits).
 .RE
 .IP
 The following actions are Nicira vendor extensions that, as of this writing, are
@@ -990,6 +1018,19 @@ invalid ttl packets.  If controller ids are not specified, the
 ``packet_in'' message will be sent only to the controllers having
 controller id zero which have registered for the invalid ttl packets.
 .
+.IP \fBset_mpls_ttl\fR:\fIttl\fR
+Set the TTL of the outer MPLS label stack entry of a packet.
+\fIttl\fR should be in the range 0 to 255 inclusive.
+.
+.IP \fBdec_mpls_ttl\fR
+Decrement TTL of the outer MPLS label stack entry of a packet.  If the TTL
+is initially zero, no decrement occurs.  Instead, a ``packet-in'' message
+with reason code \fBOFPR_INVALID_TTL\fR is sent to each connected
+controller with controller id zer that has enabled receiving them.
+Processing the current set of actions then stops.  However, if the current
+set of actions was reached through ``resubmit'' then remaining actions in
+outer levels resume processing.
+.
 .IP \fBnote:\fR[\fIhh\fR]...
 Does nothing at all.  Any number of bytes represented as hex digits
 \fIhh\fR may be included.  Pairs of hex digits may be separated by
@@ -1022,6 +1063,23 @@ in field \fIdst\fR.
 Example: \fBload:55\->NXM_NX_REG2[0..5]\fR loads value 55 (bit pattern
 \fB110111\fR) into bits 0 through 5, inclusive, in register 2.
 .
+.IP "\fBpush:\fIsrc\fB[\fIstart\fB..\fIend\fB]"
+Pushes \fIstart\fR to \fIend\fR bits inclusive, in fields
+on top of the stack.
+.IP
+Example: \fBpush:NXM_NX_REG2[0..5]\fR push the value stored in register
+2 bits 0 through 5, inclusive, on to the internal stack.
+.
+.IP "\fBpop:\fIdst\fB[\fIstart\fB..\fIend\fB]"
+Pops from the top of the stack, retrieves the \fIstart\fR to \fIend\fR bits
+inclusive, from the value popped and store them into the corresponding
+bits in \fIdst\fR.
+.
+.IP
+Example: \fBpop:NXM_NX_REG2[0..5]\fR pops the value from top of the stack.
+Set register 2 bits 0 through 5, inclusive, based on bits 0 through 5 from the
+value just popped.
+.
 .IP "\fBset_field:\fIvalue\fB\->\fIdst"
 Writes the literal \fIvalue\fR into the field \fIdst\fR, which should
 be specified as a name used for matching.  (This is similar to
@@ -1046,21 +1104,6 @@ the \fBiter_hash\fR algorithm uses \fIarg\fR.
 .IP
 Refer to \fBnicira\-ext.h\fR for more details.
 .
-.IP "\fBautopath(\fIid\fB, \fIdst\fB[\fIstart\fB..\fIend\fB])\fR"
-Deprecated and slated for removal in Feburary 2013.
-.IP
-Given \fIid\fR, chooses an OpenFlow port and populates it in
-\fIdst\fB[\fIstart\fB..\fIend\fB]\fR, which must be an NXM field as
-described above.
-.IP
-Currently, \fIid\fR should be the OpenFlow port number of an interface on the
-bridge.  If it isn't then \fIdst\fB[\fIstart\fB..\fIend\fB]\fR will be
-populated with the OpenFlow port "none".  If \fIid\fR is a member of a bond,
-the normal bond selection logic will be used to choose the destination port.
-Otherwise, the register will be populated with \fIid\fR itself.
-.IP
-Refer to \fBnicira\-ext.h\fR for more details.
-.
 .IP "\fBbundle(\fIfields\fB, \fIbasis\fB, \fIalgorithm\fB, \fIslave_type\fB, slaves:[\fIs1\fB, \fIs2\fB, ...])\fR"
 Hashes \fIfields\fR using \fIbasis\fR as a universal hash parameter, then
 applies the bundle link selection \fIalgorithm\fR to choose one of the listed
index 4d8c39f..ec775c7 100644 (file)
@@ -2182,7 +2182,7 @@ ofctl_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms)
             break;
         }
     }
-    ovs_assert(IS_POW2(protocol));
+    ovs_assert(is_pow2(protocol));
 
     printf("chosen protocol: %s\n", ofputil_protocol_to_string(protocol));
 
index 1f15410..a506375 100755 (executable)
@@ -272,7 +272,7 @@ certificate    = $dir/cacert.pem       # The CA cert
 serial         = $dir/serial           # serial no file
 private_key    = $dir/private/cakey.pem# CA private key
 RANDFILE       = $dir/private/.rand    # random number file
-default_days   = 365                   # how long to certify for
+default_days   = 36525                 # how long to certify for
 default_crl_days= 30                   # how long before next CRL
 default_md     = md5                   # md to use
 policy         = policy                # default policy
@@ -303,7 +303,7 @@ EOF
             -newkey $newkey -keyout private/cakey.pem -out careq.pem \
             1>&3 2>&3
         openssl ca -config ca.cnf -create_serial -out cacert.pem \
-            -days 2191 -batch -keyfile private/cakey.pem -selfsign \
+            -days 36525 -batch -keyfile private/cakey.pem -selfsign \
             -infiles careq.pem 1>&3 2>&3
         chmod 0700 private/cakey.pem
 
@@ -514,7 +514,7 @@ elif test "$command" = self-sign; then
     # Create both the private key and certificate with restricted permissions.
     (umask 077 && \
      openssl x509 -in "$arg1-req.pem" -out "$arg1-cert.pem.tmp" \
-        -signkey "$arg1-privkey.pem" -req -days 2191 -text) 2>&3 || exit $?
+        -signkey "$arg1-privkey.pem" -req -days 36525 -text) 2>&3 || exit $?
 
     # Reset the permissions on the certificate to the user's default.
     cat "$arg1-cert.pem.tmp" > "$arg1-cert.pem"
index 16ac879..b46f98d 100755 (executable)
@@ -1,6 +1,6 @@
 #! /bin/sh
 
-# Copyright (c) 2011 Nicira, Inc.
+# Copyright (c) 2011, 2013 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -177,7 +177,7 @@ save_flows () {
 }
 
 ovs_vsctl () {
-    ovs-vsctl --no-wait --timeout=1 "$@"
+    ovs-vsctl --no-wait "$@"
 }
 
 save_ofports ()
@@ -191,7 +191,7 @@ save_ofports ()
         count=0
         for iface in `ovs_vsctl list-ifaces ${bridge}`; do
             ofport=`ovs_vsctl get interface ${iface} ofport`
-            [ "${count}" -eq 0 ] && cmd="ovs-vsctl --no-wait --timeout=1"
+            [ "${count}" -eq 0 ] && cmd="ovs-vsctl --no-wait"
             cmd="${cmd} -- --if-exists set interface "${iface}" \
                      ofport_request="${ofport}""
 
index cf6cf88..85149a9 100644 (file)
@@ -127,6 +127,20 @@ to approximately \fIsecs\fR seconds.  If the timeout expires,
 would normally happen only if the database cannot be contacted, or if
 the system is overloaded.)
 .
+.IP "\fB\-\-retry\fR"
+Without this option, if \fBovs\-vsctl\fR connects outward to the
+database server (the default) then \fBovs\-vsctl\fR will try to
+connect once and exit with an error if the connection fails (which
+usually means that \fBovsdb\-server\fR is not running).
+.IP
+With this option, or if \fB\-\-db\fR specifies that \fBovs\-vsctl\fR
+should listen for an incoming connection from the database server,
+then \fBovs\-vsctl\fR will wait for a connection to the database
+forever.
+.IP
+Regardless of this setting, \fB\-\-timeout\fR always limits how long
+\fBovs\-vsctl\fR will wait.
+.
 .SS "Table Formatting Options"
 These options control the format of output from the \fBlist\fR and
 \fBfind\fR commands.
index 1ba8588..18ace60 100644 (file)
@@ -114,6 +114,16 @@ static bool wait_for_reload = true;
 /* --timeout: Time to wait for a connection to 'db'. */
 static int timeout;
 
+/* --retry: If true, ovs-vsctl will retry connecting to the database forever.
+ * If false and --db says to use an active connection method (e.g. "unix:",
+ * "tcp:", "ssl:"), then ovs-vsctl will try to connect once and exit with an
+ * error if the database server cannot be contacted (e.g. ovsdb-server is not
+ * running).
+ *
+ * Regardless of this setting, --timeout always limits how long ovs-vsctl will
+ * wait. */
+static bool retry;
+
 /* Format for table output. */
 static struct table_style table_style = TABLE_STYLE_DEFAULT;
 
@@ -186,7 +196,7 @@ main(int argc, char *argv[])
     }
 
     /* Initialize IDL. */
-    idl = the_idl = ovsdb_idl_create(db, &ovsrec_idl_class, false);
+    idl = the_idl = ovsdb_idl_create(db, &ovsrec_idl_class, false, retry);
     run_prerequisites(commands, n_commands, idl);
 
     /* Execute the commands.
@@ -199,6 +209,11 @@ main(int argc, char *argv[])
     seqno = ovsdb_idl_get_seqno(idl);
     for (;;) {
         ovsdb_idl_run(idl);
+        if (!ovsdb_idl_is_alive(idl)) {
+            int retval = ovsdb_idl_get_last_error(idl);
+            vsctl_fatal("%s: database connection failed (%s)",
+                        db, ovs_retval_to_string(retval));
+        }
 
         if (seqno != ovsdb_idl_get_seqno(idl)) {
             seqno = ovsdb_idl_get_seqno(idl);
@@ -247,6 +262,7 @@ parse_options(int argc, char *argv[], struct shash *local_options)
         OPT_DRY_RUN,
         OPT_PEER_CA_CERT,
         OPT_LOCAL,
+        OPT_RETRY,
         VLOG_OPTION_ENUMS,
         TABLE_OPTION_ENUMS
     };
@@ -257,6 +273,7 @@ parse_options(int argc, char *argv[], struct shash *local_options)
         {"dry-run", no_argument, NULL, OPT_DRY_RUN},
         {"oneline", no_argument, NULL, OPT_ONELINE},
         {"timeout", required_argument, NULL, 't'},
+        {"retry", no_argument, NULL, OPT_RETRY},
         {"help", no_argument, NULL, 'h'},
         {"version", no_argument, NULL, 'V'},
         VLOG_LONG_OPTIONS,
@@ -384,6 +401,10 @@ parse_options(int argc, char *argv[], struct shash *local_options)
             }
             break;
 
+        case OPT_RETRY:
+            retry = true;
+            break;
+
         VLOG_OPTION_HANDLERS
         TABLE_OPTION_HANDLERS(&table_style)
 
@@ -662,6 +683,7 @@ Options:\n\
   --db=DATABASE               connect to DATABASE\n\
                               (default: %s)\n\
   --no-wait                   do not wait for ovs-vswitchd to reconfigure\n\
+  --retry                     keep trying to connect to server forever\n\
   -t, --timeout=SECS          wait at most SECS seconds for ovs-vswitchd\n\
   --dry-run                   do not commit changes to database\n\
   --oneline                   print exactly one line of output per command\n",
index dd3099f..6dc3db2 100644 (file)
@@ -212,8 +212,7 @@ static struct port *port_lookup(const struct bridge *, const char *name);
 static void port_configure(struct port *);
 static struct lacp_settings *port_configure_lacp(struct port *,
                                                  struct lacp_settings *);
-static void port_configure_bond(struct port *, struct bond_settings *,
-                                uint32_t *bond_stable_ids);
+static void port_configure_bond(struct port *, struct bond_settings *);
 static bool port_is_synthetic(const struct port *);
 
 static void reconfigure_system_stats(const struct ovsrec_open_vswitch *);
@@ -319,7 +318,7 @@ void
 bridge_init(const char *remote)
 {
     /* Create connection to database. */
-    idl = ovsdb_idl_create(remote, &ovsrec_idl_class, true);
+    idl = ovsdb_idl_create(remote, &ovsrec_idl_class, true, true);
     idl_seqno = ovsdb_idl_get_seqno(idl);
     ovsdb_idl_set_lock(idl, "ovs_vswitchd");
     ovsdb_idl_verify_write_only(idl);
@@ -346,6 +345,7 @@ bridge_init(const char *remote)
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_speed);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_state);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_link_resets);
+    ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_mac_in_use);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_mtu);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_ofport);
     ovsdb_idl_omit_alert(idl, &ovsrec_interface_col_statistics);
@@ -761,12 +761,9 @@ port_configure(struct port *port)
     /* Get bond settings. */
     if (s.n_slaves > 1) {
         s.bond = &bond_settings;
-        s.bond_stable_ids = xmalloc(s.n_slaves * sizeof *s.bond_stable_ids);
-        port_configure_bond(port, &bond_settings, s.bond_stable_ids);
+        port_configure_bond(port, &bond_settings);
     } else {
         s.bond = NULL;
-        s.bond_stable_ids = NULL;
-
         LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
             netdev_set_miimon_interval(iface->netdev, 0);
         }
@@ -779,7 +776,6 @@ port_configure(struct port *port)
     free(s.slaves);
     free(s.trunks);
     free(s.lacp_slaves);
-    free(s.bond_stable_ids);
 }
 
 /* Pick local port hardware address and datapath ID for 'br'. */
@@ -1446,9 +1442,9 @@ iface_create(struct bridge *br, struct if_cfg *if_cfg, int ofp_port)
 
             error = netdev_open(port->name, "internal", &netdev);
             if (!error) {
-                uint16_t ofp_port = if_cfg->ofport;
+                uint16_t fake_ofp_port = if_cfg->ofport;
 
-                ofproto_port_add(br->ofproto, netdev, &ofp_port);
+                ofproto_port_add(br->ofproto, netdev, &fake_ofp_port);
                 netdev_close(netdev);
             } else {
                 VLOG_WARN("could not open network device %s (%s)",
@@ -1703,6 +1699,7 @@ iface_refresh_status(struct iface *iface)
     int64_t bps;
     int mtu;
     int64_t mtu_64;
+    uint8_t mac[ETH_ADDR_LEN];
     int error;
 
     if (iface_is_synthetic(iface)) {
@@ -1726,8 +1723,7 @@ iface_refresh_status(struct iface *iface)
                                     netdev_features_is_full_duplex(current)
                                     ? "full" : "half");
         ovsrec_interface_set_link_speed(iface->cfg, &bps, 1);
-    }
-    else {
+    } else {
         ovsrec_interface_set_duplex(iface->cfg, NULL);
         ovsrec_interface_set_link_speed(iface->cfg, NULL, 0);
     }
@@ -1736,10 +1732,19 @@ iface_refresh_status(struct iface *iface)
     if (!error) {
         mtu_64 = mtu;
         ovsrec_interface_set_mtu(iface->cfg, &mtu_64, 1);
-    }
-    else {
+    } else {
         ovsrec_interface_set_mtu(iface->cfg, NULL, 0);
     }
+
+    error = netdev_get_etheraddr(iface->netdev, mac);
+    if (!error) {
+        char mac_string[32];
+
+        sprintf(mac_string, ETH_ADDR_FMT, ETH_ADDR_ARGS(mac));
+        ovsrec_interface_set_mac_in_use(iface->cfg, mac_string);
+    } else {
+        ovsrec_interface_set_mac_in_use(iface->cfg, NULL);
+    }
 }
 
 /* Writes 'iface''s CFM statistics to the database. 'iface' must not be
@@ -1748,57 +1753,47 @@ static void
 iface_refresh_cfm_stats(struct iface *iface)
 {
     const struct ovsrec_interface *cfg = iface->cfg;
-    int fault, opup, error;
-    const uint64_t *rmps;
-    size_t n_rmps;
-    int health;
-
-    fault = ofproto_port_get_cfm_fault(iface->port->bridge->ofproto,
-                                       iface->ofp_port);
-    if (fault >= 0) {
+    struct ofproto_cfm_status status;
+
+    if (!ofproto_port_get_cfm_status(iface->port->bridge->ofproto,
+                                    iface->ofp_port, &status)) {
+        ovsrec_interface_set_cfm_fault(cfg, NULL, 0);
+        ovsrec_interface_set_cfm_fault_status(cfg, NULL, 0);
+        ovsrec_interface_set_cfm_remote_opstate(cfg, NULL);
+        ovsrec_interface_set_cfm_health(cfg, NULL, 0);
+        ovsrec_interface_set_cfm_remote_mpids(cfg, NULL, 0);
+    } else {
         const char *reasons[CFM_FAULT_N_REASONS];
-        bool fault_bool = fault;
+        int64_t cfm_health = status.health;
+        bool faulted = status.faults != 0;
         size_t i, j;
 
+        ovsrec_interface_set_cfm_fault(cfg, &faulted, 1);
+
         j = 0;
         for (i = 0; i < CFM_FAULT_N_REASONS; i++) {
             int reason = 1 << i;
-            if (fault & reason) {
+            if (status.faults & reason) {
                 reasons[j++] = cfm_fault_reason_to_str(reason);
             }
         }
-
-        ovsrec_interface_set_cfm_fault(cfg, &fault_bool, 1);
         ovsrec_interface_set_cfm_fault_status(cfg, (char **) reasons, j);
-    } else {
-        ovsrec_interface_set_cfm_fault(cfg, NULL, 0);
-        ovsrec_interface_set_cfm_fault_status(cfg, NULL, 0);
-    }
-
-    opup = ofproto_port_get_cfm_opup(iface->port->bridge->ofproto,
-                                     iface->ofp_port);
-    if (opup >= 0) {
-        ovsrec_interface_set_cfm_remote_opstate(cfg, opup ? "up" : "down");
-    } else {
-        ovsrec_interface_set_cfm_remote_opstate(cfg, NULL);
-    }
 
-    error = ofproto_port_get_cfm_remote_mpids(iface->port->bridge->ofproto,
-                                              iface->ofp_port, &rmps, &n_rmps);
-    if (error >= 0) {
-        ovsrec_interface_set_cfm_remote_mpids(cfg, (const int64_t *)rmps,
-                                              n_rmps);
-    } else {
-        ovsrec_interface_set_cfm_remote_mpids(cfg, NULL, 0);
-    }
+        if (status.remote_opstate >= 0) {
+            const char *remote_opstate = status.remote_opstate ? "up" : "down";
+            ovsrec_interface_set_cfm_remote_opstate(cfg, remote_opstate);
+        } else {
+            ovsrec_interface_set_cfm_remote_opstate(cfg, NULL);
+        }
 
-    health = ofproto_port_get_cfm_health(iface->port->bridge->ofproto,
-                                        iface->ofp_port);
-    if (health >= 0) {
-        int64_t cfm_health = health;
-        ovsrec_interface_set_cfm_health(cfg, &cfm_health, 1);
-    } else {
-        ovsrec_interface_set_cfm_health(cfg, NULL, 0);
+        ovsrec_interface_set_cfm_remote_mpids(cfg,
+                                              (const int64_t *)status.rmps,
+                                              status.n_rmps);
+        if (cfm_health >= 0) {
+            ovsrec_interface_set_cfm_health(cfg, &cfm_health, 1);
+        } else {
+            ovsrec_interface_set_cfm_health(cfg, NULL, 0);
+        }
     }
 }
 
@@ -1966,15 +1961,16 @@ run_system_stats(void)
 }
 
 static inline const char *
-nx_role_to_str(enum nx_role role)
+ofp12_controller_role_to_str(enum ofp12_controller_role role)
 {
     switch (role) {
-    case NX_ROLE_OTHER:
+    case OFPCR12_ROLE_EQUAL:
         return "other";
-    case NX_ROLE_MASTER:
+    case OFPCR12_ROLE_MASTER:
         return "master";
-    case NX_ROLE_SLAVE:
+    case OFPCR12_ROLE_SLAVE:
         return "slave";
+    case OFPCR12_ROLE_NOCHANGE:
     default:
         return "*** INVALID ROLE ***";
     }
@@ -2010,7 +2006,8 @@ refresh_controller_status(void)
             }
 
             ovsrec_controller_set_is_connected(cfg, cinfo->is_connected);
-            ovsrec_controller_set_role(cfg, nx_role_to_str(cinfo->role));
+            ovsrec_controller_set_role(cfg, ofp12_controller_role_to_str(
+                                           cinfo->role));
             ovsrec_controller_set_status(cfg, &smap);
             smap_destroy(&smap);
         } else {
@@ -2022,17 +2019,61 @@ refresh_controller_status(void)
 
     ofproto_free_ofproto_controller_info(&info);
 }
+\f
+/* "Instant" stats.
+ *
+ * Some information in the database must be kept as up-to-date as possible to
+ * allow controllers to respond rapidly to network outages.  We call these
+ * statistics "instant" stats.
+ *
+ * We wish to update these statistics every INSTANT_INTERVAL_MSEC milliseconds,
+ * assuming that they've changed.  The only means we have to determine whether
+ * they have changed are:
+ *
+ *   - Try to commit changes to the database.  If nothing changed, then
+ *     ovsdb_idl_txn_commit() returns TXN_UNCHANGED, otherwise some other
+ *     value.
+ *
+ *   - instant_stats_run() is called late in the run loop, after anything that
+ *     might change any of the instant stats.
+ *
+ * We use these two facts together to avoid waking the process up every
+ * INSTANT_INTERVAL_MSEC whether there is any change or not.
+ */
+
+/* Minimum interval between writing updates to the instant stats to the
+ * database. */
+#define INSTANT_INTERVAL_MSEC 100
+
+/* Current instant stats database transaction, NULL if there is no ongoing
+ * transaction. */
+static struct ovsdb_idl_txn *instant_txn;
+
+/* Next time (in msec on monotonic clock) at which we will update the instant
+ * stats.  */
+static long long int instant_next_txn = LLONG_MIN;
+
+/* True if the run loop has run since we last saw that the instant stats were
+ * unchanged, that is, this is true if we need to wake up at 'instant_next_txn'
+ * to refresh the instant stats. */
+static bool instant_stats_could_have_changed;
 
 static void
-refresh_instant_stats(void)
+instant_stats_run(void)
 {
-    static struct ovsdb_idl_txn *txn = NULL;
+    enum ovsdb_idl_txn_status status;
+
+    instant_stats_could_have_changed = true;
 
-    if (!txn) {
+    if (!instant_txn) {
         struct bridge *br;
 
-        txn = ovsdb_idl_txn_create(idl);
+        if (time_msec() < instant_next_txn) {
+            return;
+        }
+        instant_next_txn = time_msec() + INSTANT_INTERVAL_MSEC;
 
+        instant_txn = ovsdb_idl_txn_create(idl);
         HMAP_FOR_EACH (br, node, &all_bridges) {
             struct iface *iface;
             struct port *port;
@@ -2081,12 +2122,26 @@ refresh_instant_stats(void)
         }
     }
 
-    if (ovsdb_idl_txn_commit(txn) != TXN_INCOMPLETE) {
-        ovsdb_idl_txn_destroy(txn);
-        txn = NULL;
+    status = ovsdb_idl_txn_commit(instant_txn);
+    if (status != TXN_INCOMPLETE) {
+        ovsdb_idl_txn_destroy(instant_txn);
+        instant_txn = NULL;
+    }
+    if (status == TXN_UNCHANGED) {
+        instant_stats_could_have_changed = false;
     }
 }
 
+static void
+instant_stats_wait(void)
+{
+    if (instant_txn) {
+        ovsdb_idl_txn_wait(instant_txn);
+    } else if (instant_stats_could_have_changed) {
+        poll_timer_wait_until(instant_next_txn);
+    }
+}
+\f
 /* Performs periodic activity required by bridges that needs to be done with
  * the least possible latency.
  *
@@ -2257,7 +2312,7 @@ bridge_run(void)
     }
 
     run_system_stats();
-    refresh_instant_stats();
+    instant_stats_run();
 }
 
 void
@@ -2289,6 +2344,7 @@ bridge_wait(void)
     }
 
     system_stats_wait();
+    instant_stats_wait();
 }
 
 /* Adds some memory usage statistics for bridges into 'usage', for use with
@@ -2804,8 +2860,10 @@ bridge_configure_remotes(struct bridge *br,
             if (!strncmp(c->target, "unix:", 5)) {
                 /* Connect to a listening socket */
                 whitelist = xasprintf("unix:%s/", ovs_rundir());
-                if (!equal_pathnames(c->target, whitelist,
-                                     strlen(whitelist))) {
+                if (strchr(c->target, '/') &&
+                   !equal_pathnames(c->target, whitelist,
+                     strlen(whitelist))) {
+                    /* Absolute path specified, but not in ovs_rundir */
                     VLOG_ERR_RL(&rl, "bridge %s: Not connecting to socket "
                                   "controller \"%s\" due to possibility for "
                                   "remote exploit.  Instead, specify socket "
@@ -3111,13 +3169,11 @@ iface_configure_lacp(struct iface *iface, struct lacp_slave_settings *s)
 }
 
 static void
-port_configure_bond(struct port *port, struct bond_settings *s,
-                    uint32_t *bond_stable_ids)
+port_configure_bond(struct port *port, struct bond_settings *s)
 {
     const char *detect_s;
     struct iface *iface;
     int miimon_interval;
-    size_t i;
 
     s->name = port->name;
     s->balance = BM_AB;
@@ -3169,17 +3225,7 @@ port_configure_bond(struct port *port, struct bond_settings *s,
 
     s->fake_iface = port->cfg->bond_fake_iface;
 
-    i = 0;
     LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
-        long long stable_id;
-
-        stable_id = smap_get_int(&iface->cfg->other_config, "bond-stable-id",
-                                 0);
-        if (stable_id <= 0 || stable_id >= UINT32_MAX) {
-            stable_id = iface->ofp_port;
-        }
-        bond_stable_ids[i++] = stable_id;
-
         netdev_set_miimon_interval(iface->netdev, miimon_interval);
     }
 }
@@ -3355,6 +3401,7 @@ iface_clear_db_record(const struct ovsrec_interface *if_cfg)
         ovsrec_interface_set_duplex(if_cfg, NULL);
         ovsrec_interface_set_link_speed(if_cfg, NULL, 0);
         ovsrec_interface_set_link_state(if_cfg, NULL);
+        ovsrec_interface_set_mac_in_use(if_cfg, NULL);
         ovsrec_interface_set_mtu(if_cfg, NULL, 0);
         ovsrec_interface_set_cfm_fault(if_cfg, NULL, 0);
         ovsrec_interface_set_cfm_fault_status(if_cfg, NULL, 0);
index 764ed41..43c5d24 100644 (file)
@@ -208,6 +208,7 @@ enabled.
 .so ofproto/ofproto-unixctl.man
 .so lib/vlog-unixctl.man
 .so lib/memory-unixctl.man
+.so lib/coverage-unixctl.man
 .so lib/stress-unixctl.man
 .
 .SH "LIMITS"
index 16125a5..594ffb4 100644 (file)
@@ -1,6 +1,6 @@
 {"name": "Open_vSwitch",
- "version": "6.11.3",
- "cksum": "2234602985 17310",
+ "version": "7.1.0",
+ "cksum": "2234055133 17444",
  "tables": {
    "Open_vSwitch": {
      "columns": {
                   "min": 0, "max": 1}},
        "bond_mode": {
          "type": {"key": {"type": "string",
-           "enum": ["set", ["balance-tcp", "balance-slb", "active-backup", "stable"]]},
+           "enum": ["set", ["balance-tcp", "balance-slb", "active-backup"]]},
          "min": 0, "max": 1}},
        "lacp": {
          "type": {"key": {"type": "string",
        "ingress_policing_burst": {
          "type": {"key": {"type": "integer",
                           "minInteger": 0}}},
+       "mac_in_use": {
+         "type": {"key": {"type": "string"},
+                  "min": 0, "max": 1},
+                  "ephemeral": true},
        "mac": {
          "type": {"key": {"type": "string"},
                   "min": 0, "max": 1}},
index 18643c2..2af04bd 100644 (file)
           information such as destination MAC address, IP address, and TCP
           port.
         </dd>
-
-        <dt><code>stable</code></dt>
-        <dd>
-          <p>Deprecated and slated for removal in February 2013.</p>
-          <p>Attempts to always assign a given flow to the same slave
-          consistently.  In an effort to maintain stability, no load
-          balancing is done.  Uses a similar hashing strategy to
-          <code>balance-tcp</code>, always taking into account L3 and L4
-          fields even if LACP negotiations are unsuccessful. </p>
-          <p>Slave selection decisions are made based on <ref table="Interface"
-          column="other_config" key="bond-stable-id"/> if set.  Otherwise,
-          OpenFlow port number is used.  Decisions are consistent across all
-          <code>ovs-vswitchd</code> instances with equivalent
-          <ref table="Interface" column="other_config" key="bond-stable-id"/>
-          values.</p>
-        </dd>
       </dl>
 
       <p>These columns apply only to bonded ports.  Their values are
         on a host.
       </column>
 
+      <column name="mac_in_use">
+        The MAC address in use by this interface.
+      </column>
+
       <column name="mac">
         <p>Ethernet address to set for this interface.  If unset then the
         default MAC address is used:</p>
             Same as IPSEC_GRE except 64 bit key.
           </dd>
 
-          <dt><code>capwap</code></dt>
-          <dd>
-            An Ethernet tunnel over the UDP transport portion of CAPWAP (RFC
-            5415).  This allows interoperability with certain switches that do
-            not support GRE.  Only the tunneling component of the protocol is
-            implemented.  UDP ports 58881 and 58882 are used as the source and
-            destination ports respectively.  CAPWAP is currently supported only
-            with the Linux kernel datapath with kernel version 2.6.26 or later.
-
-            CAPWAP support is deprecated and will be removed no earlier than
-            February 2013.
-          </dd>
-
           <dt><code>vxlan</code></dt>
           <dd>
            <p>
              An Ethernet tunnel over the experimental, UDP-based VXLAN
              protocol described at
-             <code>http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-02</code>.
+             <code>http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-03</code>.
              VXLAN is currently supported only with the Linux kernel datapath
              with kernel version 2.6.26 or later.
            </p>
            </p>
           </dd>
 
+          <dt><code>lisp</code></dt>
+          <dd>
+            A layer 3 tunnel over the experimental, UDP-based Locator/ID
+            Separation Protocol (RFC 6830). LISP is currently supported only
+            with the Linux kernel datapath with kernel version 2.6.26 or later.
+          </dd>
+
           <dt><code>patch</code></dt>
           <dd>
             A pair of virtual devices that act as a patch cable.
       <p>
         These options apply to interfaces with <ref column="type"/> of
         <code>gre</code>, <code>ipsec_gre</code>, <code>gre64</code>,
-        <code>ipsec_gre64</code>, <code>capwap</code>, and
-        <code>vxlan</code>.
+        <code>ipsec_gre64</code>, <code>vxlan</code>, and <code>lisp</code>.
       </p>
 
       <p>
       </p>
 
       <column name="options" key="remote_ip">
-        <p>
-          Required.  The tunnel endpoint.  Unicast and multicast endpoints are
-          both supported.
-        </p>
-
-        <p>
-          When a multicast endpoint is specified, a routing table lookup occurs
-          only when the tunnel is created.  Following a routing change, delete
-          and then re-create the tunnel to force a new routing table lookup.
-        </p>
+          Required.  The tunnel endpoint.  Only unicast endpoints are supported.
       </column>
 
       <column name="options" key="local_ip">
         Optional.  The destination IP that received packets must match.
-        Default is to match all addresses.  Must be omitted when <ref
-        column="options" key="remote_ip"/> is a multicast address.
+        Default is to match all addresses.
       </column>
 
       <column name="options" key="in_key">
             key="in_key"/> at all.
           </li>
           <li>
-            A positive 24-bit (for VXLAN), 32-bit (for GRE) or 64-bit (for
-            CAPWAP) number.  The tunnel receives only packets with the
+            A positive 24-bit (for VXLAN and LISP), 32-bit (for GRE) or 64-bit
+            (for GRE64) number.  The tunnel receives only packets with the
             specified key.
           </li>
           <li>
             key="out_key"/> at all.
           </li>
           <li>
-            A positive 24-bit (for VXLAN), 32-bit (for GRE) or 64-bit (for
-            CAPWAP) number.  Packets sent through the tunnel will have the
+            A positive 24-bit (for VXLAN and LISP), 32-bit (for GRE) or 64-bit
+            (for GRE64) number.  Packets sent through the tunnel will have the
             specified key.
           </li>
           <li>
 
       <column name="status" key="source_ip">
         The source IP address used for an IPv4 tunnel end-point, such as
-        <code>gre</code> or <code>capwap</code>.
+        <code>gre</code>.
       </column>
 
       <column name="status" key="tunnel_egress_iface">
-        Egress interface for tunnels.  Currently only relevant for GRE and
-        CAPWAP tunnels.  On Linux systems, this column will show the name of
-        the interface which is responsible for routing traffic destined for the
-        configured <ref column="options" key="remote_ip"/>.  This could be an
-        internal interface such as a bridge port.
+        Egress interface for tunnels.  Currently only relevant for GRE tunnels
+        On Linux systems, this column will show the name of the interface
+        which is responsible for routing traffic destined for the configured
+        <ref column="options" key="remote_ip"/>.  This could be an internal
+        interface such as a bridge port.
       </column>
 
       <column name="status" key="tunnel_egress_iface_carrier"
     </group>
 
     <group title="Bonding Configuration">
-      <column name="other_config" key="bond-stable-id"
-              type='{"type": "integer", "minInteger": 1}'>
-        Used in <code>stable</code> bond mode to make slave
-        selection decisions.  Allocating <ref column="other_config"
-        key="bond-stable-id"/> values consistently across interfaces
-        participating in a bond will guarantee consistent slave selection
-        decisions across <code>ovs-vswitchd</code> instances when using
-        <code>stable</code> bonding mode.
-      </column>
-
       <column name="other_config" key="lacp-port-id"
               type='{"type": "integer", "minInteger": 1, "maxInteger": 65535}'>
         The LACP port ID of this <ref table="Interface"/>.  Port IDs are
           two different hypervisors.  That is, <code>active</code> means that
           this <ref column="external_ids" key="iface-id"/> is the active
           instance within a single hypervisor, not in a broader scope.
+          There is one exception: some hypervisors support ``migration'' from a
+          given hypervisor to itself (most often for test purposes).  During
+          such a ``migration,'' two instances of a single <ref
+          column="external_ids" key="iface-id"/> might both be briefly marked
+          <code>active</code> on a single hypervisor.
         </p>
       </column>
 
index e72655f..472159e 100644 (file)
@@ -82,10 +82,16 @@ debugging.  The sources for the extensions are in
         the following scripts, which are described below:
 
             * ovs-bugtool-cfm-show
-            * ovs-bugtool-lcap-show
+            * ovs-bugtool-lacp-show
             * ovs-bugtool-ovsdb-dump
             * ovs-bugtool-tc-class-show
             * ovs-bugtool-bond-show
+            * ovs-bugtool-ovs-ofctl-show
+            * ovs-bugtool-ovs-ofctl-dump-flows
+            * ovs-bugtool-ovs-appctl-dpif
+            * ovs-bugtool-coverage-show
+            * ovs-bugtool-memory-show
+            * ovs-bugtool-vsctl-show
 
     system-configuration/openvswitch.xml
 
@@ -122,6 +128,31 @@ scripts are located in ../utilities/bugtool:
 
         Script to dump tc class configuration for all network interfaces.
 
+    ovs-bugtool-ovs-ofctl-show
+
+        Script to dump information about flow tables and ports of each bridge.
+
+    ovs-bugtool-ovs-ofctl-dump-flows
+
+        Script to dump openflow flows of each bridge.
+
+    ovs-bugtool-ovs-appctl-dpif
+
+        Script to collect a summary of configured datapaths and datapath flows.
+
+    ovs-bugtool-coverage-show
+
+        Script to count the number of times particular events occur during
+        ovs-vswitchd's runtime.
+
+    ovs-bugtool-memory-show
+
+        Script to show some basic statistics about ovs-vswitchd's memory usage.
+
+    ovs-bugtool-vsctl-show
+
+        Script to show a brief overview of the database contents.
+
     ovs-bugtool-daemons-ver
 
         Script to dump version information for all Open vSwitch daemons.
index 534451b..9c0fe80 100755 (executable)
@@ -54,7 +54,7 @@ start_ovs_xapi_sync () {
 }
 
 start () {
-    set $ovs_ctl ${1-start}
+    set ovs_ctl ${1-start}
     set "$@" --system-id="$INSTALLATION_UUID"
     set "$@" --system-type="$PRODUCT_BRAND"
     set "$@" --system-version="$PRODUCT_VERSION-$BUILD_NUMBER"
@@ -81,7 +81,7 @@ start () {
 
     start_ovs_xapi_sync
 
-    $ovs_ctl --protocol=gre enable-protocol
+    ovs_ctl --protocol=gre enable-protocol
 
     touch /var/lock/subsys/openvswitch
 }
@@ -102,7 +102,7 @@ force_reload_kmod () {
 }
 
 stop () {
-    $ovs_ctl stop
+    ovs_ctl stop
     stop_daemon ovs-xapi-sync
     rm -f /var/lock/subsys/openvswitch
 }
@@ -117,7 +117,6 @@ restart () {
     fi
 }
 
-ovs_ctl=/usr/share/openvswitch/scripts/ovs-ctl
 case $1 in
     start)
         start
@@ -137,10 +136,10 @@ case $1 in
         fi
         ;;
     status)
-        $ovs_ctl status && daemon_status ovs-xapi-sync
+        ovs_ctl status && daemon_status ovs-xapi-sync
         ;;
     version)
-        $ovs_ctl version
+        ovs_ctl version
         ;;
     force-reload-kmod)
         force_reload_kmod
index 46b94b9..73751d4 100644 (file)
@@ -6,6 +6,8 @@
 # without warranty of any kind.
 
 /var/log/openvswitch/*.log {
+       daily
+       compress
        sharedscripts
        missingok
        postrotate
index 02927f8..2df838a 100755 (executable)
@@ -4,7 +4,7 @@
 # ovs-vswitchd configuration that are managed in the xapi database when 
 # integrated with Citrix management tools.
 
-# Copyright (C) 2009, 2010, 2011, 2012 Nicira, Inc.
+# Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -213,7 +213,7 @@ def setControllerCfg(controller):
                    "--", "set-manager", 'ssl:' + controller + ':6632'])
 
 def vswitchCfgQuery(action_args):
-    cmd = [vsctl, "--timeout=5", "-vconsole:off"] + action_args
+    cmd = [vsctl, "-vconsole:off"] + action_args
     output = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()
     if len(output) == 0 or output[0] == None:
         output = ""
index c41a7e5..4e8f576 100644 (file)
@@ -118,18 +118,16 @@ install python/compat/uuid.py $RPM_BUILD_ROOT/usr/share/openvswitch/python
 install python/compat/argparse.py $RPM_BUILD_ROOT/usr/share/openvswitch/python
 
 install -d -m 755 $RPM_BUILD_ROOT/etc/xensource/bugtool
-mv $RPM_BUILD_ROOT/usr/share/openvswitch/bugtool-plugins/* $RPM_BUILD_ROOT/etc/xensource/bugtool
+cp -rf $RPM_BUILD_ROOT/usr/share/openvswitch/bugtool-plugins/* $RPM_BUILD_ROOT/etc/xensource/bugtool
 
 # Get rid of stuff we don't want to make RPM happy.
 rm \
     $RPM_BUILD_ROOT/usr/bin/ovs-benchmark \
-    $RPM_BUILD_ROOT/usr/sbin/ovs-bugtool \
     $RPM_BUILD_ROOT/usr/bin/ovs-controller \
     $RPM_BUILD_ROOT/usr/bin/ovs-l3ping \
     $RPM_BUILD_ROOT/usr/bin/ovs-pki \
     $RPM_BUILD_ROOT/usr/bin/ovs-test \
     $RPM_BUILD_ROOT/usr/share/man/man1/ovs-benchmark.1 \
-    $RPM_BUILD_ROOT/usr/share/man/man8/ovs-bugtool.8 \
     $RPM_BUILD_ROOT/usr/share/man/man8/ovs-controller.8 \
     $RPM_BUILD_ROOT/usr/share/man/man8/ovs-l3ping.8 \
     $RPM_BUILD_ROOT/usr/share/man/man8/ovs-pki.8 \
@@ -408,6 +406,7 @@ exit 0
 /etc/logrotate.d/openvswitch
 /etc/profile.d/openvswitch.sh
 /usr/share/openvswitch/python/
+/usr/share/openvswitch/bugtool-plugins/*
 /usr/share/openvswitch/scripts/ovs-check-dead-ifs
 /usr/share/openvswitch/scripts/ovs-xapi-sync
 /usr/share/openvswitch/scripts/interface-reconfigure
@@ -421,6 +420,7 @@ exit 0
 /usr/share/openvswitch/scripts/ovs-ctl
 /usr/share/openvswitch/scripts/ovs-lib
 /usr/share/openvswitch/vswitch.ovsschema
+/usr/sbin/ovs-bugtool
 /usr/sbin/ovs-vlan-bug-workaround
 /usr/sbin/ovs-vswitchd
 /usr/sbin/ovsdb-server
@@ -441,6 +441,7 @@ exit 0
 /usr/share/man/man1/ovsdb-tool.1.gz
 /usr/share/man/man5/ovs-vswitchd.conf.db.5.gz
 /usr/share/man/man8/ovs-appctl.8.gz
+/usr/share/man/man8/ovs-bugtool.8.gz
 /usr/share/man/man8/ovs-ctl.8.gz
 /usr/share/man/man8/ovs-dpctl.8.gz
 /usr/share/man/man8/ovs-ofctl.8.gz
index 971f918..1379fb4 100644 (file)
@@ -1,5 +1,5 @@
 # Copyright (c) 2008,2009,2011 Citrix Systems, Inc.
-# Copyright (c) 2009,2010,2011,2012 Nicira, Inc.
+# Copyright (c) 2009,2010,2011,2012,2013 Nicira, Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU Lesser General Public License as published
@@ -721,7 +721,7 @@ class DatapathVswitch(Datapath):
 
 def vswitchCfgQuery(action_args):
     cmd = ['%s/usr/bin/ovs-vsctl' % root_prefix(),
-        '--timeout=5', '-vconsole:off'] + action_args
+           '-vconsole:off'] + action_args
     output = subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()
     if len(output) == 0 or output[0] == None:
         output = ""
index f62eaa8..fdbbc0e 100644 (file)
@@ -1,5 +1,5 @@
+# Copyright (c) 2009,2010,2011,2012,2013 Nicira, Inc.
 # Copyright (c) 2007-2011 Citrix Systems Inc.
-# Copyright (c) 2009,2010,2011,2012 Nicira, Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -86,7 +86,7 @@ class VSwitchConfig:
     @staticmethod
     def Get(action):
         try:
-            arg = [vsctl, "--timeout=30", "-vconsole:off"] + action.split()
+            arg = [vsctl, "-vconsole:off"] + action.split()
             output = ShellPipe(arg).Stdout()
         except StandardError, e:
             XSLogError("config retrieval error: " + str(e))