Merge branch 'master' of git://openvswitch.org/openvswitch
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Wed, 3 Apr 2013 11:52:41 +0000 (13:52 +0200)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Wed, 3 Apr 2013 11:52:41 +0000 (13:52 +0200)
141 files changed:
AUTHORS
CodingStyle
FAQ
INSTALL
INSTALL.RHEL
NEWS
acinclude.m4
build-aux/extract-ofp-errors
configure.ac
datapath/actions.c
datapath/datapath.c
datapath/datapath.h
datapath/flow.c
datapath/flow.h
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/rculist.h
datapath/linux/compat/include/linux/rcupdate.h
datapath/linux/compat/include/linux/skbuff.h
datapath/tunnel.c
datapath/tunnel.h
datapath/vport-gre.c
datapath/vport-internal_dev.c
datapath/vport-lisp.c
datapath/vport-vxlan.c
datapath/vport.c
datapath/vport.h
debian/changelog
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.3.h
include/openvswitch/automake.mk
include/openvswitch/tunnel.h [deleted file]
lib/automake.mk
lib/dpif-linux.c
lib/dpif-netdev.c
lib/flow.c
lib/flow.h
lib/json.c
lib/json.h
lib/jsonrpc.c
lib/jsonrpc.h
lib/match.c
lib/netdev-dummy.c
lib/netdev-linux.c
lib/netdev-vport.c
lib/netdev.c
lib/netdev.h
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-parse.c
lib/ofp-print.c
lib/ofp-util.c
lib/ofp-util.def
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/reconnect.c
lib/timeval.c
lib/timeval.h
manpages.mk
ofproto/connmgr.c
ofproto/ofproto-dpif.c
ofproto/ofproto-provider.h
ofproto/ofproto.c
ofproto/ofproto.h
ofproto/tunnel.c
ofproto/tunnel.h
ovsdb/jsonrpc-server.c
ovsdb/log.c
ovsdb/ovsdb-idlc.in
ovsdb/ovsdb.h
python/ovs/db/types.py
python/ovs/vlog.py
rhel/README.RHEL
rhel/automake.mk
rhel/etc_init.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/interface-reconfigure.at
tests/lacp.at
tests/odp.at
tests/ofp-print.at
tests/ofproto-dpif.at
tests/ovs-monitor-ipsec.at
tests/ovs-ofctl.at
tests/ovs-vsctl.at
tests/ovs-xapi-sync.at
tests/test-flows.c
tests/test-json.c
tests/test-ovsdb.c
tests/test-sflow.c [new file with mode: 0644]
tests/tunnel.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.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-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_xapi.d_plugins_openvswitch-cfg-update
xenserver/opt_xensource_libexec_InterfaceReconfigureVswitch.py
xenserver/usr_lib_xsconsole_plugins-base_XSFeatureVSwitch.py

diff --git a/AUTHORS b/AUTHORS
index 4b5e6fe..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
@@ -70,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
@@ -141,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 a99f808..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
 --------
 
@@ -846,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.
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
 
diff --git a/NEWS b/NEWS
index 35b9212..cbbe06b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,10 +2,16 @@ post-v1.10.0
 ---------------------
     - Stable bond mode has been removed.
     - The autopath action has been removed.
-    - CAPWAP tunneling support 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
@@ -19,8 +25,14 @@ v1.10.0 - xx xxx xxxx
       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.
+    - 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?"
@@ -29,6 +41,8 @@ v1.10.0 - xx xxx xxxx
         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).
@@ -37,6 +51,8 @@ v1.10.0 - xx xxx xxxx
       - 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.
@@ -62,8 +78,8 @@ v1.10.0 - xx xxx xxxx
       with FreeBSD and the kernel module built into Linux 3.3 and later.
 
 
-v1.9.0 - xx xxx xxxx
---------------------
+v1.9.0 - 26 Feb 2013
+------------------------
     - Datapath:
       - Support for ipv6 set action.
       - SKB mark matching and setting.
@@ -117,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 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 1cacd29..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.
@@ -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
index 9202335..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)
 {
@@ -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 bd2d57b..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);
@@ -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->userdata)
-               len += NLA_ALIGN(upcall_info->userdata->nla_len);
-
-       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;
@@ -434,10 +466,10 @@ static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, int attr_le
        int next_offset = offsetof(struct sw_flow_actions, actions) +
                                        (*sfa)->actions_len;
 
-       if (req_size <= ((*sfa)->buf_size - next_offset))
+       if (req_size <= (ksize(*sfa) - next_offset))
                goto out;
 
-       new_acts_size = (*sfa)->buf_size * 2;
+       new_acts_size = ksize(*sfa) * 2;
 
        if (new_acts_size > MAX_ACTIONS_BUFSIZE) {
                if ((MAX_ACTIONS_BUFSIZE - next_offset) < req_size)
@@ -451,7 +483,7 @@ static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, int attr_le
 
        memcpy(acts->actions, (*sfa)->actions, (*sfa)->actions_len);
        acts->actions_len = (*sfa)->actions_len;
-       ovs_flow_actions_free(*sfa);
+       kfree(*sfa);
        *sfa = acts;
 
 out:
@@ -604,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;
 
@@ -821,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]);
@@ -832,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);
@@ -840,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);
@@ -897,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 },
 };
@@ -1048,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,
@@ -1136,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,
@@ -1283,16 +1313,14 @@ 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));
        return 0;
 
 err_kfree:
