Merge branch 'mainstream'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Sun, 24 Nov 2013 08:34:46 +0000 (09:34 +0100)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Sun, 24 Nov 2013 08:34:46 +0000 (09:34 +0100)
32 files changed:
AUTHORS
BUILD.Windows [new file with mode: 0644]
COPYING
FAQ
Makefile.am
build-aux/cccl [new file with mode: 0644]
datapath/linux/compat/gre.c
datapath/linux/compat/include/net/gre.h
debian/copyright.in
debian/openvswitch-switch.init
include/openflow/openflow-1.2.h
lib/bfd.c
lib/bfd.h
lib/coverage.c
lib/coverage.h
lib/ofp-actions.c
lib/ofp-actions.h
lib/ofp-msgs.h
lib/ofp-parse.c
lib/ofp-parse.h
lib/ofp-util.c
ofproto/ofproto-dpif.c
tests/bfd.at
tests/learn.at
tests/ofp-actions.at
tests/ofproto-dpif.at
tests/ovs-ofctl.at
tests/test-controller.c
utilities/ovs-ofctl.c
vswitchd/bridge.c
vswitchd/vswitch.ovsschema
vswitchd/vswitch.xml

diff --git a/AUTHORS b/AUTHORS
index 1b508af..76951e7 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -40,6 +40,7 @@ Ethan Jackson           ethan@nicira.com
 Flavio Leitner          fbl@redhat.com
 FUJITA Tomonori         fujita.tomonori@lab.ntt.co.jp
 Gaetano Catalli         gaetano.catalli@gmail.com
+Geoffrey Wossum         gwossum@acm.org
 Giuseppe Lettieri       g.lettieri@iet.unipi.it
 Glen Gibb               grg@stanford.edu
 Guolin Yang             gyang@nicira.com
@@ -83,6 +84,7 @@ Pravin B Shelar         pshelar@nicira.com
 Raju Subramanian        rsubramanian@nicira.com
 Ravi Kerur              Ravi.Kerur@telekom.com
 Reid Price              reid@nicira.com
+Remko Tronçon           git@el-tramo.be
 Rich Lane               rlane@bigswitch.com
 Rob Hoes                rob.hoes@citrix.com
 Romain Lenglet          romain.lenglet@berabera.info
@@ -106,6 +108,7 @@ Tyler Coumbes           coumbes@gmail.com
 Valient Gough           vgough@pobox.com
 Vivien Bernet-Rollande  vbr@soprive.net
 Wei Yongjun             yjwei@cn.fujitsu.com
+William Fulton
 Yasuhito Takamiya       yasuhito@gmail.com
 Yu Zhiguo               yuzg@cn.fujitsu.com
 ZhengLingyun            konghuarukhr@163.com
diff --git a/BUILD.Windows b/BUILD.Windows
new file mode 100644 (file)
index 0000000..7012bcf
--- /dev/null
@@ -0,0 +1,38 @@
+Open vSwitch support on Windows is a work in progress.  This file describes
+the planned build system to compile Open vSwitch on Windows.  Once the work
+is complete, this file will be replaced by a INSTALL.Windows file.
+
+Autoconf, Automake and Visual C++:
+---------------------------------
+Open vSwitch on Linux uses autoconf and automake for generating Makefiles.
+It will be useful to maintain the same build system while compiling on Windows
+too.  One approach is to compile Open vSwitch in a MinGW environment that
+contains autoconf and automake utilities and then use Visual C++ as a compiler
+and linker.
+
+The following explains the steps in some detail.
+* Install Mingw on a Windows machine by following the instructions at:
+http://www.mingw.org/wiki/Getting_Started
+
+This should install mingw at C:\Mingw and msys at C:\Mingw\msys.
+Add "C:\MinGW\bin" and "C:\Mingw\msys\1.0\bin" to PATH environment variable
+of Windows.
+
+You can either use the MinGW installer or the command line utility 'mingw-get'
+to install both the base packages and additional packages like automake and
+autoconf(version 2.68).
+
+* Install the latest Python 2.x from python.org and verify that its path is
+part of Windows' PATH environment variable.
+
+* It is important to get the Visual Studio related environment variables and
+to have the $PATH inside the bash to point to the proper compiler and linker.
+One easy way to achieve this is to get into the "Developer Command prompt for
+visual studio" and through it enter into the bash shell available from msys.
+
+* Get the Open vSwitch sources from either cloning the repo using git
+or from a distribution tar ball.
+
+* Run ./boot.sh; ./configure CC=./build-aux/cccl; make
+(cccl is a wrapper script that provides the right options to Visual c++
+'cl' compiler.)
diff --git a/COPYING b/COPYING
index 22c9341..6b28b0e 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -19,6 +19,9 @@ Most files are licensed under the Apache License, Version 2.0:
 Files under the datapath directory are licensed under the GNU General
 Public License, version 2.
 
+File build-aux/cccl is licensed under the GNU General Public
+License, version 2.
+
 Files under the xenserver directory are licensed on a file-by-file
 basis.  Refer to each file for details.
 
diff --git a/FAQ b/FAQ
index 4a8a5be..2912ae3 100644 (file)
--- a/FAQ
+++ b/FAQ
@@ -418,7 +418,11 @@ A: First, why do you want to do this?  Two connected bridges are not
    ports will not work with the userspace datapath, only with the
    kernel module.
 
-Q: Why are there so many different ways to dump flows?
+
+Implementation Details
+----------------------
+
+Q: I hear OVS has a couple of kinds of flows.  Can you tell me about them?
 
 A: Open vSwitch uses different kinds of flows for different purposes:
 
@@ -434,18 +438,27 @@ A: Open vSwitch uses different kinds of flows for different purposes:
         about hidden flows.)
 
       - The Open vSwitch software switch implementation uses a second
-        kind of flow internally.  These flows, called "exact-match"
-        or "datapath" or "kernel" flows, do not support wildcards or
-        priorities and comprise only a single table, which makes them
-        suitable for caching.   OpenFlow flows and exact-match flows
+        kind of flow internally.  These flows, called "datapath" or
+        "kernel" flows, do not support priorities and comprise only a
+        single table, which makes them suitable for caching.  (Like
+        OpenFlow flows, datapath flows do support wildcarding, in Open
+        vSwitch 1.11 and later.)  OpenFlow flows and datapath flows
         also support different actions and number ports differently.
 
-        Exact-match flows are an implementation detail that is
-        subject to change in future versions of Open vSwitch.  Even
-        with the current version of Open vSwitch, hardware switch
-        implementations do not necessarily use exact-match flows.
+        Datapath flows are an implementation detail that is subject to
+        change in future versions of Open vSwitch.  Even with the
+        current version of Open vSwitch, hardware switch
+        implementations do not necessarily use this architecture.
+
+   Users and controllers directly control only the OpenFlow flow
+   table.  Open vSwitch manages the datapath flow table itself, so
+   users should not normally be concerned with it.
+
+Q: Why are there so many different ways to dump flows?
 
-  Each of the commands for dumping flows has a different purpose:
+A: Open vSwitch has two kinds of flows (see the previous question), so
+   it has commands with different purposes for dumping each kind of
+   flow:
 
       - "ovs-ofctl dump-flows <br>" dumps OpenFlow flows, excluding
         hidden flows.  This is the most commonly useful form of flow
@@ -456,7 +469,7 @@ A: Open vSwitch uses different kinds of flows for different purposes:
         including hidden flows.  This is occasionally useful for
         troubleshooting suspected issues with in-band control.
 
-      - "ovs-dpctl dump-flows [dp]" dumps the exact-match flow table
+      - "ovs-dpctl dump-flows [dp]" dumps the datapath flow table
         entries for a Linux kernel-based datapath.  In Open vSwitch
         1.10 and later, ovs-vswitchd merges multiple switches into a
         single datapath, so it will show all the flows on all your
@@ -464,8 +477,8 @@ A: Open vSwitch uses different kinds of flows for different purposes:
         useful for debugging.
 
       - "ovs-appctl dpif/dump-flows <br>", new in Open vSwitch 1.10,
