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
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
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
--- /dev/null
+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.)
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.
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:
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
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
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
DISTCLEANFILES =
PYCOV_CLEAN_FILES = build-aux/check-structs,cover
EXTRA_DIST = \
+ BUILD.Windows \
CodingStyle \
DESIGN \
FAQ \
SubmittingPatches \
WHY-OVS \
boot.sh \
+ build-aux/cccl \
build-aux/sodepends.pl \
build-aux/soexpand.pl \
$(MAN_FRAGMENTS) \
--- /dev/null
+#!/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
#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;
}
}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
+
static __sum16 check_checksum(struct sk_buff *skb)
{
__sum16 csum = 0;
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;
return ret;
}
+#endif /* 3.11 */
+
#endif /* CONFIG_NET_IPGRE_DEMUX */
}
#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
#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);
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:
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.
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}"`
#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)
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? */
/* 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);
/* 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;
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));
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);
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
}
\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. */
bfd_decay_update(bfd);
}
}
+
+ /* Updates the forwarding flag. */
+ bfd_forwarding__(bfd);
}
static uint64_t
}
}
-/* 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
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");
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 *);
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. */
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
#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
}
}
+/* 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;
(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);
(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);
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);
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;
case OFPACT_SET_IP_TTL:
case OFPACT_DEC_TTL:
if (!is_ip_any(flow)) {
- goto inconsistent;
+ inconsistent_match(usable_protocols);
}
return 0;
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
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
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;
case OFPACT_FIN_TIMEOUT:
if (flow->nw_proto != IPPROTO_TCP) {
- goto inconsistent;
+ inconsistent_match(usable_protocols);
}
return 0;
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;
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:
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;
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;
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
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);
/* 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. */
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,
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);
* 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;
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
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;
*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;
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;
}
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 *,
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,
: 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
}
/* 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);
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));
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(
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
[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
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
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
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
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
/* 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));
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);
}
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);
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,
}
}
- 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);
}
{"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,
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>