-       ovs_flow_actions_free(acts);
+       kfree(acts);
 error:
        return error;
 }
@@ -1372,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;
 }
 
@@ -1455,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)
 {
@@ -1493,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);
 
@@ -1607,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:
@@ -1638,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);
        }
@@ -1681,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;
 }
@@ -1711,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;
 }
@@ -1862,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;
 }
 
@@ -1980,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();
@@ -2011,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]));
@@ -2022,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);
 
-       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);
 
+       rtnl_unlock();
+       return 0;
+
+exit_free:
+       kfree_skb(reply);
 exit_unlock:
        rtnl_unlock();
 exit:
@@ -2070,8 +2105,7 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
        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();
@@ -2127,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,
@@ -2316,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)
@@ -2352,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:
@@ -2371,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 01e7296..9bc98fb 100644 (file)
@@ -141,6 +141,7 @@ struct dp_upcall_info {
  */
 struct ovs_net {
        struct list_head dps;
+       struct vport_net vport_net;
 };
 
 extern int ovs_net_id;
index b6bb7a7..841e8be 100644 (file)
@@ -207,29 +207,14 @@ struct sw_flow_actions *ovs_flow_actions_alloc(int size)
        if (size > MAX_ACTIONS_BUFSIZE)
                return ERR_PTR(-EINVAL);
 
-       size += sizeof(*sfa);
-       if (size <= MAX_ACTIONS_BUFSIZE_KMALLOC)
-               sfa = kmalloc(size, GFP_KERNEL);
-       else
-               sfa = vmalloc(size);
-
+       sfa = kmalloc(sizeof(*sfa) + size, GFP_KERNEL);
        if (!sfa)
                return ERR_PTR(-ENOMEM);
 
        sfa->actions_len = 0;
-       sfa->buf_size = size;
-
        return sfa;
 }
 
-void ovs_flow_actions_free(struct sw_flow_actions *sfa)
-{
-       if (sfa->buf_size <= MAX_ACTIONS_BUFSIZE_KMALLOC)
-               kfree(sfa);
-       else
-               vfree(sfa);
-}
-
 struct sw_flow *ovs_flow_alloc(void)
 {
        struct sw_flow *flow;
@@ -314,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);
                }
@@ -347,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;
 
@@ -355,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;
@@ -390,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;
@@ -452,7 +435,7 @@ static void rcu_free_acts_callback(struct rcu_head *rcu)
 {
        struct sw_flow_actions *sf_acts = container_of(rcu,
                        struct sw_flow_actions, rcu);
-       ovs_flow_actions_free(sf_acts);
+       kfree(sf_acts);
 }
 
 /* Schedules 'sf_acts' to be freed after the next RCU grace period.
@@ -499,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))
@@ -516,7 +499,7 @@ static __be16 parse_ethertype(struct sk_buff *skb)
 
        __skb_pull(skb, sizeof(struct llc_snap_hdr));
 
-       if (ntohs(llc->ethertype) >= 1536)
+       if (ntohs(llc->ethertype) >= ETH_P_802_3_MIN)
                return llc->ethertype;
 
        return htons(ETH_P_802_2);
@@ -812,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;
@@ -823,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)) {
@@ -843,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.  */
@@ -866,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,
@@ -1152,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;
@@ -1220,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 {
@@ -1320,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;
@@ -1341,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:
@@ -1413,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 3b08ea6..dba66cf 100644 (file)
@@ -37,7 +37,6 @@ struct sk_buff;
 struct sw_flow_actions {
        struct rcu_head rcu;
        u32 actions_len;
-       int buf_size;
        struct nlattr actions[];
 };
 
@@ -152,7 +151,6 @@ void ovs_flow_deferred_free(struct sw_flow *);
 void ovs_flow_free(struct sw_flow *);
 
 struct sw_flow_actions *ovs_flow_actions_alloc(int actions_len);
-void ovs_flow_actions_free(struct sw_flow_actions *sfa);
 void ovs_flow_deferred_free_acts(struct sw_flow_actions *);
 
 int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *,
@@ -160,44 +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            (32 * 1024)
-#define MAX_ACTIONS_BUFSIZE_KMALLOC    PAGE_SIZE
+#define MAX_ACTIONS_BUFSIZE    (32 * 1024)
 #define TBL_MIN_BUCKETS                1024
 
 struct flow_table {
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 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 a05cf54..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 "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)
@@ -75,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
  *
@@ -338,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);
@@ -347,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))) {
@@ -417,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)
 {
@@ -479,39 +203,6 @@ error:
        return ERR_PTR(err);
 }
 
-static int send_frags(struct sk_buff *skb,
-                     int tunnel_hlen)
-{
-       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;
-}
-
 /* Compute source UDP port for outgoing packet.
  * Currently we use the flow hash.
  */
@@ -530,143 +221,53 @@ u16 ovs_tnl_get_src_port(struct sk_buff *skb)
 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;
-       u32 skb_mark;
-       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 */
-       skb_mark = skb_get_mark(skb);
-       rt = find_route(port_key_get_net(&mutable->key), &saddr, daddr,
-                         tnl_vport->tnl_ops->ipproto, tos, skb_mark);
+       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));
@@ -676,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;
@@ -708,122 +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, 0);
-               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 err;
 
        vport = ovs_vport_alloc(sizeof(struct tnl_vport), vport_ops, parms);
@@ -837,123 +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;
-       }
-
-       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);
 }
 