-        dumps exact-match flows for only the specified bridge,
-        regardless of the type.
+        dumps datapath flows for only the specified bridge, regardless
+        of the type.
 
 
 Performance
index 0af7b46..135e58f 100644 (file)
@@ -47,6 +47,7 @@ CLEAN_LOCAL =
 DISTCLEANFILES =
 PYCOV_CLEAN_FILES = build-aux/check-structs,cover
 EXTRA_DIST = \
+       BUILD.Windows \
        CodingStyle \
        DESIGN \
        FAQ \
@@ -70,6 +71,7 @@ EXTRA_DIST = \
        SubmittingPatches \
        WHY-OVS \
        boot.sh \
+       build-aux/cccl \
        build-aux/sodepends.pl \
        build-aux/soexpand.pl \
        $(MAN_FRAGMENTS) \
diff --git a/build-aux/cccl b/build-aux/cccl
new file mode 100644 (file)
index 0000000..c614ecb
--- /dev/null
@@ -0,0 +1,201 @@
+#!/bin/sh
+
+# cccl
+# Wrapper around MS's cl.exe and link.exe to make them act more like
+# Unix cc and ld
+#
+# Copyright (C) 2000-2003 Geoffrey Wossum (gwossum@acm.org)
+#
+# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+usage()
+{
+    cat <<EOF
+Usage: cccl [OPTIONS]
+
+cccl is a wrapper around Microsoft's cl.exe and link.exe.  It translates
+parameters that Unix cc's and ld's understand to parameters that cl and link
+understand.
+EOF
+    exit $1
+}
+
+# Put /usr/bin last in the path, to avoid clashes with MSVC's link
+# Ugly workaround, but should work
+PATH=`echo $PATH | sed -e "s#/usr/bin:##" | sed -e "s#/bin:##"`:/usr/bin
+
+case $MACHTYPE in
+    *-msys)
+        slash="-"
+        ;;
+    *)
+        slash="/"
+        ;;
+esac
+# prog specifies the program that should be run (cl.exe or link.exe)
+# We'll assume cl to start out
+prog=cl
+# opts specifies the command line to pass to the MSVC program
+clopt="${slash}nologo"
+linkopt="${slash}nologo"
+# gotparam is 0 if we didn't ever see a param, in which case we show usage()
+gotparam=
+
+# We want exceptions
+clopt="$clopt ${slash}EHsc"
+
+### Run through every option and convert it to the proper MS one
+while test $# -gt 0; do
+    case "$1" in
+    -D*) optarg= ;;
+    -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+    *) optarg= ;;
+    esac
+    gotparam=1
+
+    case "$1" in
+    --version)
+        cat <<EOF
+cccl 0.03
+
+Copyright 2000-2003 Geoffrey Wossum
+This is free software; see the source for copying conditions.  There is NO
+waranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+EOF
+        exit 1;
+        ;;
+
+    -ansi)
+        clopt="$clopt ${slash}Za"
+        ;;
+
+    -c)
+        # -c (compile only) is actually the same, but for clarity...
+        clopt="$clopt ${slash}c"
+        ;;
+
+    -g[0-9] | -g)
+        # cl only supports one debugging level
+        clopt="$clopt ${slash}Zi"
+        ;;
+
+    -L*)
+        path=`echo "$1" | sed 's/-L//'`
+        linkopt="$linkopt /LIBPATH:$path"
+        ;;
+
+    -l*)
+        lib=`echo "$1" | sed 's/-l//'`
+    if [ $lib != "dnsapi" -a $lib != "ws2_32" -a $lib != "wsock32" ]; then
+      lib="lib$lib.lib"
+    else
+      lib="$lib.lib"
+    fi
+
+        clopt="$clopt $lib"
+        linkopt="$linkopt $lib"
+        ;;
+
+    -m386)
+        clopt="$clopt ${slash}G3"
+        ;;
+
+    -m486)
+        clopt="$clopt ${slash}G4"
+        ;;
+
+    -mpentium)
+        clopt="$clopt ${slash}G5"
+        ;;
+
+    -mpentiumpro)
+        clopt="$clopt ${slash}G6"
+        ;;
+
+    -o)
+        # specifying output file, is it an object or an executable
+        shift
+        case "$1" in
+        *.o | *.obj)
+            clopt="$clopt ${slash}Fo$1"
+        ;;
+        *)
+            clopt="$clopt ${slash}Fe$1";
+            linkopt="$linkopt ${slash}out:$1"
+        ;;
+        esac;;
+
+    -pedantic)
+        #ignore pedantic
+        ;;
+
+    -W*)
+        #ignore warnings
+        ;;
+
+    -isystem)
+        shift
+        clopt="$clopt -I$1"
+        ;;
+
+    -MT)
+        exit 0
+        ;;
+
+    -mno-cygwin)
+        ;;
+
+    *.cc | *.cxx | *.C)
+        # C++ source file with non .cpp extension, make sure cl understand
+        # that it is C++
+        clopt="$clopt ${slash}Tp$1"
+        ;;
+
+    *.o | *.obj | *.a | *.lib)
+        # Object files/libraries seen, this command will require link
+        # Switch the prog to link
+        linkopt="$linkopt $1"
+        prog="link"
+        ;;
+
+    *)
+        clopt="$clopt $1"
+        linkopt="$linkopt $1"
+        if test x$optarg != x ; then
+            clopt="$clopt=$optarg"
+            linkopt="$linkopt=$optarg"
+        fi
+        ;;
+
+    esac
+    shift
+done
+
+if test x$gotparam = x ; then
+    usage
+    exit 1
+fi
+
+# choose which opts we built up based on which program will actually run
+if test x$prog = xcl ; then
+    opts=$clopt
+else
+    opts=$linkopt
+fi
+
+echo "$prog $opts"
+exec $prog $opts
+exit 0
index 582bd94..f35f11f 100644 (file)
@@ -39,8 +39,6 @@
 
 #include "gso.h"
 
-static struct gre_cisco_protocol __rcu *gre_cisco_proto;
-
 static void gre_csum_fix(struct sk_buff *skb)
 {
        struct gre_base_hdr *greh;
@@ -114,6 +112,8 @@ void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
        }
 }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
+
 static __sum16 check_checksum(struct sk_buff *skb)
 {
        __sum16 csum = 0;
@@ -197,6 +197,8 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
        return iptunnel_pull_header(skb, hdr_len, tpi->proto);
 }
 
+static struct gre_cisco_protocol __rcu *gre_cisco_proto;
+
 static int gre_cisco_rcv(struct sk_buff *skb)
 {
        struct tnl_ptk_info tpi;
@@ -354,4 +356,6 @@ int gre_cisco_unregister(struct gre_cisco_protocol *proto)
        return ret;
 }
 
+#endif /* 3.11 */
+
 #endif /* CONFIG_NET_IPGRE_DEMUX */
index 5b17dcc..91fb7af 100644 (file)
@@ -73,6 +73,8 @@ static inline __be16 tnl_flags_to_gre_flags(__be16 tflags)
 }
 #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) */
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
+/* GRE demux not available, implement our own demux. */
 #define MAX_GRE_PROTO_PRIORITY 255
 #define gre_cisco_protocol rpl_gre_cisco_protocol
 
@@ -87,6 +89,8 @@ int gre_cisco_register(struct gre_cisco_protocol *proto);
 #define gre_cisco_unregister rpl_gre_cisco_unregister
 int gre_cisco_unregister(struct gre_cisco_protocol *proto);
 
+#endif
+
 #define gre_build_header rpl_gre_build_header
 void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
                      int hdr_len);
index c6631d5..986f7a1 100644 (file)
@@ -13,6 +13,7 @@ Upstream Copyright Holders:
        Copyright (c) 2008,2009,2010 Citrix Systems, Inc.
        and authors listed above.
        Copyright (c) 2011 Gaetano Catalli
+       Copyright (C) 2000-2003 Geoffrey Wossum (gwossum@acm.org)
 
 License:
 