@@ -962,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 2bdfe91..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_VXLAN      3
-#define TNL_T_PROTO_LISP       4
-
-/* 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)
-
-/**
- * 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;
 };
 
 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);
@@ -191,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 */
index 680e7b3..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,35 +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))
+       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;
 
@@ -292,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)
@@ -350,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,
index 0f01395..1fff5ae 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>
@@ -94,8 +94,7 @@ struct lisphdr {
 
 #define LISP_HLEN (sizeof(struct udphdr) + sizeof(struct lisphdr))
 
-static inline int lisp_hdr_len(const struct tnl_mutable_config *mutable,
-                              const struct ovs_key_ipv4_tunnel *tun_key)
+static inline int lisp_hdr_len(const struct ovs_key_ipv4_tunnel *tun_key)
 {
        return LISP_HLEN;
 }
@@ -103,25 +102,26 @@ static inline int lisp_hdr_len(const struct tnl_mutable_config *mutable,
 /**
  * struct lisp_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 lisp_port {
        struct list_head list;
-       __be16 port;
+       struct vport *vport;
        struct socket *lisp_rcv_socket;
-       int count;
+       struct rcu_head rcu;
 };
 
 static LIST_HEAD(lisp_ports);
 
-static struct lisp_port *lisp_port_exists(struct net *net, __be16 port)
+static struct lisp_port *lisp_find_port(struct net *net, __be16 port)
 {
        struct lisp_port *lisp_port;
 
-       list_for_each_entry(lisp_port, &lisp_ports, list) {
-               if (lisp_port->port == 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;
        }
@@ -180,21 +180,16 @@ static __be64 instance_id_to_tunnel_id(__u8 *iid)
 #endif
 }
 
-static struct sk_buff *lisp_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 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;
-       __be64 out_key;
-       u32 flags;
-
-       tnl_get_param(mutable, tun_key, &flags, &out_key);
 
-       udph->dest = mutable->dst_port;
+       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));
@@ -210,34 +205,25 @@ static struct sk_buff *lisp_build_header(const struct vport *vport,
        lisph->u1.nonce[1] = 0;
        lisph->u1.nonce[2] = 0;
 
-       tunnel_id_to_instance_id(out_key, &lisph->u2.word2.instance_id[0]);
+       tunnel_id_to_instance_id(tun_key->tun_id, &lisph->u2.word2.instance_id[0]);
        lisph->u2.word2.locator_status_bits = 1;
-
-       /*
-        * 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;
 }
 
 /* Called with rcu_read_lock and BH disabled. */
 static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
 {
-       struct vport *vport;
+       struct lisp_port *lisp_port;
        struct lisphdr *lisph;
-       const struct tnl_mutable_config *mutable;
        struct iphdr *iph, *inner_iph;
        struct ovs_key_ipv4_tunnel tun_key;
        __be64 key;
-       u32 tunnel_flags = 0;
        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;
 
@@ -250,19 +236,9 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
        else
                key = instance_id_to_tunnel_id(&lisph->u2.word2.instance_id[0]);
 
-       iph = ip_hdr(skb);
-       vport = ovs_tnl_find_port(dev_net(skb->dev), iph->daddr, iph->saddr,
-               key, TNL_T_PROTO_LISP, &mutable);
-       if (unlikely(!vport))
-               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;
 
        /* Drop non-IP inner packets */
@@ -285,7 +261,7 @@ static int lisp_rcv(struct sock *sk, struct sk_buff *skb)
        ethh->h_source[0] = 0x02;
        ethh->h_proto = protocol;
 
-       ovs_tnl_rcv(vport, skb);
+       ovs_tnl_rcv(lisp_port->vport, skb);
        goto out;
 
 error:
@@ -300,6 +276,7 @@ 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);
@@ -311,7 +288,7 @@ static int lisp_socket_init(struct lisp_port *lisp_port, struct net *net)
 
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = htonl(INADDR_ANY);
-       sin.sin_port = lisp_port->port;
+       sin.sin_port = tnl_vport->dst_port;
 
        err = kernel_bind(lisp_port->lisp_rcv_socket, (struct sockaddr *)&sin,
                          sizeof(struct sockaddr_in));
@@ -332,27 +309,33 @@ error:
        return err;
 }
 
-static void lisp_tunnel_release(struct lisp_port *lisp_port)
+
+static void free_port_rcu(struct rcu_head *rcu)
 {
-       lisp_port->count--;
+       struct lisp_port *lisp_port = container_of(rcu,
+                       struct lisp_port, rcu);
 
-       if (lisp_port->count == 0) {
-               /* Release old socket */
-               sk_release_kernel(lisp_port->lisp_rcv_socket->sk);
-               list_del(&lisp_port->list);
-               kfree(lisp_port);
-       }
+       kfree(lisp_port);
 }
 
-static int lisp_tunnel_setup(struct net *net, struct nlattr *options,
-                            struct lisp_port **lport)
+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;
-       struct lisp_port *lisp_port = NULL;
-
-       *lport = NULL;
 
        if (!options) {
                err = -EINVAL;
@@ -369,11 +352,9 @@ static int lisp_tunnel_setup(struct net *net, struct nlattr *options,
        }
 
        /* Verify if we already have a socket created for this port */
-       lisp_port = lisp_port_exists(net, htons(dst_port));
+       lisp_port = lisp_find_port(net, htons(dst_port));
        if (lisp_port) {
-               lisp_port->count++;
-               err = 0;
-               *lport = lisp_port;
+               err = -EEXIST;
                goto out;
        }
 
@@ -384,55 +365,33 @@ static int lisp_tunnel_setup(struct net *net, struct nlattr *options,
                goto out;
        }
 
-       lisp_port->port = htons(dst_port);
-       lisp_port->count = 1;
-       list_add_tail(&lisp_port->list, &lisp_ports);
+       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;
 
-       *lport = lisp_port;
-       goto out;
+       return 0;
 
 error:
-       list_del(&lisp_port->list);
+       list_del_rcu(&lisp_port->list);
        kfree(lisp_port);
 out:
        return err;
 }
 
-static int lisp_tnl_set_options(struct vport *vport, struct nlattr *options)
+static int lisp_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 lisp_port *old_port = NULL;
-       struct lisp_port *lisp_port = NULL;
-
-       config = rtnl_dereference(tnl_vport->mutable);
-
-       old_port = lisp_port_exists(net, config->dst_port);
+       const struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
 
-       err = lisp_tunnel_setup(net, options, &lisp_port);
-       if (err)
-               goto out;
-
-       err = ovs_tnl_set_options(vport, options);
-
-       if (err)
-               lisp_tunnel_release(lisp_port);
-       else {
-               /* Release old socket */
-               lisp_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_lisp_tnl_ops = {
-       .tunnel_type    = TNL_T_PROTO_LISP,
        .ipproto        = IPPROTO_UDP,
        .hdr_len        = lisp_hdr_len,
        .build_header   = lisp_build_header,
@@ -442,33 +401,29 @@ static void lisp_tnl_destroy(struct vport *vport)
 {
        struct lisp_port *lisp_port;
        struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
-       struct tnl_mutable_config *config;
 
-       config = rtnl_dereference(tnl_vport->mutable);
-
-       lisp_port = lisp_port_exists(ovs_dp_get_net(vport->dp),
-                                    config->dst_port);
+       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)
 {
-       int err;
        struct vport *vport;
-       struct lisp_port *lisp_port = NULL;
-
-       err = lisp_tunnel_setup(ovs_dp_get_net(parms->dp), parms->options,
-                               &lisp_port);
-       if (err)
-               return ERR_PTR(err);
+       int err;
 
        vport = ovs_tnl_create(parms, &ovs_lisp_vport_ops, &ovs_lisp_tnl_ops);
-
        if (IS_ERR(vport))
-               lisp_tunnel_release(lisp_port);
+               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;
 }
@@ -479,8 +434,7 @@ const struct vport_ops ovs_lisp_vport_ops = {
        .create         = lisp_tnl_create,
        .destroy        = lisp_tnl_destroy,
        .get_name       = ovs_tnl_get_name,
-       .get_options    = ovs_tnl_get_options,
-       .set_options    = lisp_tnl_set_options,
+       .get_options    = lisp_get_options,
        .send           = lisp_tnl_send,
 };
 #else
index 388d9fb..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,50 +90,36 @@ static inline struct vxlanhdr *vxlan_hdr(const struct sk_buff *skb)
        return (struct vxlanhdr *)(udp_hdr(skb) + 1);
 }
 
-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->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;
@@ -148,22 +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))
-               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:
@@ -178,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);
@@ -189,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));
@@ -210,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;
@@ -246,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;
        }
 
@@ -261,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);
-
-       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);
+       const struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
 
-       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,
@@ -319,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);
 }
 
@@ -335,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;
 }
@@ -356,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 0a0835e..e9e1444 100644 (file)
@@ -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 94c9e97..074c6ee 100644 (file)
@@ -30,6 +30,10 @@ struct vport;
 struct vport_parms;
 
 /* The following definitions are for users of the vport subsytem: */
+struct vport_net {
+       struct vport __rcu *gre_vport;
+       struct vport __rcu *gre64_vport;
+};
 
 int ovs_vport_init(void);
 void ovs_vport_exit(void);
@@ -102,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
index 7bab3e0..18b0281 100644 (file)
@@ -116,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 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 63d1cac..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.
@@ -234,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. */
 
@@ -286,7 +288,6 @@ enum ovs_key_attr {
 #endif
 
        OVS_KEY_ATTR_MPLS = 62, /* struct ovs_key_mpls */
-       OVS_KEY_ATTR_TUN_ID = 63,  /* be64 tunnel ID */
        __OVS_KEY_ATTR_MAX
 };
 
@@ -324,8 +325,8 @@ 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 {
@@ -375,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];
 };
 
 /**
index c4ff904..54fc4f9 100644 (file)
@@ -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:
  *
@@ -306,6 +308,10 @@ enum nx_action_subtype {
     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. */
@@ -560,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
@@ -1745,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. */
@@ -1768,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. */
@@ -2192,4 +2222,15 @@ struct nx_action_pop_mpls {
 };
 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 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 c535a50..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. */
-/* Bit 7 was previously used for IPsec tunnel ports. */
-
-#endif /* openvswitch/tunnel.h */
index fb9dde6..8950c05 100644 (file)
@@ -132,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 \
index 1b23b39..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"
index 80d0c43..185fe19 100644 (file)
@@ -1218,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:
index 397bda1..678b8f0 100644 (file)
@@ -404,33 +404,9 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark,
         parse_mpls(&b, flow);
     }
 