@@ -72,6 +73,11 @@ License:
   On Debian systems, the complete text of the GNU General Public License
   version 2 can be found in `/usr/share/common-licenses/GPL-2'
 
+* The following file is licensed under the GNU General Public License
+  version 2.
+
+       build-aux/cccl
+
 * The following components are dual-licensed under the
   GNU General Public License version 2 and the Apache License Version 2.0.
 
index 84aa450..481b29c 100755 (executable)
@@ -31,6 +31,7 @@
 test -e /etc/default/openvswitch-switch && . /etc/default/openvswitch-switch
 
 network_interfaces () {
+    [ -z "${RUNLEVEL}" ] && return
     INTERFACES="/etc/network/interfaces"
     [ -e "${INTERFACES}" ] || return
     bridges=`awk '{ if ($1 == "allow-ovs") { print $2; } }' "${INTERFACES}"`
index 694cd55..54b9804 100644 (file)
@@ -179,8 +179,8 @@ enum oxm12_ofb_match_fields {
 #define OXM_OF_MPLS_LABEL     OXM_HEADER   (OFPXMT12_OFB_MPLS_LABEL, 4)
 #define OXM_OF_MPLS_TC        OXM_HEADER   (OFPXMT12_OFB_MPLS_TC, 1)
 #define OXM_OF_MPLS_BOS       OXM_HEADER   (OFPXMT13_OFB_MPLS_BOS, 1)
-#define OXM_OF_PBB_ISID       OXM_HEADER   (OFPXMT12_OFB_PBB_ISID, 4)
-#define OXM_OF_PBB_ISID_W     OXM_HEADER_W (OFPXMT12_OFB_PBB_ISID, 4)
+#define OXM_OF_PBB_ISID       OXM_HEADER   (OFPXMT12_OFB_PBB_ISID, 3)
+#define OXM_OF_PBB_ISID_W     OXM_HEADER_W (OFPXMT12_OFB_PBB_ISID, 3)
 #define OXM_OF_TUNNEL_ID      OXM_HEADER   (OFPXMT13_OFB_TUNNEL_ID, 8)
 #define OXM_OF_TUNNEL_ID_W    OXM_HEADER_W (OFPXMT13_OFB_TUNNEL_ID, 8)
 #define OXM_OF_IPV6_EXTHDR    OXM_HEADER   (OFPXMT13_OFB_IPV6_EXTHDR, 2)
index 740f4fc..4582f2e 100644 (file)
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -187,6 +187,7 @@ struct bfd {
     long long int next_tx;        /* Next TX time. */
     long long int detect_time;    /* RFC 5880 6.8.4 Detection time. */
 
+    bool forwarding;              /* Interface capability of packet I/O. */
     int forwarding_override;      /* Manual override of 'forwarding' status. */
 
     atomic_bool check_tnl_key;    /* Verify tunnel key of inbound packets? */
@@ -206,13 +207,15 @@ struct bfd {
                                   /* detect interval. */
     uint64_t decay_rx_packets;    /* Packets received by 'netdev'. */
     long long int decay_detect_time; /* Decay detection time. */
+
+    uint64_t flap_count;          /* Counts bfd forwarding flaps. */
 };
 
 static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
 static struct hmap all_bfds__ = HMAP_INITIALIZER(&all_bfds__);
 static struct hmap *const all_bfds OVS_GUARDED_BY(mutex) = &all_bfds__;
 
-static bool bfd_forwarding__(const struct bfd *) OVS_REQUIRES(mutex);
+static bool bfd_forwarding__(struct bfd *) OVS_REQUIRES(mutex);
 static bool bfd_in_poll(const struct bfd *) OVS_REQUIRES(mutex);
 static void bfd_poll(struct bfd *bfd) OVS_REQUIRES(mutex);
 static const char *bfd_diag_str(enum diag) OVS_REQUIRES(mutex);
@@ -246,7 +249,7 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 20);
 /* Returns true if the interface on which 'bfd' is running may be used to
  * forward traffic according to the BFD session state. */
 bool
-bfd_forwarding(const struct bfd *bfd) OVS_EXCLUDED(mutex)
+bfd_forwarding(struct bfd *bfd) OVS_EXCLUDED(mutex)
 {
     bool ret;
 
@@ -263,9 +266,10 @@ bfd_get_status(const struct bfd *bfd, struct smap *smap)
     OVS_EXCLUDED(mutex)
 {
     ovs_mutex_lock(&mutex);
-    smap_add(smap, "forwarding", bfd_forwarding__(bfd)? "true" : "false");
+    smap_add(smap, "forwarding", bfd->forwarding ? "true" : "false");
     smap_add(smap, "state", bfd_state_str(bfd->state));
     smap_add(smap, "diagnostic", bfd_diag_str(bfd->diag));
+    smap_add_format(smap, "flap_count", "%"PRIu64, bfd->flap_count);
 
     if (bfd->state != STATE_DOWN) {
         smap_add(smap, "remote_state", bfd_state_str(bfd->rmt_state));
@@ -312,6 +316,7 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
     if (!bfd) {
         bfd = xzalloc(sizeof *bfd);
         bfd->name = xstrdup(name);
+        bfd->forwarding = false;
         bfd->forwarding_override = -1;
         bfd->disc = generate_discriminator();
         hmap_insert(all_bfds, &bfd->node, bfd->disc);
@@ -323,6 +328,7 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
         bfd->netdev = netdev_ref(netdev);
         bfd->rx_packets = bfd_rx_packets(bfd);
         bfd->in_decay = false;
+        bfd->flap_count = 0;
 
         /* RFC 5881 section 4
          * The source port MUST be in the range 49152 through 65535.  The same
@@ -805,21 +811,28 @@ bfd_set_netdev(struct bfd *bfd, const struct netdev *netdev)
 }
 
 \f
+/* Updates the forwarding flag.  If override is not configured and
+ * the forwarding flag value changes, increments the flap count. */
 static bool
-bfd_forwarding__(const struct bfd *bfd) OVS_REQUIRES(mutex)
+bfd_forwarding__(struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     long long int time;
+    bool forwarding_old = bfd->forwarding;
 
     if (bfd->forwarding_override != -1) {
         return bfd->forwarding_override == 1;
     }
 
     time = bfd->forwarding_if_rx_detect_time;
-    return (bfd->state == STATE_UP
-            || (bfd->forwarding_if_rx && time > time_msec()))
-           && bfd->rmt_diag != DIAG_PATH_DOWN
-           && bfd->rmt_diag != DIAG_CPATH_DOWN
-           && bfd->rmt_diag != DIAG_RCPATH_DOWN;
+    bfd->forwarding = (bfd->state == STATE_UP
+                       || (bfd->forwarding_if_rx && time > time_msec()))
+                       && bfd->rmt_diag != DIAG_PATH_DOWN
+                       && bfd->rmt_diag != DIAG_CPATH_DOWN
+                       && bfd->rmt_diag != DIAG_RCPATH_DOWN;
+    if (bfd->forwarding != forwarding_old) {
+        bfd->flap_count++;
+    }
+    return bfd->forwarding;
 }
 
 /* Helpers. */
@@ -1020,6 +1033,9 @@ bfd_set_state(struct bfd *bfd, enum state state, enum diag diag)
             bfd_decay_update(bfd);
         }
     }
+
+    /* Updates the forwarding flag. */
+    bfd_forwarding__(bfd);
 }
 
 static uint64_t
@@ -1084,12 +1100,13 @@ bfd_check_rx(struct bfd *bfd) OVS_REQUIRES(mutex)
     }
 }
 
-/* Updates the forwarding_if_rx_detect_time. */
+/* Updates the forwarding_if_rx_detect_time and the forwarding flag. */
 static void
 bfd_forwarding_if_rx_update(struct bfd *bfd) OVS_REQUIRES(mutex)
 {
     int64_t incr = bfd_rx_interval(bfd) * bfd->mult;
     bfd->forwarding_if_rx_detect_time = MAX(incr, 2000) + time_msec();
+    bfd_forwarding__(bfd);
 }
 
 static uint32_t
@@ -1135,8 +1152,7 @@ bfd_find_by_name(const char *name) OVS_REQUIRES(mutex)
 static void
 bfd_put_details(struct ds *ds, const struct bfd *bfd) OVS_REQUIRES(mutex)
 {
-    ds_put_format(ds, "\tForwarding: %s\n",
-                  bfd_forwarding__(bfd) ? "true" : "false");
+    ds_put_format(ds, "\tForwarding: %s\n", bfd->forwarding ? "true" : "false");
     ds_put_format(ds, "\tDetect Multiplier: %d\n", bfd->mult);
     ds_put_format(ds, "\tConcatenated Path Down: %s\n",
                   bfd->cpath_down ? "true" : "false");
index f49a3d6..0ad86e9 100644 (file)
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -46,7 +46,7 @@ struct bfd *bfd_configure(struct bfd *, const char *name,
 struct bfd *bfd_ref(const struct bfd *);
 void bfd_unref(struct bfd *);
 
-bool bfd_forwarding(const struct bfd *);
+bool bfd_forwarding(struct bfd *);
 void bfd_get_status(const struct bfd *, struct smap *);
 void bfd_set_netdev(struct bfd *, const struct netdev *);
 long long int bfd_wake_time(const struct bfd *);
index 4364734..80316ef 100644 (file)
@@ -63,6 +63,7 @@ struct coverage_counter *coverage_counters[] = {
 
 static struct ovs_mutex coverage_mutex = OVS_MUTEX_INITIALIZER;
 
+DEFINE_STATIC_PER_THREAD_DATA(long long int, coverage_clear_time, LLONG_MIN);
 static long long int coverage_run_time = LLONG_MIN;
 
 /* Index counter used to compute the moving average array's index. */
@@ -258,17 +259,33 @@ coverage_read(struct svec *lines)
     free(totals);
 }
 
+/* Runs approximately every COVERAGE_CLEAR_INTERVAL amount of time to
+ * synchronize per-thread counters with global counters. Every thread maintains
+ * a separate timer to ensure all counters are periodically aggregated. */
 void
 coverage_clear(void)
 {
-    size_t i;
+    long long int now, *thread_time;
 
-    ovs_mutex_lock(&coverage_mutex);
-    for (i = 0; i < n_coverage_counters; i++) {
-        struct coverage_counter *c = coverage_counters[i];
-        c->total += c->count();
+    now = time_msec();
+    thread_time = coverage_clear_time_get();
+
+    /* Initialize the coverage_clear_time. */
+    if (*thread_time == LLONG_MIN) {
+        *thread_time = now + COVERAGE_CLEAR_INTERVAL;
+    }
+
+    if (now >= *thread_time) {
+        size_t i;
+
+        ovs_mutex_lock(&coverage_mutex);
+        for (i = 0; i < n_coverage_counters; i++) {
+            struct coverage_counter *c = coverage_counters[i];
+            c->total += c->count();
+        }
+        ovs_mutex_unlock(&coverage_mutex);
+        *thread_time = now + COVERAGE_CLEAR_INTERVAL;
     }
-    ovs_mutex_unlock(&coverage_mutex);
 }
 
 /* Runs approximately every COVERAGE_RUN_INTERVAL amount of time to update the
index 163728e..4e6c050 100644 (file)
@@ -36,6 +36,9 @@
 #define COVERAGE_RUN_INTERVAL    5000
 BUILD_ASSERT_DECL(60000 % COVERAGE_RUN_INTERVAL == 0);
 
+#define COVERAGE_CLEAR_INTERVAL  1000
+BUILD_ASSERT_DECL(COVERAGE_RUN_INTERVAL % COVERAGE_CLEAR_INTERVAL == 0);
+
 /* Defines the moving average array length. */
 #define MIN_AVG_LEN (60000/COVERAGE_RUN_INTERVAL)
 #define HR_AVG_LEN  60
index 4558669..e07ea1d 100644 (file)
@@ -1867,14 +1867,26 @@ ofpact_check_output_port(ofp_port_t port, ofp_port_t max_ports)
     }
 }
 
+/* Removes the protocols that require consistency between match and actions
+ * (that's everything but OpenFlow 1.0) from '*usable_protocols'.
+ *
+ * (An example of an inconsistency between match and actions is a flow that
+ * does not match on an MPLS Ethertype but has an action that pops an MPLS
+ * label.) */
+static void
+inconsistent_match(enum ofputil_protocol *usable_protocols)
+{
+    *usable_protocols &= OFPUTIL_P_OF10_ANY;
+}
+
 /* May modify flow->dl_type, flow->nw_proto and flow->vlan_tci,
  * caller must restore them.
  *
  * Modifies some actions, filling in fields that could not be properly set
  * without context. */
 static enum ofperr
-ofpact_check__(struct ofpact *a, struct flow *flow,
-               bool enforce_consistency, ofp_port_t max_ports,
+ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
+               struct flow *flow, ofp_port_t max_ports,
                uint8_t table_id, uint8_t n_tables)
 {
     const struct ofpact_enqueue *enqueue;
@@ -1910,7 +1922,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
             (flow->vlan_tci & htons(VLAN_CFI)) == htons(VLAN_CFI);
         if (!(flow->vlan_tci & htons(VLAN_CFI)) &&
             !ofpact_get_SET_VLAN_VID(a)->push_vlan_if_needed) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         /* Temporary mark that we have a vlan tag. */
         flow->vlan_tci |= htons(VLAN_CFI);
@@ -1923,7 +1935,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
             (flow->vlan_tci & htons(VLAN_CFI)) == htons(VLAN_CFI);
         if (!(flow->vlan_tci & htons(VLAN_CFI)) &&
             !ofpact_get_SET_VLAN_PCP(a)->push_vlan_if_needed) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         /* Temporary mark that we have a vlan tag. */
         flow->vlan_tci |= htons(VLAN_CFI);
@@ -1931,7 +1943,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
 
     case OFPACT_STRIP_VLAN:
         if (!(flow->vlan_tci & htons(VLAN_CFI))) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         /* Temporary mark that we have no vlan tag. */
         flow->vlan_tci = htons(0);
@@ -1953,7 +1965,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
     case OFPACT_SET_IPV4_SRC:
     case OFPACT_SET_IPV4_DST:
         if (flow->dl_type != htons(ETH_TYPE_IP)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         return 0;
 
@@ -1962,7 +1974,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
     case OFPACT_SET_IP_TTL:
     case OFPACT_DEC_TTL:
         if (!is_ip_any(flow)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         return 0;
 
@@ -1970,7 +1982,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
         if (!is_ip_any(flow) ||
             (flow->nw_proto != IPPROTO_TCP && flow->nw_proto != IPPROTO_UDP
              && flow->nw_proto != IPPROTO_SCTP)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         /* Note on which transport protocol the port numbers are set.
          * This allows this set action to be converted to an OF1.2 set field
@@ -1982,7 +1994,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
         if (!is_ip_any(flow) ||
             (flow->nw_proto != IPPROTO_TCP && flow->nw_proto != IPPROTO_UDP
              && flow->nw_proto != IPPROTO_SCTP)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         /* Note on which transport protocol the port numbers are set.
          * This allows this set action to be converted to an OF1.2 set field
@@ -2027,7 +2039,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
     case OFPACT_SET_MPLS_TTL:
     case OFPACT_DEC_MPLS_TTL:
         if (!eth_type_mpls(flow->dl_type)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         return 0;
 
@@ -2039,7 +2051,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
 
     case OFPACT_FIN_TIMEOUT:
         if (flow->nw_proto != IPPROTO_TCP) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         return 0;
 
@@ -2064,7 +2076,7 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
     case OFPACT_POP_MPLS:
         flow->dl_type = ofpact_get_POP_MPLS(a)->ethertype;
         if (!eth_type_mpls(flow->dl_type)) {
-            goto inconsistent;
+            inconsistent_match(usable_protocols);
         }
         return 0;
 
@@ -2075,9 +2087,12 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
         return 0;
 
     case OFPACT_WRITE_ACTIONS: {
+        /* Use a temporary copy of 'usable_protocols' because we can't check
+         * consistency of an action set. */
         struct ofpact_nest *on = ofpact_get_WRITE_ACTIONS(a);
+        enum ofputil_protocol p = *usable_protocols;
         return ofpacts_check(on->actions, ofpact_nest_get_action_len(on),
-                             flow, false, max_ports, table_id, n_tables);
+                             flow, max_ports, table_id, n_tables, &p);
     }
 
     case OFPACT_WRITE_METADATA:
@@ -2106,26 +2121,25 @@ ofpact_check__(struct ofpact *a, struct flow *flow,
     default:
         NOT_REACHED();
     }
-
- inconsistent:
-    if (enforce_consistency) {
-        return OFPERR_OFPBAC_MATCH_INCONSISTENT;
-    }
-    return 0;
 }
 
 /* Checks that the 'ofpacts_len' bytes of actions in 'ofpacts' are
  * appropriate for a packet with the prerequisites satisfied by 'flow' in a
  * switch with no more than 'max_ports' ports.
  *
+ * If 'ofpacts' and 'flow' are inconsistent with one another, un-sets in
+ * '*usable_protocols' the protocols that forbid the inconsistency.  (An
+ * example of an inconsistency between match and actions is a flow that does
+ * not match on an MPLS Ethertype but has an action that pops an MPLS label.)
+ *
  * May annotate ofpacts with information gathered from the 'flow'.
  *
  * May temporarily modify 'flow', but restores the changes before returning. */
 enum ofperr
 ofpacts_check(struct ofpact ofpacts[], size_t ofpacts_len,
-              struct flow *flow, bool enforce_consistency,
-              ofp_port_t max_ports,
-              uint8_t table_id, uint8_t n_tables)
+              struct flow *flow, ofp_port_t max_ports,
+              uint8_t table_id, uint8_t n_tables,
+              enum ofputil_protocol *usable_protocols)
 {
     struct ofpact *a;
     ovs_be16 dl_type = flow->dl_type;
@@ -2134,7 +2148,7 @@ ofpacts_check(struct ofpact ofpacts[], size_t ofpacts_len,
     enum ofperr error = 0;
 
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
-        error = ofpact_check__(a, flow, enforce_consistency,
+        error = ofpact_check__(usable_protocols, a, flow,
                                max_ports, table_id, n_tables);
         if (error) {
             break;
@@ -2147,6 +2161,24 @@ ofpacts_check(struct ofpact ofpacts[], size_t ofpacts_len,
     return error;
 }
 
+/* Like ofpacts_check(), but reports inconsistencies as
+ * OFPERR_OFPBAC_MATCH_INCONSISTENT rather than clearing bits. */
+enum ofperr
+ofpacts_check_consistency(struct ofpact ofpacts[], size_t ofpacts_len,
+                          struct flow *flow, ofp_port_t max_ports,
+                          uint8_t table_id, uint8_t n_tables,
+                          enum ofputil_protocol usable_protocols)
+{
+    enum ofputil_protocol p = usable_protocols;
+    enum ofperr error;
+
+    error = ofpacts_check(ofpacts, ofpacts_len, flow, max_ports,
+                          table_id, n_tables, &p);
+    return (error ? error
+            : p != usable_protocols ? OFPERR_OFPBAC_MATCH_INCONSISTENT
+            : 0);
+}
+
 /* Verifies that the 'ofpacts_len' bytes of actions in 'ofpacts' are
  * in the appropriate order as defined by the OpenFlow spec. */
 enum ofperr
index 70ad4b6..470a371 100644 (file)
@@ -607,9 +607,13 @@ enum ofperr ofpacts_pull_openflow_instructions(struct ofpbuf *openflow,
                                                enum ofp_version version,
                                                struct ofpbuf *ofpacts);
 enum ofperr ofpacts_check(struct ofpact[], size_t ofpacts_len,
-                          struct flow *, bool enforce_consistency,
-                          ofp_port_t max_ports,
-                          uint8_t table_id, uint8_t n_tables);
+                          struct flow *, ofp_port_t max_ports,
+                          uint8_t table_id, uint8_t n_tables,
+                          enum ofputil_protocol *usable_protocols);
+enum ofperr ofpacts_check_consistency(struct ofpact[], size_t ofpacts_len,
+                                      struct flow *, ofp_port_t max_ports,
+                                      uint8_t table_id, uint8_t n_tables,
+                                      enum ofputil_protocol usable_protocols);
 enum ofperr ofpacts_verify(const struct ofpact ofpacts[], size_t ofpacts_len);
 enum ofperr ofpact_check_output_port(ofp_port_t port, ofp_port_t max_ports);
 
index c526a15..26fd6a3 100644 (file)
@@ -343,10 +343,10 @@ enum ofpraw {
     /* OFPST 1.3+ (11): struct ofp13_meter_features. */
     OFPRAW_OFPST13_METER_FEATURES_REPLY,
 
-    /* OFPST 1.3+ (12): struct ofp13_table_features[]. */
+    /* OFPST 1.3+ (12): void. */
     OFPRAW_OFPST13_TABLE_FEATURES_REQUEST,
 
-    /* OFPST 1.3+ (12): struct ofp13_table_features[]. */
+    /* OFPST 1.3+ (12): struct ofp13_table_features, uint8_t[8][]. */
     OFPRAW_OFPST13_TABLE_FEATURES_REPLY,
 
     /* OFPST 1.0+ (13): void. */
index 8698030..5b07d14 100644 (file)
@@ -1205,8 +1205,7 @@ parse_field(const struct mf_field *mf, const char *s, struct match *match,
 
 static char * WARN_UNUSED_RESULT
 parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
-                enum ofputil_protocol *usable_protocols,
-                bool enforce_consistency)
+                enum ofputil_protocol *usable_protocols)
 {
     enum {
         F_OUT_PORT = 1 << 0,
@@ -1414,23 +1413,15 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
             enum ofperr err;
 
             err = ofpacts_check(ofpacts.data, ofpacts.size, &fm->match.flow,
-                                true, OFPP_MAX, fm->table_id, 255);
+                                OFPP_MAX, fm->table_id, 255, usable_protocols);
+            if (!err && !usable_protocols) {
+                err = OFPERR_OFPBAC_MATCH_INCONSISTENT;
+            }
             if (err) {
-                if (!enforce_consistency &&
-                    err == OFPERR_OFPBAC_MATCH_INCONSISTENT) {
-                    /* Allow inconsistent actions to be used with OF 1.0. */
-                    *usable_protocols &= OFPUTIL_P_OF10_ANY;
-                    /* Try again, allowing for inconsistency.
-                     * XXX: As a side effect, logging may be duplicated. */
-                    err = ofpacts_check(ofpacts.data, ofpacts.size,
-                                        &fm->match.flow, false,
-                                        OFPP_MAX, fm->table_id, 255);
-                }
-                if (err) {
-                    error = xasprintf("actions are invalid with specified match "
-                                      "(%s)", ofperr_to_string(err));
-                }
+                error = xasprintf("actions are invalid with specified match "
+                                  "(%s)", ofperr_to_string(err));
             }
+
         }
         if (error) {
             ofpbuf_uninit(&ofpacts);
@@ -1459,14 +1450,12 @@ parse_ofp_str__(struct ofputil_flow_mod *fm, int command, char *string,
  * error.  The caller is responsible for freeing the returned string. */
 char * WARN_UNUSED_RESULT
 parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
-              enum ofputil_protocol *usable_protocols,
-              bool enforce_consistency)
+              enum ofputil_protocol *usable_protocols)
 {
     char *string = xstrdup(str_);
     char *error;
 
-    error = parse_ofp_str__(fm, command, string, usable_protocols,
-                            enforce_consistency);
+    error = parse_ofp_str__(fm, command, string, usable_protocols);
     if (error) {
         fm->ofpacts = NULL;
         fm->ofpacts_len = 0;
@@ -1813,11 +1802,9 @@ parse_ofpacts(const char *s_, struct ofpbuf *ofpacts,
 char * WARN_UNUSED_RESULT
 parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string,
                        uint16_t command,
-                       enum ofputil_protocol *usable_protocols,
-                       bool enforce_consistency)
+                       enum ofputil_protocol *usable_protocols)
 {
-    char *error = parse_ofp_str(fm, command, string, usable_protocols,
-                                enforce_consistency);
+    char *error = parse_ofp_str(fm, command, string, usable_protocols);
     if (!error) {
         /* Normalize a copy of the match.  This ensures that non-normalized
          * flows get logged but doesn't affect what gets sent to the switch, so
@@ -1879,8 +1866,7 @@ parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id,
 char * WARN_UNUSED_RESULT
 parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
                         struct ofputil_flow_mod **fms, size_t *n_fms,
-                        enum ofputil_protocol *usable_protocols,
-                        bool enforce_consistency)
+                        enum ofputil_protocol *usable_protocols)
 {
     size_t allocated_fms;
     int line_number;
@@ -1909,7 +1895,7 @@ parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
             *fms = x2nrealloc(*fms, &allocated_fms, sizeof **fms);
         }
         error = parse_ofp_flow_mod_str(&(*fms)[*n_fms], ds_cstr(&s), command,
-                                       &usable, enforce_consistency);
+                                       &usable);
         if (error) {
             size_t i;
 
@@ -1941,14 +1927,12 @@ parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
 char * WARN_UNUSED_RESULT
 parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *fsr,
                                  bool aggregate, const char *string,
-                                 enum ofputil_protocol *usable_protocols,
-                                 bool enforce_consistency)
+                                 enum ofputil_protocol *usable_protocols)
 {
     struct ofputil_flow_mod fm;
     char *error;
 
-    error = parse_ofp_str(&fm, -1, string, usable_protocols,
-                          enforce_consistency);
+    error = parse_ofp_str(&fm, -1, string, usable_protocols);
     if (error) {
         return error;
     }
index 58a3e87..515ccd7 100644 (file)
@@ -36,14 +36,12 @@ struct simap;
 enum ofputil_protocol;
 
 char *parse_ofp_str(struct ofputil_flow_mod *, int command, const char *str_,
-                    enum ofputil_protocol *usable_protocols,
-                    bool enforce_consistency)
+                    enum ofputil_protocol *usable_protocols)
     WARN_UNUSED_RESULT;
 
 char *parse_ofp_flow_mod_str(struct ofputil_flow_mod *, const char *string,
                              uint16_t command,
-                             enum ofputil_protocol *usable_protocols,
-                             bool enforce_consistency)
+                             enum ofputil_protocol *usable_protocols)
     WARN_UNUSED_RESULT;
 
 char *parse_ofp_table_mod(struct ofputil_table_mod *,
@@ -53,14 +51,12 @@ char *parse_ofp_table_mod(struct ofputil_table_mod *,
 
 char *parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
                               struct ofputil_flow_mod **fms, size_t *n_fms,
-                              enum ofputil_protocol *usable_protocols,
-                              bool enforce_consistency)
+                              enum ofputil_protocol *usable_protocols)
     WARN_UNUSED_RESULT;
 
 char *parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *,
                                        bool aggregate, const char *string,
-                                       enum ofputil_protocol *usable_protocols,
-                                       bool enforce_consistency)
+                                       enum ofputil_protocol *usable_protocols)
     WARN_UNUSED_RESULT;
 
 char *parse_ofpacts(const char *, struct ofpbuf *ofpacts,
index 7903de8..d8a9754 100644 (file)
@@ -1672,9 +1672,9 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
                 : OFPERR_OFPFMFC_TABLE_FULL);
     }
 
-    return ofpacts_check(fm->ofpacts, fm->ofpacts_len, &fm->match.flow,
-                         oh->version > OFP10_VERSION, max_port,
-                         fm->table_id, max_table);
+    return ofpacts_check_consistency(fm->ofpacts, fm->ofpacts_len,
+                                     &fm->match.flow, max_port,
+                                     fm->table_id, max_table, protocol);
 }
 
 static enum ofperr
index 6c1d5a9..c1c206b 100644 (file)
@@ -5464,13 +5464,14 @@ ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
     }
 
     /* OpenFlow 1.1 and later suggest that the switch enforces certain forms of
-     * consistency between the flow and the actions, so enforce these by
-     * default if the actions can only work in OF1.1 or later. */
-    enforce_consistency = !(usable_protocols & OFPUTIL_P_OF10_ANY);
+     * consistency between the flow and the actions.  With -consistent, we
+     * enforce consistency even for a flow supported in OpenFlow 1.0. */
     if (!strcmp(argv[1], "-consistent")) {
         enforce_consistency = true;
         argv++;
         argc--;
+    } else {
+        enforce_consistency = false;
     }
 
     error = parse_flow_and_packet(argc, argv, &ofproto, &flow, &packet);
@@ -5494,9 +5495,16 @@ ofproto_unixctl_trace_actions(struct unixctl_conn *conn, int argc,
         unixctl_command_reply_error(conn, "invalid in_port");
         goto exit;
     }
-    retval = ofpacts_check(ofpacts.data, ofpacts.size, &flow,
-                           enforce_consistency,
-                           u16_to_ofp(ofproto->up.max_ports), 0, 0);
+    if (enforce_consistency) {
+        retval = ofpacts_check_consistency(ofpacts.data, ofpacts.size, &flow,
+                                           u16_to_ofp(ofproto->up.max_ports),
+                                           0, 0, usable_protocols);
+    } else {
+        retval = ofpacts_check(ofpacts.data, ofpacts.size, &flow,
+                               u16_to_ofp(ofproto->up.max_ports), 0, 0,
+                               &usable_protocols);
+    }
+
     if (retval) {
         ds_clear(&result);
         ds_put_format(&result, "Bad actions: %s", ofperr_to_string(retval));
index 73bf07f..15d2b1a 100644 (file)
@@ -34,6 +34,14 @@ AT_CHECK([ovs-appctl bfd/show $1 | sed -n '/RX Interval/p'],[0],
        Remote Minimum RX Interval: $4
 ])
 ])
+
+m4_define([BFD_VSCTL_LIST_IFACE], [
+AT_CHECK([ovs-vsctl list interface $1 | sed -n $2],[0],
+[dnl
+$3
+])
+])
+
 AT_SETUP([bfd - basic config on different bridges])
 #Create 2 bridges connected by patch ports and enable BFD
 OVS_VSWITCHD_START(
@@ -699,4 +707,127 @@ BFD_CHECK_TX([p0], [300ms], [300ms], [300ms])
 BFD_CHECK_RX([p0], [1000ms], [1000ms], [300ms])
 
 AT_CHECK([ovs-vsctl del-br br1], [0], [ignore])
+AT_CLEANUP
+
+# test bfd:flap_count.
+AT_SETUP([bfd - flap_count])
+#Create 2 bridges connected by patch ports and enable bfd
+OVS_VSWITCHD_START([add-br br1 -- \
+                    set bridge br1 datapath-type=dummy \
+                    other-config:hwaddr=aa:55:aa:56:00:00 -- \
+                    add-port br1 p1 -- set Interface p1 type=patch \
+                    options:peer=p0 ofport_request=2 -- \
+                    add-port br0 p0 -- set Interface p0 type=patch \
+                    options:peer=p1 ofport_request=1 -- \
+                    set Interface p0 bfd:enable=true bfd:min_tx=100 bfd:min_rx=100 -- \
+                    set Interface p1 bfd:enable=true bfd:min_tx=100 bfd:min_rx=100])
+
+ovs-appctl time/stop
+
+# Part-1 wait for a while to stablize bfd.
+for i in `seq 0 100`; do ovs-appctl time/warp 100; done
+BFD_CHECK([p0], [true], [false], [none], [up], [No Diagnostic], [none], [up], [No Diagnostic])
+BFD_CHECK([p1], [true], [false], [none], [up], [No Diagnostic], [none], [up], [No Diagnostic])
+BFD_CHECK_TX([p0], [100ms], [100ms], [100ms])
+BFD_CHECK_RX([p0], [100ms], [100ms], [100ms])
+# both p0 and p1 should have flap_count = "1". since down->up.
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
+BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
+
+# turn bfd on p1 off, should increment the bfd:flap_count on p0.
+AT_CHECK([ovs-vsctl set interface p1 bfd:enable=false])
+for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["2"])
+AT_CHECK([ovs-vsctl list interface p1 | sed -n "s/^.*flap_count=\(.*\), forwarding.*$/\1/p"])
+
+# turn bfd on p1 on again, should increment the bfd:flap_count on p0.
+# p1 should still have flap_count = "1", since it is reset.
+AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
+for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["3"])
+BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
+
+
+# Part-2 now turn on the forwarding_override.
+AT_CHECK([ovs-appctl bfd/set-forwarding p0 true], [0], [dnl
+OK
+])
+
+# turn bfd on p1 off, should not increment the bfd:flap_count on p0, since forwarding_override is on.
+AT_CHECK([ovs-vsctl set interface p1 bfd:enable=false])
+for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["3"])
+AT_CHECK([ovs-vsctl list interface p1 | sed -n "s/^.*flap_count=\(.*\), forwarding.*$/\1/p"])
+
+# turn bfd on p1 on again, should not increment the bfd:flap_count on p0, since forwarding override is on.
+# p1 should still have flap_count = "1", since it is reset.
+AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
+for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["3"])
+BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
+
+# turn the forwarding_override back to normal.
+AT_CHECK([ovs-appctl bfd/set-forwarding p0 normal], [0], [dnl
+OK
+])
+
+# turn bfd on p1 off and on, should increment the bfd:flap_count on p0.
+AT_CHECK([ovs-vsctl set interface p1 bfd:enable=false])
+for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
+for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["5"])
+BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
+
+# Part-3 now turn on forwarding_if_rx.
+AT_CHECK([ovs-vsctl set Interface p0 bfd:forwarding_if_rx=true], [0])
+# disable the bfd on p1.
+AT_CHECK([ovs-vsctl set Interface p1 bfd:enable=false], [0])
+
+# advance clock by 4000ms, while receiving packets.
+# the STATE should go DOWN, due to Control Detection Time Expired.
+# but forwarding flag should be true.
+for i in `seq 0 39`
+do
+    ovs-appctl time/warp 100
+    AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
+# flap_count should remain unchanged.
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["5"])
+
+# stop the traffic for 4000ms, the forwarding flag of p0 should turn false.
+# and there should be the increment of flap_count.
+for i in `seq 0 7`; do ovs-appctl time/warp 500; done
+BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["6"])
+
+# advance clock by 4000ms, and resume the traffic.
+for i in `seq 0 39`
+do
+    ovs-appctl time/warp 100
+    AT_CHECK([ovs-ofctl packet-out br1 3 2 "90e2ba01475000101856b2e80806000108000604000100101856b2e80202020300000000000002020202"],
+             [0], [stdout], [])
+done
+BFD_CHECK([p0], [true], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
+# flap_count should be incremented again.
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["7"])
+
+# stop the traffic for 4000ms, the forwarding flag of p0 should turn false.
+# and there should be the increment of flap_count.
+for i in `seq 0 7`; do ovs-appctl time/warp 500; done
+BFD_CHECK([p0], [false], [false], [none], [down], [Control Detection Time Expired], [none], [down], [No Diagnostic])
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["8"])
+
+# turn on the bfd on p1.
+AT_CHECK([ovs-vsctl set interface p1 bfd:enable=true])
+for i in `seq 0 10`; do ovs-appctl time/warp 100; done
+# even though there is no data traffic, since p1 bfd is on again, should increment the flap_count.
+BFD_VSCTL_LIST_IFACE([p0], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["9"])
+BFD_VSCTL_LIST_IFACE([p1], ["s/^.*flap_count=\(.*\), forwarding.*$/\1/p"], ["1"])
+
+OVS_VSWITCHD_STOP
 AT_CLEANUP
\ No newline at end of file
index 491cd5e..66343d3 100644 (file)
@@ -75,14 +75,12 @@ AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:5->NXM_OF_IP_DST[])']],
   [1], [], [stderr])
 AT_CHECK([sed -e 's/.*|meta_flow|WARN|//' < stderr], [0],
   [[destination field ip_dst lacks correct prerequisites
-destination field ip_dst lacks correct prerequisites
 ovs-ofctl: actions are invalid with specified match (OFPBAC_MATCH_INCONSISTENT)
 ]], [[]])
 AT_CHECK([[ovs-ofctl parse-flow 'actions=learn(load:NXM_OF_IP_DST[]->NXM_NX_REG1[])']],
   [1], [], [stderr])
 AT_CHECK([sed -e 's/.*|meta_flow|WARN|//' < stderr], [0],
   [[source field ip_dst lacks correct prerequisites
-source field ip_dst lacks correct prerequisites
 ovs-ofctl: actions are invalid with specified match (OFPBAC_MATCH_INCONSISTENT)
 ]])
 AT_CLEANUP
index 08ebccf..452bdbf 100644 (file)
@@ -485,7 +485,7 @@ AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-flow br0 'tcp actions=fin_timeout(i
 dnl Bad: Use fin_timeout action on TCP flow that has been converted to MPLS
 AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-flow br0 'tcp actions=push_mpls:0x8847,fin_timeout(idle_timeout=1)'],
          [1], [], [dnl
-ovs-ofctl: actions are invalid with specified match (OFPBAC_MATCH_INCONSISTENT)
+ovs-ofctl: none of the usable flow formats (OpenFlow10,NXM) is among the allowed flow formats (OpenFlow11)
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
index 9a7c8ff..b78e156 100644 (file)
@@ -926,12 +926,6 @@ arp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:f
 arp,metadata=0,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.128.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41
 ])
 
-# Check that each of the packets actually passed through the slow-path.
-AT_CHECK([ovs-appctl coverage/show], [0], [stdout])
-AT_CHECK([sed -n 's/[[         ]]\{2,\}/ /g
-s/^dpif_execute_with_help.*total: //p' stdout], [0], [3
-])
-
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
index a99a161..3434592 100644 (file)
@@ -285,7 +285,7 @@ AT_CLEANUP
 
 AT_SETUP([ovs-ofctl action inconsistency (OpenFlow 1.1)])
 AT_CHECK([ovs-ofctl --protocols OpenFlow11 add-flow br0 'ip actions=mod_tp_dst:1234'
-], [1], [stdout], [ovs-ofctl: actions are invalid with specified match (OFPBAC_MATCH_INCONSISTENT)
+], [1], [stdout], [ovs-ofctl: none of the usable flow formats (OpenFlow10,NXM) is among the allowed flow formats (OpenFlow11)
 ])
 AT_CLEANUP
 
index 9596ad4..f487d8c 100644 (file)
@@ -332,7 +332,7 @@ parse_options(int argc, char *argv[])
         case OPT_WITH_FLOWS:
             error = parse_ofp_flow_mod_file(optarg, OFPFC_ADD, &default_flows,
                                             &n_default_flows,
-                                            &usable_protocols, false);
+                                            &usable_protocols);
             if (error) {
                 ovs_fatal(0, "%s", error);
             }
index f3b58dd..1d1b47f 100644 (file)
@@ -890,9 +890,7 @@ prepare_dump_flows(int argc, char *argv[], bool aggregate,
 
     error = parse_ofp_flow_stats_request_str(&fsr, aggregate,
                                              argc > 2 ? argv[2] : "",
-                                             &usable_protocols,
-                                             !(allowed_protocols
-                                               & OFPUTIL_P_OF10_ANY));
+                                             &usable_protocols);
     if (error) {
         ovs_fatal(0, "%s", error);
     }
@@ -1134,8 +1132,7 @@ ofctl_flow_mod_file(int argc OVS_UNUSED, char *argv[], uint16_t command)
     char *error;
 
     error = parse_ofp_flow_mod_file(argv[2], command, &fms, &n_fms,
-                                    &usable_protocols,
-                                    !(allowed_protocols & OFPUTIL_P_OF10_ANY));
+                                    &usable_protocols);
     if (error) {
         ovs_fatal(0, "%s", error);
     }
@@ -1154,9 +1151,7 @@ ofctl_flow_mod(int argc, char *argv[], uint16_t command)
         enum ofputil_protocol usable_protocols;
 
         error = parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "", command,
-                                       &usable_protocols,
-                                       !(allowed_protocols
-                                         & OFPUTIL_P_OF10_ANY));
+                                       &usable_protocols);
         if (error) {
             ovs_fatal(0, "%s", error);
         }
@@ -2231,8 +2226,7 @@ read_flows_from_file(const char *filename, struct classifier *cls, int index)
         char *error;
         enum ofputil_protocol usable;
 
-        error = parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), &usable,
-                              !(allowed_protocols & OFPUTIL_P_OF10_ANY));
+        error = parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), &usable);
         if (error) {
             ovs_fatal(0, "%s:%d: %s", filename, line_number, error);
         }
@@ -2651,8 +2645,7 @@ ofctl_parse_flow(int argc OVS_UNUSED, char *argv[])
     struct ofputil_flow_mod fm;
     char *error;
 
-    error = parse_ofp_flow_mod_str(&fm, argv[1], OFPFC_ADD, &usable_protocols,
-                                   !(allowed_protocols & OFPUTIL_P_OF10_ANY));
+    error = parse_ofp_flow_mod_str(&fm, argv[1], OFPFC_ADD, &usable_protocols);
     if (error) {
         ovs_fatal(0, "%s", error);
     }
@@ -2670,8 +2663,7 @@ ofctl_parse_flows(int argc OVS_UNUSED, char *argv[])
     char *error;
 
     error = parse_ofp_flow_mod_file(argv[1], OFPFC_ADD, &fms, &n_fms,
-                                    &usable_protocols,
-                                    !(allowed_protocols & OFPUTIL_P_OF10_ANY));
+                                    &usable_protocols);
     if (error) {
         ovs_fatal(0, "%s", error);
     }
@@ -3077,9 +3069,10 @@ ofctl_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
             /* Verify actions, enforce consistency. */
             struct flow flow;
             memset(&flow, 0, sizeof flow);
-            error = ofpacts_check(ofpacts.data, ofpacts.size, &flow,
-                                  true, OFPP_MAX,
-                                  table_id ? atoi(table_id) : 0, 255);
+            error = ofpacts_check_consistency(ofpacts.data, ofpacts.size,
+                                              &flow, OFPP_MAX,
+                                              table_id ? atoi(table_id) : 0,
+                                              255, OFPUTIL_P_OF11_STD);
         }
         if (error) {
             printf("bad OF1.1 instructions: %s\n\n", ofperr_get_name(error));
@@ -3177,8 +3170,7 @@ ofctl_check_vlan(int argc OVS_UNUSED, char *argv[])
     string_s = match_to_string(&match, OFP_DEFAULT_PRIORITY);
     printf("%s -> ", string_s);
     fflush(stdout);
-    error_s = parse_ofp_str(&fm, -1, string_s, &usable_protocols,
-                            !(allowed_protocols & OFPUTIL_P_OF10_ANY));
+    error_s = parse_ofp_str(&fm, -1, string_s, &usable_protocols);
     if (error_s) {
         ovs_fatal(0, "%s", error_s);
     }
index 555f45d..6ce7d2b 100644 (file)
@@ -984,28 +984,44 @@ bridge_configure_sflow(struct bridge *br, int *sflow_bridge_number)
     sset_destroy(&oso.targets);
 }
 
+/* Returns whether a IPFIX row is valid. */
+static bool
+ovsrec_ipfix_is_valid(const struct ovsrec_ipfix *ipfix)
+{
+    return ipfix && ipfix->n_targets > 0;
+}
+
+/* Returns whether a Flow_Sample_Collector_Set row is valid. */
+static bool
+ovsrec_fscs_is_valid(const struct ovsrec_flow_sample_collector_set *fscs,
+                     const struct bridge *br)
+{
+    return ovsrec_ipfix_is_valid(fscs->ipfix) && fscs->bridge == br->cfg;
+}
+
 /* Set IPFIX configuration on 'br'. */
 static void
 bridge_configure_ipfix(struct bridge *br)
 {
     const struct ovsrec_ipfix *be_cfg = br->cfg->ipfix;
+    bool valid_be_cfg = ovsrec_ipfix_is_valid(be_cfg);
     const struct ovsrec_flow_sample_collector_set *fe_cfg;
     struct ofproto_ipfix_bridge_exporter_options be_opts;
     struct ofproto_ipfix_flow_exporter_options *fe_opts = NULL;
     size_t n_fe_opts = 0;
 
     OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) {
-        if (fe_cfg->bridge == br->cfg) {
+        if (ovsrec_fscs_is_valid(fe_cfg, br)) {
             n_fe_opts++;
         }
     }
 
-    if (!be_cfg && n_fe_opts == 0) {
+    if (!valid_be_cfg && n_fe_opts == 0) {
         ofproto_set_ipfix(br->ofproto, NULL, NULL, 0);
         return;
     }
 
-    if (be_cfg) {
+    if (valid_be_cfg) {
         memset(&be_opts, 0, sizeof be_opts);
 
         sset_init(&be_opts.targets);
@@ -1035,7 +1051,7 @@ bridge_configure_ipfix(struct bridge *br)
         fe_opts = xcalloc(n_fe_opts, sizeof *fe_opts);
         opts = fe_opts;
         OVSREC_FLOW_SAMPLE_COLLECTOR_SET_FOR_EACH(fe_cfg, idl) {
-            if (fe_cfg->bridge == br->cfg) {
+            if (ovsrec_fscs_is_valid(fe_cfg, br)) {
                 opts->collector_set_id = fe_cfg->id;
                 sset_init(&opts->targets);
                 sset_add_array(&opts->targets, fe_cfg->ipfix->targets,
@@ -1049,10 +1065,10 @@ bridge_configure_ipfix(struct bridge *br)
         }
     }
 
-    ofproto_set_ipfix(br->ofproto, be_cfg ? &be_opts : NULL, fe_opts,
+    ofproto_set_ipfix(br->ofproto, valid_be_cfg ? &be_opts : NULL, fe_opts,
                       n_fe_opts);
 
-    if (be_cfg) {
+    if (valid_be_cfg) {
         sset_destroy(&be_opts.targets);
     }
 
index 78ebc89..9392457 100644 (file)
@@ -1,6 +1,6 @@
 {"name": "Open_vSwitch",
  "version": "7.3.0",
- "cksum": "2811681289 20311",
+ "cksum": "2495231516 20311",
  "tables": {
    "Open_vSwitch": {
      "columns": {
    "IPFIX": {
      "columns": {
        "targets": {
-         "type": {"key": "string", "min": 1, "max": "unlimited"}},
+         "type": {"key": "string", "min": 0, "max": "unlimited"}},
        "sampling": {
          "type": {"key": {"type": "integer",
                           "minInteger": 1,
index 35d59b9..f6a8db1 100644 (file)
          In case of a problem, set to a short message that reports what the
          remote endpoint's BFD session thinks is wrong.
        </column>
+
+        <column name="bfd_status" key="flap_count"
+          type='{"type": "integer", "minInteger": 0}'>
+          Counts the number of <ref column="bfd_status" key="forwarding" />
+          flaps since start.  A flap is considered as a change of the
+          <ref column="bfd_status" key="forwarding" /> value.
+        </column>
       </group>
     </group>