-    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));
-
     /* 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;
@@ -463,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;
         }
@@ -478,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)
@@ -516,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 == 19);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     fmd->tun_id = flow->tunnel.tun_id;
     fmd->metadata = flow->metadata;
@@ -848,6 +824,14 @@ 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
@@ -872,9 +856,6 @@ flow_set_mpls_bos(struct flow *flow, uint8_t bos)
 void
 flow_compose(struct ofpbuf *b, const struct flow *flow)
 {
-    ovs_be16 inner_dl_type;
-
-    inner_dl_type = flow_innermost_dl_type(flow);
     eth_compose(b, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0);
     if (flow->dl_type == htons(FLOW_DL_TYPE_NONE)) {
         struct eth_header *eth = b->l2;
@@ -886,7 +867,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
         eth_push_vlan(b, flow->vlan_tci);
     }
 
-    if (inner_dl_type == htons(ETH_TYPE_IP)) {
+    if (flow->dl_type == htons(ETH_TYPE_IP)) {
         struct ip_header *ip;
 
         b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip);
@@ -932,10 +913,10 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
         ip->ip_tot_len = htons((uint8_t *) b->data + b->size
                                - (uint8_t *) b->l3);
         ip->ip_csum = csum(ip, sizeof *ip);
-    } else if (inner_dl_type == htons(ETH_TYPE_IPV6)) {
+    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
         /* XXX */
-    } else if (inner_dl_type == htons(ETH_TYPE_ARP) ||
-               inner_dl_type == htons(ETH_TYPE_RARP)) {
+    } else if (flow->dl_type == htons(ETH_TYPE_ARP) ||
+               flow->dl_type == htons(ETH_TYPE_RARP)) {
         struct arp_eth_header *arp;
 
         b->l3 = arp = ofpbuf_put_zeros(b, sizeof *arp);
index e6da480..6e169d6 100644 (file)
@@ -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 19
+#define FLOW_WC_SEQ 20
 
 #define FLOW_N_REGS 8
 BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
@@ -95,7 +95,6 @@ struct flow {
     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 encap_dl_type;     /* MPLS encapsulated Ethernet frame type */
     ovs_be16 tp_src;            /* TCP/UDP source port. */
     ovs_be16 tp_dst;            /* TCP/UDP destination port. */
     uint8_t dl_src[6];          /* Ethernet source address. */
@@ -106,7 +105,7 @@ 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);
 
@@ -114,7 +113,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
 
 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
 BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 160 &&
-                  FLOW_WC_SEQ == 19);
+                  FLOW_WC_SEQ == 20);
 
 /* Represents the metadata fields of struct flow. */
 struct flow_metadata {
@@ -126,19 +125,6 @@ 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);
-
-/* Returns the innermost dl_type.
- * If there's an outer and an inner type then the inner type is returned.
- * Otherwise, if there is only one type then it is returned. */
-static inline ovs_be16
-flow_innermost_dl_type(const struct flow *flow)
-{
-    return (flow->encap_dl_type == htons(0)
-            ? flow->dl_type
-            : flow->encap_dl_type);
-}
 
 void flow_zero_wildcards(struct flow *, const struct flow_wildcards *);
 void flow_get_metadata(const struct flow *, struct flow_metadata *);
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 f4b0a6c..2aa4e89 100644 (file)
@@ -849,7 +849,7 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
 
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     if (priority != OFP_DEFAULT_PRIORITY) {
         ds_put_format(s, "priority=%u,", priority);
index 234d7bc..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)
 {
@@ -283,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,
@@ -337,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,
@@ -356,7 +388,7 @@ static const struct netdev_class dummy_class = {
     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 */
index 4ea7a36..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);
index d696404..4aa8bb0 100644 (file)
@@ -329,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;
             }
@@ -446,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;
     }
@@ -521,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);
         }
     }
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 4ff516e..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 == 19);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     /* Metadata. */
     if (match->wc.masks.in_port) {
@@ -1217,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
@@ -1315,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 7bc1f6c..751c1c9 100644 (file)
@@ -96,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";
@@ -665,7 +664,6 @@ 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);
@@ -870,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) {
@@ -1120,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;
@@ -1538,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) {
@@ -1734,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) {
@@ -1748,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)) {
@@ -1825,32 +1806,16 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
                   const struct nlattr *key, size_t key_len)
 {
     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
-    ovs_be16 dl_type;
 
-    /* Parse MPLS label stack entry */
     if (eth_type_mpls(flow->dl_type)) {
-        /* Calculate fitness of outer attributes. */
         expected_attrs |= (UINT64_C(1) << OVS_KEY_ATTR_MPLS);
 
-        /* Get the MPLS LSE value. */
         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++;
-
-        if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV4)) {
-            flow->encap_dl_type = htons(ETH_TYPE_IP);
-        } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV6)) {
-            flow->encap_dl_type = htons(ETH_TYPE_IPV6);
-        } else if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ARP)) {
-            flow->encap_dl_type = htons(ETH_TYPE_ARP);
-        }
-    }
-
-    dl_type = flow_innermost_dl_type(flow);
-
-    if (dl_type == htons(ETH_TYPE_IP)) {
+    } 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;
@@ -1865,7 +1830,7 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
                 return ODP_FIT_ERROR;
             }
         }
-    } else if (dl_type == htons(ETH_TYPE_IPV6)) {
+    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_IPV6;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IPV6)) {
             const struct ovs_key_ipv6 *ipv6_key;
@@ -1881,8 +1846,8 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
                 return ODP_FIT_ERROR;
             }
         }
-    } 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)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ARP;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ARP)) {
             const struct ovs_key_arp *arp_key;
@@ -1902,8 +1867,8 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
     }
 
     if (flow->nw_proto == IPPROTO_TCP
-        && (dl_type == htons(ETH_TYPE_IP) ||
-            dl_type == htons(ETH_TYPE_IPV6))
+        && (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)) {
@@ -1914,8 +1879,8 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
             flow->tp_dst = tcp_key->tcp_dst;
         }
     } else if (flow->nw_proto == IPPROTO_UDP
-               && (dl_type == htons(ETH_TYPE_IP) ||
-                   dl_type == htons(ETH_TYPE_IPV6))
+               && (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)) {
@@ -1926,7 +1891,7 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
             flow->tp_dst = udp_key->udp_dst;
         }
     } else if (flow->nw_proto == IPPROTO_ICMP
-               && dl_type == htons(ETH_TYPE_IP)
+               && flow->dl_type == htons(ETH_TYPE_IP)
                && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ICMP;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ICMP)) {
@@ -1937,7 +1902,7 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
             flow->tp_dst = htons(icmp_key->icmp_code);
         }
     } else if (flow->nw_proto == IPPROTO_ICMPV6
-               && dl_type == htons(ETH_TYPE_IPV6)
+               && flow->dl_type == htons(ETH_TYPE_IPV6)
                && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
         expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ICMPV6;
         if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ICMPV6)) {
@@ -2072,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;
 
@@ -2209,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);
     }
 }
 
@@ -2362,16 +2319,14 @@ static void
 commit_set_nw_action(const struct flow *flow, struct flow *base,
                      struct ofpbuf *odp_actions)
 {
-    ovs_be16 dl_type = flow_innermost_dl_type(flow);
-
     /* Check if flow really have an IP header. */
     if (!flow->nw_proto) {
         return;
     }
 
-    if (dl_type == htons(ETH_TYPE_IP)) {
+    if (base->dl_type == htons(ETH_TYPE_IP)) {
         commit_set_ipv4_action(flow, base, odp_actions);
-    } else if (dl_type == htons(ETH_TYPE_IPV6)) {
+    } else if (base->dl_type == htons(ETH_TYPE_IPV6)) {
         commit_set_ipv6_action(flow, base, odp_actions);
     }
 }
@@ -2380,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;
     }
 
@@ -2444,9 +2399,13 @@ commit_odp_actions(const struct flow *flow, struct flow *base,
 {
     commit_set_ether_addr_action(flow, base, odp_actions);
     commit_vlan_action(flow, base, odp_actions);
-    commit_mpls_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 1b13e64..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.
index d6fc429..d405d2d 100644 (file)
@@ -339,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);
@@ -406,6 +416,16 @@ ofpact_from_nxast(const union ofp_action *a, enum ofputil_action_code code,
         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)) {
@@ -786,6 +806,16 @@ 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)) {
@@ -1135,7 +1165,15 @@ ofpact_check__(const struct ofpact *a, const struct flow *flow, int max_ports,
             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:
@@ -1379,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;
@@ -1549,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:
@@ -1682,6 +1741,15 @@ 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;
@@ -1706,6 +1774,8 @@ 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:
@@ -1825,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:
@@ -2044,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,
index c4e1b4a..0189c8a 100644 (file)
     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)    \
                                                                     \
@@ -302,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. */
@@ -440,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 5fda08a..e8abc9f 100644 (file)
@@ -317,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)
 {
@@ -550,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;
@@ -569,6 +591,12 @@ parse_named_action(enum ofputil_action_code code, const struct flow *flow,
         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;
     }
 }
 
index f7872cb..95d9b73 100644 (file)
@@ -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"
index dd6eed8..6b78f84 100644 (file)
@@ -84,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 == 19);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     /* Initialize most of wc. */
     flow_wildcards_init_catchall(wc);
@@ -1058,7 +1058,7 @@ ofputil_usable_protocols(const struct match *match)
 {
     const struct flow_wildcards *wc = &match->wc;
 
-    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 19);
+    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)) {
@@ -2345,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);
@@ -2424,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);
index ff7e1b3..b7dde48 100644 (file)
@@ -30,6 +30,8 @@ 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")
@@ -48,6 +50,8 @@ 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")
@@ -63,6 +67,8 @@ 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")
 
index fd10da3..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.
@@ -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()
index bae3c0a..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.
@@ -52,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 fbf4bba..116aa86 100644 (file)
@@ -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
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 a39cddf..77aa7d3 100644 (file)
@@ -259,7 +259,7 @@ static bool is_mpls(struct ofpbuf *packet)
 }
 
 /* Set time to live (TTL) of an MPLS label stack entry (LSE). */
-static void
+void
 set_mpls_lse_ttl(ovs_be32 *lse, uint8_t ttl)
 {
     *lse &= ~htonl(MPLS_TTL_MASK);
@@ -887,8 +887,7 @@ 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)
 {
-    ovs_be16 dl_type = flow_innermost_dl_type(flow);
-    if (dl_type_is_ip_any(dl_type) &&
+    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);
index 0f97fe6..b73ff63 100644 (file)
@@ -155,6 +155,7 @@ 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);
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 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 2f00355..6e41514 100644 (file)
@@ -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);
     }
 
@@ -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,
@@ -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 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 1a9dc21..b8cdfa5 100644 (file)
@@ -1189,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);
index a4d7e59..47830c1 100644 (file)
@@ -78,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;
@@ -118,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 *);
@@ -216,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;
@@ -285,9 +290,28 @@ struct action_xlate_ctx {
     bool exit;                  /* No further actions should be processed. */
 };
 
+/* 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,
@@ -341,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. */
@@ -365,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
@@ -384,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);
@@ -473,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 *,
@@ -496,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 *);
 
@@ -576,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;
@@ -647,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;
@@ -672,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];
@@ -696,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.) */
@@ -719,8 +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 *);
+                          const struct ofpbuf *,
+                          const struct initial_vals *, struct ds *);
 
 /* Packet processing. */
 static void update_learning_table(struct ofproto_dpif *,
@@ -830,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;
@@ -843,6 +923,16 @@ 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;
@@ -920,16 +1010,17 @@ type_run(const char *type)
         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;
             }
 
-            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();
                 }
             }
         }
@@ -997,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.
      *
@@ -1019,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;
         }
@@ -1030,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)
 {
@@ -1225,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];
@@ -1273,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;
 }
 
@@ -1446,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,
@@ -1786,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. */
 
@@ -2861,6 +2995,8 @@ mirror_get_stats(struct ofproto *ofproto_, void *aux,
         return 0;
     }
 
+    push_all_stats();
+
     *packets = mirror->packet_count;
     *bytes = mirror->byte_count;
 
@@ -3119,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) {
@@ -3288,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;
@@ -3296,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. */
 };
@@ -3376,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
@@ -3386,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;
@@ -3469,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);
@@ -3530,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;
@@ -3552,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;
@@ -3660,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
@@ -3676,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;
@@ -3688,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) {
@@ -3793,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;
 
@@ -3822,6 +3961,8 @@ 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);
 
@@ -3858,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);
 }
@@ -4032,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);
@@ -4093,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
@@ -4125,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)
@@ -4147,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;
 
@@ -4168,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);
 }
@@ -4366,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;
 }
 
@@ -4438,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
@@ -4448,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,
@@ -4459,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;
@@ -4478,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) {
@@ -4608,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)
 {
@@ -4693,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);
 
@@ -4731,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) {
@@ -4770,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)
 {
@@ -4791,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.
@@ -4809,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);
 
@@ -4911,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)
 {
@@ -4926,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);
@@ -4948,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;
         }
     }
@@ -4990,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;
@@ -5009,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;
@@ -5025,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;
 }
 
@@ -5039,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);
@@ -5068,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];
     }
@@ -5089,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();
     }
 }
 
@@ -5123,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;
@@ -5158,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;
@@ -5174,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);
@@ -5202,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);
@@ -5269,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);
     }
 }
@@ -5429,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;
@@ -5448,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;
@@ -5458,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);
@@ -5735,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 == 19);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 20);
 
     if (!ofport) {
         xlate_report(ctx, "Nonexistent output port");
@@ -5808,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) {
@@ -5823,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);
@@ -5846,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);
@@ -6052,7 +6243,6 @@ execute_mpls_push_action(struct action_xlate_ctx *ctx, ovs_be16 eth_type)
         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.encap_dl_type = ctx->flow.dl_type;
         ctx->flow.mpls_depth = 1;
     }
     ctx->flow.dl_type = eth_type;
@@ -6069,7 +6259,6 @@ execute_mpls_pop_action(struct action_xlate_ctx *ctx, ovs_be16 eth_type)
         ctx->flow.mpls_lse = htonl(0);
         if (!ctx->flow.mpls_depth) {
             ctx->flow.dl_type = eth_type;
-            ctx->flow.encap_dl_type = htons(0);
         }
     }
 }
@@ -6098,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)
@@ -6316,6 +6537,24 @@ 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)
@@ -6328,6 +6567,8 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
         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;
@@ -6386,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:
@@ -6402,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:
@@ -6433,6 +6682,16 @@ 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;
@@ -6441,6 +6700,18 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
             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;
@@ -6495,11 +6766,34 @@ 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;
         }
         }
@@ -6514,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;
@@ -6544,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;
@@ -6590,6 +6886,8 @@ 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. */
@@ -6625,12 +6923,15 @@ xlate_actions(struct action_xlate_ctx *ctx,
         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);
 
-        if (!in_port || may_receive(in_port, 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
@@ -6650,7 +6951,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
                 struct ds ds = DS_EMPTY_INITIALIZER;
 
                 ofproto_trace(ctx->ofproto, &orig_flow, ctx->packet,
-                              initial_tci, &ds);
+                              &initial_vals, &ds);
                 VLOG_ERR("Trace triggered by excessive resubmit "
                          "recursion:\n%s", ds_cstr(&ds));
                 ds_destroy(&ds);
@@ -6674,6 +6975,8 @@ xlate_actions(struct action_xlate_ctx *ctx,
         }
         fix_sflow_action(ctx);
     }
+
+    ofpbuf_uninit(&ctx->stack);
 }
 
 /* Translates the 'ofpacts_len' bytes of "struct ofpact"s starting at 'ofpacts'
@@ -7370,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;
 
@@ -7385,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;
 
@@ -7625,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;
@@ -7666,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;
 
@@ -7686,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. */
@@ -7720,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:
@@ -7737,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;
 
@@ -7768,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;
@@ -7939,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++) {
@@ -8064,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);
@@ -8084,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');
     }
 
@@ -8363,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,
@@ -8414,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 a9c7e76..03ca59b 100644 (file)
@@ -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
index 3a66d1b..b3a55a4 100644 (file)
@@ -33,7 +33,6 @@
 extern "C" {
 #endif
 
-struct cfm_settings;
 struct cls_rule;
 struct netdev;
 struct ofproto;
@@ -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,
@@ -356,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 7d45930..8aa7fbe 100644 (file)
 
 /* XXX:
  *
- * Ability to generate actions on input for ECN
  * Ability to generate metadata for packet-outs
- * VXLAN.
- * Multicast group management (possibly).
  * Disallow netdevs with names like "gre64_system" to prevent collisions. */
 
 VLOG_DEFINE_THIS_MODULE(tunnel);
 
-/* skb mark used for IPsec tunnel packets */
-#define IPSEC_MARK 1
-
 struct tnl_match {
     ovs_be64 in_key;
     ovs_be32 ip_src;
@@ -199,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);
     }
@@ -322,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 */
@@ -342,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;
 }
 
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 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 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 bd1c259..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.
@@ -353,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 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 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 b11e0a2..275ff53 100644 (file)
@@ -232,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)
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 49f3bb1..0bcd4b3 100644 (file)
@@ -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 dcf7465..95cfba8 100644 (file)
@@ -90,7 +90,6 @@ userspace(pid=9765,slow_path(cfm))
 userspace(pid=9765,slow_path(cfm,match))
 userspace(pid=9123,userdata=0x815309)
 userspace(pid=1234567,userdata(0102030405060708090a0b0c0d0e0f))
-set(tun_id(0x7f10354))
 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 2939125..35f599c 100644 (file)
@@ -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 8f11b82..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])
@@ -233,6 +267,10 @@ 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
@@ -355,6 +393,82 @@ NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len
 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])
 
@@ -395,22 +509,29 @@ mplsm(label:1000,tc:7,ttl:64,bos:1),metadata=0,in_port=0,vlan_tci=0x0000,dl_src=
 
 
 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 '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),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no)'
+    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=56 in_port=1 (via action) data_len=56 (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 tcp_csum:0
+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=56 in_port=1 (via action) data_len=56 (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 tcp_csum:0
+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=56 in_port=1 (via action) data_len=56 (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 tcp_csum:0
+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.
@@ -487,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
@@ -500,9 +622,13 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
  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=180, dl_src=60:66:66:66:66:66 actions=pop_mpls:0x0800,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:
 ])
@@ -1080,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.
@@ -1354,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)
@@ -1391,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
@@ -1416,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])
@@ -1429,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
@@ -1455,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)
@@ -1491,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 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 7395fd1..075f2e4 100644 (file)
@@ -243,6 +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=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])
@@ -271,6 +272,7 @@ 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=push:NXM_NX_REG0[],pop:NXM_NX_REG0[]
 NXT_FLOW_MOD: ADD NXM_OF_VLAN_TCI_W(1123/1fff) actions=drop
 ]])
 AT_CLEANUP
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 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 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);
+}
index 55fd5b3..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)
@@ -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)
@@ -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 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 c5a4366..ffaf753 100755 (executable)
@@ -549,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')
@@ -575,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)
@@ -597,7 +596,7 @@ exclude those logs from the archive.
         '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-xapi-sync.log', 'ovs-monitor-ipsec.log', 'ovs-ctl.log']])
     log_output(CAP_SYSTEM_LOGS, system_logs)
     log_output(CAP_OPENVSWITCH_LOGS, ovs_logs)
 
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 e186e71..5ad5f26 100755 (executable)
@@ -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
 }
 
@@ -275,7 +275,6 @@ ovs_save () {
         chmod +x "$2"
         return 0
     fi
-    eval $3=""
     [ -z "${bridges}" ] && return 0
 }
 
@@ -284,10 +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=""
+                "${script_ofports}"
             ;;
     esac
 }
@@ -298,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
 
@@ -354,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"
 }
@@ -372,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
@@ -386,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 363485b..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[])
 {
@@ -1004,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 6589eff..3cc618d 100644 (file)
@@ -962,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
@@ -1018,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
@@ -1050,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
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 ab0ecd6..6dc3db2 100644 (file)
@@ -318,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);
@@ -345,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);
@@ -1698,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)) {
@@ -1721,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);
     }
@@ -1731,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
@@ -1743,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);
+        }
     }
 }
 
@@ -2019,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;
@@ -2078,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.
  *
@@ -2254,7 +2312,7 @@ bridge_run(void)
     }
 
     run_system_stats();
-    refresh_instant_stats();
+    instant_stats_run();
 }
 
 void
@@ -2286,6 +2344,7 @@ bridge_wait(void)
     }
 
     system_stats_wait();
+    instant_stats_wait();
 }
 
 /* Adds some memory usage statistics for bridges into 'usage', for use with
@@ -3342,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 a7901a8..594ffb4 100644 (file)
@@ -1,6 +1,6 @@
 {"name": "Open_vSwitch",
- "version": "7.0.0",
- "cksum": "3537583872 17299",
+ "version": "7.1.0",
+ "cksum": "2234055133 17444",
  "tables": {
    "Open_vSwitch": {
      "columns": {
        "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 e1d9372..2af04bd 100644 (file)
         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>
       </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">
           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 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 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))