summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Pettit <jpettit@nicira.com>2015-04-12 10:13:59 -0700
committerJustin Pettit <jpettit@nicira.com>2015-04-12 10:13:59 -0700
commitdaaeeec0bd4348b1f6ac5ca5a302e57bd11cca01 (patch)
tree5b34ccd589c61547044dfbfcf77636bfcd8ebb61
parent717c7fc508044d08210c686c1e8576c29a108f86 (diff)
parente8fe6ad03aa3d25b5ae99190d5aa065705a1b3c8 (diff)
downloadopenvswitch-daaeeec0bd4348b1f6ac5ca5a302e57bd11cca01.tar.gz
Merge remote-tracking branch 'origin/master' into ovn
Conflicts: tutorial/ovs-sandbox
-rwxr-xr-x.travis/build.sh1
-rwxr-xr-x.travis/prepare.sh3
-rw-r--r--AUTHORS5
-rw-r--r--Documentation/automake.mk2
-rw-r--r--Documentation/group-selection-method-property.txt153
-rw-r--r--FAQ.md9
-rw-r--r--INSTALL.DPDK.md256
-rw-r--r--INSTALL.Windows.md443
-rw-r--r--INSTALL.md22
-rw-r--r--INSTALL.userspace.md2
-rw-r--r--Makefile.am9
-rw-r--r--NEWS10
-rw-r--r--acinclude.m466
-rw-r--r--build-aux/cccl2
-rw-r--r--datapath-windows/include/OvsDpInterfaceExt.h18
-rw-r--r--datapath-windows/ovsext/BufferMgmt.c6
-rw-r--r--datapath-windows/ovsext/Datapath.c133
-rw-r--r--datapath-windows/ovsext/Datapath.h31
-rw-r--r--datapath-windows/ovsext/Event.c18
-rw-r--r--datapath-windows/ovsext/Flow.c13
-rw-r--r--datapath-windows/ovsext/IpHelper.c70
-rw-r--r--datapath-windows/ovsext/Oid.c41
-rw-r--r--datapath-windows/ovsext/Oid.h3
-rw-r--r--datapath-windows/ovsext/Switch.c109
-rw-r--r--datapath-windows/ovsext/Switch.h6
-rw-r--r--datapath-windows/ovsext/TunnelFilter.c99
-rw-r--r--datapath-windows/ovsext/TunnelIntf.h8
-rw-r--r--datapath-windows/ovsext/User.c18
-rw-r--r--datapath-windows/ovsext/Util.c15
-rw-r--r--datapath-windows/ovsext/Util.h12
-rw-r--r--datapath-windows/ovsext/Vport.c36
-rw-r--r--datapath-windows/ovsext/Vxlan.c5
-rw-r--r--datapath/Modules.mk20
-rw-r--r--datapath/compat.h6
-rw-r--r--datapath/datapath.c17
-rw-r--r--datapath/linux/Kbuild.in4
-rw-r--r--datapath/linux/compat/flow_dissector.c1
-rw-r--r--datapath/linux/compat/genetlink-openvswitch.c2
-rw-r--r--datapath/linux/compat/geneve.c11
-rw-r--r--datapath/linux/compat/gre.c4
-rw-r--r--datapath/linux/compat/include/linux/skbuff.h5
-rw-r--r--datapath/linux/compat/include/net/genetlink.h6
-rw-r--r--datapath/linux/compat/include/net/ip.h2
-rw-r--r--datapath/linux/compat/include/net/udp.h19
-rw-r--r--datapath/linux/compat/include/net/udp_tunnel.h1
-rw-r--r--datapath/linux/compat/ip_tunnels_core.c4
-rw-r--r--datapath/linux/compat/udp.c2
-rw-r--r--datapath/linux/compat/udp_tunnel.c6
-rw-r--r--datapath/linux/compat/vxlan.c11
-rw-r--r--datapath/vport-geneve.c22
-rw-r--r--datapath/vport-gre.c39
-rw-r--r--datapath/vport-internal_dev.c17
-rw-r--r--datapath/vport-lisp.c22
-rw-r--r--datapath/vport-netdev.c13
-rw-r--r--datapath/vport-netdev.h3
-rw-r--r--datapath/vport-vxlan.c23
-rw-r--r--datapath/vport.c100
-rw-r--r--datapath/vport.h16
-rw-r--r--debian/openvswitch-common.install1
-rw-r--r--debian/openvswitch-switch.install1
-rw-r--r--include/openflow/automake.mk37
-rw-r--r--include/openflow/netronome-ext.h66
-rw-r--r--include/openflow/openflow-common.h2
-rw-r--r--lib/cfm.c1
-rw-r--r--lib/dp-packet.c5
-rw-r--r--lib/dpif-netdev.c109
-rw-r--r--lib/flow.c12
-rw-r--r--lib/hmap.h13
-rw-r--r--lib/jsonrpc.c29
-rw-r--r--lib/lacp.c3
-rw-r--r--lib/list.h3
-rw-r--r--lib/lldp/aa-structs.h6
-rw-r--r--lib/lldp/lldp-tlv.h30
-rw-r--r--lib/lldp/lldp.c127
-rw-r--r--lib/lldp/lldpd-structs.c5
-rw-r--r--lib/lldp/lldpd.c5
-rw-r--r--lib/lockfile.c8
-rw-r--r--lib/mcast-snooping.c5
-rw-r--r--lib/meta-flow.c44
-rw-r--r--lib/meta-flow.h12
-rw-r--r--lib/netdev-bsd.c6
-rw-r--r--lib/netdev-dpdk.c562
-rw-r--r--lib/netdev-dummy.c3
-rw-r--r--lib/netdev-linux.c748
-rw-r--r--lib/netdev-provider.h11
-rw-r--r--lib/netdev-vport.c317
-rw-r--r--lib/netdev.c42
-rw-r--r--lib/netdev.h4
-rw-r--r--lib/netlink-socket.c56
-rw-r--r--lib/nx-match.c124
-rw-r--r--lib/nx-match.h5
-rw-r--r--lib/odp-util.c92
-rw-r--r--lib/ofp-actions.c36
-rw-r--r--lib/ofp-actions.h12
-rw-r--r--lib/ofp-parse.c94
-rw-r--r--lib/ofp-print.c32
-rw-r--r--lib/ofp-util.c282
-rw-r--r--lib/ofp-util.h15
-rw-r--r--lib/ofpbuf.c5
-rw-r--r--lib/ovs-lldp.c33
-rw-r--r--lib/ovs-lldp.h1
-rw-r--r--lib/ovs-numa.c5
-rw-r--r--lib/ovs-rcu.c5
-rw-r--r--lib/ovsdb-idl.c211
-rw-r--r--lib/ovsdb-parser.c16
-rw-r--r--lib/ovsdb-parser.h5
-rw-r--r--lib/packets.c14
-rw-r--r--lib/packets.h22
-rw-r--r--lib/sset.c38
-rw-r--r--lib/sset.h3
-rw-r--r--lib/vconn.c6
-rw-r--r--ofproto/bond.c7
-rw-r--r--ofproto/bundles.c5
-rw-r--r--ofproto/connmgr.c16
-rw-r--r--ofproto/ofproto-dpif-rid.c357
-rw-r--r--ofproto/ofproto-dpif-rid.h167
-rw-r--r--ofproto/ofproto-dpif-upcall.c103
-rw-r--r--ofproto/ofproto-dpif-xlate.c933
-rw-r--r--ofproto/ofproto-dpif-xlate.h72
-rw-r--r--ofproto/ofproto-dpif.c219
-rw-r--r--ofproto/ofproto-dpif.h95
-rw-r--r--ofproto/ofproto-provider.h2
-rw-r--r--ofproto/ofproto.c10
-rw-r--r--ofproto/tunnel.c2
-rw-r--r--ovsdb/jsonrpc-server.c26
-rw-r--r--ovsdb/ovsdb-server.1.in29
-rw-r--r--rhel/openvswitch-fedora.spec.in4
-rw-r--r--rhel/openvswitch-kmod-fedora.spec.in4
-rw-r--r--rhel/openvswitch.spec.in2
-rw-r--r--tests/automake.mk8
-rw-r--r--tests/completion.at10
-rw-r--r--tests/idltest2.ovsschema85
-rw-r--r--tests/library.at4
-rw-r--r--tests/mpls-xlate.at22
-rw-r--r--tests/odp.at8
-rw-r--r--tests/ofp-print.at44
-rw-r--r--tests/ofproto-dpif.at800
-rw-r--r--tests/ofproto.at42
-rw-r--r--tests/ovsdb-idl.at75
-rw-r--r--tests/ovsdb-server.at2
-rw-r--r--tests/test-aa.c33
-rw-r--r--tests/test-csum.c34
-rw-r--r--tests/test-list.c26
-rw-r--r--tests/tunnel-push-pop.at51
-rwxr-xr-xtutorial/ovs-sandbox7
-rw-r--r--utilities/automake.mk7
-rwxr-xr-xutilities/ovs-appctl-bashcomp.bash3
-rw-r--r--utilities/ovs-command-bashcomp.INSTALL.md13
-rwxr-xr-xutilities/ovs-dev.py5
-rw-r--r--utilities/ovs-ofctl.8.in34
-rwxr-xr-xutilities/ovs-vsctl-bashcomp.bash55
-rw-r--r--utilities/ovs-vsctl.c13
-rwxr-xr-xutilities/qemu-wrap.py389
-rw-r--r--vswitchd/automake.mk2
-rw-r--r--vswitchd/bridge.c78
-rw-r--r--vswitchd/ovs-vswitchd.c10
-rw-r--r--vswitchd/vswitch.ovsschema12
-rw-r--r--vswitchd/vswitch.xml142
-rw-r--r--vtep/automake.mk2
-rw-r--r--xenserver/openvswitch-xen.spec.in5
160 files changed, 7296 insertions, 2107 deletions
diff --git a/.travis/build.sh b/.travis/build.sh
index 942265af3..b6b701c3a 100755
--- a/.travis/build.sh
+++ b/.travis/build.sh
@@ -48,6 +48,7 @@ function install_dpdk()
fi
find ./ -type f | xargs sed -i 's/max-inline-insns-single=100/max-inline-insns-single=400/'
sed -ri 's,(CONFIG_RTE_BUILD_COMBINE_LIBS=).*,\1y,' config/common_linuxapp
+ sed -ri 's,(CONFIG_RTE_LIBRTE_VHOST=).*,\1y,' config/common_linuxapp
sed -ri '/CONFIG_RTE_LIBNAME/a CONFIG_RTE_BUILD_FPIC=y' config/common_linuxapp
sed -ri '/EXECENV_CFLAGS = -pthread -fPIC/{s/$/\nelse ifeq ($(CONFIG_RTE_BUILD_FPIC),y)/;s/$/\nEXECENV_CFLAGS = -pthread -fPIC/}' mk/exec-env/linuxapp/rte.vars.mk
make config CC=gcc T=x86_64-native-linuxapp-gcc
diff --git a/.travis/prepare.sh b/.travis/prepare.sh
index a78282be5..cda80c22b 100755
--- a/.travis/prepare.sh
+++ b/.travis/prepare.sh
@@ -3,6 +3,9 @@
sudo apt-get update -qq
sudo apt-get install -qq libssl-dev llvm-dev
sudo apt-get install -qq gcc-multilib
+if [ "$DPDK" ]; then
+ sudo apt-get install -qq libfuse-dev
+fi
git clone git://git.kernel.org/pub/scm/devel/sparse/chrisl/sparse.git
cd sparse && make && sudo make install PREFIX=/usr && cd ..
diff --git a/AUTHORS b/AUTHORS
index fe79acd28..d17ae7acb 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -85,12 +85,14 @@ Jesse Gross jesse@nicira.com
Jing Ai jinga@google.com
Joe Perches joe@perches.com
Joe Stringer joestringer@nicira.com
+Jonathan Vestin jonavest@kau.se
Jun Nakajima jun.nakajima@intel.com
Justin Pettit jpettit@nicira.com
Keith Amidon keith@nicira.com
Ken Ajiro ajiro@mxw.nes.nec.co.jp
Kenneth Duda kduda@arista.com
Kentaro Ebisawa ebiken.g@gmail.com
+Kevin Lo kevlo@FreeBSD.org
Kevin Traynor kevin.traynor@intel.com
Kmindg G kmindg@gmail.com
Krishna Kondaka kkondaka@vmware.com
@@ -215,6 +217,7 @@ Brad Hall brad@nicira.com
Brandon Heller brandonh@stanford.edu
Brendan Kelley bkelley@nicira.com
Brent Salisbury brent.salisbury@gmail.com
+Brian Field Brian_Field@cable.comcast.com
Bryan Fulton bryan@nicira.com
Bryan Osoro bosoro@nicira.com
Cedric Hobbs cedric@nicira.com
@@ -246,6 +249,7 @@ Gur Stavi gstavi@mrv.com
Hari Sasank Bhamidipalli hbhamidi@cisco.com
Hassan Khan hassan.khan@seecs.edu.pk
Hector Oron hector.oron@gmail.com
+Hemanth Kumar Mantri mantri@nutanix.com
Henrik Amren henrik@nicira.com
Hiroshi Tanaka htanaka@nicira.com
Hiroshi Miyata miyahiro.dazu@gmail.com
@@ -345,6 +349,7 @@ Voravit T. voravit@kth.se
Yeming Zhao zhaoyeming@gmail.com
Ying Chen yingchen@vmware.com
Yongqiang Liu liuyq7809@gmail.com
+Zhangguanghui zhang.guanghui@h3c.com
Ziyou Wang ziyouw@vmware.com
Zoltán Balogh zoltan.balogh@ericsson.com
ankur dwivedi ankurengg2003@gmail.com
diff --git a/Documentation/automake.mk b/Documentation/automake.mk
new file mode 100644
index 000000000..e5048018b
--- /dev/null
+++ b/Documentation/automake.mk
@@ -0,0 +1,2 @@
+EXTRA_DIST += \
+ Documentation/group-selection-method-property.txt
diff --git a/Documentation/group-selection-method-property.txt b/Documentation/group-selection-method-property.txt
new file mode 100644
index 000000000..36337c6b5
--- /dev/null
+++ b/Documentation/group-selection-method-property.txt
@@ -0,0 +1,153 @@
+Proposal for Group Selection Method Property
+Version: 0.0.3
+
+Author: Simon Horman <simon.horman@netronome.com>, et al.
+Initial Public Revision: September 2014
+
+
+Contents
+========
+
+1. Introduction
+2. How it Works
+3. Experimenter Id
+4. Experimenter Messages
+5. History
+
+
+1. Introduction
+===============
+
+This text describes a Netronome Extension to (draft) OpenFlow 1.5 that allows a
+controller to provide more information on the selection method for select
+groups. This proposal is in the form of an enhanced select group type.
+
+This may subsequently be proposed as an extension or update to
+the OpenFlow specification.
+
+
+2. How it works
+===============
+
+A new Netronome group experimenter property is defined which provides
+compatibility with the group mod message defined in draft Open Flow 1.5
+(also known as ONF EXT-350) and allows parameters for the selection
+method of select groups to be passed by the controller. In particular it
+allows controllers to:
+
+* Specify the fields used for bucket selection by the select group.
+
+* Designate the selection method used.
+
+* Provide a non-field parameter to the selection method.
+
+
+3. Experimenter ID
+==================
+
+The Experimenter ID of this extension is:
+
+NTR_VENDOR_ID = 0x00001540
+
+
+4. Group Experimenter Property
+==============================
+
+The following group property experimenter type defined by this extension.
+
+enum ntr_group_mod_subtype {
+ NTRT_SELECTION_METHOD = 1,
+};
+
+
+Modifications to the group table from the controller may be done with a
+OFPT_GROUP_MOD message described (draft) Open Flow 1.5. Group Entry
+Message. Of relevance here is that (draft) Open Flow 1.5 group messages
+have properties.
+
+This proposal is defined in terms of an implementation of struct
+ofp_group_prop_experimenter which is described in (draft) Open Flow 1.5.
+The implementation is:
+
+struct ntr_group_prop_selection_method {
+ ovs_be16 type; /* OFPGPT_EXPERIMENTER. */
+ ovs_be16 length; /* Length in bytes of this property. */
+ ovs_be32 experimenter; /* NTR_VENDOR_ID. */
+ ovs_be32 exp_type; /* NTRT_SELECTION_METHOD. */
+ ovs_be32 pad;
+ char selection_method[NTR_MAX_SELECTION_METHOD_LEN];
+ /* Null-terminated */
+ ovs_be64 selection_method_param; /* Non-Field parameter for
+ * bucket selection. */
+
+ /* Followed by:
+ * - Exactly (length - 40) (possibly 0) bytes containing OXM TLVs, then
+ * - Exactly ((length + 7)/8*8 - length) (between 0 and 7) bytes of
+ * all-zero bytes
+ * In summary, ntr_group_prop_selection_method is padded as needed,
+ * to make its overall size a multiple of 8, to preserve alignment
+ * in structures using it.
+ */
+ /* uint8_t field_array[0]; */ /* Zero or more fields encoded as
+ * OXM TLVs where the has_mask bit must
+ * be zero and the value it specifies is
+ * a mask to apply to packet fields and
+ * then input them to the selection
+ * method of a select group. */
+ /* uint8_t pad2[0]; */
+};
+OFP_ASSERT(sizeof(struct ntr_group_mod) == 40);
+
+
+This property may only be used with group mod messages whose:
+* command is OFPGC_ADD or OFPGC_MODIFY; and
+* type is OFPGT_SELECT
+
+
+The type field is the OFPGPT_EXPERIMENTER which is
+defined in EXT-350 as 0xffff.
+
+
+The experimenter field is the Experimenter ID (see 3).
+
+
+The exp_type field is NTRT_SELECTION_METHOD.
+
+
+The group selection_method is a null-terminated string which if non-zero
+length specifies a selection method known to an underlying layer of the
+switch. The value of NTR_MAX_SELECTION_METHOD_LEN is 16.
+
+The group selection_method may be zero-length to request compatibility with
+Open Flow 1.4.
+
+
+The selection_method_param provides a non-field parameter for
+the group selection_method. It must be all-zeros unless the
+group selection_method is non-zero length.
+
+The selection_method_param may for example be used as an initial value for
+the hash of a hash group selection method.
+
+
+The fields field is an ofp_match structure which includes the fields which
+should be used as inputs to bucket selection. ofp_match is described in
+Open Flow 1.4 section 7.2.2 Flow Match Structures.
+
+Fields must not be specified unless the group selection_method is non-zero
+length.
+
+The pre-requisites for fields specified must be satisfied in the match for
+any flow that uses the group.
+
+Masking is allowed but not required for fields whose TLVs allow masking.
+
+The fields may for example be used as the fields that are hashed
+by a hash group selection method.
+
+
+5. History
+==========
+
+This proposal has been developed independently of any similar work in this
+area. No such work is known.
diff --git a/FAQ.md b/FAQ.md
index b112dfb41..21d4e7a67 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -207,6 +207,7 @@ A: Support for tunnels was added to the upstream Linux kernel module
|:--------:|:-------------:
| GRE | 3.11
| VXLAN | 3.12
+| Geneve | 3.18
| LISP | <not upstream>
If you are using a version of the kernel that is older than the one
@@ -216,6 +217,14 @@ A: Support for tunnels was added to the upstream Linux kernel module
persist after doing this, check to make sure that the module that is
loaded is the one you expect.
+### Q: Why are UDP tunnel checksums not computed for VXLAN or Geneve?
+
+A: Generating outer UDP checksums requires kernel support that was not
+ part of the initial implementation of these protocols. If using the
+ upstream Linux Open vSwitch module, you must use kernel 4.0 or
+ newer. The out-of-tree modules from Open vSwitch release 2.4 and later
+ support UDP checksums.
+
### Q: What features are not available when using the userspace datapath?
A: Tunnel virtual ports are not supported, as described in the
diff --git a/INSTALL.DPDK.md b/INSTALL.DPDK.md
index 276fe562e..60889d01d 100644
--- a/INSTALL.DPDK.md
+++ b/INSTALL.DPDK.md
@@ -16,7 +16,7 @@ OVS needs a system with 1GB hugepages support.
Building and Installing:
------------------------
-Required DPDK 1.8.0
+Required DPDK 1.8.0, `fuse`, `fuse-devel` (`libfuse-dev` on Debian/Ubuntu)
1. Configure build & install DPDK:
1. Set `$DPDK_DIR`
@@ -31,7 +31,12 @@ Required DPDK 1.8.0
`CONFIG_RTE_BUILD_COMBINE_LIBS=y`
- Then run `make install` to build and isntall the library.
+ Update `config/common_linuxapp` so that DPDK is built with vhost
+ libraries:
+
+ `CONFIG_RTE_LIBRTE_VHOST=y`
+
+ Then run `make install` to build and install the library.
For default install without IVSHMEM:
`make install T=x86_64-native-linuxapp-gcc`
@@ -290,12 +295,256 @@ A general rule of thumb for better performance is that the client
application should not be assigned the same dpdk core mask "-c" as
the vswitchd.
+DPDK vhost:
+-----------
+
+vhost-cuse is only supported at present i.e. not using the standard QEMU
+vhost-user interface. It is intended that vhost-user support will be added
+in future releases when supported in DPDK and that vhost-cuse will eventually
+be deprecated. See [DPDK Docs] for more info on vhost.
+
+Prerequisites:
+1. Insert the Cuse module:
+
+ `modprobe cuse`
+
+2. Build and insert the `eventfd_link` module:
+
+ `cd $DPDK_DIR/lib/librte_vhost/eventfd_link/`
+ `make`
+ `insmod $DPDK_DIR/lib/librte_vhost/eventfd_link.ko`
+
+Following the steps above to create a bridge, you can now add DPDK vhost
+as a port to the vswitch.
+
+`ovs-vsctl add-port br0 dpdkvhost0 -- set Interface dpdkvhost0 type=dpdkvhost`
+
+Unlike DPDK ring ports, DPDK vhost ports can have arbitrary names:
+
+`ovs-vsctl add-port br0 port123ABC -- set Interface port123ABC type=dpdkvhost`
+
+However, please note that when attaching userspace devices to QEMU, the
+name provided during the add-port operation must match the ifname parameter
+on the QEMU command line.
+
+
+DPDK vhost VM configuration:
+----------------------------
+
+ vhost ports use a Linux* character device to communicate with QEMU.
+ By default it is set to `/dev/vhost-net`. It is possible to reuse this
+ standard device for DPDK vhost, which makes setup a little simpler but it
+ is better practice to specify an alternative character device in order to
+ avoid any conflicts if kernel vhost is to be used in parallel.
+
+1. This step is only needed if using an alternative character device.
+
+ The new character device filename must be specified on the vswitchd
+ commandline:
+
+ `./vswitchd/ovs-vswitchd --dpdk --cuse_dev_name my-vhost-net -c 0x1 ...`
+
+ Note that the `--cuse_dev_name` argument and associated string must be the first
+ arguments after `--dpdk` and come before the EAL arguments. In the example
+ above, the character device to be used will be `/dev/my-vhost-net`.
+
+2. This step is only needed if reusing the standard character device. It will
+ conflict with the kernel vhost character device so the user must first
+ remove it.
+
+ `rm -rf /dev/vhost-net`
+
+3a. Configure virtio-net adaptors:
+ The following parameters must be passed to the QEMU binary:
+
+ ```
+ -netdev tap,id=<id>,script=no,downscript=no,ifname=<name>,vhost=on
+ -device virtio-net-pci,netdev=net1,mac=<mac>
+ ```
+
+ Repeat the above parameters for multiple devices.
+
+ The DPDK vhost library will negiotiate its own features, so they
+ need not be passed in as command line params. Note that as offloads are
+ disabled this is the equivalent of setting:
+
+ `csum=off,gso=off,guest_tso4=off,guest_tso6=off,guest_ecn=off`
+
+3b. If using an alternative character device. It must be also explicitly
+ passed to QEMU using the `vhostfd` argument:
+
+ ```
+ -netdev tap,id=<id>,script=no,downscript=no,ifname=<name>,vhost=on,
+ vhostfd=<open_fd>
+ -device virtio-net-pci,netdev=net1,mac=<mac>
+ ```
+
+ The open file descriptor must be passed to QEMU running as a child
+ process. This could be done with a simple python script.
+
+ ```
+ #!/usr/bin/python
+ fd = os.open("/dev/usvhost", os.O_RDWR)
+ subprocess.call("qemu-system-x86_64 .... -netdev tap,id=vhostnet0,\
+ vhost=on,vhostfd=" + fd +"...", shell=True)
+
+ Alternatively the the `qemu-wrap.py` script can be used to automate the
+ requirements specified above and can be used in conjunction with libvirt if
+ desired. See the "DPDK vhost VM configuration with QEMU wrapper" section
+ below.
+
+4. Configure huge pages:
+ QEMU must allocate the VM's memory on hugetlbfs. Vhost ports access a
+ virtio-net device's virtual rings and packet buffers mapping the VM's
+ physical memory on hugetlbfs. To enable vhost-ports to map the VM's
+ memory into their process address space, pass the following paramters
+ to QEMU:
+
+ `-object memory-backend-file,id=mem,size=4096M,mem-path=/dev/hugepages,
+ share=on -numa node,memdev=mem -mem-prealloc`
+
+
+DPDK vhost VM configuration with QEMU wrapper:
+----------------------------------------------
+
+The QEMU wrapper script automatically detects and calls QEMU with the
+necessary parameters. It performs the following actions:
+
+ * Automatically detects the location of the hugetlbfs and inserts this
+ into the command line parameters.
+ * Automatically open file descriptors for each virtio-net device and
+ inserts this into the command line parameters.
+ * Calls QEMU passing both the command line parameters passed to the
+ script itself and those it has auto-detected.
+
+Before use, you **must** edit the configuration parameters section of the
+script to point to the correct emulator location and set additional
+settings. Of these settings, `emul_path` and `us_vhost_path` **must** be
+set. All other settings are optional.
+
+To use directly from the command line simply pass the wrapper some of the
+QEMU parameters: it will configure the rest. For example:
+
+```
+qemu-wrap.py -cpu host -boot c -hda <disk image> -m 4096 -smp 4
+ --enable-kvm -nographic -vnc none -net none -netdev tap,id=net1,
+ script=no,downscript=no,ifname=if1,vhost=on -device virtio-net-pci,
+ netdev=net1,mac=00:00:00:00:00:01
+```
+
+DPDK vhost VM configuration with libvirt:
+-----------------------------------------
+
+If you are using libvirt, you must enable libvirt to access the character
+device by adding it to controllers cgroup for libvirtd using the following
+steps.
+
+ 1. In `/etc/libvirt/qemu.conf` add/edit the following lines:
+
+ ```
+ 1) clear_emulator_capabilities = 0
+ 2) user = "root"
+ 3) group = "root"
+ 4) cgroup_device_acl = [
+ "/dev/null", "/dev/full", "/dev/zero",
+ "/dev/random", "/dev/urandom",
+ "/dev/ptmx", "/dev/kvm", "/dev/kqemu",
+ "/dev/rtc", "/dev/hpet", "/dev/net/tun",
+ "/dev/<my-vhost-device>",
+ "/dev/hugepages"]
+ ```
+
+ <my-vhost-device> refers to "vhost-net" if using the `/dev/vhost-net`
+ device. If you have specificed a different name on the ovs-vswitchd
+ commandline using the "--cuse_dev_name" parameter, please specify that
+ filename instead.
+
+ 2. Disable SELinux or set to permissive mode
+
+ 3. Restart the libvirtd process
+ For example, on Fedora:
+
+ `systemctl restart libvirtd.service`
+
+After successfully editing the configuration, you may launch your
+vhost-enabled VM. The XML describing the VM can be configured like so
+within the <qemu:commandline> section:
+
+ 1. Set up shared hugepages:
+
+ ```
+ <qemu:arg value='-object'/>
+ <qemu:arg value='memory-backend-file,id=mem,size=4096M,mem-path=/dev/hugepages,share=on'/>
+ <qemu:arg value='-numa'/>
+ <qemu:arg value='node,memdev=mem'/>
+ <qemu:arg value='-mem-prealloc'/>
+ ```
+
+ 2. Set up your tap devices:
+
+ ```
+ <qemu:arg value='-netdev'/>
+ <qemu:arg value='type=tap,id=net1,script=no,downscript=no,ifname=vhost0,vhost=on'/>
+ <qemu:arg value='-device'/>
+ <qemu:arg value='virtio-net-pci,netdev=net1,mac=00:00:00:00:00:01'/>
+ ```
+
+ Repeat for as many devices as are desired, modifying the id, ifname
+ and mac as necessary.
+
+ Again, if you are using an alternative character device (other than
+ `/dev/vhost-net`), please specify the file descriptor like so:
+
+ `<qemu:arg value='type=tap,id=net3,script=no,downscript=no,ifname=vhost0,vhost=on,vhostfd=<open_fd>'/>`
+
+ Where <open_fd> refers to the open file descriptor of the character device.
+ Instructions of how to retrieve the file descriptor can be found in the
+ "DPDK vhost VM configuration" section.
+ Alternatively, the process is automated with the qemu-wrap.py script,
+ detailed in the next section.
+
+Now you may launch your VM using virt-manager, or like so:
+
+ `virsh create my_vhost_vm.xml`
+
+DPDK vhost VM configuration with libvirt and QEMU wrapper:
+----------------------------------------------------------
+
+To use the qemu-wrapper script in conjuntion with libvirt, follow the
+steps in the previous section before proceeding with the following steps:
+
+ 1. Place `qemu-wrap.py` in libvirtd's binary search PATH ($PATH)
+ Ideally in the same directory that the QEMU binary is located.
+
+ 2. Ensure that the script has the same owner/group and file permissions
+ as the QEMU binary.
+
+ 3. Update the VM xml file using "virsh edit VM.xml"
+
+ 1. Set the VM to use the launch script.
+ Set the emulator path contained in the `<emulator><emulator/>` tags.
+ For example, replace:
+
+ `<emulator>/usr/bin/qemu-kvm<emulator/>`
+
+ with:
+
+ `<emulator>/usr/bin/qemu-wrap.py<emulator/>`
+
+ 4. Edit the Configuration Parameters section of the script to point to
+ the correct emulator location and set any additional options. If you are
+ using a alternative character device name, please set "us_vhost_path" to the
+ location of that device. The script will automatically detect and insert
+ the correct "vhostfd" value in the QEMU command line arguements.
+
+ 5. Use virt-manager to launch the VM
+
Restrictions:
-------------
- - This Support is for Physical NIC. I have tested with Intel NIC only.
- Work with 1500 MTU, needs few changes in DPDK lib to fix this issue.
- Currently DPDK port does not make use any offload functionality.
+ - DPDK-vHost support works with 1G huge pages.
ivshmem:
- The shared memory is currently restricted to the use of a 1GB
@@ -311,3 +560,4 @@ Please report problems to bugs@openvswitch.org.
[INSTALL.userspace.md]:INSTALL.userspace.md
[INSTALL.md]:INSTALL.md
[DPDK Linux GSG]: http://www.dpdk.org/doc/guides/linux_gsg/build_dpdk.html#binding-and-unbinding-network-ports-to-from-the-igb-uioor-vfio-modules
+[DPDK Docs]: http://dpdk.org/doc
diff --git a/INSTALL.Windows.md b/INSTALL.Windows.md
index 258e2fb79..00db4a374 100644
--- a/INSTALL.Windows.md
+++ b/INSTALL.Windows.md
@@ -35,16 +35,19 @@ install Windows Driver Kit (WDK) 8.1 Update.
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.
+studio" and through it enter into the bash shell available from msys by typing
+'bash --login'.
If after the above step, a 'which link' inside MSYS's bash says,
"/bin/link.exe", rename /bin/link.exe to something else so that the
-Visual studio's linker is used.
+Visual studio's linker is used. You should also see a 'which sort' report
+"/bin/sort.exe".
* For pthread support, install the library, dll and includes of pthreads-win32
project from
ftp://sourceware.org/pub/pthreads-win32/prebuilt-dll-2-9-1-release to a
-directory (e.g.: C:/pthread).
+directory (e.g.: C:/pthread). You should add the pthread-win32's dll
+path (e.g.: C:\pthread\dll\x86) to the Windows' PATH environment variable.
* Get the Open vSwitch sources from either cloning the repo using git
or from a distribution tar ball.
@@ -71,10 +74,32 @@ or from a distribution tar ball.
% make
-* To run all the unit tests:
+ For faster compilation, you can pass the '-j' argument to make. For
+ example, to run 4 jobs simultaneously, run 'make -j4'.
+
+ Note: MSYS 1.0.18 has a bug that causes parallel make to hang. You
+ can overcome this by downgrading to MSYS 1.0.17. A simple way to
+ downgrade is to exit all MinGW sessions and then run the command
+ 'mingw-get upgrade msys-core-bin=1.0.17-1' from MSVC developers command
+ prompt.
+
+* To run all the unit tests in Open vSwitch, one at a time:
% make check
+ To run all the unit tests in Open vSwitch, up to 8 in parallel:
+
+ % make check TESTSUITEFLAGS="-j8"
+
+* To install all the compiled executables on the local machine, run:
+
+ % make install
+
+ The above command will install the Open vSwitch executables in
+ C:/openvswitch. You can add 'C:\openvswitch\usr\bin' and
+ 'C:\openvswitch\usr\sbin' to Windows' PATH environment variable
+ for easy access.
+
OpenSSL, Open vSwitch and Visual C++
------------------------------------
To get SSL support for Open vSwitch on Windows, do the following:
@@ -134,128 +159,254 @@ Steps to install the module
---------------------------
01> Run ./uninstall.cmd to remove the old extension.
-02> Run ./install.cmd to insert the new one. For this to work you will have to
+
+02> Run ./install.cmd to insert the new one. For this to work you will have to
turn on TESTSIGNING boot option or 'Disable Driver Signature Enforcement'
during boot.
-03> In the Virtual Switch Manager configuration you should now see "VMWare OVS
-Extension" under 'Virtual Switch Extensions'. Click the check box to enable the
-extension.
-
-Steps to run the user processes & configure VXLAN ports
--------------------------------------------------------
-
-01> Create the conf db file.
-ovsdb\ovsdb-tool.exe create conf.db .\vswitchd\vswitch.ovsschema
-
-02> Run ovsdb-server
-ovsdb\ovsdb-server.exe -v --remote=ptcp:6640:127.0.0.1 conf.db
-
-03> Create integration bridge & pif bridge
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-br br-int
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-br br-pif
-
-04> Dump the ports
-utilities\ovs-dpctl.exe show
-
-* Sample output shows up like this. Currently it is not possible to figure out
-* the mapping between VIF and VM from the output.
-
-$ utilities\ovs-dpctl.exe show
-2014-06-27T01:55:32Z|00001|socket_util|ERR|4789:0.0.0.0:
-socket: Either the application has not called WSAStartup, or WSAStartup failed.
- <<< Ignore this error, it is harmless.
-system@ovs-system:
- lookups: hit:0 missed:0 lost:0
- flows: 0
- masks: hit:0 total:0 hit/pkt:0.00
- port 16777216: internal <<< VTEP created by AllowManagementOS
- setting
- port 16777225: external.1 <<< Physical NIC
- port 16777288: vmNICEmu.1000048 <<< VIF #1
- port 16777289: vmNICSyn.1000049 <<< VIF #2
-
-
-05> Add the physical NIC and the internal port to br-pif
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-pif <port name>
-
-Eg:
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-pif external.1
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-pif internal
-
-06> Add the VIFs to br-int
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-int <port name>
-
-Eg:
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-int vmNICEmu.1000048
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-int vmNICSyn.1000049
-
-07> Verify the status
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 show
-
-Eg:
-$ utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 show
-4cd86499-74df-48bd-a64d-8d115b12a9f2
- Bridge br-pif
- Port internal
- Interface internal
- Port "external.1"
- Interface "external.1"
- Port br-pif
- Interface br-pif
- type: internal
- Bridge br-int
- Port br-int
- Interface br-int
- type: internal
- Port "vmNICEmu.1000048"
- Interface "vmNICEmu.1000048"
- Port "vmNICSyn.1000049"
- Interface "vmNICSyn.1000049"
-
-
-09> Run vswitchd
-vswitchd\ovs-vswitchd.exe -v tcp:127.0.0.1:6640
-
-10> You can figure out the port name to MAC address mapping now. (optional)
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 list interface
-
-//********** VXLAN PORT CONFIGURATION (Supports Multiple ports) ************//
-(Remove all patch ports added to create VLAN networks.)
-11> Add the vxlan port between 172.168.201.101 <-> 172.168.201.102
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-int vxlan-1
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-1 type=vxlan
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-1 options:local_ip=172.168.201.101
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-1 options:remote_ip=172.168.201.102
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-1 options:in_key=flow
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-1 options:out_key=flow
-
-12> Add the vxlan port between 172.168.201.101 <-> 172.168.201.105
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 add-port br-int vxlan-2
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-2 type=vxlan
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-2 options:local_ip=172.168.201.102
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-2 options:remote_ip=172.168.201.105
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-2 options:in_key=flow
-utilities\ovs-vsctl.exe --db=tcp:127.0.0.1:6640 set Interface vxlan-2 options:out_key=flow
-
-
-//********** VLAN CONFIGURATION (Using patch ports) ************//
-(Remove all VXLAN ports from the configuration.)
-13> Add a patch port from br-int to br-pif
-utilities/ovs-vsctl.exe -- add-port br-int patch-to-pif
-utilities/ovs-vsctl.exe -- set interface patch-to-pif type=patch options:peer=patch-to-int
-
-14> Add a patch port from br-pif to br-int
-utilities/ovs-vsctl.exe -- add-port br-pif patch-to-int
-utilities/ovs-vsctl.exe -- set interface patch-to-int type=patch options:peer=patch-to-pif
-
-15> Re-Add the VIF ports with the VLAN tag
-utilities\ovs-vsctl.exe add-port br-int vmNICEmu.1000048 tag=900
-utilities\ovs-vsctl.exe add-port br-int vmNICSyn.1000049 tag=900
+
+03> In the Virtual Switch Manager configuration you can enable the Open vSwitch
+Extension on an existing switch or create a new switch. If you are using an
+existing switch, make sure to enable the "Allow Management OS" option for VXLAN
+to work (covered later).
+
+The command to create a new switch named 'OVS-Extended-Switch' using a physical
+NIC named 'Ethernet 1' is:
+ % New-VMSwitch "OVS-Extended-Switch" -AllowManagementOS $true \
+ -NetAdapterName "Ethernet 1"
+
+Note: you can obtain the list of physical NICs on the host using
+'Get-NetAdapter' command.
+
+04> In the properties of any switch, you should should now see "Open
+vSwitch Extension" under 'Extensions'. Click the check box to enable the
+extension. An alternative way to do the same is to run the following command:
+ % Enable-VMSwitchExtension "Open vSwitch Extension" OVS-Extended-Switch
+
+Note: If you enabled the extension using the command line, a delay of a few
+seconds has been observed for the change to be reflected in the UI. This is
+not a bug in Open vSwitch.
+
+Steps to run the user processes & configure ports
+-------------------------------------------------
+The following steps assume that you have installed the Open vSwitch
+utilities in the local machine via 'make install'.
+
+01> Create the database.
+ % ovsdb-tool create C:\openvswitch\etc\openvswitch\conf.db \
+ C:\openvswitch\usr\share\openvswitch\vswitch.ovsschema
+
+02> Start the ovsdb-server and initialize the database.
+ % ovsdb-server -vfile:info --remote=punix:db.sock --log-file --pidfile \
+ --detach
+ % ovs-vsctl --no-wait init
+
+ If you would like to terminate the started ovsdb-server, run:
+ % ovs-appctl -t ovsdb-server exit
+
+ (Note that the logfile is created at C:/openvswitch/var/log/openvswitch/)
+
+03> Start ovs-vswitchd.
+ % ovs-vswitchd -vfile:info --log-file --pidfile --detach
+
+ If you would like to terminate the started ovs-vswitchd, run:
+ % ovs-appctl exit
+
+ (Note that the logfile is created at C:/openvswitch/var/log/openvswitch/)
+
+04> Create integration bridge & pif bridge
+ % ovs-vsctl add-br br-int
+ % ovs-vsctl add-br br-pif
+
+NOTE: There's a known bug that running the ovs-vsctl command does not
+terminate. This is generally solved by having ovs-vswitchd running. If
+you face the issue despite that, hit Ctrl-C to terminate ovs-vsctl and
+check the output to see if your command succeeded.
+
+NOTE: There's a known bug that the ports added to OVSDB via ovs-vsctl don't
+get to the kernel datapath immediately, ie. they don't show up in the output of
+"ovs-dpctl show" even though they show up in output of "ovs-vsctl show".
+In order to workaround this issue, restart ovs-vswitchd. (You can terminate
+ovs-vswitchd by running 'ovs-appctl exit'.)
+
+05> Dump the ports in the kernel datapath
+ % ovs-dpctl show
+
+* Sample output is as follows:
+
+ % ovs-dpctl show
+ system@ovs-system:
+ lookups: hit:0 missed:0 lost:0
+ flows: 0
+ port 2: br-pif (internal) <<< internal port on 'br-pif' bridge
+ port 1: br-int (internal) <<< internal port on 'br-int' bridge
+
+06> Dump the ports in the OVSDB
+ % ovs-vsctl show
+
+* Sample output is as follows:
+ % ovs-vsctl show
+ a56ec7b5-5b1f-49ec-a795-79f6eb63228b
+ Bridge br-pif
+ Port br-pif
+ Interface br-pif
+ type: internal
+ Bridge br-int
+ Port br-int
+ Interface br-int
+ type: internal
+
+07> Add the physical NIC and the internal port to br-pif.
+
+In OVS for Hyper-V, we use 'external' as a special name to refer to the
+physical NICs connected to the Hyper-V switch. An index is added to this
+special name to refer to the particular physical NIC. Eg. 'external.1' refers
+to the first physical NIC on the Hyper-V switch.
+
+Note: Currently, we assume that the Hyper-V switch on which OVS extension is
+enabled has a single physical NIC connected to it.
+
+Interal port is the virtual adapter created on the Hyper-V switch using the
+'AllowManagementOS' setting. This has already been setup while creating the
+switch using the instructions above. In OVS for Hyper-V, we use a 'internal'
+as a special name to refer to that adapter.
+
+ % ovs-vsctl add-port br-pif external.1
+ % ovs-vsctl add-port br-pif internal
+
+* Dumping the ports should show the additional ports that were just added.
+ Sample output shows up as follows:
+
+ % ovs-dpctl show
+ system@ovs-system:
+ lookups: hit:0 missed:0 lost:0
+ flows: 0
+ port 4: internal (internal) <<< 'AllowManagementOS' adapter on
+ Hyper-V switch
+ port 2: br-pif (internal)
+ port 1: br-int (internal
+ port 3: external.1 <<< Physical NIC
+
+ % ovs-vsctl show
+ a56ec7b5-5b1f-49ec-a795-79f6eb63228b
+ Bridge br-pif
+ Port internal
+ Interface internal
+ Port br-pif
+ Interface br-pif
+ type: internal
+ Bridge br-int
+ Port "external.1"
+ Interface "external.1"
+ Port br-int
+ Interface br-int
+ type: internal
+
+08> Add the VIFs to br-int
+
+Adding VIFs to openvswitch is a two step procedure. The first step is to
+assign a 'OVS port name' which is a unique name across all VIFs on this
+Hyper-V. The next step is to add the VIF to the ovsdb using its 'OVS port
+name' as key.
+
+08a> Assign a unique 'OVS port name' to the VIF
+
+Note that the VIF needs to have been disconnected from the Hyper-V switch
+before assigning a 'OVS port name' to it. In the example below, we assign a
+'OVS port name' called 'ovs-port-a' to a VIF on a VM by name 'VM1'. By using
+index 0 for '$vnic', the first VIF of the VM is being addressed. After
+assigning the name 'ovs-port-a', the VIF is connected back to the Hyper-V
+switch with name 'OVS-HV-Switch', which is assumed to be the Hyper-V switch
+with OVS extension enabled.
+
+ Eg:
+ % import-module .\datapath-windows\misc\OVS.psm1
+ % $vnic = Get-VMNetworkAdapter <Name of the VM>
+ % Disconnect-VMNetworkAdapter -VMNetworkAdapter $vnic[0]
+ % $vnic[0] | Set-VMNetworkAdapterOVSPort -OVSPortName ovs-port-a
+ % Connect-VMNetworkAdapter -VMNetworkAdapter $vnic[0] \
+ -SwitchName OVS-Extended-Switch
+
+08b> Add the VIFs to br-int in ovsdb
+
+ Eg:
+ % ovs-vsctl add-port br-int ovs-port-a
+
+09> Verify the status
+ % ovs-dpctl show
+ system@ovs-system:
+ lookups: hit:0 missed:0 lost:0
+ flows: 0
+ port 4: internal (internal)
+ port 5: ovs-port-a
+ port 2: br-pif (internal)
+ port 1: br-int (internal
+ port 3: external.1
+
+ % ovs-vsctl show
+ 4cd86499-74df-48bd-a64d-8d115b12a9f2
+ Bridge br-pif
+ Port internal
+ Interface internal
+ Port "external.1"
+ Interface "external.1"
+ Port br-pif
+ Interface br-pif
+ type: internal
+ Bridge br-int
+ Port br-int
+ Interface br-int
+ type: internal
+ Port "ovs-port-a"
+ Interface "ovs-port-a"
+
+Steps to configure patch ports and switch VLAN tagging
+------------------------------------------------------
+The Windows Open vSwitch implementation support VLAN tagging in the switch.
+Switch VLAN tagging along with patch ports between 'br-int' and 'br-pif' is
+used to configure VLAN tagging functionality between two VMs on different
+Hyper-Vs. The following examples demonstrate how it can be done:
+
+01> Add a patch port from br-int to br-pif
+ % ovs-vsctl add-port br-int patch-to-pif
+ % ovs-vsctl set interface patch-to-pif type=patch \
+ options:peer=patch-to-int
+
+02> Add a patch port from br-pif to br-int
+ % ovs-vsctl add-port br-pif patch-to-int
+ % ovs-vsctl set interface patch-to-int type=patch \
+ options:peer=patch-to-pif
+
+03> Re-Add the VIF ports with the VLAN tag
+ % ovs-vsctl add-port br-int ovs-port-a tag=900
+ % ovs-vsctl add-port br-int ovs-port-b tag=900
+
+Steps to add VXLAN tunnels
+--------------------------
+The Windows Open vSwitch implementation support VXLAN tunnels. To add VXLAN
+tunnels, the following steps serve as examples.
+
+Note that, any patch ports created between br-int and br-pif MUST be beleted
+prior to adding VXLAN tunnels.
+
+01> Add the vxlan port between 172.168.201.101 <-> 172.168.201.102
+ % ovs-vsctl add-port br-int vxlan-1
+ % ovs-vsctl set Interface vxlan-1 type=vxlan
+ % ovs-vsctl set Interface vxlan-1 options:local_ip=172.168.201.101
+ % ovs-vsctl set Interface vxlan-1 options:remote_ip=172.168.201.102
+ % ovs-vsctl set Interface vxlan-1 options:in_key=flow
+ % ovs-vsctl set Interface vxlan-1 options:out_key=flow
+
+02> Add the vxlan port between 172.168.201.101 <-> 172.168.201.105
+ % ovs-vsctl add-port br-int vxlan-2
+ % ovs-vsctl set Interface vxlan-2 type=vxlan
+ % ovs-vsctl set Interface vxlan-2 options:local_ip=172.168.201.102
+ % ovs-vsctl set Interface vxlan-2 options:remote_ip=172.168.201.105
+ % ovs-vsctl set Interface vxlan-2 options:in_key=flow
+ % ovs-vsctl set Interface vxlan-2 options:out_key=flow
Requirements
------------
-
* We require that you don't disable the "Allow management operating system to
share this network adapter" under 'Virtual Switch Properties' > 'Connection
type: External network', in the HyperV virtual network switch configuration.
@@ -265,9 +416,59 @@ type: External network', in the HyperV virtual network switch configuration.
this is still a work in progress. Till the support is complete we recommend
disabling TX/RX offloads for both the VM's as well as the HyperV.
+Windows Services
+----------------
+Open vSwitch daemons come with support to run as a Windows service. The
+instructions here assume that you have installed the Open vSwitch utilities
+and daemons via 'make install'. The commands shown here can be run from
+MSYS bash or Windows command prompt.
+
+* Create the database.
+
+ % ovsdb-tool create C:/openvswitch/etc/openvswitch/conf.db \
+ "C:/openvswitch/usr/share/openvswitch/vswitch.ovsschema"
+
+* Create the ovsdb-server service and start it.
+
+ % sc create ovsdb-server binpath="C:/Shares/openvswitch/ovsdb/ovsdb-server.exe C:/openvswitch/etc/openvswitch/conf.db -vfile:info --log-file --pidfile --remote=punix:db.sock --service --service-monitor"
+
+ One of the common issues with creating a Windows service is with mungled
+ paths. You can make sure that the correct path has been registered with
+ the Windows services manager by running:
+
+ % sc qc ovsdb-server
+
+ Start the service.
+
+ % sc start ovsdb-server
+
+ Check that the service is healthy by running:
+
+ % sc query ovsdb-server
+
+* Initialize the database.
+
+ % ovs-vsctl --no-wait init
+
+* Create the ovs-vswitchd service and start it.
+
+ % sc create ovs-vswitchd binpath="C:/Shares/openvswitch/vswitchd/ovs-vswitchd.exe --pidfile -vfile:info --log-file --service --service-monitor"
+
+ % sc start ovs-vswitchd
+
+ Check that the service is healthy by running:
+
+ % sc query ovs-vswitchd
+
+* To stop and delete the services, run:
+
+ % sc stop ovs-vswitchd
+ % sc stop ovsdb-server
+ % sc delete ovs-vswitchd
+ % sc delete ovsdb-server
+
Windows autobuild service
-------------------------
-
AppVeyor (appveyor.com) provides a free Windows autobuild service for
opensource projects. Open vSwitch has integration with AppVeyor for
continuous build. A developer can build test his changes for Windows by
diff --git a/INSTALL.md b/INSTALL.md
index 273093baf..81568987d 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -10,6 +10,7 @@ on a specific platform, please see one of these files:
- [INSTALL.RHEL.md]
- [INSTALL.XenServer.md]
- [INSTALL.NetBSD.md]
+ - [INSTALL.Windows.md]
- [INSTALL.DPDK.md]
Build Requirements
@@ -28,6 +29,9 @@ you will need the following software:
analysis and thread-safety checks. For Ubuntu, there are
nightly built packages available on clang's website.
+ * MSVC 2013. See [INSTALL.Windows] for additional Windows build
+ instructions.
+
While OVS may be compatible with other compilers, optimal
support for atomic operations may be missing, making OVS very
slow (see lib/ovs-atomic.h).
@@ -192,6 +196,20 @@ To use 'clang' compiler:
`% ./configure CC=clang`
+To supply special flags to the C compiler, specify them as CFLAGS on
+the configure command line. If you want the default CFLAGS, which
+include "-g" to build debug symbols and "-O2" to enable optimizations,
+you must include them yourself. For example, to build with the
+default CFLAGS plus "-mssse3", you might run configure as follows:
+
+ `% ./configure CFLAGS="-g -O2 -mssse3"`
+
+Note that these CFLAGS are not applied when building the Linux
+kernel module. Custom CFLAGS for the kernel module are supplied
+using the EXTRA_CFLAGS variable when running make. So, for example:
+
+ `% make EXTRA_CFLAGS="-Wno-error=date-time"
+
To build the Linux kernel module, so that you can run the
kernel-based switch, pass the location of the kernel build
directory on --with-linux. For example, to build for a running
@@ -255,6 +273,10 @@ Building the Sources
For improved warnings if you installed "sparse" (see "Prerequisites"),
add C=1 to the command line.
+ Some versions of Clang and ccache are not completely compatible.
+ If you see unusual warnings when you use both together, consider
+ disabling ccache for use with Clang.
+
2. Consider running the testsuite. Refer to "Running the Testsuite"
below, for instructions.
diff --git a/INSTALL.userspace.md b/INSTALL.userspace.md
index 300d6c131..04c02cd8a 100644
--- a/INSTALL.userspace.md
+++ b/INSTALL.userspace.md
@@ -76,7 +76,7 @@ Other settings
On NetBSD, depending on your network topology and applications, the
following configuration might help. See sysctl(7).
- sysctl net.inet.ip.checkinterface=1
+ sysctl -w net.inet.ip.checkinterface=1
Bug Reporting
-------------
diff --git a/Makefile.am b/Makefile.am
index 16d8e8d9e..ef4e2098b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,6 +32,10 @@ AM_CFLAGS = -Wstrict-prototypes
AM_CFLAGS += $(WARNING_FLAGS)
AM_CFLAGS += $(OVS_CFLAGS)
+if DPDK_NETDEV
+AM_CFLAGS += -D_FILE_OFFSET_BITS=64
+endif
+
if NDEBUG
AM_CPPFLAGS += -DNDEBUG
AM_CFLAGS += -fomit-frame-pointer
@@ -133,6 +137,7 @@ OVSIDL_BUILT =
pkgdata_DATA =
sbin_SCRIPTS =
scripts_SCRIPTS =
+completion_SCRIPTS =
scripts_DATA =
SUFFIXES =
check_DATA =
@@ -140,6 +145,7 @@ check_SCRIPTS =
pkgconfig_DATA =
scriptsdir = $(pkgdatadir)/scripts
+completiondir = $(sysconfdir)/bash_completion.d
pkgconfigdir = $(libdir)/pkgconfig
# This ensures that files added to EXTRA_DIST are always distributed,
@@ -196,7 +202,7 @@ dist-hook-git: distfiles
LC_ALL=C sort -u > all-gitfiles; \
LC_ALL=C comm -1 -3 all-distfiles all-gitfiles > missing-distfiles; \
if test -s missing-distfiles; then \
- echo "The distribution is missing the following files:"; \
+ echo "The following files are in git but not the distribution:"; \
cat missing-distfiles; \
exit 1; \
fi; \
@@ -352,6 +358,7 @@ dist-docs:
VERSION=$(VERSION) $(srcdir)/build-aux/dist-docs $(srcdir) $(docs)
.PHONY: dist-docs
+include Documentation/automake.mk
include m4/automake.mk
include lib/automake.mk
include ofproto/automake.mk
diff --git a/NEWS b/NEWS
index 9c7ba62bb..87460a712 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,6 @@
Post-v2.3.0
---------------------
+ - Added support for SFQ, FQ_CoDel and CoDel qdiscs.
- Add bash command-line completion support for ovs-vsctl Please check
utilities/ovs-command-compgen.INSTALL.md for how to use.
- The MAC learning feature now includes per-port fairness to mitigate
@@ -37,6 +38,9 @@ Post-v2.3.0
is executed last, and only if the action set has no "output" or "group"
action.
* OpenFlow 1.4+ flow "importance" is now maintained in the flow table.
+ * A new Netronome extension to OpenFlow 1.5+ allows control over the
+ fields hashed for OpenFlow select groups. See "selection_method" and
+ related options in ovs-ofctl(8) for details.
- ovs-pki: Changed message digest algorithm from MD5 to SHA-1 because
MD5 is no longer secure and some operating systems have started to disable
it in OpenSSL.
@@ -58,8 +62,8 @@ Post-v2.3.0
- A simple wrapper script, 'ovs-docker', to integrate OVS with Docker
containers. If and when there is a native integration of Open vSwitch
with Docker, the wrapper script will be retired.
- - Added support for DPDK Tunneling. VXLAN and GRE are supported protocols.
- This is generic tunneling mechanism for userspace datapath.
+ - Added support for DPDK Tunneling. VXLAN, GRE, and Geneve are supported
+ protocols. This is generic tunneling mechanism for userspace datapath.
- Support for multicast snooping (IGMPv1 and IGMPv2)
- Support for Linux kernels up to 3.19.x
- The documentation now use the term 'destination' to mean one of syslog,
@@ -71,6 +75,8 @@ Post-v2.3.0
Auto-Attach.
- The default OpenFlow and OVSDB ports are now the IANA-assigned
numbers. OpenFlow is 6653 and OVSDB is 6640.
+ - Support for DPDK vHost.
+ - Support for outer UDP checksums in Geneve and VXLAN.
v2.3.0 - 14 Aug 2014
diff --git a/acinclude.m4 b/acinclude.m4
index 18598b333..b09f2f258 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -1,6 +1,6 @@
# -*- autoconf -*-
-# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+# Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -170,7 +170,8 @@ AC_DEFUN([OVS_CHECK_DPDK], [
DPDK_INCLUDE=$RTE_SDK/include
DPDK_LIB_DIR=$RTE_SDK/lib
- DPDK_LIB=-lintel_dpdk
+ DPDK_LIB="-lintel_dpdk"
+ DPDK_EXTRA_LIB="-lfuse"
ovs_save_CFLAGS="$CFLAGS"
ovs_save_LDFLAGS="$LDFLAGS"
@@ -187,7 +188,7 @@ AC_DEFUN([OVS_CHECK_DPDK], [
found=false
save_LIBS=$LIBS
for extras in "" "-ldl"; do
- LIBS="$DPDK_LIB $extras $save_LIBS"
+ LIBS="$DPDK_LIB $extras $save_LIBS $DPDK_EXTRA_LIB"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <rte_config.h>
#include <rte_eal.h>],
@@ -206,7 +207,7 @@ AC_DEFUN([OVS_CHECK_DPDK], [
OVS_LDFLAGS="$OVS_LDFLAGS -L$DPDK_LIB_DIR"
OVS_CFLAGS="$OVS_CFLAGS -I$DPDK_INCLUDE"
- # DPDK 1.7 pmd drivers are not linked unless --whole-archive is used.
+ # DPDK pmd drivers are not linked unless --whole-archive is used.
#
# This happens because the rest of the DPDK code doesn't use any symbol in
# the pmd driver objects, and the drivers register themselves using an
@@ -253,6 +254,37 @@ AC_DEFUN([OVS_GREP_IFELSE], [
fi
])
+dnl OVS_FIND_FIELD_IFELSE(FILE, STRUCTURE, REGEX, [IF-MATCH], [IF-NO-MATCH])
+dnl
+dnl Looks for STRUCTURE in FILE. If it is found, greps for REGEX within the
+dnl structure definition. If this is successful, runs IF-MATCH, otherwise
+dnl IF_NO_MATCH. If IF-MATCH is empty then it defines to
+dnl OVS_DEFINE(HAVE_<STRUCTURE>_WITH_<REGEX>), with <STRUCTURE> and <REGEX>
+dnl translated to uppercase.
+AC_DEFUN([OVS_FIND_FIELD_IFELSE], [
+ AC_MSG_CHECKING([whether $2 has member $3 in $1])
+ if test -f $1; then
+ awk '/$2.{/,/^}/' $1 2>/dev/null | grep '$3'
+ status=$?
+ case $status in
+ 0)
+ AC_MSG_RESULT([yes])
+ m4_if([$4], [], [OVS_DEFINE([HAVE_]m4_toupper([$2])[_WITH_]m4_toupper([$3]))], [$4])
+ ;;
+ 1)
+ AC_MSG_RESULT([no])
+ $5
+ ;;
+ *)
+ AC_MSG_ERROR([grep exited with status $status])
+ ;;
+ esac
+ else
+ AC_MSG_RESULT([file not found])
+ $5
+ fi
+])
+
dnl OVS_DEFINE(NAME)
dnl
dnl Defines NAME to 1 in kcompat.h.
@@ -293,6 +325,8 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
OVS_GREP_IFELSE([$KSRC/include/linux/in.h], [ipv4_is_multicast])
OVS_GREP_IFELSE([$KSRC/include/net/ip.h], [__ip_select_ident.*dst_entry],
[OVS_DEFINE([HAVE_IP_SELECT_IDENT_USING_DST_ENTRY])])
+ OVS_GREP_IFELSE([$KSRC/include/net/ip.h], [inet_get_local_port_range.*net],
+ [OVS_DEFINE([HAVE_INET_GET_LOCAL_PORT_RANGE_USING_NET])])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [dev_disable_lro])
OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], [dev_get_stats])
@@ -365,6 +399,12 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
OVS_GREP_IFELSE([$KSRC/include/net/genetlink.h], [netlink_has_listeners(net->genl_sock],
[OVS_DEFINE([HAVE_GENL_HAS_LISTENERS_TAKES_NET])])
OVS_GREP_IFELSE([$KSRC/include/net/genetlink.h], [genlmsg_parse])
+ OVS_GREP_IFELSE([$KSRC/include/net/genetlink.h], [genl_notify.*family],
+ [OVS_DEFINE([HAVE_GENL_NOTIFY_TAKES_FAMILY])])
+
+ OVS_FIND_FIELD_IFELSE([$KSRC/include/net/genetlink.h],
+ [genl_multicast_group], [id])
+
OVS_GREP_IFELSE([$KSRC/include/net/gre.h], [gre_cisco_register])
OVS_GREP_IFELSE([$KSRC/include/net/ipv6.h], [IP6_FH_F_SKIP_RH])
OVS_GREP_IFELSE([$KSRC/include/net/netlink.h], [nla_get_be16])
@@ -389,9 +429,16 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [
OVS_GREP_IFELSE([$KSRC/include/net/vxlan.h], [struct vxlan_metadata],
[OVS_DEFINE([HAVE_VXLAN_METADATA])])
OVS_GREP_IFELSE([$KSRC/include/net/udp.h], [udp_flow_src_port],
- [OVS_DEFINE([HAVE_UDP_FLOW_SRC_PORT])])
+ [OVS_GREP_IFELSE([$KSRC/include/net/udp.h], [inet_get_local_port_range(net],
+ [OVS_DEFINE([HAVE_UDP_FLOW_SRC_PORT])])])
+ OVS_GREP_IFELSE([$KSRC/include/net/udp.h], [udp_v4_check])
+ OVS_GREP_IFELSE([$KSRC/include/net/udp.h], [udp_set_csum])
OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [ignore_df:1],
[OVS_DEFINE([HAVE_IGNORE_DF_RENAME])])
+ OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [SKB_GSO_GRE_CSUM],
+ [OVS_DEFINE([HAVE_SKB_GSO_GRE_CSUM])])
+ OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [SKB_GSO_UDP_TUNNEL_CSUM],
+ [OVS_DEFINE([HAVE_SKB_GSO_UDP_TUNNEL_CSUM])])
OVS_GREP_IFELSE([$KSRC/include/uapi/linux/netdevice.h], [NET_NAME_UNKNOWN],
[OVS_DEFINE([HAVE_NET_NAME_UNKNOWN])])
@@ -447,7 +494,13 @@ AC_DEFUN([OVS_CHECK_STRTOK_R],
[AC_LANG_PROGRAM([#include <stdio.h>
#include <string.h>
],
- [[char string[] = ":::";
+ [[#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8
+ /* Assume bug is present, because relatively minor
+ changes in compiler settings (e.g. optimization
+ level) can make it crop up. */
+ return 1;
+ #else
+ char string[] = ":::";
char *save_ptr = (char *) 0xc0ffee;
char *token1, *token2;
token1 = strtok_r(string, ":", &save_ptr);
@@ -455,6 +508,7 @@ AC_DEFUN([OVS_CHECK_STRTOK_R],
freopen ("/dev/null", "w", stdout);
printf ("%s %s\n", token1, token2);
return 0;
+ #endif
]])],
[ovs_cv_strtok_r_bug=no],
[ovs_cv_strtok_r_bug=yes],
diff --git a/build-aux/cccl b/build-aux/cccl
index 2a4dccc52..456292e5f 100644
--- a/build-aux/cccl
+++ b/build-aux/cccl
@@ -90,7 +90,7 @@ EOF
;;
-O0)
- clopt="$clopt ${slash}Ot"
+ clopt="$clopt ${slash}Od ${slash}D_DEBUG"
;;
-O2)
diff --git a/datapath-windows/include/OvsDpInterfaceExt.h b/datapath-windows/include/OvsDpInterfaceExt.h
index 7e09caf77..e2353767d 100644
--- a/datapath-windows/include/OvsDpInterfaceExt.h
+++ b/datapath-windows/include/OvsDpInterfaceExt.h
@@ -29,22 +29,27 @@
#define OVS_IOCTL_DEVICE_TYPE 45000
-/* We used Direct I/O (zero copy) for the buffers. */
#define OVS_IOCTL_START 0x100
+/* We used Direct I/O (zero copy) for the buffers. */
+/* Non-Netlink-based IOCTLs. */
+#define OVS_IOCTL_GET_PID \
+ CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x0, METHOD_BUFFERED,\
+ FILE_WRITE_ACCESS)
+/* Netlink-based IOCTLs. */
#define OVS_IOCTL_READ \
- CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x0, METHOD_OUT_DIRECT,\
+ CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x1, METHOD_OUT_DIRECT,\
FILE_READ_ACCESS)
#define OVS_IOCTL_READ_EVENT \
- CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x1, METHOD_OUT_DIRECT, \
+ CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x2, METHOD_OUT_DIRECT, \
FILE_READ_ACCESS)
#define OVS_IOCTL_READ_PACKET \
- CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x2, METHOD_OUT_DIRECT, \
+ CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x3, METHOD_OUT_DIRECT, \
FILE_READ_ACCESS)
#define OVS_IOCTL_WRITE \
- CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x3, METHOD_IN_DIRECT,\
+ CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x4, METHOD_IN_DIRECT,\
FILE_READ_ACCESS)
#define OVS_IOCTL_TRANSACT \
- CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x4, METHOD_OUT_DIRECT,\
+ CTL_CODE (OVS_IOCTL_DEVICE_TYPE, OVS_IOCTL_START + 0x5, METHOD_OUT_DIRECT,\
FILE_WRITE_ACCESS)
/*
@@ -75,7 +80,6 @@
/* Commands available under the OVS_WIN_CONTROL_FAMILY. */
enum ovs_win_control_cmd {
- OVS_CTRL_CMD_WIN_GET_PID,
OVS_CTRL_CMD_WIN_PEND_REQ,
OVS_CTRL_CMD_WIN_PEND_PACKET_REQ,
OVS_CTRL_CMD_MC_SUBSCRIBE_REQ,
diff --git a/datapath-windows/ovsext/BufferMgmt.c b/datapath-windows/ovsext/BufferMgmt.c
index e0377c13a..572b2988a 100644
--- a/datapath-windows/ovsext/BufferMgmt.c
+++ b/datapath-windows/ovsext/BufferMgmt.c
@@ -433,14 +433,14 @@ OvsAllocateMDLAndData(NDIS_HANDLE ndisHandle,
PMDL mdl;
PVOID data;
- data = OvsAllocateMemory(dataSize);
+ data = OvsAllocateMemoryWithTag(dataSize, OVS_MDL_POOL_TAG);
if (data == NULL) {
return NULL;
}
mdl = NdisAllocateMdl(ndisHandle, data, dataSize);
if (mdl == NULL) {
- OvsFreeMemory(data);
+ OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
}
return mdl;
@@ -454,7 +454,7 @@ OvsFreeMDLAndData(PMDL mdl)
data = MmGetMdlVirtualAddress(mdl);
NdisFreeMdl(mdl);
- OvsFreeMemory(data);
+ OvsFreeMemoryWithTag(data, OVS_MDL_POOL_TAG);
}
diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c
index 8eb13f14a..fea7d3a7a 100644
--- a/datapath-windows/ovsext/Datapath.c
+++ b/datapath-windows/ovsext/Datapath.c
@@ -87,8 +87,7 @@ typedef struct _NETLINK_FAMILY {
} NETLINK_FAMILY, *PNETLINK_FAMILY;
/* Handlers for the various netlink commands. */
-static NetlinkCmdHandler OvsGetPidCmdHandler,
- OvsPendEventCmdHandler,
+static NetlinkCmdHandler OvsPendEventCmdHandler,
OvsPendPacketCmdHandler,
OvsSubscribeEventCmdHandler,
OvsSubscribePacketCmdHandler,
@@ -110,6 +109,8 @@ static NTSTATUS HandleGetDpDump(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
UINT32 *replyLen);
static NTSTATUS HandleDpTransactionCommon(
POVS_USER_PARAMS_CONTEXT usrParamsCtx, UINT32 *replyLen);
+static NTSTATUS OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+ UINT32 *replyLen);
/*
* The various netlink families, along with the supported commands. Most of
@@ -120,11 +121,6 @@ static NTSTATUS HandleDpTransactionCommon(
/* Netlink control family: this is a Windows specific family. */
NETLINK_CMD nlControlFamilyCmdOps[] = {
- { .cmd = OVS_CTRL_CMD_WIN_GET_PID,
- .handler = OvsGetPidCmdHandler,
- .supportedDevOp = OVS_TRANSACTION_DEV_OP,
- .validateDpIndex = FALSE,
- },
{ .cmd = OVS_CTRL_CMD_WIN_PEND_REQ,
.handler = OvsPendEventCmdHandler,
.supportedDevOp = OVS_WRITE_DEV_OP,
@@ -349,39 +345,54 @@ extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
NDIS_SPIN_LOCK ovsCtrlLockObj;
PNDIS_SPIN_LOCK gOvsCtrlLock;
+NTSTATUS
+InitUserDumpState(POVS_OPEN_INSTANCE instance,
+ POVS_MESSAGE ovsMsg)
+{
+ /* Clear the dumpState from a previous dump sequence. */
+ ASSERT(instance->dumpState.ovsMsg == NULL);
+ ASSERT(ovsMsg);
+
+ instance->dumpState.ovsMsg =
+ (POVS_MESSAGE)OvsAllocateMemoryWithTag(sizeof(OVS_MESSAGE),
+ OVS_DATAPATH_POOL_TAG);
+ if (instance->dumpState.ovsMsg == NULL) {
+ return STATUS_NO_MEMORY;
+ }
+ RtlCopyMemory(instance->dumpState.ovsMsg, ovsMsg,
+ sizeof *instance->dumpState.ovsMsg);
+ RtlZeroMemory(instance->dumpState.index,
+ sizeof instance->dumpState.index);
+
+ return STATUS_SUCCESS;
+}
VOID
-OvsInit()
+FreeUserDumpState(POVS_OPEN_INSTANCE instance)
{
- HANDLE handle = NULL;
+ if (instance->dumpState.ovsMsg != NULL) {
+ OvsFreeMemoryWithTag(instance->dumpState.ovsMsg,
+ OVS_DATAPATH_POOL_TAG);
+ RtlZeroMemory(&instance->dumpState, sizeof instance->dumpState);
+ }
+}
+VOID
+OvsInit()
+{
gOvsCtrlLock = &ovsCtrlLockObj;
NdisAllocateSpinLock(gOvsCtrlLock);
OvsInitEventQueue();
-
- OvsTunnelEngineOpen(&handle);
- if (handle) {
- OvsTunnelAddSystemProvider(handle);
- }
- OvsTunnelEngineClose(&handle);
}
VOID
OvsCleanup()
{
- HANDLE handle = NULL;
-
OvsCleanupEventQueue();
if (gOvsCtrlLock) {
NdisFreeSpinLock(gOvsCtrlLock);
gOvsCtrlLock = NULL;
}
-
- OvsTunnelEngineOpen(&handle);
- if (handle) {
- OvsTunnelRemoveSystemProvider(handle);
- }
- OvsTunnelEngineClose(&handle);
}
VOID
@@ -448,6 +459,8 @@ OvsCreateDeviceObject(NDIS_HANDLE ovsExtDriverHandle)
if (ovsExt) {
ovsExt->numberOpenInstance = 0;
}
+ } else {
+ OvsRegisterSystemProvider((PVOID)gOvsDeviceObject);
}
OVS_LOG_TRACE("DeviceObject: %p", gOvsDeviceObject);
@@ -471,6 +484,8 @@ OvsDeleteDeviceObject()
NdisDeregisterDeviceEx(gOvsDeviceHandle);
gOvsDeviceHandle = NULL;
gOvsDeviceObject = NULL;
+
+ OvsUnregisterSystemProvider();
}
}
@@ -509,7 +524,8 @@ OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt,
PFILE_OBJECT fileObject)
{
POVS_OPEN_INSTANCE instance =
- (POVS_OPEN_INSTANCE) OvsAllocateMemory(sizeof (OVS_OPEN_INSTANCE));
+ (POVS_OPEN_INSTANCE)OvsAllocateMemoryWithTag(sizeof(OVS_OPEN_INSTANCE),
+ OVS_DATAPATH_POOL_TAG);
UINT32 i;
if (instance == NULL) {
@@ -520,7 +536,7 @@ OvsAddOpenInstance(POVS_DEVICE_EXTENSION ovsExt,
if (ovsNumberOfOpenInstances >= OVS_MAX_OPEN_INSTANCES) {
OvsReleaseCtrlLock();
- OvsFreeMemory(instance);
+ OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(instance, sizeof (OVS_OPEN_INSTANCE));
@@ -571,7 +587,7 @@ OvsRemoveOpenInstance(PFILE_OBJECT fileObject)
OvsReleaseCtrlLock();
ASSERT(instance->eventQueue == NULL);
ASSERT (instance->packetQueue == NULL);
- OvsFreeMemory(instance);
+ OvsFreeMemoryWithTag(instance, OVS_DATAPATH_POOL_TAG);
}
NTSTATUS
@@ -701,8 +717,13 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
/* Check if the extension is enabled. */
if (NULL == gOvsSwitchContext) {
- status = STATUS_DEVICE_NOT_READY;
- goto done;
+ status = STATUS_NOT_FOUND;
+ goto exit;
+ }
+
+ if (!OvsAcquireSwitchContext()) {
+ status = STATUS_NOT_FOUND;
+ goto exit;
}
/* Concurrent netlink operations are not supported. */
@@ -716,6 +737,24 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
* operation.
*/
switch (code) {
+ case OVS_IOCTL_GET_PID:
+ /* Both input buffer and output buffer use the same location. */
+ outputBuffer = irp->AssociatedIrp.SystemBuffer;
+ if (outputBufferLen != 0) {
+ InitUserParamsCtx(irp, instance, 0, NULL,
+ inputBuffer, inputBufferLen,
+ outputBuffer, outputBufferLen,
+ &usrParamsCtx);
+
+ ASSERT(outputBuffer);
+ } else {
+ status = STATUS_NDIS_INVALID_LENGTH;
+ goto done;
+ }
+
+ status = OvsGetPidHandler(&usrParamsCtx, &replyLen);
+ goto done;
+
case OVS_IOCTL_TRANSACT:
/* Both input buffer and output buffer are mandatory. */
if (outputBufferLen != 0) {
@@ -874,6 +913,9 @@ OvsDeviceControl(PDEVICE_OBJECT deviceObject,
status = InvokeNetlinkCmdHandler(&usrParamsCtx, nlFamilyOps, &replyLen);
done:
+ OvsReleaseSwitchContext(gOvsSwitchContext);
+
+exit:
KeMemoryBarrier();
instance->inUse = 0;
@@ -927,11 +969,9 @@ ValidateNetlinkCmd(UINT32 devOp,
}
/* Validate the PID. */
- if (ovsMsg->genlMsg.cmd != OVS_CTRL_CMD_WIN_GET_PID) {
- if (ovsMsg->nlMsg.nlmsgPid != instance->pid) {
- status = STATUS_INVALID_PARAMETER;
- goto done;
- }
+ if (ovsMsg->nlMsg.nlmsgPid != instance->pid) {
+ status = STATUS_INVALID_PARAMETER;
+ goto done;
}
status = STATUS_SUCCESS;
@@ -972,38 +1012,33 @@ InvokeNetlinkCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
/*
* --------------------------------------------------------------------------
- * Command Handler for 'OVS_CTRL_CMD_WIN_GET_PID'.
+ * Handler for 'OVS_IOCTL_GET_PID'.
*
* Each handle on the device is assigned a unique PID when the handle is
- * created. On platforms that support netlink natively, the PID is available
- * to userspace when the netlink socket is created. However, without native
- * netlink support on Windows, OVS datapath generates the PID and lets the
- * userspace query it.
- *
- * This function implements the query.
+ * created. This function passes the PID to userspace using METHOD_BUFFERED
+ * method.
* --------------------------------------------------------------------------
*/
static NTSTATUS
-OvsGetPidCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
- UINT32 *replyLen)
+OvsGetPidHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+ UINT32 *replyLen)
{
- POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
- POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
+ NTSTATUS status = STATUS_SUCCESS;
+ PUINT32 msgOut = (PUINT32)usrParamsCtx->outputBuffer;
if (usrParamsCtx->outputLength >= sizeof *msgOut) {
POVS_OPEN_INSTANCE instance =
(POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
RtlZeroMemory(msgOut, sizeof *msgOut);
- msgOut->nlMsg.nlmsgSeq = msgIn->nlMsg.nlmsgSeq;
- msgOut->nlMsg.nlmsgPid = instance->pid;
+ RtlCopyMemory(msgOut, &instance->pid, sizeof(*msgOut));
*replyLen = sizeof *msgOut;
- /* XXX: We might need to return the DP index as well. */
} else {
- return STATUS_NDIS_INVALID_LENGTH;
+ *replyLen = sizeof *msgOut;
+ status = STATUS_NDIS_INVALID_LENGTH;
}
- return STATUS_SUCCESS;
+ return status;
}
/*
diff --git a/datapath-windows/ovsext/Datapath.h b/datapath-windows/ovsext/Datapath.h
index ba31ece4b..863afc4ca 100644
--- a/datapath-windows/ovsext/Datapath.h
+++ b/datapath-windows/ovsext/Datapath.h
@@ -129,35 +129,10 @@ InitUserParamsCtx(PIRP irp,
usrParamsCtx->outputLength = outputLength;
}
-static __inline NTSTATUS
-InitUserDumpState(POVS_OPEN_INSTANCE instance,
- POVS_MESSAGE ovsMsg)
-{
- /* Clear the dumpState from a previous dump sequence. */
- ASSERT(instance->dumpState.ovsMsg == NULL);
- ASSERT(ovsMsg);
-
- instance->dumpState.ovsMsg =
- (POVS_MESSAGE) OvsAllocateMemory(sizeof (OVS_MESSAGE));
- if (instance->dumpState.ovsMsg == NULL) {
- return STATUS_NO_MEMORY;
- }
- RtlCopyMemory(instance->dumpState.ovsMsg, ovsMsg,
- sizeof *instance->dumpState.ovsMsg);
- RtlZeroMemory(instance->dumpState.index,
- sizeof instance->dumpState.index);
-
- return STATUS_SUCCESS;
-}
+NTSTATUS InitUserDumpState(POVS_OPEN_INSTANCE instance,
+ POVS_MESSAGE ovsMsg);
-static __inline VOID
-FreeUserDumpState(POVS_OPEN_INSTANCE instance)
-{
- if (instance->dumpState.ovsMsg != NULL) {
- OvsFreeMemory(instance->dumpState.ovsMsg);
- RtlZeroMemory(&instance->dumpState, sizeof instance->dumpState);
- }
-}
+VOID FreeUserDumpState(POVS_OPEN_INSTANCE instance);
NTSTATUS OvsSetupDumpStart(POVS_USER_PARAMS_CONTEXT usrParamsCtx);
diff --git a/datapath-windows/ovsext/Event.c b/datapath-windows/ovsext/Event.c
index 00f461609..cca9575b7 100644
--- a/datapath-windows/ovsext/Event.c
+++ b/datapath-windows/ovsext/Event.c
@@ -96,9 +96,9 @@ OvsCleanupEvent(POVS_OPEN_INSTANCE instance)
LIST_FORALL_SAFE(&queue->elemList, link, next) {
elem = CONTAINING_RECORD(link, OVS_EVENT_QUEUE_ELEM, link);
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_EVENT_POOL_TAG);
}
- OvsFreeMemory(queue);
+ OvsFreeMemoryWithTag(queue, OVS_EVENT_POOL_TAG);
}
}
@@ -139,7 +139,8 @@ OvsPostEvent(UINT32 portNo,
portNo == OVS_DEFAULT_PORT_NO) {
queue->pollAll = TRUE;
} else {
- elem = (POVS_EVENT_QUEUE_ELEM)OvsAllocateMemory(sizeof(*elem));
+ elem = (POVS_EVENT_QUEUE_ELEM)OvsAllocateMemoryWithTag(
+ sizeof(*elem), OVS_EVENT_POOL_TAG);
if (elem == NULL) {
queue->pollAll = TRUE;
} else {
@@ -158,7 +159,7 @@ OvsPostEvent(UINT32 portNo,
LIST_FORALL_SAFE(&queue->elemList, curr, next) {
RemoveEntryList(curr);
elem = CONTAINING_RECORD(curr, OVS_EVENT_QUEUE_ELEM, link);
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_EVENT_POOL_TAG);
}
queue->numElems = 0;
}
@@ -243,7 +244,8 @@ OvsSubscribeEventIoctl(PFILE_OBJECT fileObject,
}
if (request->subscribe) {
- queue = (POVS_EVENT_QUEUE)OvsAllocateMemory(sizeof (OVS_EVENT_QUEUE));
+ queue = (POVS_EVENT_QUEUE)OvsAllocateMemoryWithTag(
+ sizeof(OVS_EVENT_QUEUE), OVS_EVENT_POOL_TAG);
if (queue == NULL) {
status = STATUS_NO_MEMORY;
OVS_LOG_WARN("Fail to allocate event queue");
@@ -284,9 +286,9 @@ done_event_subscribe:
}
LIST_FORALL_SAFE(&queue->elemList, link, next) {
elem = CONTAINING_RECORD(link, OVS_EVENT_QUEUE_ELEM, link);
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_EVENT_POOL_TAG);
}
- OvsFreeMemory(queue);
+ OvsFreeMemoryWithTag(queue, OVS_EVENT_POOL_TAG);
} else {
OvsReleaseEventQueueLock();
}
@@ -446,7 +448,7 @@ OvsRemoveEventEntry(POVS_OPEN_INSTANCE instance,
elem = (POVS_EVENT_QUEUE_ELEM)RemoveHeadList(&queue->elemList);
entry->portNo = elem->portNo;
entry->status = elem->status;
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_EVENT_POOL_TAG);
queue->numElems--;
status = STATUS_SUCCESS;
}
diff --git a/datapath-windows/ovsext/Flow.c b/datapath-windows/ovsext/Flow.c
index d3de8cc45..f25fe9a4f 100644
--- a/datapath-windows/ovsext/Flow.c
+++ b/datapath-windows/ovsext/Flow.c
@@ -319,7 +319,7 @@ OvsFlowNlCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
rc = OvsPutFlowIoctl(&mappedFlow, sizeof (struct OvsFlowPut),
&stats);
if (rc != STATUS_SUCCESS) {
- OVS_LOG_ERROR("OvsFlowPut failed.");
+ OVS_LOG_ERROR("OvsPutFlowIoctl failed.");
goto done;
}
@@ -1512,7 +1512,7 @@ OvsDeleteFlowTable(OVS_DATAPATH *datapath)
}
DeleteAllFlows(datapath);
- OvsFreeMemory(datapath->flowTable);
+ OvsFreeMemoryWithTag(datapath->flowTable, OVS_FLOW_POOL_TAG);
datapath->flowTable = NULL;
NdisFreeRWLock(datapath->lock);
@@ -1534,8 +1534,8 @@ OvsAllocateFlowTable(OVS_DATAPATH *datapath,
PLIST_ENTRY bucket;
int i;
- datapath->flowTable = OvsAllocateMemory(OVS_FLOW_TABLE_SIZE *
- sizeof (LIST_ENTRY));
+ datapath->flowTable = OvsAllocateMemoryWithTag(
+ OVS_FLOW_TABLE_SIZE * sizeof(LIST_ENTRY), OVS_FLOW_POOL_TAG);
if (!datapath->flowTable) {
return NDIS_STATUS_RESOURCES;
}
@@ -1976,7 +1976,7 @@ VOID
FreeFlow(OvsFlow *flow)
{
ASSERT(flow);
- OvsFreeMemory(flow);
+ OvsFreeMemoryWithTag(flow, OVS_FLOW_POOL_TAG);
}
NTSTATUS
@@ -2259,7 +2259,8 @@ OvsPrepareFlow(OvsFlow **flow,
do {
*flow = localFlow =
- OvsAllocateMemory(sizeof(OvsFlow) + put->actionsLen);
+ OvsAllocateMemoryWithTag(sizeof(OvsFlow) + put->actionsLen,
+ OVS_FLOW_POOL_TAG);
if (localFlow == NULL) {
status = STATUS_NO_MEMORY;
break;
diff --git a/datapath-windows/ovsext/IpHelper.c b/datapath-windows/ovsext/IpHelper.c
index 0c64be44b..de0d4579a 100644
--- a/datapath-windows/ovsext/IpHelper.c
+++ b/datapath-windows/ovsext/IpHelper.c
@@ -777,7 +777,8 @@ OvsCreateIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
UINT64 timeVal;
ASSERT(ipNeigh != NULL);
- entry = (POVS_IPNEIGH_ENTRY)OvsAllocateMemory(sizeof (OVS_IPNEIGH_ENTRY));
+ entry = (POVS_IPNEIGH_ENTRY)OvsAllocateMemoryWithTag(
+ sizeof(OVS_IPNEIGH_ENTRY), OVS_IPHELPER_POOL_TAG);
if (entry == NULL) {
return NULL;
}
@@ -802,8 +803,8 @@ OvsCreateIPForwardEntry(PMIB_IPFORWARD_ROW2 ipRoute)
ASSERT(ipRoute);
- entry =
- (POVS_IPFORWARD_ENTRY)OvsAllocateMemory(sizeof (OVS_IPFORWARD_ENTRY));
+ entry = (POVS_IPFORWARD_ENTRY)OvsAllocateMemoryWithTag(
+ sizeof(OVS_IPFORWARD_ENTRY), OVS_IPHELPER_POOL_TAG);
if (entry == NULL) {
return NULL;
}
@@ -823,7 +824,8 @@ OvsCreateFwdEntry(POVS_FWD_INFO fwdInfo)
{
POVS_FWD_ENTRY entry;
- entry = (POVS_FWD_ENTRY)OvsAllocateMemory(sizeof (OVS_FWD_ENTRY));
+ entry = (POVS_FWD_ENTRY)OvsAllocateMemoryWithTag(
+ sizeof(OVS_FWD_ENTRY), OVS_IPHELPER_POOL_TAG);
if (entry == NULL) {
return NULL;
}
@@ -855,7 +857,7 @@ OvsRemoveFwdEntry(POVS_FWD_ENTRY fwdEntry)
if (ipf->refCount == 0) {
ASSERT(IsListEmpty(&ipf->fwdList));
RemoveEntryList(&ipf->link);
- OvsFreeMemory(ipf);
+ OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
}
if (ipn->refCount == 0) {
@@ -864,10 +866,10 @@ OvsRemoveFwdEntry(POVS_FWD_ENTRY fwdEntry)
NdisAcquireSpinLock(&ovsIpHelperLock);
RemoveEntryList(&ipn->slink);
NdisReleaseSpinLock(&ovsIpHelperLock);
- OvsFreeMemory(ipn);
+ OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
}
- OvsFreeMemory(fwdEntry);
+ OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG);
}
@@ -886,7 +888,7 @@ OvsRemoveIPForwardEntry(POVS_IPFORWARD_ENTRY ipf)
ASSERT(ipf->refCount == 1);
RemoveEntryList(&ipf->link);
- OvsFreeMemory(ipf);
+ OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
}
@@ -908,7 +910,7 @@ OvsRemoveIPNeighEntry(POVS_IPNEIGH_ENTRY ipn)
NdisAcquireSpinLock(&ovsIpHelperLock);
RemoveEntryList(&ipn->slink);
NdisReleaseSpinLock(&ovsIpHelperLock);
- OvsFreeMemory(ipn);
+ OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
}
}
@@ -1041,7 +1043,7 @@ OvsCleanupIpHelperRequestList(VOID)
STATUS_DEVICE_NOT_READY,
NULL);
}
- OvsFreeMemory(request);
+ OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
}
}
@@ -1076,8 +1078,8 @@ OvsInternalAdapterUp(UINT32 portNo,
RtlCopyMemory(&ovsInternalNetCfgId, netCfgInstanceId, sizeof (GUID));
RtlZeroMemory(&ovsInternalRow, sizeof (MIB_IF_ROW2));
- request =
- (POVS_IP_HELPER_REQUEST)OvsAllocateMemory(sizeof (OVS_IP_HELPER_REQUEST));
+ request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
+ sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
if (request == NULL) {
OVS_LOG_ERROR("Fail to initialize Internal Adapter");
return;
@@ -1103,7 +1105,7 @@ OvsHandleInternalAdapterUp(POVS_IP_HELPER_REQUEST request)
MIB_UNICASTIPADDRESS_ROW ipEntry;
GUID *netCfgInstanceId = &ovsInternalNetCfgId;
- OvsFreeMemory(request);
+ OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
status = OvsGetIfEntry(&ovsInternalNetCfgId, &ovsInternalRow);
@@ -1161,7 +1163,7 @@ OvsEnqueueIpHelperRequest(POVS_IP_HELPER_REQUEST request)
if (ovsInternalPortNo == OVS_DEFAULT_PORT_NO ||
ovsInternalIPConfigured == FALSE) {
NdisReleaseSpinLock(&ovsIpHelperLock);
- OvsFreeMemory(request);
+ OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
return STATUS_NDIS_ADAPTER_NOT_READY;
} else {
InsertHeadList(&ovsIpHelperRequestList, &request->link);
@@ -1185,8 +1187,8 @@ OvsFwdIPHelperRequest(PNET_BUFFER_LIST nbl,
{
POVS_IP_HELPER_REQUEST request;
- request =
- (POVS_IP_HELPER_REQUEST)OvsAllocateMemory(sizeof (OVS_IP_HELPER_REQUEST));
+ request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
+ sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
if (request == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
@@ -1328,15 +1330,15 @@ fwd_handle_nbl:
if (status != STATUS_SUCCESS) {
if (newFWD) {
ASSERT(fwdEntry != NULL);
- OvsFreeMemory(fwdEntry);
+ OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG);
}
if (newIPF) {
ASSERT(ipf && ipf->refCount == 0);
- OvsFreeMemory(ipf);
+ OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
}
if (newIPN) {
ASSERT(ipn && ipn->refCount == 0);
- OvsFreeMemory(ipn);
+ OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
}
ipAddr = request->fwdReq.tunnelKey.dst;
OVS_LOG_INFO("Fail to handle IP helper request for dst: %d.%d.%d.%d",
@@ -1352,7 +1354,7 @@ fwd_handle_nbl:
status,
status == STATUS_SUCCESS ? &fwdInfo : NULL);
}
- OvsFreeMemory(request);
+ OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
}
@@ -1477,7 +1479,7 @@ OvsStartIpHelper(PVOID data)
OvsHandleFwdRequest(req);
break;
default:
- OvsFreeMemory(req);
+ OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);
}
NdisAcquireSpinLock(&ovsIpHelperLock);
}
@@ -1539,14 +1541,14 @@ OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)
HANDLE threadHandle;
UINT32 i;
- ovsFwdHashTable = (PLIST_ENTRY)OvsAllocateMemory(sizeof(LIST_ENTRY) *
- OVS_FWD_HASH_TABLE_SIZE);
+ ovsFwdHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+ sizeof(LIST_ENTRY) * OVS_FWD_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
- ovsRouteHashTable = (PLIST_ENTRY)OvsAllocateMemory(sizeof(LIST_ENTRY) *
- OVS_ROUTE_HASH_TABLE_SIZE);
+ ovsRouteHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+ sizeof(LIST_ENTRY) * OVS_ROUTE_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
- ovsNeighHashTable = (PLIST_ENTRY)OvsAllocateMemory(sizeof(LIST_ENTRY) *
- OVS_NEIGH_HASH_TABLE_SIZE);
+ ovsNeighHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+ sizeof(LIST_ENTRY) * OVS_NEIGH_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
RtlZeroMemory(&ovsInternalRow, sizeof(MIB_IF_ROW2));
RtlZeroMemory(&ovsInternalIPRow, sizeof (MIB_IPINTERFACE_ROW));
@@ -1609,15 +1611,15 @@ init_cleanup:
if (status != STATUS_SUCCESS) {
OvsCancelChangeNotification();
if (ovsFwdHashTable) {
- OvsFreeMemory(ovsFwdHashTable);
+ OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
ovsFwdHashTable = NULL;
}
if (ovsRouteHashTable) {
- OvsFreeMemory(ovsRouteHashTable);
+ OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
ovsRouteHashTable = NULL;
}
if (ovsNeighHashTable) {
- OvsFreeMemory(ovsNeighHashTable);
+ OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
ovsNeighHashTable = NULL;
}
if (ovsTableLock) {
@@ -1644,9 +1646,9 @@ OvsCleanupIpHelper(VOID)
KernelMode, FALSE, NULL);
ObDereferenceObject(ovsIpHelperThreadContext.threadObject);
- OvsFreeMemory(ovsFwdHashTable);
- OvsFreeMemory(ovsRouteHashTable);
- OvsFreeMemory(ovsNeighHashTable);
+ OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
+ OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
+ OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
NdisFreeRWLock(ovsTableLock);
NdisFreeSpinLock(&ovsIpHelperLock);
@@ -1684,6 +1686,6 @@ OvsCancelFwdIpHelperRequest(PNET_BUFFER_LIST nbl)
STATUS_DEVICE_NOT_READY,
NULL);
}
- OvsFreeMemory(req);
+ OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);
}
}
diff --git a/datapath-windows/ovsext/Oid.c b/datapath-windows/ovsext/Oid.c
index 83fa1e306..ea187906d 100644
--- a/datapath-windows/ovsext/Oid.c
+++ b/datapath-windows/ovsext/Oid.c
@@ -605,7 +605,7 @@ OvsIssueOidRequest(POVS_SWITCH_CONTEXT switchContext,
NDIS_STATUS status;
PNDIS_OID_REQUEST oidRequest;
POVS_OID_CONTEXT oidContext;
- ULONG OvsExtOidRequestId = 'ISVO';
+ ULONG OvsExtOidRequestId = 'ISVO';
DBG_UNREFERENCED_PARAMETER(inputSize);
DBG_UNREFERENCED_PARAMETER(oidInputBuffer);
@@ -617,15 +617,17 @@ OvsIssueOidRequest(POVS_SWITCH_CONTEXT switchContext,
ASSERT(oidOutputBuffer == NULL || outputSize != 0);
ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
- oidRequest = OvsAllocateMemory(sizeof *oidRequest);
+ oidRequest = OvsAllocateMemoryWithTag(sizeof *oidRequest,
+ OVS_OID_POOL_TAG);
if (!oidRequest) {
status = NDIS_STATUS_RESOURCES;
goto done;
}
- oidContext = OvsAllocateMemory(sizeof *oidContext);
+ oidContext = OvsAllocateMemoryWithTag(sizeof *oidContext,
+ OVS_OID_POOL_TAG);
if (!oidContext) {
- OvsFreeMemory(oidRequest);
+ OvsFreeMemoryWithTag(oidRequest, OVS_OID_POOL_TAG);
status = NDIS_STATUS_RESOURCES;
goto done;
}
@@ -684,8 +686,8 @@ OvsIssueOidRequest(POVS_SWITCH_CONTEXT switchContext,
status = oidContext->status;
ASSERT(status != NDIS_STATUS_PENDING);
- OvsFreeMemory(oidRequest);
- OvsFreeMemory(oidContext);
+ OvsFreeMemoryWithTag(oidRequest, OVS_OID_POOL_TAG);
+ OvsFreeMemoryWithTag(oidContext, OVS_OID_POOL_TAG);
done:
OVS_LOG_TRACE("Exit: status %8x.", status);
@@ -710,7 +712,8 @@ OvsQuerySwitchActivationComplete(POVS_SWITCH_CONTEXT switchContext,
OVS_LOG_TRACE("Enter: switchContext: %p, switchActive: %p",
switchContext, switchActive);
- switchParams = OvsAllocateMemory(sizeof *switchParams);
+ switchParams = OvsAllocateMemoryWithTag(sizeof *switchParams,
+ OVS_OID_POOL_TAG);
if (!switchParams) {
status = NDIS_STATUS_RESOURCES;
goto done;
@@ -741,7 +744,7 @@ OvsQuerySwitchActivationComplete(POVS_SWITCH_CONTEXT switchContext,
*switchActive = switchParams->IsActive;
}
- OvsFreeMemory(switchParams);
+ OvsFreeMemoryWithTag(switchParams, OVS_OID_POOL_TAG);
done:
OVS_LOG_TRACE("Exit: status %8x, switchActive: %d.",
@@ -769,7 +772,7 @@ OvsGetPortsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
do {
UINT32 reqdArraySize;
- portArray = OvsAllocateMemory(arraySize);
+ portArray = OvsAllocateMemoryWithTag(arraySize, OVS_OID_POOL_TAG);
if (!portArray) {
status = NDIS_STATUS_RESOURCES;
goto done;
@@ -794,7 +797,7 @@ OvsGetPortsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
break;
}
- OvsFreeMemory(portArray);
+ OvsFreeMemoryWithTag(portArray, OVS_OID_POOL_TAG);
arraySize = reqdArraySize;
if (status != NDIS_STATUS_INVALID_LENGTH) {
break;
@@ -827,7 +830,7 @@ OvsGetNicsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
do {
UINT32 reqdArraySize;
- nicArray = OvsAllocateMemory(arraySize);
+ nicArray = OvsAllocateMemoryWithTag(arraySize, OVS_OID_POOL_TAG);
if (!nicArray) {
status = NDIS_STATUS_RESOURCES;
goto done;
@@ -852,7 +855,7 @@ OvsGetNicsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
break;
}
- OvsFreeMemory(nicArray);
+ OvsFreeMemoryWithTag(nicArray, OVS_OID_POOL_TAG);
arraySize = reqdArraySize;
if (status != NDIS_STATUS_INVALID_LENGTH) {
break;
@@ -863,3 +866,17 @@ done:
OVS_LOG_TRACE("Exit: status %8x.", status);
return status;
}
+
+VOID OvsFreeSwitchPortsArray(PNDIS_SWITCH_PORT_ARRAY portsArray)
+{
+ if (portsArray) {
+ OvsFreeMemoryWithTag(portsArray, OVS_OID_POOL_TAG);
+ }
+}
+
+VOID OvsFreeSwitchNicsArray(PNDIS_SWITCH_NIC_ARRAY nicsArray)
+{
+ if (nicsArray) {
+ OvsFreeMemoryWithTag(nicsArray, OVS_OID_POOL_TAG);
+ }
+}
diff --git a/datapath-windows/ovsext/Oid.h b/datapath-windows/ovsext/Oid.h
index 88a3d7d04..ffa4d60cb 100644
--- a/datapath-windows/ovsext/Oid.h
+++ b/datapath-windows/ovsext/Oid.h
@@ -23,4 +23,7 @@ NDIS_STATUS OvsGetPortsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
PNDIS_SWITCH_PORT_ARRAY *portArrayOut);
NDIS_STATUS OvsGetNicsOnSwitch(POVS_SWITCH_CONTEXT switchContext,
PNDIS_SWITCH_NIC_ARRAY *nicArrayOut);
+VOID OvsFreeSwitchPortsArray(PNDIS_SWITCH_PORT_ARRAY portsArray);
+VOID OvsFreeSwitchNicsArray(PNDIS_SWITCH_NIC_ARRAY nicsArray);
+
#endif /* __OID_H_ */
diff --git a/datapath-windows/ovsext/Switch.c b/datapath-windows/ovsext/Switch.c
index a228d8e3b..4f4591fca 100644
--- a/datapath-windows/ovsext/Switch.c
+++ b/datapath-windows/ovsext/Switch.c
@@ -42,6 +42,12 @@ extern PNDIS_SPIN_LOCK gOvsCtrlLock;
extern NDIS_HANDLE gOvsExtDriverHandle;
extern NDIS_HANDLE gOvsExtDriverObject;
+/*
+ * Reference count used to prevent premature deallocation of the global switch
+ * context structure, gOvsSwitchContext.
+ */
+volatile LONG gOvsSwitchContextRefCount = 1;
+
static NDIS_STATUS OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
POVS_SWITCH_CONTEXT *switchContextOut);
static NDIS_STATUS OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext);
@@ -168,8 +174,8 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
OVS_LOG_TRACE("Enter: Create switch object");
- switchContext =
- (POVS_SWITCH_CONTEXT) OvsAllocateMemory(sizeof(OVS_SWITCH_CONTEXT));
+ switchContext = (POVS_SWITCH_CONTEXT) OvsAllocateMemoryWithTag(
+ sizeof(OVS_SWITCH_CONTEXT), OVS_SWITCH_POOL_TAG);
if (switchContext == NULL) {
status = NDIS_STATUS_RESOURCES;
goto create_switch_done;
@@ -187,7 +193,7 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
if (status != NDIS_STATUS_SUCCESS) {
OVS_LOG_ERROR("OvsExtAttach: Extension is running in "
"non-switch environment.");
- OvsFreeMemory(switchContext);
+ OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG);
goto create_switch_done;
}
@@ -198,14 +204,14 @@ OvsCreateSwitch(NDIS_HANDLE ndisFilterHandle,
status = OvsInitSwitchContext(switchContext);
if (status != NDIS_STATUS_SUCCESS) {
- OvsFreeMemory(switchContext);
+ OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG);
goto create_switch_done;
}
status = OvsTunnelFilterInitialize(gOvsExtDriverObject);
if (status != NDIS_STATUS_SUCCESS) {
OvsUninitSwitchContext(switchContext);
- OvsFreeMemory(switchContext);
+ OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG);
goto create_switch_done;
}
*switchContextOut = switchContext;
@@ -264,7 +270,7 @@ OvsDeleteSwitch(POVS_SWITCH_CONTEXT switchContext)
OvsTunnelFilterUninitialize(gOvsExtDriverObject);
OvsClearAllSwitchVports(switchContext);
OvsUninitSwitchContext(switchContext);
- OvsFreeMemory(switchContext);
+ OvsFreeMemoryWithTag(switchContext, OVS_SWITCH_POOL_TAG);
}
OVS_LOG_TRACE("Exit: deleted switch %p dpNo: %d", switchContext, dpNo);
}
@@ -358,14 +364,14 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
switchContext->dispatchLock =
NdisAllocateRWLock(switchContext->NdisFilterHandle);
- switchContext->portNoHashArray = (PLIST_ENTRY)
- OvsAllocateMemory(sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE);
- switchContext->ovsPortNameHashArray = (PLIST_ENTRY)
- OvsAllocateMemory(sizeof (LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE);
- switchContext->portIdHashArray= (PLIST_ENTRY)
- OvsAllocateMemory(sizeof (LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE);
- switchContext->pidHashArray = (PLIST_ENTRY)
- OvsAllocateMemory(sizeof(LIST_ENTRY) * OVS_MAX_PID_ARRAY_SIZE);
+ switchContext->portNoHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+ sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
+ switchContext->ovsPortNameHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+ sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
+ switchContext->portIdHashArray= (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+ sizeof(LIST_ENTRY) * OVS_MAX_VPORT_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
+ switchContext->pidHashArray = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
+ sizeof(LIST_ENTRY) * OVS_MAX_PID_ARRAY_SIZE, OVS_SWITCH_POOL_TAG);
status = OvsAllocateFlowTable(&switchContext->datapath, switchContext);
if (status == NDIS_STATUS_SUCCESS) {
@@ -381,17 +387,20 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
NdisFreeRWLock(switchContext->dispatchLock);
}
if (switchContext->portNoHashArray) {
- OvsFreeMemory(switchContext->portNoHashArray);
+ OvsFreeMemoryWithTag(switchContext->portNoHashArray,
+ OVS_SWITCH_POOL_TAG);
}
if (switchContext->ovsPortNameHashArray) {
- OvsFreeMemory(switchContext->ovsPortNameHashArray);
+ OvsFreeMemoryWithTag(switchContext->ovsPortNameHashArray,
+ OVS_SWITCH_POOL_TAG);
}
if (switchContext->portIdHashArray) {
- OvsFreeMemory(switchContext->portIdHashArray);
+ OvsFreeMemoryWithTag(switchContext->portIdHashArray,
+ OVS_SWITCH_POOL_TAG);
}
-
if (switchContext->pidHashArray) {
- OvsFreeMemory(switchContext->pidHashArray);
+ OvsFreeMemoryWithTag(switchContext->pidHashArray,
+ OVS_SWITCH_POOL_TAG);
}
OvsDeleteFlowTable(&switchContext->datapath);
@@ -420,6 +429,7 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
switchContext->isActivateFailed = FALSE;
switchContext->dpNo = OVS_DP_NUMBER;
ovsTimeIncrementPerTick = KeQueryTimeIncrement() / 10000;
+
OVS_LOG_TRACE("Exit: Succesfully initialized switchContext: %p",
switchContext);
return NDIS_STATUS_SUCCESS;
@@ -428,6 +438,12 @@ OvsInitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
static VOID
OvsUninitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
{
+ OvsReleaseSwitchContext(switchContext);
+}
+
+VOID
+OvsDeleteSwitchContext(POVS_SWITCH_CONTEXT switchContext)
+{
OVS_LOG_TRACE("Enter: Delete switchContext:%p", switchContext);
/* We need to do cleanup for tunnel port here. */
@@ -437,19 +453,66 @@ OvsUninitSwitchContext(POVS_SWITCH_CONTEXT switchContext)
NdisFreeRWLock(switchContext->dispatchLock);
switchContext->dispatchLock = NULL;
NdisFreeSpinLock(&(switchContext->pidHashLock));
- OvsFreeMemory(switchContext->ovsPortNameHashArray);
+ OvsFreeMemoryWithTag(switchContext->ovsPortNameHashArray,
+ OVS_SWITCH_POOL_TAG);
switchContext->ovsPortNameHashArray = NULL;
- OvsFreeMemory(switchContext->portIdHashArray);
+ OvsFreeMemoryWithTag(switchContext->portIdHashArray,
+ OVS_SWITCH_POOL_TAG);
switchContext->portIdHashArray = NULL;
- OvsFreeMemory(switchContext->portNoHashArray);
+ OvsFreeMemoryWithTag(switchContext->portNoHashArray,
+ OVS_SWITCH_POOL_TAG);
switchContext->portNoHashArray = NULL;
- OvsFreeMemory(switchContext->pidHashArray);
+ OvsFreeMemoryWithTag(switchContext->pidHashArray,
+ OVS_SWITCH_POOL_TAG);
switchContext->pidHashArray = NULL;
OvsDeleteFlowTable(&switchContext->datapath);
OvsCleanupBufferPool(switchContext);
OVS_LOG_TRACE("Exit: Delete switchContext: %p", switchContext);
}
+VOID
+OvsReleaseSwitchContext(POVS_SWITCH_CONTEXT switchContext)
+{
+ LONG ref = 0;
+ LONG newRef = 0;
+ LONG icxRef = 0;
+
+ do {
+ ref = gOvsSwitchContextRefCount;
+ newRef = (0 == ref) ? 0 : ref - 1;
+ icxRef = InterlockedCompareExchange(&gOvsSwitchContextRefCount,
+ newRef,
+ ref);
+ } while (icxRef != ref);
+
+ if (ref == 1) {
+ OvsDeleteSwitchContext(switchContext);
+ }
+}
+
+BOOLEAN
+OvsAcquireSwitchContext(VOID)
+{
+ LONG ref = 0;
+ LONG newRef = 0;
+ LONG icxRef = 0;
+ BOOLEAN ret = FALSE;
+
+ do {
+ ref = gOvsSwitchContextRefCount;
+ newRef = (0 == ref) ? 0 : ref + 1;
+ icxRef = InterlockedCompareExchange(&gOvsSwitchContextRefCount,
+ newRef,
+ ref);
+ } while (icxRef != ref);
+
+ if (ref != 0) {
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
/*
* --------------------------------------------------------------------------
* This function activates the switch by initializing it with all the runtime
diff --git a/datapath-windows/ovsext/Switch.h b/datapath-windows/ovsext/Switch.h
index 796007254..6ec34e1f4 100644
--- a/datapath-windows/ovsext/Switch.h
+++ b/datapath-windows/ovsext/Switch.h
@@ -202,7 +202,6 @@ OvsAcquireDatapathWrite(OVS_DATAPATH *datapath,
dispatch ? NDIS_RWL_AT_DISPATCH_LEVEL : 0);
}
-
static __inline VOID
OvsReleaseDatapath(OVS_DATAPATH *datapath,
LOCK_STATE_EX *lockState)
@@ -211,6 +210,11 @@ OvsReleaseDatapath(OVS_DATAPATH *datapath,
NdisReleaseRWLock(datapath->lock, lockState);
}
+BOOLEAN
+OvsAcquireSwitchContext(VOID);
+
+VOID
+OvsReleaseSwitchContext(POVS_SWITCH_CONTEXT switchContext);
PVOID OvsGetExternalVport();
diff --git a/datapath-windows/ovsext/TunnelFilter.c b/datapath-windows/ovsext/TunnelFilter.c
index e0adc3726..4b879c059 100644
--- a/datapath-windows/ovsext/TunnelFilter.c
+++ b/datapath-windows/ovsext/TunnelFilter.c
@@ -111,6 +111,7 @@ DEFINE_GUID(
PDEVICE_OBJECT gDeviceObject;
HANDLE gEngineHandle = NULL;
+HANDLE gBfeSubscriptionHandle = NULL;
UINT32 gCalloutIdV4;
@@ -173,17 +174,20 @@ OvsTunnelAddSystemProvider(HANDLE handle)
provider.displayData.name = OVS_TUNNEL_PROVIDER_NAME;
provider.displayData.description = OVS_TUNNEL_PROVIDER_DESC;
/*
- * Since we always want the provider to be present, it's easiest to add
- * it as persistent object during driver load.
- */
+ * Since we always want the provider to be present, it's easiest to add
+ * it as persistent object during driver load.
+ */
provider.flags = FWPM_PROVIDER_FLAG_PERSISTENT;
status = FwpmProviderAdd(handle,
&provider,
NULL);
if (!NT_SUCCESS(status)) {
- OVS_LOG_ERROR("Fail to add WFP provider, status: %x.", status);
- break;
+ if (STATUS_FWP_ALREADY_EXISTS != status) {
+ OVS_LOG_ERROR("Failed to add WFP provider, status: %x.",
+ status);
+ break;
+ }
}
status = FwpmTransactionCommit(handle);
@@ -541,3 +545,88 @@ Exit:
return status;
}
+
+VOID NTAPI
+OvsBfeStateChangeCallback(PVOID context,
+ FWPM_SERVICE_STATE bfeState)
+{
+ HANDLE handle = NULL;
+
+ DBG_UNREFERENCED_PARAMETER(context);
+
+ if (FWPM_SERVICE_RUNNING == bfeState) {
+ OvsTunnelEngineOpen(&handle);
+ if (handle) {
+ OvsTunnelAddSystemProvider(handle);
+ }
+ OvsTunnelEngineClose(&handle);
+ }
+}
+
+NTSTATUS
+OvsSubscribeBfeStateChanges(PVOID deviceObject)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (!gBfeSubscriptionHandle) {
+ status = FwpmBfeStateSubscribeChanges(deviceObject,
+ OvsBfeStateChangeCallback,
+ NULL,
+ &gBfeSubscriptionHandle);
+ if (!NT_SUCCESS(status)) {
+ OVS_LOG_ERROR(
+ "Failed to open subscribe BFE state change callback, status: %x.",
+ status);
+ }
+ }
+
+ return status;
+}
+
+VOID
+OvsUnsubscribeBfeStateChanges()
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ if (gBfeSubscriptionHandle) {
+ status = FwpmBfeStateUnsubscribeChanges(gBfeSubscriptionHandle);
+ if (!NT_SUCCESS(status)) {
+ OVS_LOG_ERROR(
+ "Failed to open unsubscribe BFE state change callback, status: %x.",
+ status);
+ }
+ gBfeSubscriptionHandle = NULL;
+ }
+}
+
+VOID OvsRegisterSystemProvider(PVOID deviceObject)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ HANDLE handle = NULL;
+
+ status = OvsSubscribeBfeStateChanges(deviceObject);
+ if (NT_SUCCESS(status)) {
+ if (FWPM_SERVICE_RUNNING == FwpmBfeStateGet()) {
+ OvsTunnelEngineOpen(&handle);
+ if (handle) {
+ OvsTunnelAddSystemProvider(handle);
+ }
+ OvsTunnelEngineClose(&handle);
+
+ OvsUnsubscribeBfeStateChanges();
+ }
+ }
+}
+
+VOID OvsUnregisterSystemProvider()
+{
+ HANDLE handle = NULL;
+
+ OvsTunnelEngineOpen(&handle);
+ if (handle) {
+ OvsTunnelRemoveSystemProvider(handle);
+ }
+ OvsTunnelEngineClose(&handle);
+
+ OvsUnsubscribeBfeStateChanges();
+}
diff --git a/datapath-windows/ovsext/TunnelIntf.h b/datapath-windows/ovsext/TunnelIntf.h
index b2bba308e..728a53f7f 100644
--- a/datapath-windows/ovsext/TunnelIntf.h
+++ b/datapath-windows/ovsext/TunnelIntf.h
@@ -22,12 +22,8 @@ NTSTATUS OvsTunnelFilterInitialize(PDRIVER_OBJECT driverObject);
VOID OvsTunnelFilterUninitialize(PDRIVER_OBJECT driverObject);
-NTSTATUS OvsTunnelEngineOpen(HANDLE *handle);
+VOID OvsRegisterSystemProvider(PVOID deviceObject);
-VOID OvsTunnelEngineClose(HANDLE *handle);
-
-VOID OvsTunnelAddSystemProvider(HANDLE handle);
-
-VOID OvsTunnelRemoveSystemProvider(HANDLE handle);
+VOID OvsUnregisterSystemProvider();
#endif /* __TUNNEL_INTF_H_ */
diff --git a/datapath-windows/ovsext/User.c b/datapath-windows/ovsext/User.c
index d8a657e32..03f0377d9 100644
--- a/datapath-windows/ovsext/User.c
+++ b/datapath-windows/ovsext/User.c
@@ -85,7 +85,7 @@ OvsPurgePacketQueue(POVS_USER_PACKET_QUEUE queue,
LIST_FORALL_SAFE(&tmp, link, next) {
RemoveEntryList(link);
elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
}
}
@@ -132,13 +132,13 @@ OvsCleanupPacketQueue(POVS_OPEN_INSTANCE instance)
LIST_FORALL_SAFE(&tmp, link, next) {
RemoveEntryList(link);
elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
}
if (irp) {
OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
}
if (queue) {
- OvsFreeMemory(queue);
+ OvsFreeMemoryWithTag(queue, OVS_USER_POOL_TAG);
}
/* Verify if gOvsSwitchContext exists. */
@@ -170,7 +170,8 @@ OvsSubscribeDpIoctl(PVOID instanceP,
OvsReleasePidHashLock();
} else if (instance->packetQueue == NULL && join) {
- queue = (POVS_USER_PACKET_QUEUE) OvsAllocateMemory(sizeof *queue);
+ queue = (POVS_USER_PACKET_QUEUE) OvsAllocateMemoryWithTag(
+ sizeof *queue, OVS_USER_POOL_TAG);
if (queue == NULL) {
return STATUS_NO_MEMORY;
}
@@ -248,7 +249,7 @@ OvsReadDpIoctl(PFILE_OBJECT fileObject,
}
*replyLen = len;
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
}
return STATUS_SUCCESS;
}
@@ -762,7 +763,7 @@ OvsQueuePackets(PLIST_ENTRY packetList,
while (!IsListEmpty(&dropPackets)) {
link = RemoveHeadList(&dropPackets);
elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
num++;
}
@@ -1060,7 +1061,8 @@ OvsCreateQueueNlPacket(PVOID userData,
dataLen + extraLen);
allocLen = sizeof (OVS_PACKET_QUEUE_ELEM) + nlMsgSize;
- elem = (POVS_PACKET_QUEUE_ELEM)OvsAllocateMemory(allocLen);
+ elem = (POVS_PACKET_QUEUE_ELEM)OvsAllocateMemoryWithTag(allocLen,
+ OVS_USER_POOL_TAG);
if (elem == NULL) {
ovsUserStats.dropDuetoResource++;
return NULL;
@@ -1163,6 +1165,6 @@ OvsCreateQueueNlPacket(PVOID userData,
return elem;
fail:
- OvsFreeMemory(elem);
+ OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
return NULL;
}
diff --git a/datapath-windows/ovsext/Util.c b/datapath-windows/ovsext/Util.c
index 2dfba8e3a..65dd1327a 100644
--- a/datapath-windows/ovsext/Util.c
+++ b/datapath-windows/ovsext/Util.c
@@ -24,6 +24,21 @@
extern NDIS_HANDLE gOvsExtDriverHandle;
+VOID*
+OvsAllocateMemoryWithTag(size_t size, ULONG tag)
+{
+ OVS_VERIFY_IRQL_LE(DISPATCH_LEVEL);
+ return NdisAllocateMemoryWithTagPriority(gOvsExtDriverHandle,
+ (UINT32)size, tag, NormalPoolPriority);
+}
+
+VOID
+OvsFreeMemoryWithTag(VOID *ptr, ULONG tag)
+{
+ ASSERT(ptr);
+ NdisFreeMemoryWithTagPriority(gOvsExtDriverHandle, ptr, tag);
+}
+
VOID *
OvsAllocateMemory(size_t size)
{
diff --git a/datapath-windows/ovsext/Util.h b/datapath-windows/ovsext/Util.h
index e75220931..9a0124245 100644
--- a/datapath-windows/ovsext/Util.h
+++ b/datapath-windows/ovsext/Util.h
@@ -23,10 +23,22 @@
#define OVS_NBL_ONLY_POOL_TAG 'OSVO'
#define OVS_NET_BUFFER_POOL_TAG 'NSVO'
#define OVS_OTHER_POOL_TAG 'MSVO'
+#define OVS_MDL_POOL_TAG 'BSVO'
+#define OVS_DATAPATH_POOL_TAG 'DSVO'
+#define OVS_EVENT_POOL_TAG 'ESVO'
+#define OVS_FLOW_POOL_TAG 'LSVO'
+#define OVS_VXLAN_POOL_TAG 'XSVO'
+#define OVS_IPHELPER_POOL_TAG 'HSVO'
+#define OVS_OID_POOL_TAG 'ASVO'
+#define OVS_SWITCH_POOL_TAG 'SSVO'
+#define OVS_USER_POOL_TAG 'USVO'
+#define OVS_VPORT_POOL_TAG 'PSVO'
VOID *OvsAllocateMemory(size_t size);
+VOID *OvsAllocateMemoryWithTag(size_t size, ULONG tag);
VOID *OvsAllocateAlignedMemory(size_t size, UINT16 align);
VOID OvsFreeMemory(VOID *ptr);
+VOID OvsFreeMemoryWithTag(VOID *ptr, ULONG tag);
VOID OvsFreeAlignedMemory(VOID *ptr);
#define LIST_FORALL(_headPtr, _itemPtr) \
diff --git a/datapath-windows/ovsext/Vport.c b/datapath-windows/ovsext/Vport.c
index c9dfaeaf6..f46a0ac04 100644
--- a/datapath-windows/ovsext/Vport.c
+++ b/datapath-windows/ovsext/Vport.c
@@ -167,8 +167,8 @@ HvUpdatePort(POVS_SWITCH_CONTEXT switchContext,
* Update properties only for NETDEV ports for supprting PS script
* We don't allow changing the names of the internal or external ports
*/
- if (vport == NULL || ( vport->portType != NdisSwitchPortTypeSynthetic) ||
- ( vport->portType != NdisSwitchPortTypeEmulated)) {
+ if (vport == NULL || (( vport->portType != NdisSwitchPortTypeSynthetic) &&
+ ( vport->portType != NdisSwitchPortTypeEmulated))) {
goto update_port_done;
}
@@ -306,7 +306,7 @@ HvCreateNic(POVS_SWITCH_CONTEXT switchContext,
OvsInitPhysNicVport(vport, virtExtVport, nicParam->NicIndex);
status = InitHvVportCommon(switchContext, vport, TRUE);
if (status != NDIS_STATUS_SUCCESS) {
- OvsFreeMemory(vport);
+ OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
goto add_nic_done;
}
}
@@ -404,6 +404,7 @@ HvUpdateNic(POVS_SWITCH_CONTEXT switchContext,
nicParam->PortId,
nicParam->NicIndex);
if (vport == NULL) {
+ NdisReleaseRWLock(switchContext->dispatchLock, &lockState);
OVS_LOG_WARN("Vport search failed.");
goto update_nic_done;
}
@@ -658,7 +659,7 @@ OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext,
SIZE_T wstrSize = length * sizeof(WCHAR);
UINT i;
- PWSTR wsName = OvsAllocateMemory(wstrSize);
+ PWSTR wsName = OvsAllocateMemoryWithTag(wstrSize, OVS_VPORT_POOL_TAG);
if (!wsName) {
return NULL;
}
@@ -666,7 +667,7 @@ OvsFindVportByHvNameA(POVS_SWITCH_CONTEXT switchContext,
wsName[i] = name[i];
}
vport = OvsFindVportByHvNameW(switchContext, wsName, wstrSize);
- OvsFreeMemory(wsName);
+ OvsFreeMemoryWithTag(wsName, OVS_VPORT_POOL_TAG);
return vport;
}
@@ -703,7 +704,8 @@ POVS_VPORT_ENTRY
OvsAllocateVport(VOID)
{
POVS_VPORT_ENTRY vport;
- vport = (POVS_VPORT_ENTRY)OvsAllocateMemory(sizeof (OVS_VPORT_ENTRY));
+ vport = (POVS_VPORT_ENTRY)OvsAllocateMemoryWithTag(
+ sizeof(OVS_VPORT_ENTRY), OVS_VPORT_POOL_TAG);
if (vport == NULL) {
return NULL;
}
@@ -1073,7 +1075,7 @@ OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
ASSERT(switchContext->numPhysicalNics == 0);
switchContext->virtualExternalPortId = 0;
switchContext->virtualExternalVport = NULL;
- OvsFreeMemory(vport);
+ OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
if (vportDeallocated) {
*vportDeallocated = TRUE;
}
@@ -1151,7 +1153,7 @@ OvsRemoveAndDeleteVport(POVS_SWITCH_CONTEXT switchContext,
} else {
switchContext->numNonHvVports--;
}
- OvsFreeMemory(vport);
+ OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
if (vportDeallocated) {
*vportDeallocated = TRUE;
}
@@ -1189,19 +1191,20 @@ OvsAddConfiguredSwitchPorts(POVS_SWITCH_CONTEXT switchContext)
OvsInitVportWithPortParam(vport, portParam);
status = InitHvVportCommon(switchContext, vport, TRUE);
if (status != NDIS_STATUS_SUCCESS) {
- OvsFreeMemory(vport);
+ OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
goto cleanup;
}
}
+
cleanup:
if (status != NDIS_STATUS_SUCCESS) {
OvsClearAllSwitchVports(switchContext);
}
- if (portArray != NULL) {
- OvsFreeMemory(portArray);
- }
+ OvsFreeSwitchPortsArray(portArray);
+
OVS_LOG_TRACE("Exit: status: %x", status);
+
return status;
}
@@ -1248,7 +1251,7 @@ OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
nicParam->NicIndex);
status = InitHvVportCommon(switchContext, vport, TRUE);
if (status != NDIS_STATUS_SUCCESS) {
- OvsFreeMemory(vport);
+ OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
vport = NULL;
}
}
@@ -1268,9 +1271,8 @@ OvsInitConfiguredSwitchNics(POVS_SWITCH_CONTEXT switchContext)
}
cleanup:
- if (nicArray != NULL) {
- OvsFreeMemory(nicArray);
- }
+ OvsFreeSwitchNicsArray(nicArray);
+
OVS_LOG_TRACE("Exit: status: %x", status);
return status;
}
@@ -2129,7 +2131,7 @@ Cleanup:
OvsCleanupVxlanTunnel(vport);
}
}
- OvsFreeMemory(vport);
+ OvsFreeMemoryWithTag(vport, OVS_VPORT_POOL_TAG);
}
NlBuildErrorMsg(msgIn, msgError, nlError);
diff --git a/datapath-windows/ovsext/Vxlan.c b/datapath-windows/ovsext/Vxlan.c
index 1ce5af249..8c5718506 100644
--- a/datapath-windows/ovsext/Vxlan.c
+++ b/datapath-windows/ovsext/Vxlan.c
@@ -59,7 +59,8 @@ OvsInitVxlanTunnel(POVS_VPORT_ENTRY vport,
{
POVS_VXLAN_VPORT vxlanPort;
- vxlanPort = OvsAllocateMemory(sizeof (*vxlanPort));
+ vxlanPort = OvsAllocateMemoryWithTag(sizeof (*vxlanPort),
+ OVS_VXLAN_POOL_TAG);
if (vxlanPort == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
@@ -86,7 +87,7 @@ OvsCleanupVxlanTunnel(POVS_VPORT_ENTRY vport)
return;
}
- OvsFreeMemory(vport->priv);
+ OvsFreeMemoryWithTag(vport->priv, OVS_VXLAN_POOL_TAG);
vport->priv = NULL;
}
diff --git a/datapath/Modules.mk b/datapath/Modules.mk
index 33f9dd9b5..e9f40797e 100644
--- a/datapath/Modules.mk
+++ b/datapath/Modules.mk
@@ -2,7 +2,14 @@
#
# Some modules should be built but not distributed, e.g. third-party
# hwtable modules.
-both_modules = openvswitch
+build_multi_modules = \
+ openvswitch
+both_modules = \
+ $(build_multi_modules) \
+ vport_geneve \
+ vport_gre \
+ vport_lisp \
+ vport_vxlan
build_modules = $(both_modules) # Modules to build
dist_modules = $(both_modules) # Modules to distribute
@@ -14,12 +21,13 @@ openvswitch_sources = \
flow_netlink.c \
flow_table.c \
vport.c \
- vport-geneve.c \
- vport-gre.c \
vport-internal_dev.c \
- vport-lisp.c \
- vport-netdev.c \
- vport-vxlan.c
+ vport-netdev.c
+
+vport_geneve_sources = vport-geneve.c
+vport_vxlan_sources = vport-vxlan.c
+vport_gre_sources = vport-gre.c
+vport_lisp_sources = vport-lisp.c
openvswitch_headers = \
compat.h \
diff --git a/datapath/compat.h b/datapath/compat.h
index 5ef626fdb..c827b11aa 100644
--- a/datapath/compat.h
+++ b/datapath/compat.h
@@ -25,10 +25,10 @@
#include <net/route.h>
#include <net/xfrm.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,13,0)
-#define GROUP_ID(grp) 0
-#else
+#ifdef HAVE_GENL_MULTICAST_GROUP_WITH_ID
#define GROUP_ID(grp) ((grp)->id)
+#else
+#define GROUP_ID(grp) 0
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 7f431ed8e..c0af9ad09 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -61,6 +61,7 @@
#include "vport-netdev.h"
int ovs_net_id __read_mostly;
+EXPORT_SYMBOL_GPL(ovs_net_id);
static struct genl_family dp_packet_genl_family;
static struct genl_family dp_flow_genl_family;
@@ -134,6 +135,7 @@ int lockdep_ovsl_is_held(void)
else
return 1;
}
+EXPORT_SYMBOL_GPL(lockdep_ovsl_is_held);
#endif
static int queue_gso_packets(struct datapath *dp, struct sk_buff *,
@@ -1900,6 +1902,7 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
return -ENOMEM;
ovs_lock();
+restart:
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
err = -ENODEV;
if (!dp)
@@ -1931,8 +1934,11 @@ static int ovs_vport_cmd_new(struct sk_buff *skb, struct genl_info *info)
vport = new_vport(&parms);
err = PTR_ERR(vport);
- if (IS_ERR(vport))
+ if (IS_ERR(vport)) {
+ if (err == -EAGAIN)
+ goto restart;
goto exit_unlock_free;
+ }
err = ovs_vport_cmd_fill_info(vport, reply, info->snd_portid,
info->snd_seq, 0, OVS_VPORT_CMD_NEW);
@@ -2291,12 +2297,18 @@ static int __init dp_init(void)
if (err)
goto error_netns_exit;
+ err = ovs_netdev_init();
+ if (err)
+ goto error_unreg_notifier;
+
err = dp_register_genl();
if (err < 0)
- goto error_unreg_notifier;
+ goto error_unreg_netdev;
return 0;
+error_unreg_netdev:
+ ovs_netdev_exit();
error_unreg_notifier:
unregister_netdevice_notifier(&ovs_dp_device_notifier);
error_netns_exit:
@@ -2316,6 +2328,7 @@ error:
static void dp_cleanup(void)
{
dp_unregister_genl(ARRAY_SIZE(dp_genl_families));
+ ovs_netdev_exit();
unregister_netdevice_notifier(&ovs_dp_device_notifier);
unregister_pernet_device(&ovs_net_ops);
rcu_barrier();
diff --git a/datapath/linux/Kbuild.in b/datapath/linux/Kbuild.in
index cb98c1126..9e3259f19 100644
--- a/datapath/linux/Kbuild.in
+++ b/datapath/linux/Kbuild.in
@@ -18,10 +18,10 @@ ccflags-y += -include $(builddir)/kcompat.h
# right place, even though it's conceptually incorrect.
NOSTDINC_FLAGS += -I$(top_srcdir)/include -I$(srcdir)/compat -I$(srcdir)/compat/include
-obj-m := $(patsubst %,%.o,$(build_modules))
+obj-m := $(subst _,-,$(patsubst %,%.o,$(build_modules)))
define module_template
$(1)-y = $$(notdir $$(patsubst %.c,%.o,$($(1)_sources)))
endef
-$(foreach module,$(build_modules),$(eval $(call module_template,$(module))))
+$(foreach module,$(build_multi_modules),$(eval $(call module_template,$(module))))
diff --git a/datapath/linux/compat/flow_dissector.c b/datapath/linux/compat/flow_dissector.c
index ab60daa3b..a68f84f52 100644
--- a/datapath/linux/compat/flow_dissector.c
+++ b/datapath/linux/compat/flow_dissector.c
@@ -231,4 +231,5 @@ u32 __skb_get_hash(struct sk_buff *skb)
#endif
return hash;
}
+EXPORT_SYMBOL_GPL(__skb_get_hash);
#endif
diff --git a/datapath/linux/compat/genetlink-openvswitch.c b/datapath/linux/compat/genetlink-openvswitch.c
index 08f0fab8b..ab149c35d 100644
--- a/datapath/linux/compat/genetlink-openvswitch.c
+++ b/datapath/linux/compat/genetlink-openvswitch.c
@@ -1,7 +1,7 @@
#include <net/genetlink.h>
#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+#ifndef HAVE_GENL_NOTIFY_TAKES_FAMILY
#undef genl_notify
diff --git a/datapath/linux/compat/geneve.c b/datapath/linux/compat/geneve.c
index 35c01bb30..48a306e93 100644
--- a/datapath/linux/compat/geneve.c
+++ b/datapath/linux/compat/geneve.c
@@ -91,10 +91,6 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt,
int min_headroom;
int err;
- skb = udp_tunnel_handle_offloads(skb, csum, (opt_len == 0));
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
+ GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr)
+ (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
@@ -109,6 +105,10 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt,
if (unlikely(!skb))
return -ENOMEM;
+ skb = udp_tunnel_handle_offloads(skb, csum, (opt_len == 0));
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
gnvh = (struct genevehdr *)__skb_push(skb, sizeof(*gnvh) + opt_len);
geneve_build_header(gnvh, tun_flags, vni, opt_len, opt);
@@ -118,6 +118,7 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt,
tos, ttl, df, src_port, dst_port, xnet,
!csum);
}
+EXPORT_SYMBOL_GPL(geneve_xmit_skb);
/* Callback from net/ipv4/udp.c to receive packets */
static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
@@ -226,6 +227,7 @@ struct geneve_sock *geneve_sock_add(struct net *net, __be16 port,
{
return geneve_socket_create(net, port, rcv, data, ipv6);
}
+EXPORT_SYMBOL_GPL(geneve_sock_add);
static void rcu_free_gs(struct rcu_head *rcu)
{
@@ -239,3 +241,4 @@ void geneve_sock_release(struct geneve_sock *gs)
udp_tunnel_sock_release(gs->sock);
call_rcu(&gs->rcu, rcu_free_gs);
}
+EXPORT_SYMBOL_GPL(geneve_sock_release);
diff --git a/datapath/linux/compat/gre.c b/datapath/linux/compat/gre.c
index 22bbf2fb4..06956f049 100644
--- a/datapath/linux/compat/gre.c
+++ b/datapath/linux/compat/gre.c
@@ -250,6 +250,7 @@ int gre_cisco_register(struct gre_cisco_protocol *newp)
return (cmpxchg((struct gre_cisco_protocol **)&gre_cisco_proto, NULL, newp) == NULL) ?
0 : -EBUSY;
}
+EXPORT_SYMBOL_GPL(gre_cisco_register);
int gre_cisco_unregister(struct gre_cisco_protocol *proto)
{
@@ -265,6 +266,7 @@ int gre_cisco_unregister(struct gre_cisco_protocol *proto)
ret = gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
return ret;
}
+EXPORT_SYMBOL_GPL(gre_cisco_unregister);
#endif /* !HAVE_GRE_CISCO_REGISTER */
@@ -297,6 +299,7 @@ struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum)
return ovs_iptunnel_handle_offloads(skb, gre_csum, type, fix_segment);
}
+EXPORT_SYMBOL_GPL(gre_handle_offloads);
static bool is_gre_gso(struct sk_buff *skb)
{
@@ -334,6 +337,7 @@ void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
ovs_skb_set_inner_protocol(skb, tpi->proto);
}
+EXPORT_SYMBOL_GPL(gre_build_header);
#endif /* CONFIG_NET_IPGRE_DEMUX */
diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h
index 78d84cc2b..d14719232 100644
--- a/datapath/linux/compat/include/linux/skbuff.h
+++ b/datapath/linux/compat/include/linux/skbuff.h
@@ -14,8 +14,11 @@
#define SKB_GSO_UDP_TUNNEL 0
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
+#ifndef HAVE_SKB_GSO_GRE_CSUM
#define SKB_GSO_GRE_CSUM 0
+#endif
+
+#ifndef HAVE_SKB_GSO_UDP_TUNNEL_CSUM
#define SKB_GSO_UDP_TUNNEL_CSUM 0
#endif
diff --git a/datapath/linux/compat/include/net/genetlink.h b/datapath/linux/compat/include/net/genetlink.h
index 9edfd3142..edf681562 100644
--- a/datapath/linux/compat/include/net/genetlink.h
+++ b/datapath/linux/compat/include/net/genetlink.h
@@ -17,7 +17,7 @@
#define portid pid
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+#ifndef HAVE_GENL_NOTIFY_TAKES_FAMILY
struct rpl_genl_family {
struct genl_family compat_family;
unsigned int id;
@@ -122,7 +122,11 @@ static inline int genl_has_listeners(struct genl_family *family,
static inline int rpl_genl_has_listeners(struct genl_family *family,
struct net *net, unsigned int group)
{
+#ifdef HAVE_GENL_NOTIFY_TAKES_FAMILY
return genl_has_listeners(family, net->genl_sock, group);
+#else
+ return genl_has_listeners(&family->compat_family, net->genl_sock, group);
+#endif
}
#define genl_has_listeners rpl_genl_has_listeners
diff --git a/datapath/linux/compat/include/net/ip.h b/datapath/linux/compat/include/net/ip.h
index c819e4d99..b60617750 100644
--- a/datapath/linux/compat/include/net/ip.h
+++ b/datapath/linux/compat/include/net/ip.h
@@ -12,7 +12,7 @@ static inline bool ip_is_fragment(const struct iphdr *iph)
}
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0)
+#ifndef HAVE_INET_GET_LOCAL_PORT_RANGE_USING_NET
static inline void rpl_inet_get_local_port_range(struct net *net, int *low,
int *high)
{
diff --git a/datapath/linux/compat/include/net/udp.h b/datapath/linux/compat/include/net/udp.h
index f1841d4a2..02eb68878 100644
--- a/datapath/linux/compat/include/net/udp.h
+++ b/datapath/linux/compat/include/net/udp.h
@@ -2,11 +2,20 @@
#define __NET_UDP_WRAPPER_H 1
#include <linux/version.h>
+
+#ifdef inet_get_local_port_range
+/* RHEL7 backports udp_flow_src_port() using an older version of
+ * inet_get_local_port_range(). */
+#undef inet_get_local_port_range
+#include_next <net/udp.h>
+#define inet_get_local_port_range rpl_inet_get_local_port_range
+#else
#include_next <net/udp.h>
+#endif
#ifndef HAVE_UDP_FLOW_SRC_PORT
-static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb,
- int min, int max, bool use_eth)
+static inline __be16 rpl_udp_flow_src_port(struct net *net, struct sk_buff *skb,
+ int min, int max, bool use_eth)
{
u32 hash;
@@ -33,15 +42,19 @@ static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb,
return htons((((u64) hash * (max - min)) >> 32) + min);
}
+
+#define udp_flow_src_port rpl_udp_flow_src_port
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
+#ifndef HAVE_UDP_V4_CHECK
static inline __sum16 udp_v4_check(int len, __be32 saddr,
__be32 daddr, __wsum base)
{
return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base);
}
+#endif
+#ifndef HAVE_UDP_SET_CSUM
void udp_set_csum(bool nocheck, struct sk_buff *skb,
__be32 saddr, __be32 daddr, int len);
#endif
diff --git a/datapath/linux/compat/include/net/udp_tunnel.h b/datapath/linux/compat/include/net/udp_tunnel.h
index 7dadac16c..6c25ca54b 100644
--- a/datapath/linux/compat/include/net/udp_tunnel.h
+++ b/datapath/linux/compat/include/net/udp_tunnel.h
@@ -49,6 +49,7 @@ struct udp_port_cfg {
use_udp6_rx_checksums:1;
};
+#define udp_sock_create rpl_udp_sock_create
int udp_sock_create(struct net *net, struct udp_port_cfg *cfg,
struct socket **sockp);
diff --git a/datapath/linux/compat/ip_tunnels_core.c b/datapath/linux/compat/ip_tunnels_core.c
index 5e38603b9..f2c4ffd67 100644
--- a/datapath/linux/compat/ip_tunnels_core.c
+++ b/datapath/linux/compat/ip_tunnels_core.c
@@ -80,6 +80,7 @@ int rpl_iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
pkt_len = 0;
return pkt_len;
}
+EXPORT_SYMBOL_GPL(rpl_iptunnel_xmit);
struct sk_buff *ovs_iptunnel_handle_offloads(struct sk_buff *skb,
bool csum_help, int gso_type_mask,
@@ -132,6 +133,7 @@ error:
kfree_skb(skb);
return ERR_PTR(err);
}
+EXPORT_SYMBOL_GPL(ovs_iptunnel_handle_offloads);
int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
{
@@ -166,6 +168,7 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto)
skb->pkt_type = PACKET_HOST;
return 0;
}
+EXPORT_SYMBOL_GPL(iptunnel_pull_header);
#endif
@@ -176,3 +179,4 @@ bool skb_is_encapsulated(struct sk_buff *skb)
*/
return ovs_skb_get_inner_protocol(skb) || skb_encapsulation(skb);
}
+EXPORT_SYMBOL_GPL(skb_is_encapsulated);
diff --git a/datapath/linux/compat/udp.c b/datapath/linux/compat/udp.c
index a27928f2c..834a86b71 100644
--- a/datapath/linux/compat/udp.c
+++ b/datapath/linux/compat/udp.c
@@ -1,6 +1,6 @@
#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
+#ifndef HAVE_UDP_SET_CSUM
#include <net/udp.h>
diff --git a/datapath/linux/compat/udp_tunnel.c b/datapath/linux/compat/udp_tunnel.c
index a1c4951f2..f64011387 100644
--- a/datapath/linux/compat/udp_tunnel.c
+++ b/datapath/linux/compat/udp_tunnel.c
@@ -95,6 +95,7 @@ error:
*sockp = NULL;
return err;
}
+EXPORT_SYMBOL_GPL(udp_sock_create);
void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
struct udp_tunnel_sock_cfg *cfg)
@@ -114,6 +115,7 @@ void setup_udp_tunnel_sock(struct net *net, struct socket *sock,
udp_tunnel_encap_enable(sock);
}
+EXPORT_SYMBOL_GPL(setup_udp_tunnel_sock);
void ovs_udp_gso(struct sk_buff *skb)
{
@@ -123,6 +125,7 @@ void ovs_udp_gso(struct sk_buff *skb)
uh = udp_hdr(skb);
uh->len = htons(skb->len - udp_offset);
}
+EXPORT_SYMBOL_GPL(ovs_udp_gso);
void ovs_udp_csum_gso(struct sk_buff *skb)
{
@@ -137,6 +140,7 @@ void ovs_udp_csum_gso(struct sk_buff *skb)
udp_set_csum(true, skb, iph->saddr, iph->daddr,
skb->len - udp_offset);
}
+EXPORT_SYMBOL_GPL(ovs_udp_csum_gso);
int udp_tunnel_xmit_skb(struct rtable *rt, struct sk_buff *skb,
__be32 src, __be32 dst, __u8 tos, __u8 ttl,
@@ -158,6 +162,7 @@ int udp_tunnel_xmit_skb(struct rtable *rt, struct sk_buff *skb,
return iptunnel_xmit(skb->sk, rt, skb, src, dst, IPPROTO_UDP,
tos, ttl, df, xnet);
}
+EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb);
void udp_tunnel_sock_release(struct socket *sock)
{
@@ -165,5 +170,6 @@ void udp_tunnel_sock_release(struct socket *sock)
kernel_sock_shutdown(sock, SHUT_RDWR);
sk_release_kernel(sock->sk);
}
+EXPORT_SYMBOL_GPL(udp_tunnel_sock_release);
#endif /* Linux version < 3.20 */
diff --git a/datapath/linux/compat/vxlan.c b/datapath/linux/compat/vxlan.c
index 960ddba63..51135fac7 100644
--- a/datapath/linux/compat/vxlan.c
+++ b/datapath/linux/compat/vxlan.c
@@ -191,10 +191,6 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
int err;
bool udp_sum = !!(vxflags & VXLAN_F_UDP_CSUM);
- skb = udp_tunnel_handle_offloads(skb, udp_sum, true);
- if (IS_ERR(skb))
- return PTR_ERR(skb);
-
min_headroom = LL_RESERVED_SPACE(rt_dst(rt).dev) + rt_dst(rt).header_len
+ VXLAN_HLEN + sizeof(struct iphdr)
+ (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
@@ -210,6 +206,10 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
if (WARN_ON(!skb))
return -ENOMEM;
+ skb = udp_tunnel_handle_offloads(skb, udp_sum, true);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
vxh->vx_flags = htonl(VXLAN_HF_VNI);
vxh->vx_vni = md->vni;
@@ -225,6 +225,7 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
ttl, df, src_port, dst_port, xnet,
!udp_sum);
}
+EXPORT_SYMBOL_GPL(vxlan_xmit_skb);
static void rcu_free_vs(struct rcu_head *rcu)
{
@@ -313,6 +314,7 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
{
return vxlan_socket_create(net, port, rcv, data, flags);
}
+EXPORT_SYMBOL_GPL(vxlan_sock_add);
void vxlan_sock_release(struct vxlan_sock *vs)
{
@@ -320,5 +322,6 @@ void vxlan_sock_release(struct vxlan_sock *vs)
queue_work(system_wq, &vs->del_work);
}
+EXPORT_SYMBOL_GPL(vxlan_sock_release);
#endif /* !USE_UPSTREAM_VXLAN */
diff --git a/datapath/vport-geneve.c b/datapath/vport-geneve.c
index 624a6a0ec..2d7a6b38c 100644
--- a/datapath/vport-geneve.c
+++ b/datapath/vport-geneve.c
@@ -27,6 +27,8 @@
#include "datapath.h"
#include "vport.h"
+static struct vport_ops ovs_geneve_vport_ops;
+
/**
* struct geneve_port - Keeps track of open UDP ports
* @gs: The socket created for this port number.
@@ -248,7 +250,7 @@ static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
IPPROTO_UDP, skb->mark, sport, dport);
}
-const struct vport_ops ovs_geneve_vport_ops = {
+static struct vport_ops ovs_geneve_vport_ops = {
.type = OVS_VPORT_TYPE_GENEVE,
.create = geneve_tnl_create,
.destroy = geneve_tnl_destroy,
@@ -256,4 +258,22 @@ const struct vport_ops ovs_geneve_vport_ops = {
.get_options = geneve_get_options,
.send = geneve_tnl_send,
.get_egress_tun_info = geneve_get_egress_tun_info,
+ .owner = THIS_MODULE,
};
+
+static int __init ovs_geneve_tnl_init(void)
+{
+ return ovs_vport_ops_register(&ovs_geneve_vport_ops);
+}
+
+static void __exit ovs_geneve_tnl_exit(void)
+{
+ ovs_vport_ops_unregister(&ovs_geneve_vport_ops);
+}
+
+module_init(ovs_geneve_tnl_init);
+module_exit(ovs_geneve_tnl_exit);
+
+MODULE_DESCRIPTION("OVS: Geneve swiching port");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("vport-type-5");
diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c
index c0ed00972..7bbcf579f 100644
--- a/datapath/vport-gre.c
+++ b/datapath/vport-gre.c
@@ -31,6 +31,7 @@
#include <linux/jhash.h>
#include <linux/list.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/workqueue.h>
#include <linux/rculist.h>
#include <net/net_namespace.h>
@@ -47,6 +48,9 @@
#include "datapath.h"
#include "vport.h"
+static struct vport_ops ovs_gre_vport_ops;
+static struct vport_ops ovs_gre64_vport_ops;
+
/* Returns the least-significant 32 bits of a __be64. */
static __be32 be64_get_low32(__be64 x)
{
@@ -308,13 +312,14 @@ static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
IPPROTO_GRE, skb->mark, 0, 0);
}
-const struct vport_ops ovs_gre_vport_ops = {
+static struct vport_ops ovs_gre_vport_ops = {
.type = OVS_VPORT_TYPE_GRE,
.create = gre_create,
.destroy = gre_tnl_destroy,
.get_name = gre_get_name,
.send = gre_send,
.get_egress_tun_info = gre_get_egress_tun_info,
+ .owner = THIS_MODULE,
};
/* GRE64 vport. */
@@ -387,12 +392,42 @@ static int gre64_send(struct vport *vport, struct sk_buff *skb)
return __send(vport, skb, hlen, seq, (TUNNEL_KEY|TUNNEL_SEQ));
}
-const struct vport_ops ovs_gre64_vport_ops = {
+static struct vport_ops ovs_gre64_vport_ops = {
.type = OVS_VPORT_TYPE_GRE64,
.create = gre64_create,
.destroy = gre64_tnl_destroy,
.get_name = gre_get_name,
.send = gre64_send,
.get_egress_tun_info = gre_get_egress_tun_info,
+ .owner = THIS_MODULE,
};
+
+static int __init ovs_gre_tnl_init(void)
+{
+ int err;
+
+ err = ovs_vport_ops_register(&ovs_gre_vport_ops);
+ if (err < 0)
+ return err;
+
+ err = ovs_vport_ops_register(&ovs_gre64_vport_ops);
+ if (err < 0)
+ ovs_vport_ops_unregister(&ovs_gre_vport_ops);
+
+ return err;
+}
+
+static void __exit ovs_gre_tnl_exit(void)
+{
+ ovs_vport_ops_unregister(&ovs_gre64_vport_ops);
+ ovs_vport_ops_unregister(&ovs_gre_vport_ops);
+}
+
+module_init(ovs_gre_tnl_init);
+module_exit(ovs_gre_tnl_exit);
+
+MODULE_DESCRIPTION("OVS: GRE switching port");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("vport-type-3");
+MODULE_ALIAS("vport-type-104");
#endif
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index 040b37196..f38f9be07 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -38,6 +38,8 @@ struct internal_dev {
struct vport *vport;
};
+static struct vport_ops ovs_internal_vport_ops;
+
static struct internal_dev *internal_dev_priv(struct net_device *netdev)
{
return netdev_priv(netdev);
@@ -285,7 +287,7 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb)
return len;
}
-const struct vport_ops ovs_internal_vport_ops = {
+static struct vport_ops ovs_internal_vport_ops = {
.type = OVS_VPORT_TYPE_INTERNAL,
.create = internal_dev_create,
.destroy = internal_dev_destroy,
@@ -308,10 +310,21 @@ struct vport *ovs_internal_dev_get_vport(struct net_device *netdev)
int ovs_internal_dev_rtnl_link_register(void)
{
- return rtnl_link_register(&internal_dev_link_ops);
+ int err;
+
+ err = rtnl_link_register(&internal_dev_link_ops);
+ if (err < 0)
+ return err;
+
+ err = ovs_vport_ops_register(&ovs_internal_vport_ops);
+ if (err < 0)
+ rtnl_link_unregister(&internal_dev_link_ops);
+
+ return err;
}
void ovs_internal_dev_rtnl_link_unregister(void)
{
+ ovs_vport_ops_unregister(&ovs_internal_vport_ops);
rtnl_link_unregister(&internal_dev_link_ops);
}
diff --git a/datapath/vport-lisp.c b/datapath/vport-lisp.c
index 293002fe9..0024eb480 100644
--- a/datapath/vport-lisp.c
+++ b/datapath/vport-lisp.c
@@ -24,6 +24,7 @@
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/net.h>
+#include <linux/module.h>
#include <linux/rculist.h>
#include <linux/udp.h>
@@ -110,6 +111,7 @@ struct lisp_port {
};
static LIST_HEAD(lisp_ports);
+static struct vport_ops ovs_lisp_vport_ops;
static inline struct lisp_port *lisp_vport(const struct vport *vport)
{
@@ -493,7 +495,7 @@ static int lisp_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
lisp_port->dst_port);
}
-const struct vport_ops ovs_lisp_vport_ops = {
+static struct vport_ops ovs_lisp_vport_ops = {
.type = OVS_VPORT_TYPE_LISP,
.create = lisp_tnl_create,
.destroy = lisp_tnl_destroy,
@@ -501,4 +503,22 @@ const struct vport_ops ovs_lisp_vport_ops = {
.get_options = lisp_get_options,
.send = lisp_send,
.get_egress_tun_info = lisp_get_egress_tun_info,
+ .owner = THIS_MODULE,
};
+
+static int __init ovs_lisp_tnl_init(void)
+{
+ return ovs_vport_ops_register(&ovs_lisp_vport_ops);
+}
+
+static void __exit ovs_lisp_tnl_exit(void)
+{
+ ovs_vport_ops_unregister(&ovs_lisp_vport_ops);
+}
+
+module_init(ovs_lisp_tnl_init);
+module_exit(ovs_lisp_tnl_exit);
+
+MODULE_DESCRIPTION("OVS: LISP switching port");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("vport-type-105");
diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
index 9c0908a03..05ad0b4ab 100644
--- a/datapath/vport-netdev.c
+++ b/datapath/vport-netdev.c
@@ -35,6 +35,7 @@
#include "vport-internal_dev.h"
#include "vport-netdev.h"
+static struct vport_ops ovs_netdev_vport_ops;
static void netdev_port_receive(struct vport *vport, struct sk_buff *skb);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39)
@@ -274,7 +275,7 @@ struct vport *ovs_netdev_get_vport(struct net_device *dev)
#endif
}
-const struct vport_ops ovs_netdev_vport_ops = {
+static struct vport_ops ovs_netdev_vport_ops = {
.type = OVS_VPORT_TYPE_NETDEV,
.create = netdev_create,
.destroy = netdev_destroy,
@@ -282,6 +283,16 @@ const struct vport_ops ovs_netdev_vport_ops = {
.send = netdev_send,
};
+int __init ovs_netdev_init(void)
+{
+ return ovs_vport_ops_register(&ovs_netdev_vport_ops);
+}
+
+void ovs_netdev_exit(void)
+{
+ ovs_vport_ops_unregister(&ovs_netdev_vport_ops);
+}
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) && \
!defined HAVE_RHEL_OVS_HOOK
/*
diff --git a/datapath/vport-netdev.h b/datapath/vport-netdev.h
index 8df01c112..6f7038e79 100644
--- a/datapath/vport-netdev.h
+++ b/datapath/vport-netdev.h
@@ -41,4 +41,7 @@ netdev_vport_priv(const struct vport *vport)
const char *ovs_netdev_get_name(const struct vport *);
void ovs_netdev_detach_dev(struct vport *);
+int __init ovs_netdev_init(void);
+void ovs_netdev_exit(void);
+
#endif /* vport_netdev.h */
diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
index c25cc5889..eff7ca23c 100644
--- a/datapath/vport-vxlan.c
+++ b/datapath/vport-vxlan.c
@@ -26,6 +26,7 @@
#include <linux/net.h>
#include <linux/rculist.h>
#include <linux/udp.h>
+#include <linux/module.h>
#include <net/icmp.h>
#include <net/ip.h>
@@ -54,6 +55,8 @@ struct vxlan_port {
u32 exts; /* VXLAN_F_* in <net/vxlan.h> */
};
+static struct vport_ops ovs_vxlan_vport_ops;
+
static inline struct vxlan_port *vxlan_vport(const struct vport *vport)
{
return vport_priv(vport);
@@ -293,7 +296,7 @@ static const char *vxlan_get_name(const struct vport *vport)
return vxlan_port->name;
}
-const struct vport_ops ovs_vxlan_vport_ops = {
+static struct vport_ops ovs_vxlan_vport_ops = {
.type = OVS_VPORT_TYPE_VXLAN,
.create = vxlan_tnl_create,
.destroy = vxlan_tnl_destroy,
@@ -301,4 +304,22 @@ const struct vport_ops ovs_vxlan_vport_ops = {
.get_options = vxlan_get_options,
.send = vxlan_tnl_send,
.get_egress_tun_info = vxlan_get_egress_tun_info,
+ .owner = THIS_MODULE,
};
+
+static int __init ovs_vxlan_tnl_init(void)
+{
+ return ovs_vport_ops_register(&ovs_vxlan_vport_ops);
+}
+
+static void __exit ovs_vxlan_tnl_exit(void)
+{
+ ovs_vport_ops_unregister(&ovs_vxlan_vport_ops);
+}
+
+module_init(ovs_vxlan_tnl_init);
+module_exit(ovs_vxlan_tnl_exit);
+
+MODULE_DESCRIPTION("OVS: VXLAN switching port");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("vport-type-4");
diff --git a/datapath/vport.c b/datapath/vport.c
index 5a7067b2f..4486d06cd 100644
--- a/datapath/vport.c
+++ b/datapath/vport.c
@@ -23,6 +23,7 @@
#include <linux/kconfig.h>
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/percpu.h>
#include <linux/rcupdate.h>
@@ -39,20 +40,7 @@
static void ovs_vport_record_error(struct vport *,
enum vport_err_type err_type);
-/* List of statically compiled vport implementations. Don't forget to also
- * add yours to the list at the bottom of vport.h.
- */
-static const struct vport_ops *vport_ops_list[] = {
- &ovs_netdev_vport_ops,
- &ovs_internal_vport_ops,
- &ovs_geneve_vport_ops,
-#if IS_ENABLED(CONFIG_NET_IPGRE_DEMUX)
- &ovs_gre_vport_ops,
- &ovs_gre64_vport_ops,
-#endif
- &ovs_vxlan_vport_ops,
- &ovs_lisp_vport_ops,
-};
+static LIST_HEAD(vport_ops_list);
/* Protected by RCU read lock for reading, ovs_mutex for writing. */
static struct hlist_head *dev_table;
@@ -89,6 +77,32 @@ static struct hlist_head *hash_bucket(const struct net *net, const char *name)
return &dev_table[hash & (VPORT_HASH_BUCKETS - 1)];
}
+int ovs_vport_ops_register(struct vport_ops *ops)
+{
+ int err = -EEXIST;
+ struct vport_ops *o;
+
+ ovs_lock();
+ list_for_each_entry(o, &vport_ops_list, list)
+ if (ops->type == o->type)
+ goto errout;
+
+ list_add_tail(&ops->list, &vport_ops_list);
+ err = 0;
+errout:
+ ovs_unlock();
+ return err;
+}
+EXPORT_SYMBOL_GPL(ovs_vport_ops_register);
+
+void ovs_vport_ops_unregister(struct vport_ops *ops)
+{
+ ovs_lock();
+ list_del(&ops->list);
+ ovs_unlock();
+}
+EXPORT_SYMBOL_GPL(ovs_vport_ops_unregister);
+
/**
* ovs_vport_locate - find a port that has already been created
*
@@ -154,6 +168,18 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
return vport;
}
+EXPORT_SYMBOL_GPL(ovs_vport_alloc);
+
+static struct vport_ops *ovs_vport_lookup(const struct vport_parms *parms)
+{
+ struct vport_ops *ops;
+
+ list_for_each_entry(ops, &vport_ops_list, list)
+ if (ops->type == parms->type)
+ return ops;
+
+ return NULL;
+}
/**
* ovs_vport_free - uninitialize and free vport
@@ -171,6 +197,7 @@ void ovs_vport_free(struct vport *vport)
free_percpu(vport->percpu_stats);
kfree(vport);
}
+EXPORT_SYMBOL_GPL(ovs_vport_free);
/**
* ovs_vport_add - add vport device (for kernel callers)
@@ -182,31 +209,40 @@ void ovs_vport_free(struct vport *vport)
*/
struct vport *ovs_vport_add(const struct vport_parms *parms)
{
+ struct vport_ops *ops;
struct vport *vport;
- int err = 0;
- int i;
- for (i = 0; i < ARRAY_SIZE(vport_ops_list); i++) {
- if (vport_ops_list[i]->type == parms->type) {
- struct hlist_head *bucket;
+ ops = ovs_vport_lookup(parms);
+ if (ops) {
+ struct hlist_head *bucket;
- vport = vport_ops_list[i]->create(parms);
- if (IS_ERR(vport)) {
- err = PTR_ERR(vport);
- goto out;
- }
+ if (!try_module_get(ops->owner))
+ return ERR_PTR(-EAFNOSUPPORT);
- bucket = hash_bucket(ovs_dp_get_net(vport->dp),
- vport->ops->get_name(vport));
- hlist_add_head_rcu(&vport->hash_node, bucket);
+ vport = ops->create(parms);
+ if (IS_ERR(vport)) {
+ module_put(ops->owner);
return vport;
}
+
+ bucket = hash_bucket(ovs_dp_get_net(vport->dp),
+ vport->ops->get_name(vport));
+ hlist_add_head_rcu(&vport->hash_node, bucket);
+ return vport;
}
- err = -EAFNOSUPPORT;
+ /* Unlock to attempt module load and return -EAGAIN if load
+ * was successful as we need to restart the port addition
+ * workflow.
+ */
+ ovs_unlock();
+ request_module("vport-type-%d", parms->type);
+ ovs_lock();
-out:
- return ERR_PTR(err);
+ if (!ovs_vport_lookup(parms))
+ return ERR_PTR(-EAFNOSUPPORT);
+ else
+ return ERR_PTR(-EAGAIN);
}
/**
@@ -238,6 +274,7 @@ void ovs_vport_del(struct vport *vport)
ASSERT_OVSL();
hlist_del_rcu(&vport->hash_node);
+ module_put(vport->ops->owner);
vport->ops->destroy(vport);
}
@@ -467,6 +504,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
ovs_dp_process_packet(skb, &key);
}
+EXPORT_SYMBOL_GPL(ovs_vport_receive);
/**
* ovs_vport_send - send a packet on a device
@@ -544,6 +582,7 @@ void ovs_vport_deferred_free(struct vport *vport)
call_rcu(&vport->rcu, free_vport_rcu);
}
+EXPORT_SYMBOL_GPL(ovs_vport_deferred_free);
int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info,
struct net *net,
@@ -592,6 +631,7 @@ int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info,
return 0;
}
+EXPORT_SYMBOL_GPL(ovs_tunnel_get_egress_info);
int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb,
struct ovs_tunnel_info *info)
diff --git a/datapath/vport.h b/datapath/vport.h
index e256fc0a4..c289d60ed 100644
--- a/datapath/vport.h
+++ b/datapath/vport.h
@@ -175,6 +175,9 @@ struct vport_ops {
int (*send)(struct vport *, struct sk_buff *);
int (*get_egress_tun_info)(struct vport *, struct sk_buff *,
struct ovs_tunnel_info *);
+
+ struct module *owner;
+ struct list_head list;
};
enum vport_err_type {
@@ -223,16 +226,6 @@ static inline struct vport *vport_from_priv(void *priv)
void ovs_vport_receive(struct vport *, struct sk_buff *,
const struct ovs_tunnel_info *);
-/* List of statically compiled vport implementations. Don't forget to also
- * add yours to the list at the top of vport.c.
- */
-extern const struct vport_ops ovs_netdev_vport_ops;
-extern const struct vport_ops ovs_internal_vport_ops;
-extern const struct vport_ops ovs_geneve_vport_ops;
-extern const struct vport_ops ovs_gre_vport_ops;
-extern const struct vport_ops ovs_gre64_vport_ops;
-extern const struct vport_ops ovs_vxlan_vport_ops;
-extern const struct vport_ops ovs_lisp_vport_ops;
static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb,
const void *start, unsigned int len)
@@ -240,4 +233,7 @@ static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb,
if (skb->ip_summed == CHECKSUM_COMPLETE)
skb->csum = csum_add(skb->csum, csum_partial(start, len, 0));
}
+
+int ovs_vport_ops_register(struct vport_ops *ops);
+void ovs_vport_ops_unregister(struct vport_ops *ops);
#endif /* vport.h */
diff --git a/debian/openvswitch-common.install b/debian/openvswitch-common.install
index 11bb59670..f0841529a 100644
--- a/debian/openvswitch-common.install
+++ b/debian/openvswitch-common.install
@@ -1,3 +1,4 @@
+etc/bash_completion.d/ovs-appctl-bashcomp.bash
usr/bin/ovs-appctl
usr/bin/ovs-benchmark
usr/bin/ovs-docker
diff --git a/debian/openvswitch-switch.install b/debian/openvswitch-switch.install
index c4f1426fe..b5d006321 100644
--- a/debian/openvswitch-switch.install
+++ b/debian/openvswitch-switch.install
@@ -1,3 +1,4 @@
+etc/bash_completion.d/ovs-vsctl-bashcomp.bash
usr/bin/ovs-dpctl
usr/bin/ovs-dpctl-top
usr/bin/ovs-pcap
diff --git a/include/openflow/automake.mk b/include/openflow/automake.mk
index 512991e57..d7dac9132 100644
--- a/include/openflow/automake.mk
+++ b/include/openflow/automake.mk
@@ -1,5 +1,6 @@
openflowincludedir = $(includedir)/openflow
openflowinclude_HEADERS = \
+ include/openflow/netronome-ext.h \
include/openflow/nicira-ext.h \
include/openflow/openflow-1.0.h \
include/openflow/openflow-1.1.h \
@@ -17,42 +18,10 @@ SUFFIXES += .h .hstamp
$(AM_V_GEN)$(run_python) $(srcdir)/build-aux/check-structs -I$(srcdir)/include $< && \
touch $@
-HSTAMP_FILES = \
- include/openflow/nicira-ext.hstamp \
- include/openflow/openflow-1.0.hstamp \
- include/openflow/openflow-1.1.hstamp \
- include/openflow/openflow-1.2.hstamp \
- include/openflow/openflow-1.3.hstamp \
- include/openflow/openflow-1.4.hstamp \
- include/openflow/openflow-1.5.hstamp \
- include/openflow/openflow-common.hstamp \
- include/openflow/openflow.hstamp
+HSTAMP_FILES = $(openflowinclude_HEADERS:.h=.hstamp)
CLEANFILES += $(HSTAMP_FILES)
ALL_LOCAL += $(HSTAMP_FILES)
-$(HSTAMP_FILES): build-aux/check-structs
-
-include/openflow/openflow-1.0.hstamp: \
- include/openflow/openflow-common.h
-include/openflow/openflow-1.1.hstamp: \
- include/openflow/openflow-common.h
-include/openflow/openflow-1.2.hstamp: \
- include/openflow/openflow-common.h \
- include/openflow/openflow-1.1.h
-include/openflow/openflow-1.3.hstamp: \
- include/openflow/openflow-common.h \
- include/openflow/openflow-1.1.h \
- include/openflow/openflow-1.2.h
-include/openflow/openflow-1.4.hstamp: \
- include/openflow/openflow-1.4.h
-include/openflow/openflow-1.5.hstamp: \
- include/openflow/openflow-1.5.h
-include/openflow/nicira-ext.hstamp: \
- include/openflow/openflow.h \
- include/openflow/openflow-common.h \
- include/openflow/openflow-1.0.h \
- include/openflow/openflow-1.1.h \
- include/openflow/openflow-1.2.h \
- include/openflow/openflow-1.3.h
+$(HSTAMP_FILES): build-aux/check-structs $(openflowinclude_HEADERS)
endif
EXTRA_DIST += build-aux/check-structs
diff --git a/include/openflow/netronome-ext.h b/include/openflow/netronome-ext.h
new file mode 100644
index 000000000..8db7b79fc
--- /dev/null
+++ b/include/openflow/netronome-ext.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014 Netronome.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OPENFLOW_NETRONOME_EXT_H
+#define OPENFLOW_NETRONOME_EXT_H 1
+
+#include "openflow/openflow.h"
+#include "openvswitch/types.h"
+
+/* The following vendor extension, proposed by Netronome, is not yet
+ * standardized, so they are not included in openflow.h. It may
+ * be suitable for standardization */
+
+
+/* Netronome enhanced select group */
+
+enum ntr_group_mod_subtype {
+ NTRT_SELECTION_METHOD = 1,
+};
+
+#define NTR_MAX_SELECTION_METHOD_LEN 16
+
+struct ntr_group_prop_selection_method {
+ ovs_be16 type; /* OFPGPT15_EXPERIMENTER. */
+ ovs_be16 length; /* Length in bytes of this property
+ * excluding trailing padding. */
+ ovs_be32 experimenter; /* NTR_VENDOR_ID. */
+ ovs_be32 exp_type; /* NTRT_SELECTION_METHOD. */
+ ovs_be32 pad;
+ char selection_method[NTR_MAX_SELECTION_METHOD_LEN];
+ /* Null-terminated */
+ ovs_be64 selection_method_param; /* Non-Field parameter for
+ * bucket selection. */
+
+ /* Followed by:
+ * - Exactly (length - 40) (possibly 0) bytes containing OXM TLVs, then
+ * - Exactly ((length + 7)/8*8 - length) (between 0 and 7) bytes of
+ * all-zero bytes
+ * In summary, ntr_group_prop_selection_method is padded as needed,
+ * to make its overall size a multiple of 8, to preserve alignment
+ * in structures using it.
+ */
+ /* uint8_t field_array[0]; */ /* Zero or more fields encoded as
+ * OXM TLVs where the has_mask bit must
+ * be zero and the value it specifies is
+ * a mask to apply to packet fields and
+ * then input them to the selection
+ * method of a select group. */
+ /* uint8_t pad2[0]; */
+};
+OFP_ASSERT(sizeof(struct ntr_group_prop_selection_method) == 40);
+
+#endif /* openflow/netronome-ext.h */
diff --git a/include/openflow/openflow-common.h b/include/openflow/openflow-common.h
index e68ab1424..e4fecceef 100644
--- a/include/openflow/openflow-common.h
+++ b/include/openflow/openflow-common.h
@@ -103,7 +103,7 @@ enum ofp_version {
*/
#define OF_VENDOR_ID 0
#define HPL_VENDOR_ID 0x000004EA /* HP Labs. */
-#define NMX_VENDOR_ID 0x00001540 /* Netronome. */
+#define NTR_VENDOR_ID 0x00001540 /* Netronome. */
#define NX_VENDOR_ID 0x00002320 /* Nicira. */
#define ONF_VENDOR_ID 0x4f4e4600 /* Open Networking Foundation. */
diff --git a/lib/cfm.c b/lib/cfm.c
index 380c5b06f..6a507a17d 100644
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -29,6 +29,7 @@
#include "hash.h"
#include "hmap.h"
#include "netdev.h"
+#include "ovs-atomic.h"
#include "packets.h"
#include "poll-loop.h"
#include "random.h"
diff --git a/lib/dp-packet.c b/lib/dp-packet.c
index 88b570886..8a4cf43ea 100644
--- a/lib/dp-packet.c
+++ b/lib/dp-packet.c
@@ -465,10 +465,9 @@ dp_packet_to_string(const struct dp_packet *b, size_t maxbytes)
void
dp_packet_list_delete(struct ovs_list *list)
{
- struct dp_packet *b, *next;
+ struct dp_packet *b;
- LIST_FOR_EACH_SAFE (b, next, list_node, list) {
- list_remove(&b->list_node);
+ LIST_FOR_EACH_POP (b, list_node, list) {
dp_packet_delete(b);
}
}
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index f01fecb68..61d9211c2 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -220,7 +220,8 @@ static struct dp_netdev_port *dp_netdev_lookup_port(const struct dp_netdev *dp,
odp_port_t);
enum dp_stat_type {
- DP_STAT_HIT, /* Packets that matched in the flow table. */
+ DP_STAT_EXACT_HIT, /* Packets that had an exact match (emc). */
+ DP_STAT_MASKED_HIT, /* Packets that matched in the flow table. */
DP_STAT_MISS, /* Packets that did not match. */
DP_STAT_LOST, /* Packets not passed up to the client. */
DP_N_STATS
@@ -239,10 +240,10 @@ struct dp_netdev_port {
/* Contained by struct dp_netdev_flow's 'stats' member. */
struct dp_netdev_flow_stats {
- long long int used; /* Last used time, in monotonic msecs. */
- long long int packet_count; /* Number of packets matched. */
- long long int byte_count; /* Number of bytes matched. */
- uint16_t tcp_flags; /* Bitwise-OR of seen tcp_flags values. */
+ atomic_llong used; /* Last used time, in monotonic msecs. */
+ atomic_ullong packet_count; /* Number of packets matched. */
+ atomic_ullong byte_count; /* Number of bytes matched. */
+ atomic_uint16_t tcp_flags; /* Bitwise-OR of seen tcp_flags values. */
};
/* A flow in 'dp_netdev_pmd_thread's 'flow_table'.
@@ -338,7 +339,7 @@ static void dp_netdev_actions_free(struct dp_netdev_actions *);
/* Contained by struct dp_netdev_pmd_thread's 'stats' member. */
struct dp_netdev_pmd_stats {
/* Indexed by DP_STAT_*. */
- unsigned long long int n[DP_N_STATS];
+ atomic_ullong n[DP_N_STATS];
};
/* PMD: Poll modes drivers. PMD accesses devices via polling to eliminate
@@ -746,6 +747,21 @@ dpif_netdev_destroy(struct dpif *dpif)
return 0;
}
+/* Add 'n' to the atomic variable 'var' non-atomically and using relaxed
+ * load/store semantics. While the increment is not atomic, the load and
+ * store operations are, making it impossible to read inconsistent values.
+ *
+ * This is used to update thread local stats counters. */
+static void
+non_atomic_ullong_add(atomic_ullong *var, unsigned long long n)
+{
+ unsigned long long tmp;
+
+ atomic_read_relaxed(var, &tmp);
+ tmp += n;
+ atomic_store_relaxed(var, tmp);
+}
+
static int
dpif_netdev_get_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
{
@@ -754,10 +770,17 @@ dpif_netdev_get_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
stats->n_flows = stats->n_hit = stats->n_missed = stats->n_lost = 0;
CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
+ unsigned long long n;
stats->n_flows += cmap_count(&pmd->flow_table);
- stats->n_hit += pmd->stats.n[DP_STAT_HIT];
- stats->n_missed += pmd->stats.n[DP_STAT_MISS];
- stats->n_lost += pmd->stats.n[DP_STAT_LOST];
+
+ atomic_read_relaxed(&pmd->stats.n[DP_STAT_MASKED_HIT], &n);
+ stats->n_hit += n;
+ atomic_read_relaxed(&pmd->stats.n[DP_STAT_EXACT_HIT], &n);
+ stats->n_hit += n;
+ atomic_read_relaxed(&pmd->stats.n[DP_STAT_MISS], &n);
+ stats->n_missed += n;
+ atomic_read_relaxed(&pmd->stats.n[DP_STAT_LOST], &n);
+ stats->n_lost += n;
}
stats->n_masks = UINT32_MAX;
stats->n_mask_hit = UINT64_MAX;
@@ -1545,13 +1568,24 @@ dp_netdev_pmd_find_flow(const struct dp_netdev_pmd_thread *pmd,
}
static void
-get_dpif_flow_stats(const struct dp_netdev_flow *netdev_flow,
+get_dpif_flow_stats(const struct dp_netdev_flow *netdev_flow_,
struct dpif_flow_stats *stats)
{
- stats->n_packets = netdev_flow->stats.packet_count;
- stats->n_bytes = netdev_flow->stats.byte_count;
- stats->used = netdev_flow->stats.used;
- stats->tcp_flags = netdev_flow->stats.tcp_flags;
+ struct dp_netdev_flow *netdev_flow;
+ unsigned long long n;
+ long long used;
+ uint16_t flags;
+
+ netdev_flow = CONST_CAST(struct dp_netdev_flow *, netdev_flow_);
+
+ atomic_read_relaxed(&netdev_flow->stats.packet_count, &n);
+ stats->n_packets = n;
+ atomic_read_relaxed(&netdev_flow->stats.byte_count, &n);
+ stats->n_bytes = n;
+ atomic_read_relaxed(&netdev_flow->stats.used, &used);
+ stats->used = used;
+ atomic_read_relaxed(&netdev_flow->stats.tcp_flags, &flags);
+ stats->tcp_flags = flags;
}
/* Converts to the dpif_flow format, using 'key_buf' and 'mask_buf' for
@@ -1842,7 +1876,16 @@ dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
get_dpif_flow_stats(netdev_flow, put->stats);
}
if (put->flags & DPIF_FP_ZERO_STATS) {
- memset(&netdev_flow->stats, 0, sizeof netdev_flow->stats);
+ /* XXX: The userspace datapath uses thread local statistics
+ * (for flows), which should be updated only by the owning
+ * thread. Since we cannot write on stats memory here,
+ * we choose not to support this flag. Please note:
+ * - This feature is currently used only by dpctl commands with
+ * option --clear.
+ * - Should the need arise, this operation can be implemented
+ * by keeping a base value (to be update here) for each
+ * counter, and subtracting it before outputting the stats */
+ error = EOPNOTSUPP;
}
ovsrcu_postpone(dp_netdev_actions_free, old_actions);
@@ -2669,19 +2712,22 @@ static void
dp_netdev_flow_used(struct dp_netdev_flow *netdev_flow, int cnt, int size,
uint16_t tcp_flags)
{
- long long int now = time_msec();
+ long long now = time_msec();
+ uint16_t flags;
- netdev_flow->stats.used = MAX(now, netdev_flow->stats.used);
- netdev_flow->stats.packet_count += cnt;
- netdev_flow->stats.byte_count += size;
- netdev_flow->stats.tcp_flags |= tcp_flags;
+ atomic_store_relaxed(&netdev_flow->stats.used, now);
+ non_atomic_ullong_add(&netdev_flow->stats.packet_count, cnt);
+ non_atomic_ullong_add(&netdev_flow->stats.byte_count, size);
+ atomic_read_relaxed(&netdev_flow->stats.tcp_flags, &flags);
+ flags |= tcp_flags;
+ atomic_store_relaxed(&netdev_flow->stats.tcp_flags, flags);
}
static void
dp_netdev_count_packet(struct dp_netdev_pmd_thread *pmd,
enum dp_stat_type type, int cnt)
{
- pmd->stats.n[type] += cnt;
+ non_atomic_ullong_add(&pmd->stats.n[type], cnt);
}
static int
@@ -2692,10 +2738,6 @@ dp_netdev_upcall(struct dp_netdev_pmd_thread *pmd, struct dp_packet *packet_,
{
struct dp_netdev *dp = pmd->dp;
- if (type == DPIF_UC_MISS) {
- dp_netdev_count_packet(pmd, DP_STAT_MISS, 1);
- }
-
if (OVS_UNLIKELY(!dp->upcall_cb)) {
return ENODEV;
}
@@ -2771,7 +2813,8 @@ packet_batch_init(struct packet_batch *batch, struct dp_netdev_flow *flow)
static inline void
packet_batch_execute(struct packet_batch *batch,
- struct dp_netdev_pmd_thread *pmd)
+ struct dp_netdev_pmd_thread *pmd,
+ enum dp_stat_type hit_type)
{
struct dp_netdev_actions *actions;
struct dp_netdev_flow *flow = batch->flow;
@@ -2784,7 +2827,7 @@ packet_batch_execute(struct packet_batch *batch,
dp_netdev_execute_actions(pmd, batch->packets, batch->packet_count, true,
actions->actions, actions->size);
- dp_netdev_count_packet(pmd, DP_STAT_HIT, batch->packet_count);
+ dp_netdev_count_packet(pmd, hit_type, batch->packet_count);
}
static inline bool
@@ -2875,7 +2918,7 @@ emc_processing(struct dp_netdev_pmd_thread *pmd, struct dp_packet **packets,
}
for (i = 0; i < n_batches; i++) {
- packet_batch_execute(&batches[i], pmd);
+ packet_batch_execute(&batches[i], pmd, DP_STAT_EXACT_HIT);
}
return notfound_cnt;
@@ -2907,6 +2950,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
if (OVS_UNLIKELY(any_miss) && !fat_rwlock_tryrdlock(&dp->upcall_rwlock)) {
uint64_t actions_stub[512 / 8], slow_stub[512 / 8];
struct ofpbuf actions, put_actions;
+ int miss_cnt = 0, lost_cnt = 0;
ovs_u128 ufid;
ofpbuf_use_stub(&actions, actions_stub, sizeof actions_stub);
@@ -2931,6 +2975,8 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
continue;
}
+ miss_cnt++;
+
miniflow_expand(&keys[i].mf, &match.flow);
ofpbuf_clear(&actions);
@@ -2941,6 +2987,8 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
&ufid, DPIF_UC_MISS, NULL, &actions,
&put_actions);
if (OVS_UNLIKELY(error && error != ENOSPC)) {
+ dp_packet_delete(packets[i]);
+ lost_cnt++;
continue;
}
@@ -2974,6 +3022,8 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
ofpbuf_uninit(&actions);
ofpbuf_uninit(&put_actions);
fat_rwlock_unlock(&dp->upcall_rwlock);
+ dp_netdev_count_packet(pmd, DP_STAT_MISS, miss_cnt);
+ dp_netdev_count_packet(pmd, DP_STAT_LOST, lost_cnt);
} else if (OVS_UNLIKELY(any_miss)) {
int dropped_cnt = 0;
@@ -2984,6 +3034,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
}
}
+ dp_netdev_count_packet(pmd, DP_STAT_MISS, dropped_cnt);
dp_netdev_count_packet(pmd, DP_STAT_LOST, dropped_cnt);
}
@@ -3004,7 +3055,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
}
for (i = 0; i < n_batches; i++) {
- packet_batch_execute(&batches[i], pmd);
+ packet_batch_execute(&batches[i], pmd, DP_STAT_MASKED_HIT);
}
}
diff --git a/lib/flow.c b/lib/flow.c
index aa1cc47ea..e54280a45 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -859,10 +859,14 @@ flow_format(struct ds *ds, const struct flow *flow)
/* As this function is most often used for formatting a packet in a
* packet-in message, skip formatting the packet context fields that are
- * all-zeroes (Openflow spec encourages leaving out all-zeroes context
- * fields from the packet-in messages). We make an exception with the
- * 'in_port' field, which we always format, as packets usually have an
- * in_port, and 0 is a port just like any other port. */
+ * all-zeroes to make the print-out easier on the eyes. This means that a
+ * missing context field implies a zero value for that field. This is
+ * similar to OpenFlow encoding of these fields, as the specification
+ * states that all-zeroes context fields should not be encoded in the
+ * packet-in messages. */
+ if (!flow->in_port.ofp_port) {
+ WC_UNMASK_FIELD(wc, in_port);
+ }
if (!flow->skb_priority) {
WC_UNMASK_FIELD(wc, skb_priority);
}
diff --git a/lib/hmap.h b/lib/hmap.h
index 85241f0e8..345bf7fd4 100644
--- a/lib/hmap.h
+++ b/lib/hmap.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, 2010, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2012, 2013, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +19,6 @@
#include <stdbool.h>
#include <stdlib.h>
-#include "ovs-atomic.h"
#include "util.h"
#ifdef __cplusplus
@@ -124,6 +123,16 @@ struct hmap_node *hmap_random_node(const struct hmap *);
* iteration).
*
* HASH is only evaluated once.
+ *
+ *
+ * Warning
+ * -------
+ *
+ * When the loop terminates, &NODE->MEMBER will equal NULL. Unless MEMBER is
+ * the first member in its struct, this means that NODE itself will not be
+ * NULL.
+ *
+ * (This is true for all of the HMAP_FOR_EACH_*() macros.)
*/
#define HMAP_FOR_EACH_WITH_HASH(NODE, MEMBER, HASH, HMAP) \
for (INIT_CONTAINER(NODE, hmap_first_with_hash(HMAP, HASH), MEMBER); \
diff --git a/lib/jsonrpc.c b/lib/jsonrpc.c
index 86531b822..ae51b4299 100644
--- a/lib/jsonrpc.c
+++ b/lib/jsonrpc.c
@@ -1063,36 +1063,49 @@ jsonrpc_session_recv_wait(struct jsonrpc_session *s)
}
}
+/* Returns true if 's' is currently connected or trying to connect. */
bool
jsonrpc_session_is_alive(const struct jsonrpc_session *s)
{
return s->rpc || s->stream || reconnect_get_max_tries(s->reconnect);
}
+/* Returns true if 's' is currently connected. */
bool
jsonrpc_session_is_connected(const struct jsonrpc_session *s)
{
return s->rpc != NULL;
}
+/* Returns a sequence number for 's'. The sequence number increments every
+ * time 's' connects or disconnects. Thus, a caller can use the change (or
+ * lack of change) in the sequence number to figure out whether the underlying
+ * connection is the same as before. */
unsigned int
jsonrpc_session_get_seqno(const struct jsonrpc_session *s)
{
return s->seqno;
}
+/* Returns the current status of 's'. If 's' is NULL or is disconnected, this
+ * is 0, otherwise it is the status of the connection, as reported by
+ * jsonrpc_get_status(). */
int
jsonrpc_session_get_status(const struct jsonrpc_session *s)
{
return s && s->rpc ? jsonrpc_get_status(s->rpc) : 0;
}
+/* Returns the last error reported on a connection by 's'. The return value is
+ * 0 only if no connection made by 's' has ever encountered an error. See
+ * jsonrpc_get_status() for return value interpretation. */
int
jsonrpc_session_get_last_error(const struct jsonrpc_session *s)
{
return s->last_error;
}
+/* Populates 'stats' with statistics from 's'. */
void
jsonrpc_session_get_reconnect_stats(const struct jsonrpc_session *s,
struct reconnect_stats *stats)
@@ -1100,6 +1113,7 @@ jsonrpc_session_get_reconnect_stats(const struct jsonrpc_session *s,
reconnect_get_stats(s->reconnect, time_msec(), stats);
}
+/* Enables 's' to reconnect to the peer if the connection drops. */
void
jsonrpc_session_enable_reconnect(struct jsonrpc_session *s)
{
@@ -1108,18 +1122,27 @@ jsonrpc_session_enable_reconnect(struct jsonrpc_session *s)
RECONNECT_DEFAULT_MAX_BACKOFF);
}
+/* Forces 's' to drop its connection (if any) and reconnect. */
void
jsonrpc_session_force_reconnect(struct jsonrpc_session *s)
{
reconnect_force_reconnect(s->reconnect, time_msec());
}
+/* Sets 'max_backoff' as the maximum time, in milliseconds, to wait after a
+ * connection attempt fails before attempting to connect again. */
void
jsonrpc_session_set_max_backoff(struct jsonrpc_session *s, int max_backoff)
{
reconnect_set_backoff(s->reconnect, 0, max_backoff);
}
+/* Sets the "probe interval" for 's' to 'probe_interval', in milliseconds. If
+ * this is zero, it disables the connection keepalive feature. Otherwise, if
+ * 's' is idle for 'probe_interval' milliseconds then 's' will send an echo
+ * request and, if no reply is received within an additional 'probe_interval'
+ * milliseconds, close the connection (then reconnect, if that feature is
+ * enabled). */
void
jsonrpc_session_set_probe_interval(struct jsonrpc_session *s,
int probe_interval)
@@ -1127,9 +1150,11 @@ jsonrpc_session_set_probe_interval(struct jsonrpc_session *s,
reconnect_set_probe_interval(s->reconnect, probe_interval);
}
+/* Sets the DSCP value used for 's''s connection to 'dscp'. If this is
+ * different from the DSCP value currently in use then the connection is closed
+ * and reconnected. */
void
-jsonrpc_session_set_dscp(struct jsonrpc_session *s,
- uint8_t dscp)
+jsonrpc_session_set_dscp(struct jsonrpc_session *s, uint8_t dscp)
{
if (s->dscp != dscp) {
pstream_close(s->pstream);
diff --git a/lib/lacp.c b/lib/lacp.c
index 6535e6dfe..65149fdb3 100644
--- a/lib/lacp.c
+++ b/lib/lacp.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
+/* Copyright (c) 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@
#include "hash.h"
#include "hmap.h"
#include "dp-packet.h"
+#include "ovs-atomic.h"
#include "packets.h"
#include "poll-loop.h"
#include "seq.h"
diff --git a/lib/list.h b/lib/list.h
index b40bbef72..7ba1e3549 100644
--- a/lib/list.h
+++ b/lib/list.h
@@ -73,6 +73,9 @@ static inline bool list_is_short(const struct ovs_list *);
? INIT_CONTAINER(NEXT, (ITER)->MEMBER.next, MEMBER), 1 \
: 0); \
(ITER) = (NEXT))
+#define LIST_FOR_EACH_POP(ITER, MEMBER, LIST) \
+ while (!list_is_empty(LIST) \
+ && (INIT_CONTAINER(ITER, list_pop_front(LIST), MEMBER), 1))
/* Inline implementations. */
diff --git a/lib/lldp/aa-structs.h b/lib/lldp/aa-structs.h
index 567a831af..983c74c31 100644
--- a/lib/lldp/aa-structs.h
+++ b/lib/lldp/aa-structs.h
@@ -26,12 +26,14 @@
struct lldp_aa_element_system_id {
uint8_t system_mac[6];
uint16_t conn_type;
- uint16_t smlt_id;
- uint8_t mlt_id[2];
+ uint16_t rsvd;
+ uint8_t rsvd2[2];
};
struct lldpd_aa_element_tlv {
uint16_t type;
+ uint16_t vlan_tagging;
+ uint16_t auto_prov_mode;
uint16_t mgmt_vlan;
struct lldp_aa_element_system_id system_id;
};
diff --git a/lib/lldp/lldp-tlv.h b/lib/lldp/lldp-tlv.h
index 237414d5a..2b948281f 100644
--- a/lib/lldp/lldp-tlv.h
+++ b/lib/lldp/lldp-tlv.h
@@ -36,7 +36,7 @@
#define LLDP_TLV_ORG_DOT1 {0x00, 0x80, 0xc2}
#define LLDP_TLV_ORG_DOT3 {0x00, 0x12, 0x0f}
#define LLDP_TLV_ORG_MED {0x00, 0x12, 0xbb}
-#define LLDP_TLV_ORG_AVAYA {0x00, 0x40, 0x0D}
+#define LLDP_TLV_ORG_AVAYA {0x00, 0x04, 0x0D}
#define LLDP_TLV_ORG_DCBX {0x00, 0x1b, 0x21}
#define LLDP_TLV_DOT1_PVID 1
@@ -61,16 +61,26 @@
#define LLDP_TLV_MED_IV_MODEL 10
#define LLDP_TLV_MED_IV_ASSET 11
-#define LLDP_TLV_AA_ELEMENT_SUBTYPE 0x08
-#define LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE 0x09
+#define LLDP_TLV_AA_ELEMENT_SUBTYPE 0x0b
+#define LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE 0x0c
#define LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH 32
-#define LLDP_TLV_AA_ELEM_TYPE_UNKNOWN 1
-#define LLDP_TLV_AA_ELEM_TYPE_SERVER 2
-#define LLDP_TLV_AA_ELEM_TYPE_PROXY 3
-#define LLDP_TLV_AA_ELEM_TYPE_UNTAG_CLIENT 4
-#define LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT 5
-#define LLDP_TLV_AA_ELEM_TYPE_SERV_NO_AUTH 6
-#define LLDP_TLV_AA_ELEM_TYPE_PROXY_NO_AUTH 7
+
+#define LLDP_TLV_AA_ELEM_TYPE_UNKNOWN 1
+#define LLDP_TLV_AA_ELEM_TYPE_SERVER 2
+#define LLDP_TLV_AA_ELEM_TYPE_PROXY 3
+#define LLDP_TLV_AA_ELEM_TYPE_SERV_NO_AUTH 4
+#define LLDP_TLV_AA_ELEM_TYPE_PROXY_NO_AUTH 5
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_WIRELESS_ACCESS_POINT_TYPE1 6
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_WIRELESS_ACCESS_POINT_TYPE2 7
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_SWITCH 8
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_ROUTER 9
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_IP_PHONE 10
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_IP_CAMERA 11
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_IP_VIDEO 12
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_SECURITY_DEVICE 13
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH 14
+#define LLDP_TLV_AA_ELEM_TYPE_CLIENT_SERVER_ENDPOINT 15
+
#define LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE 0
#define LLDP_TLV_AA_ELEM_CONN_TYPE_MLT 1
#define LLDP_TLV_AA_ELEM_CONN_TYPE_SLT 2
diff --git a/lib/lldp/lldp.c b/lib/lldp/lldp.c
index d77bcd082..493c2ffa9 100644
--- a/lib/lldp/lldp.c
+++ b/lib/lldp/lldp.c
@@ -235,53 +235,69 @@ lldp_send(struct lldpd *global OVS_UNUSED,
lldp_tlv_end(p, start);
}
- /* Add Auto Attach tlvs to packet */
+ /* Add Auto Attach tlvs V3.1 to packet. LLDP FA element v3.1 format:
+ TLV Type[127] TLV Length[50 octets] Avaya OUI[00-04-0D] Subtype[11]
+ 7 bits 9 bits 3 octets 1 octet
+ HMAC-SHA Digest Element Type State Mgmt VLAN Rsvd System ID
+ 32 octets 6 bits 6 bits 12 bits 1 octet 10 octets
+ */
/* AA-ELEMENT */
if (port->p_element.type != 0) {
- u_int8_t aa_element_first_byte;
- u_int8_t aa_element_second_byte = 0;
+ u_int16_t aa_element_first_word = 0;
+ u_int16_t aa_element_second_word = 0;
+ u_int16_t aa_element_state = 0;
u_int8_t aa_elem_sys_id_first_byte;
u_int8_t aa_elem_sys_id_second_byte;
- /* Element type should be first 4 most significant bits, so bitwise OR
- * that with the first 4 bits of the 12-bit-wide mgmt_vlan
- */
- aa_element_first_byte = (((port->p_element.type & 0xF) << 4) |
- ((port->p_element.mgmt_vlan >> 8) & 0xF));
-
- /* Second byte should just be the remaining 8 bits of .mgmt_vlan */
- aa_element_second_byte = port->p_element.mgmt_vlan & 0x0FF;
-
- /* .conn_type should be 4 most sig. bits, so bitwise OR that
- * with the first 4 bits of the 12-bit-wide .smlt_id
- */
+ /* Link VLAN Tagging Requirements (bit 1),
+ * Automatic Provisioning Mode (bit 2/3) (left to right, 1 based) */
+ aa_element_state = ((port->p_element.vlan_tagging & 0x1) << 5) |
+ ((port->p_element.auto_prov_mode & 0x3) << 3);
+
+ /* Element first word should be first 6 most significant bits of
+ * element type, bitwise OR that with the next 6 bits of the state,
+ * bitwise OR with the first 4 bits of mgmt vlan id.
+ * Element type should be LLDP_TLV_AA_ELEM_TYPE_VIRTUAL_SWITCH for
+ * AA client */
+ aa_element_first_word = (port->p_element.type << 10) |
+ (aa_element_state << 4) |
+ ((port->p_element.mgmt_vlan & 0x0F00)>> 8);
+
+ /* Element second type should be the first 8 most significant bits
+ * of the remaining 8 bits of mgmt vlan id. */
+ aa_element_second_word = (port->p_element.mgmt_vlan & 0xFF) << 8;
+
+ /* System id first byte should be first 3 most significant bits of
+ * connecion type, bitwise OR that with the device state and bitwise
+ * OR that with the first 2 most significant bitsof rsvd (10 bits). */
aa_elem_sys_id_first_byte =
- ((port->p_element.system_id.conn_type & 0xF) << 4) |
- ((port->p_element.system_id.smlt_id >> 8) & 0xF);
+ ((port->p_element.system_id.conn_type & 0x7) << 5) |
+ ((port->p_element.system_id.rsvd >> 8) & 0x3);
- /* Second byte should just be the remaining 8 bits of .smlt_id */
- aa_elem_sys_id_second_byte = port->p_element.system_id.smlt_id & 0x0FF;
+ /* Second byte should just be the remaining 8 bits of 10 bits rsvd */
+ aa_elem_sys_id_second_byte =
+ (port->p_element.system_id.rsvd & 0xFF);
+
+ memset(msg_auth_digest, 0, sizeof msg_auth_digest);
lldp_tlv_start(p, LLDP_TLV_ORG, &start);
dp_packet_put(p, avaya, sizeof avaya);
lldp_tlv_put_u8(p, LLDP_TLV_AA_ELEMENT_SUBTYPE);
- lldp_tlv_put_u8(p, aa_element_first_byte);
- lldp_tlv_put_u8(p, aa_element_second_byte);
+ dp_packet_put(p, msg_auth_digest, sizeof msg_auth_digest);
+ lldp_tlv_put_u16(p, aa_element_first_word);
+ lldp_tlv_put_u16(p, aa_element_second_word);
dp_packet_put(p, &port->p_element.system_id.system_mac,
sizeof port->p_element.system_id.system_mac);
lldp_tlv_put_u8(p, aa_elem_sys_id_first_byte);
lldp_tlv_put_u8(p, aa_elem_sys_id_second_byte);
- dp_packet_put(p, &port->p_element.system_id.mlt_id,
- sizeof port->p_element.system_id.mlt_id);
+ dp_packet_put(p, &port->p_element.system_id.rsvd2,
+ sizeof port->p_element.system_id.rsvd2);
lldp_tlv_end(p, start);
}
if (!list_is_empty(&port->p_isid_vlan_maps)) {
- int j;
- for (j = 0; j < LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH; j++) {
- msg_auth_digest[j] = 0;
- }
+ memset(msg_auth_digest, 0, sizeof msg_auth_digest);
lldp_tlv_start(p, LLDP_TLV_ORG, &start);
dp_packet_put(p, avaya, sizeof avaya);
@@ -314,6 +330,7 @@ lldp_send(struct lldpd *global OVS_UNUSED,
if (!hardware->h_lport.p_lastframe
|| hardware->h_lport.p_lastframe->size != lldp_len
|| memcmp(hardware->h_lport.p_lastframe->frame, lldp, lldp_len)) {
+
struct lldpd_frame *frame = xmalloc(sizeof *frame + lldp_len);
frame->size = lldp_len;
memcpy(frame->frame, lldp, lldp_len);
@@ -327,8 +344,8 @@ lldp_send(struct lldpd *global OVS_UNUSED,
int
lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
- struct lldpd_hardware *hardware, struct lldpd_chassis **newchassis,
- struct lldpd_port **newport)
+ struct lldpd_hardware *hardware, struct lldpd_chassis **newchassis,
+ struct lldpd_port **newport)
{
struct lldpd_chassis *chassis;
struct lldpd_port *port;
@@ -372,6 +389,7 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
"received on %s", hardware->h_ifname);
goto malformed;
}
+
PEEK_DISCARD(ETH_ADDR_LEN); /* Skip source address */
if (PEEK_UINT16 != ETHERTYPE_LLDP) {
VLOG_INFO("non LLDP frame received on %s", hardware->h_ifname);
@@ -498,34 +516,57 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
/* LLDP-MED */
hardware->h_rx_unrecognized_cnt++;
} else if (memcmp(avaya_oid, orgid, sizeof orgid) == 0) {
- u_int16_t aa_element_word;
- u_int16_t aa_status_vlan_word;
+ u_int32_t aa_element_dword;
u_int16_t aa_system_id_word;
+ u_int16_t aa_status_vlan_word;
+ u_int8_t aa_element_state;
unsigned short num_mappings;
switch(tlv_subtype) {
case LLDP_TLV_AA_ELEMENT_SUBTYPE:
- aa_element_word = PEEK_UINT16;
+ PEEK_BYTES(&msg_auth_digest, sizeof msg_auth_digest);
+
+ aa_element_dword = PEEK_UINT32;
+
+ /* Type is first 6 most-significant bits of
+ * aa_element_dword */
+ port->p_element.type = aa_element_dword >> 26;
- /* Type is first 4 most-significant bits */
- port->p_element.type = aa_element_word >> 12;
+ /* State is 6 most significant bits of aa_element_dword */
+ aa_element_state = (aa_element_dword >> 20) & 0x3F;
- /* mgmt_vlan is last 12 bits */
- port->p_element.mgmt_vlan = aa_element_word & 0x0FFF;
- VLOG_INFO("Element type: %X, Mgmt vlan: %X",
+ /* vlan tagging requirement is the bit 1(left to right)
+ * of the 6 bits state (1 based) */
+ port->p_element.vlan_tagging =
+ (aa_element_state >> 5) & 0x1;
+
+ /* Automatic provision mode is the bit 2/3(left to right)
+ * of the 6 bits state (1 based) */
+ port->p_element.auto_prov_mode =
+ (aa_element_state >> 3) & 0x3;
+
+ /* mgmt_vlan is the 12 bits of aa_element_dword from
+ * bit 12 */
+ port->p_element.mgmt_vlan =
+ (aa_element_dword >> 8) & 0xFFF;
+ VLOG_INFO("Element type: %X, vlan tagging %X, "
+ "auto prov mode %x, Mgmt vlan: %X",
port->p_element.type,
+ port->p_element.vlan_tagging,
+ port->p_element.auto_prov_mode,
port->p_element.mgmt_vlan);
+
PEEK_BYTES(&port->p_element.system_id.system_mac,
sizeof port->p_element.system_id.system_mac);
VLOG_INFO("System mac: "ETH_ADDR_FMT,
- ETH_ADDR_ARGS(port->p_element.system_id.system_mac));
+ ETH_ADDR_ARGS(port->p_element.system_id.system_mac));
aa_system_id_word = PEEK_UINT16;
port->p_element.system_id.conn_type =
- aa_system_id_word >> 12;
- port->p_element.system_id.smlt_id =
- aa_system_id_word & 0x0FFF;
- PEEK_BYTES(&port->p_element.system_id.mlt_id,
- sizeof port->p_element.system_id.mlt_id);
+ aa_system_id_word >> 13;
+ port->p_element.system_id.rsvd = aa_system_id_word &
+ 0x03FF;
+ PEEK_BYTES(&port->p_element.system_id.rsvd2,
+ sizeof port->p_element.system_id.rsvd2);
break;
case LLDP_TLV_AA_ISID_VLAN_ASGNS_SUBTYPE:
diff --git a/lib/lldp/lldpd-structs.c b/lib/lldp/lldpd-structs.c
index e2f8f2293..b78c2e19a 100644
--- a/lib/lldp/lldpd-structs.c
+++ b/lib/lldp/lldpd-structs.c
@@ -28,13 +28,12 @@ VLOG_DEFINE_THIS_MODULE(lldpd_structs);
void
lldpd_chassis_mgmt_cleanup(struct lldpd_chassis *chassis)
{
- struct lldpd_mgmt *mgmt, *mgmt_next;
+ struct lldpd_mgmt *mgmt;
VLOG_DBG("cleanup management addresses for chassis %s",
chassis->c_name ? chassis->c_name : "(unknown)");
- LIST_FOR_EACH_SAFE (mgmt, mgmt_next, m_entries, &chassis->c_mgmt) {
- list_remove(&mgmt->m_entries);
+ LIST_FOR_EACH_POP (mgmt, m_entries, &chassis->c_mgmt) {
free(mgmt);
}
diff --git a/lib/lldp/lldpd.c b/lib/lldp/lldpd.c
index 7f6e348b0..71d3938d1 100644
--- a/lib/lldp/lldpd.c
+++ b/lib/lldp/lldpd.c
@@ -164,7 +164,7 @@ static void
lldpd_move_chassis(struct lldpd_chassis *ochassis,
struct lldpd_chassis *chassis)
{
- struct lldpd_mgmt *mgmt, *mgmt_next;
+ struct lldpd_mgmt *mgmt;
int refcount = ochassis->c_refcount;
int index = ochassis->c_index;
struct ovs_list listcopy;
@@ -182,8 +182,7 @@ lldpd_move_chassis(struct lldpd_chassis *ochassis,
list_init(&ochassis->c_mgmt);
/* Copy of management addresses */
- LIST_FOR_EACH_SAFE (mgmt, mgmt_next, m_entries, &chassis->c_mgmt) {
- list_remove(&mgmt->m_entries);
+ LIST_FOR_EACH_POP (mgmt, m_entries, &chassis->c_mgmt) {
list_insert(&ochassis->c_mgmt, &mgmt->m_entries);
}
diff --git a/lib/lockfile.c b/lib/lockfile.c
index 26aee3324..864d3eff0 100644
--- a/lib/lockfile.c
+++ b/lib/lockfile.c
@@ -82,6 +82,14 @@ lockfile_name(const char *filename_)
* symlink, not one for each. */
filename = follow_symlinks(filename_);
slash = strrchr(filename, '/');
+
+#ifdef _WIN32
+ char *backslash = strrchr(filename, '\\');
+ if (backslash && (!slash || backslash > slash)) {
+ slash = backslash;
+ }
+#endif
+
lockname = (slash
? xasprintf("%.*s/.%s.~lock~",
(int) (slash - filename), filename, slash + 1)
diff --git a/lib/mcast-snooping.c b/lib/mcast-snooping.c
index 6fe3890c7..c3ffd6b77 100644
--- a/lib/mcast-snooping.c
+++ b/lib/mcast-snooping.c
@@ -307,10 +307,9 @@ static void
mcast_snooping_flush_group(struct mcast_snooping *ms, struct mcast_group *grp)
OVS_REQ_WRLOCK(ms->rwlock)
{
- struct mcast_group_bundle *b, *next_b;
+ struct mcast_group_bundle *b;
- LIST_FOR_EACH_SAFE (b, next_b, bundle_node, &grp->bundle_lru) {
- list_remove(&b->bundle_node);
+ LIST_FOR_EACH_POP (b, bundle_node, &grp->bundle_lru) {
free(b);
}
mcast_snooping_flush_group__(ms, grp);
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 8058e072e..124b5256c 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -352,6 +352,41 @@ mf_mask_field_and_prereqs(const struct mf_field *mf, struct flow *mask)
}
}
+/* Set bits of 'bm' corresponding to the field 'mf' and it's prerequisities. */
+void
+mf_bitmap_set_field_and_prereqs(const struct mf_field *mf, struct mf_bitmap *bm)
+{
+ bitmap_set1(bm->bm, mf->id);
+
+ switch (mf->prereqs) {
+ case MFP_ND:
+ case MFP_ND_SOLICIT:
+ case MFP_ND_ADVERT:
+ bitmap_set1(bm->bm, MFF_TCP_SRC);
+ bitmap_set1(bm->bm, MFF_TCP_DST);
+ /* Fall through. */
+ case MFP_TCP:
+ case MFP_UDP:
+ case MFP_SCTP:
+ case MFP_ICMPV4:
+ case MFP_ICMPV6:
+ /* nw_frag always unwildcarded. */
+ bitmap_set1(bm->bm, MFF_IP_PROTO);
+ /* Fall through. */
+ case MFP_ARP:
+ case MFP_IPV4:
+ case MFP_IPV6:
+ case MFP_MPLS:
+ case MFP_IP_ANY:
+ bitmap_set1(bm->bm, MFF_ETH_TYPE);
+ break;
+ case MFP_VLAN_VID:
+ bitmap_set1(bm->bm, MFF_VLAN_TCI);
+ break;
+ case MFP_NONE:
+ break;
+ }
+}
/* Returns true if 'value' may be a valid value *as part of a masked match*,
* false otherwise.
@@ -2278,3 +2313,12 @@ mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s)
}
ds_put_char(s, '0');
}
+
+void
+field_array_set(enum mf_field_id id, const union mf_value *value,
+ struct field_array *fa)
+{
+ ovs_assert(id < MFF_N_IDS);
+ bitmap_set1(fa->used.bm, id);
+ fa->value[id] = *value;
+}
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index de02d1a37..78e34c5aa 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -1590,6 +1590,12 @@ union mf_subvalue {
};
BUILD_ASSERT_DECL(sizeof(union mf_value) == sizeof (union mf_subvalue));
+/* An array of fields with values */
+struct field_array {
+ struct mf_bitmap used;
+ union mf_value value[MFF_N_IDS];
+};
+
/* Finding mf_fields. */
const struct mf_field *mf_from_name(const char *name);
@@ -1611,6 +1617,8 @@ void mf_get_mask(const struct mf_field *, const struct flow_wildcards *,
/* Prerequisites. */
bool mf_are_prereqs_ok(const struct mf_field *, const struct flow *);
void mf_mask_field_and_prereqs(const struct mf_field *, struct flow *mask);
+void mf_bitmap_set_field_and_prereqs(const struct mf_field *mf, struct
+ mf_bitmap *bm);
static inline bool
mf_is_l3_or_higher(const struct mf_field *mf)
@@ -1668,4 +1676,8 @@ void mf_format(const struct mf_field *,
struct ds *);
void mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s);
+/* Field Arrays. */
+void field_array_set(enum mf_field_id id, const union mf_value *,
+ struct field_array *);
+
#endif /* meta-flow.h */
diff --git a/lib/netdev-bsd.c b/lib/netdev-bsd.c
index f97a5c35d..9ed2823b8 100644
--- a/lib/netdev-bsd.c
+++ b/lib/netdev-bsd.c
@@ -1785,7 +1785,7 @@ static int
ifr_get_flags(const struct ifreq *ifr)
{
#ifdef HAVE_STRUCT_IFREQ_IFR_FLAGSHIGH
- return (ifr->ifr_flagshigh << 16) | ifr->ifr_flags;
+ return (ifr->ifr_flagshigh << 16) | (ifr->ifr_flags & 0xffff);
#else
return ifr->ifr_flags;
#endif
@@ -1794,9 +1794,11 @@ ifr_get_flags(const struct ifreq *ifr)
static void
ifr_set_flags(struct ifreq *ifr, int flags)
{
- ifr->ifr_flags = flags;
#ifdef HAVE_STRUCT_IFREQ_IFR_FLAGSHIGH
+ ifr->ifr_flags = flags & 0xffff;
ifr->ifr_flagshigh = flags >> 16;
+#else
+ ifr->ifr_flags = flags;
#endif
}
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index 1ba83109e..f69154b07 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -49,6 +49,7 @@
#include "rte_config.h"
#include "rte_mbuf.h"
+#include "rte_virtio_net.h"
VLOG_DEFINE_THIS_MODULE(dpdk);
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
@@ -67,9 +68,23 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
#define MBUF_SIZE(mtu) (MTU_TO_MAX_LEN(mtu) + (512) + \
sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
-/* XXX: mempool size should be based on system resources. */
-#define NB_MBUF (4096 * 64)
-#define MP_CACHE_SZ (256 * 2)
+/* Max and min number of packets in the mempool. OVS tries to allocate a
+ * mempool with MAX_NB_MBUF: if this fails (because the system doesn't have
+ * enough hugepages) we keep halving the number until the allocation succeeds
+ * or we reach MIN_NB_MBUF */
+
+#define MAX_NB_MBUF (4096 * 64)
+#define MIN_NB_MBUF (4096 * 4)
+#define MP_CACHE_SZ RTE_MEMPOOL_CACHE_MAX_SIZE
+
+/* MAX_NB_MBUF can be divided by 2 many times, until MIN_NB_MBUF */
+BUILD_ASSERT_DECL(MAX_NB_MBUF % ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF) == 0);
+
+/* The smallest possible NB_MBUF that we're going to try should be a multiple
+ * of MP_CACHE_SZ. This is advised by DPDK documentation. */
+BUILD_ASSERT_DECL((MAX_NB_MBUF / ROUND_DOWN_POW2(MAX_NB_MBUF/MIN_NB_MBUF))
+ % MP_CACHE_SZ == 0);
+
#define SOCKET0 0
#define NIC_PORT_RX_Q_SIZE 2048 /* Size of Physical NIC RX Queue, Max (n+32<=4096)*/
@@ -84,6 +99,11 @@ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
#define TX_HTHRESH 0 /* Default values of TX host threshold reg. */
#define TX_WTHRESH 0 /* Default values of TX write-back threshold reg. */
+#define MAX_PKT_BURST 32 /* Max burst size for RX/TX */
+
+/* Character device cuse_dev_name. */
+char *cuse_dev_name = NULL;
+
static const struct rte_eth_conf port_conf = {
.rxmode = {
.mq_mode = ETH_MQ_RX_RSS,
@@ -131,6 +151,11 @@ enum { DPDK_RING_SIZE = 256 };
BUILD_ASSERT_DECL(IS_POW2(DPDK_RING_SIZE));
enum { DRAIN_TSC = 200000ULL };
+enum dpdk_dev_type {
+ DPDK_DEV_ETH = 0,
+ DPDK_DEV_VHOST = 1
+};
+
static int rte_eal_init_ret = ENODEV;
static struct ovs_mutex dpdk_mutex = OVS_MUTEX_INITIALIZER;
@@ -185,6 +210,7 @@ struct netdev_dpdk {
struct netdev up;
int port_id;
int max_packet_len;
+ enum dpdk_dev_type type;
struct dpdk_tx_queue *tx_q;
@@ -202,9 +228,12 @@ struct netdev_dpdk {
struct rte_eth_link link;
int link_reset_cnt;
+ /* virtio-net structure for vhost device */
+ OVSRCU_TYPE(struct virtio_net *) virtio_dev;
+
/* In dpdk_list. */
struct ovs_list list_node OVS_GUARDED_BY(dpdk_mutex);
- rte_spinlock_t dpdkr_tx_lock;
+ rte_spinlock_t txq_lock;
};
struct netdev_rxq_dpdk {
@@ -216,14 +245,16 @@ static bool thread_is_pmd(void);
static int netdev_dpdk_construct(struct netdev *);
+struct virtio_net * netdev_dpdk_get_virtio(const struct netdev_dpdk *dev);
+
static bool
is_dpdk_class(const struct netdev_class *class)
{
return class->construct == netdev_dpdk_construct;
}
-/* XXX: use dpdk malloc for entire OVS. infact huge page shld be used
- * for all other sengments data, bss and text. */
+/* XXX: use dpdk malloc for entire OVS. in fact huge page should be used
+ * for all other segments data, bss and text. */
static void *
dpdk_rte_mzalloc(size_t sz)
@@ -293,6 +324,7 @@ dpdk_mp_get(int socket_id, int mtu) OVS_REQUIRES(dpdk_mutex)
{
struct dpdk_mp *dmp = NULL;
char mp_name[RTE_MEMPOOL_NAMESIZE];
+ unsigned mp_size;
LIST_FOR_EACH (dmp, list_node, &dpdk_mp_list) {
if (dmp->socket_id == socket_id && dmp->mtu == mtu) {
@@ -306,20 +338,25 @@ dpdk_mp_get(int socket_id, int mtu) OVS_REQUIRES(dpdk_mutex)
dmp->mtu = mtu;
dmp->refcount = 1;
- if (snprintf(mp_name, RTE_MEMPOOL_NAMESIZE, "ovs_mp_%d_%d", dmp->mtu,
- dmp->socket_id) < 0) {
- return NULL;
- }
+ mp_size = MAX_NB_MBUF;
+ do {
+ if (snprintf(mp_name, RTE_MEMPOOL_NAMESIZE, "ovs_mp_%d_%d_%u",
+ dmp->mtu, dmp->socket_id, mp_size) < 0) {
+ return NULL;
+ }
- dmp->mp = rte_mempool_create(mp_name, NB_MBUF, MBUF_SIZE(mtu),
- MP_CACHE_SZ,
- sizeof(struct rte_pktmbuf_pool_private),
- rte_pktmbuf_pool_init, NULL,
- ovs_rte_pktmbuf_init, NULL,
- socket_id, 0);
+ dmp->mp = rte_mempool_create(mp_name, mp_size, MBUF_SIZE(mtu),
+ MP_CACHE_SZ,
+ sizeof(struct rte_pktmbuf_pool_private),
+ rte_pktmbuf_pool_init, NULL,
+ ovs_rte_pktmbuf_init, NULL,
+ socket_id, 0);
+ } while (!dmp->mp && rte_errno == ENOMEM && (mp_size /= 2) >= MIN_NB_MBUF);
if (dmp->mp == NULL) {
return NULL;
+ } else {
+ VLOG_DBG("Allocated \"%s\" mempool with %u mbufs", mp_name, mp_size );
}
list_push_back(&dpdk_mp_list, &dmp->list_node);
@@ -483,7 +520,8 @@ netdev_dpdk_alloc_txq(struct netdev_dpdk *netdev, unsigned int n_txqs)
}
static int
-netdev_dpdk_init(struct netdev *netdev_, unsigned int port_no)
+netdev_dpdk_init(struct netdev *netdev_, unsigned int port_no,
+ enum dpdk_dev_type type)
OVS_REQUIRES(dpdk_mutex)
{
struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_);
@@ -491,20 +529,24 @@ netdev_dpdk_init(struct netdev *netdev_, unsigned int port_no)
int err = 0;
ovs_mutex_init(&netdev->mutex);
-
ovs_mutex_lock(&netdev->mutex);
/* If the 'sid' is negative, it means that the kernel fails
* to obtain the pci numa info. In that situation, always
* use 'SOCKET0'. */
- sid = rte_eth_dev_socket_id(port_no);
+ if (type == DPDK_DEV_ETH) {
+ sid = rte_eth_dev_socket_id(port_no);
+ } else {
+ sid = rte_lcore_to_socket_id(rte_get_master_lcore());
+ }
+
netdev->socket_id = sid < 0 ? SOCKET0 : sid;
- netdev_dpdk_alloc_txq(netdev, NR_QUEUE);
netdev->port_id = port_no;
+ netdev->type = type;
netdev->flags = 0;
netdev->mtu = ETHER_MTU;
netdev->max_packet_len = MTU_TO_MAX_LEN(netdev->mtu);
- rte_spinlock_init(&netdev->dpdkr_tx_lock);
+ rte_spinlock_init(&netdev->txq_lock);
netdev->dpdk_mp = dpdk_mp_get(netdev->socket_id, netdev->mtu);
if (!netdev->dpdk_mp) {
@@ -514,9 +556,13 @@ netdev_dpdk_init(struct netdev *netdev_, unsigned int port_no)
netdev_->n_txq = NR_QUEUE;
netdev_->n_rxq = NR_QUEUE;
- err = dpdk_eth_dev_init(netdev);
- if (err) {
- goto unlock;
+
+ if (type == DPDK_DEV_ETH) {
+ netdev_dpdk_alloc_txq(netdev, NR_QUEUE);
+ err = dpdk_eth_dev_init(netdev);
+ if (err) {
+ goto unlock;
+ }
}
list_push_back(&dpdk_list, &netdev->list_node);
@@ -545,6 +591,22 @@ dpdk_dev_parse_name(const char dev_name[], const char prefix[],
}
static int
+netdev_dpdk_vhost_construct(struct netdev *netdev_)
+{
+ int err;
+
+ if (rte_eal_init_ret) {
+ return rte_eal_init_ret;
+ }
+
+ ovs_mutex_lock(&dpdk_mutex);
+ err = netdev_dpdk_init(netdev_, -1, DPDK_DEV_VHOST);
+ ovs_mutex_unlock(&dpdk_mutex);
+
+ return err;
+}
+
+static int
netdev_dpdk_construct(struct netdev *netdev)
{
unsigned int port_no;
@@ -561,7 +623,7 @@ netdev_dpdk_construct(struct netdev *netdev)
}
ovs_mutex_lock(&dpdk_mutex);
- err = netdev_dpdk_init(netdev, port_no);
+ err = netdev_dpdk_init(netdev, port_no, DPDK_DEV_ETH);
ovs_mutex_unlock(&dpdk_mutex);
return err;
}
@@ -580,8 +642,23 @@ netdev_dpdk_destruct(struct netdev *netdev_)
list_remove(&dev->list_node);
dpdk_mp_put(dev->dpdk_mp);
ovs_mutex_unlock(&dpdk_mutex);
+}
- ovs_mutex_destroy(&dev->mutex);
+static void
+netdev_dpdk_vhost_destruct(struct netdev *netdev_)
+{
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev_);
+
+ /* Can't remove a port while a guest is attached to it. */
+ if (netdev_dpdk_get_virtio(dev) != NULL) {
+ VLOG_ERR("Can not remove port, vhost device still attached");
+ return;
+ }
+
+ ovs_mutex_lock(&dpdk_mutex);
+ list_remove(&dev->list_node);
+ dpdk_mp_put(dev->dpdk_mp);
+ ovs_mutex_unlock(&dpdk_mutex);
}
static void
@@ -635,6 +712,7 @@ netdev_dpdk_set_multiq(struct netdev *netdev_, unsigned int n_txq,
netdev->up.n_txq = n_txq;
netdev->up.n_rxq = n_rxq;
+
rte_free(netdev->tx_q);
netdev_dpdk_alloc_txq(netdev, n_txq);
err = dpdk_eth_dev_init(netdev);
@@ -645,6 +723,29 @@ netdev_dpdk_set_multiq(struct netdev *netdev_, unsigned int n_txq,
return err;
}
+static int
+netdev_dpdk_vhost_set_multiq(struct netdev *netdev_, unsigned int n_txq,
+ unsigned int n_rxq)
+{
+ struct netdev_dpdk *netdev = netdev_dpdk_cast(netdev_);
+ int err = 0;
+
+ if (netdev->up.n_txq == n_txq && netdev->up.n_rxq == n_rxq) {
+ return err;
+ }
+
+ ovs_mutex_lock(&dpdk_mutex);
+ ovs_mutex_lock(&netdev->mutex);
+
+ netdev->up.n_txq = n_txq;
+ netdev->up.n_rxq = n_rxq;
+
+ ovs_mutex_unlock(&netdev->mutex);
+ ovs_mutex_unlock(&dpdk_mutex);
+
+ return err;
+}
+
static struct netdev_rxq *
netdev_dpdk_rxq_alloc(void)
{
@@ -731,6 +832,43 @@ dpdk_queue_flush(struct netdev_dpdk *dev, int qid)
dpdk_queue_flush__(dev, qid);
}
+static bool
+is_vhost_running(struct virtio_net *dev)
+{
+ return (dev != NULL && (dev->flags & VIRTIO_DEV_RUNNING));
+}
+
+/*
+ * The receive path for the vhost port is the TX path out from guest.
+ */
+static int
+netdev_dpdk_vhost_rxq_recv(struct netdev_rxq *rxq_,
+ struct dp_packet **packets, int *c)
+{
+ struct netdev_rxq_dpdk *rx = netdev_rxq_dpdk_cast(rxq_);
+ struct netdev *netdev = rx->up.netdev;
+ struct netdev_dpdk *vhost_dev = netdev_dpdk_cast(netdev);
+ struct virtio_net *virtio_dev = netdev_dpdk_get_virtio(vhost_dev);
+ int qid = 1;
+ uint16_t nb_rx = 0;
+
+ if (OVS_UNLIKELY(!is_vhost_running(virtio_dev))) {
+ return EAGAIN;
+ }
+
+ nb_rx = rte_vhost_dequeue_burst(virtio_dev, qid,
+ vhost_dev->dpdk_mp->mp,
+ (struct rte_mbuf **)packets,
+ MAX_PKT_BURST);
+ if (!nb_rx) {
+ return EAGAIN;
+ }
+
+ vhost_dev->stats.rx_packets += (uint64_t)nb_rx;
+ *c = (int) nb_rx;
+ return 0;
+}
+
static int
netdev_dpdk_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet **packets,
int *c)
@@ -759,6 +897,38 @@ netdev_dpdk_rxq_recv(struct netdev_rxq *rxq_, struct dp_packet **packets,
return 0;
}
+static void
+__netdev_dpdk_vhost_send(struct netdev *netdev, struct dp_packet **pkts,
+ int cnt, bool may_steal)
+{
+ struct netdev_dpdk *vhost_dev = netdev_dpdk_cast(netdev);
+ struct virtio_net *virtio_dev = netdev_dpdk_get_virtio(vhost_dev);
+ int tx_pkts, i;
+
+ if (OVS_UNLIKELY(!is_vhost_running(virtio_dev))) {
+ ovs_mutex_lock(&vhost_dev->mutex);
+ vhost_dev->stats.tx_dropped+= cnt;
+ ovs_mutex_unlock(&vhost_dev->mutex);
+ goto out;
+ }
+
+ /* There is vHost TX single queue, So we need to lock it for TX. */
+ rte_spinlock_lock(&vhost_dev->txq_lock);
+ tx_pkts = rte_vhost_enqueue_burst(virtio_dev, VIRTIO_RXQ,
+ (struct rte_mbuf **)pkts, cnt);
+
+ vhost_dev->stats.tx_packets += tx_pkts;
+ vhost_dev->stats.tx_dropped += (cnt - tx_pkts);
+ rte_spinlock_unlock(&vhost_dev->txq_lock);
+
+out:
+ if (may_steal) {
+ for (i = 0; i < cnt; i++) {
+ dp_packet_delete(pkts[i]);
+ }
+ }
+}
+
inline static void
dpdk_queue_pkts(struct netdev_dpdk *dev, int qid,
struct rte_mbuf **pkts, int cnt)
@@ -790,7 +960,7 @@ dpdk_queue_pkts(struct netdev_dpdk *dev, int qid,
/* Tx function. Transmit packets indefinitely */
static void
-dpdk_do_tx_copy(struct netdev *netdev, int qid, struct dp_packet ** pkts,
+dpdk_do_tx_copy(struct netdev *netdev, int qid, struct dp_packet **pkts,
int cnt)
OVS_NO_THREAD_SAFETY_ANALYSIS
{
@@ -840,14 +1010,37 @@ dpdk_do_tx_copy(struct netdev *netdev, int qid, struct dp_packet ** pkts,
ovs_mutex_unlock(&dev->mutex);
}
- dpdk_queue_pkts(dev, qid, mbufs, newcnt);
- dpdk_queue_flush(dev, qid);
+ if (dev->type == DPDK_DEV_VHOST) {
+ __netdev_dpdk_vhost_send(netdev, (struct dp_packet **) mbufs, newcnt, true);
+ } else {
+ dpdk_queue_pkts(dev, qid, mbufs, newcnt);
+ dpdk_queue_flush(dev, qid);
+ }
if (!thread_is_pmd()) {
ovs_mutex_unlock(&nonpmd_mempool_mutex);
}
}
+static int
+netdev_dpdk_vhost_send(struct netdev *netdev, int qid OVS_UNUSED, struct dp_packet **pkts,
+ int cnt, bool may_steal)
+{
+ if (OVS_UNLIKELY(pkts[0]->source != DPBUF_DPDK)) {
+ int i;
+
+ dpdk_do_tx_copy(netdev, qid, pkts, cnt);
+ if (may_steal) {
+ for (i = 0; i < cnt; i++) {
+ dp_packet_delete(pkts[i]);
+ }
+ }
+ } else {
+ __netdev_dpdk_vhost_send(netdev, pkts, cnt, may_steal);
+ }
+ return 0;
+}
+
static inline void
netdev_dpdk_send__(struct netdev_dpdk *dev, int qid,
struct dp_packet **pkts, int cnt, bool may_steal)
@@ -1002,6 +1195,44 @@ static int
netdev_dpdk_get_carrier(const struct netdev *netdev_, bool *carrier);
static int
+netdev_dpdk_vhost_get_stats(const struct netdev *netdev,
+ struct netdev_stats *stats)
+{
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+
+ ovs_mutex_lock(&dev->mutex);
+ memset(stats, 0, sizeof(*stats));
+ /* Unsupported Stats */
+ stats->rx_errors = UINT64_MAX;
+ stats->tx_errors = UINT64_MAX;
+ stats->multicast = UINT64_MAX;
+ stats->collisions = UINT64_MAX;
+ stats->rx_crc_errors = UINT64_MAX;
+ stats->rx_fifo_errors = UINT64_MAX;
+ stats->rx_frame_errors = UINT64_MAX;
+ stats->rx_length_errors = UINT64_MAX;
+ stats->rx_missed_errors = UINT64_MAX;
+ stats->rx_over_errors = UINT64_MAX;
+ stats->tx_aborted_errors = UINT64_MAX;
+ stats->tx_carrier_errors = UINT64_MAX;
+ stats->tx_errors = UINT64_MAX;
+ stats->tx_fifo_errors = UINT64_MAX;
+ stats->tx_heartbeat_errors = UINT64_MAX;
+ stats->tx_window_errors = UINT64_MAX;
+ stats->rx_bytes += UINT64_MAX;
+ stats->rx_dropped += UINT64_MAX;
+ stats->tx_bytes += UINT64_MAX;
+
+ /* Supported Stats */
+ stats->rx_packets += dev->stats.rx_packets;
+ stats->tx_packets += dev->stats.tx_packets;
+ stats->tx_dropped += dev->stats.tx_dropped;
+ ovs_mutex_unlock(&dev->mutex);
+
+ return 0;
+}
+
+static int
netdev_dpdk_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
{
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
@@ -1095,6 +1326,26 @@ netdev_dpdk_get_carrier(const struct netdev *netdev_, bool *carrier)
ovs_mutex_lock(&dev->mutex);
check_link_status(dev);
*carrier = dev->link.link_status;
+
+ ovs_mutex_unlock(&dev->mutex);
+
+ return 0;
+}
+
+static int
+netdev_dpdk_vhost_get_carrier(const struct netdev *netdev_, bool *carrier)
+{
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev_);
+ struct virtio_net *virtio_dev = netdev_dpdk_get_virtio(dev);
+
+ ovs_mutex_lock(&dev->mutex);
+
+ if (is_vhost_running(virtio_dev)) {
+ *carrier = 1;
+ } else {
+ *carrier = 0;
+ }
+
ovs_mutex_unlock(&dev->mutex);
return 0;
@@ -1139,18 +1390,20 @@ netdev_dpdk_update_flags__(struct netdev_dpdk *dev,
return 0;
}
- if (dev->flags & NETDEV_UP) {
- err = rte_eth_dev_start(dev->port_id);
- if (err)
- return -err;
- }
+ if (dev->type == DPDK_DEV_ETH) {
+ if (dev->flags & NETDEV_UP) {
+ err = rte_eth_dev_start(dev->port_id);
+ if (err)
+ return -err;
+ }
- if (dev->flags & NETDEV_PROMISC) {
- rte_eth_promiscuous_enable(dev->port_id);
- }
+ if (dev->flags & NETDEV_PROMISC) {
+ rte_eth_promiscuous_enable(dev->port_id);
+ }
- if (!(dev->flags & NETDEV_UP)) {
- rte_eth_dev_stop(dev->port_id);
+ if (!(dev->flags & NETDEV_UP)) {
+ rte_eth_dev_stop(dev->port_id);
+ }
}
return 0;
@@ -1261,6 +1514,139 @@ netdev_dpdk_set_admin_state(struct unixctl_conn *conn, int argc,
unixctl_command_reply(conn, "OK");
}
+/*
+ * Set virtqueue flags so that we do not receive interrupts.
+ */
+static void
+set_irq_status(struct virtio_net *dev)
+{
+ dev->virtqueue[VIRTIO_RXQ]->used->flags = VRING_USED_F_NO_NOTIFY;
+ dev->virtqueue[VIRTIO_TXQ]->used->flags = VRING_USED_F_NO_NOTIFY;
+}
+
+/*
+ * A new virtio-net device is added to a vhost port.
+ */
+static int
+new_device(struct virtio_net *dev)
+{
+ struct netdev_dpdk *netdev;
+ bool exists = false;
+
+ ovs_mutex_lock(&dpdk_mutex);
+ /* Add device to the vhost port with the same name as that passed down. */
+ LIST_FOR_EACH(netdev, list_node, &dpdk_list) {
+ if (strncmp(dev->ifname, netdev->up.name, IFNAMSIZ) == 0) {
+ ovs_mutex_lock(&netdev->mutex);
+ ovsrcu_set(&netdev->virtio_dev, dev);
+ ovs_mutex_unlock(&netdev->mutex);
+ exists = true;
+ dev->flags |= VIRTIO_DEV_RUNNING;
+ /* Disable notifications. */
+ set_irq_status(dev);
+ break;
+ }
+ }
+ ovs_mutex_unlock(&dpdk_mutex);
+
+ if (!exists) {
+ VLOG_INFO("vHost Device '%s' (%ld) can't be added - name not found",
+ dev->ifname, dev->device_fh);
+
+ return -1;
+ }
+
+ VLOG_INFO("vHost Device '%s' (%ld) has been added",
+ dev->ifname, dev->device_fh);
+ return 0;
+}
+
+/*
+ * Remove a virtio-net device from the specific vhost port. Use dev->remove
+ * flag to stop any more packets from being sent or received to/from a VM and
+ * ensure all currently queued packets have been sent/received before removing
+ * the device.
+ */
+static void
+destroy_device(volatile struct virtio_net *dev)
+{
+ struct netdev_dpdk *vhost_dev;
+
+ ovs_mutex_lock(&dpdk_mutex);
+ LIST_FOR_EACH (vhost_dev, list_node, &dpdk_list) {
+ if (netdev_dpdk_get_virtio(vhost_dev) == dev) {
+
+ ovs_mutex_lock(&vhost_dev->mutex);
+ dev->flags &= ~VIRTIO_DEV_RUNNING;
+ ovsrcu_set(&vhost_dev->virtio_dev, NULL);
+ ovs_mutex_unlock(&vhost_dev->mutex);
+
+ /*
+ * Wait for other threads to quiesce before
+ * setting the virtio_dev to NULL.
+ */
+ ovsrcu_synchronize();
+ /*
+ * As call to ovsrcu_synchronize() will end the quiescent state,
+ * put thread back into quiescent state before returning.
+ */
+ ovsrcu_quiesce_start();
+ }
+ }
+ ovs_mutex_unlock(&dpdk_mutex);
+
+ VLOG_INFO("vHost Device '%s' (%ld) has been removed",
+ dev->ifname, dev->device_fh);
+}
+
+struct virtio_net *
+netdev_dpdk_get_virtio(const struct netdev_dpdk *dev)
+{
+ return ovsrcu_get(struct virtio_net *, &dev->virtio_dev);
+}
+
+/*
+ * These callbacks allow virtio-net devices to be added to vhost ports when
+ * configuration has been fully complete.
+ */
+const struct virtio_net_device_ops virtio_net_device_ops =
+{
+ .new_device = new_device,
+ .destroy_device = destroy_device,
+};
+
+static void *
+start_cuse_session_loop(void *dummy OVS_UNUSED)
+{
+ pthread_detach(pthread_self());
+ /* Put the cuse thread into quiescent state. */
+ ovsrcu_quiesce_start();
+ rte_vhost_driver_session_start();
+ return NULL;
+}
+
+static int
+dpdk_vhost_class_init(void)
+{
+ int err = -1;
+
+ rte_vhost_driver_callback_register(&virtio_net_device_ops);
+
+ /* Register CUSE device to handle IOCTLs.
+ * Unless otherwise specified on the vswitchd command line, cuse_dev_name
+ * is set to vhost-net.
+ */
+ err = rte_vhost_driver_register(cuse_dev_name);
+
+ if (err != 0) {
+ VLOG_ERR("CUSE device setup failure.");
+ return -1;
+ }
+
+ ovs_thread_create("cuse_thread", start_cuse_session_loop, NULL);
+ return 0;
+}
+
static void
dpdk_common_init(void)
{
@@ -1345,7 +1731,7 @@ dpdk_ring_open(const char dev_name[], unsigned int *eth_port_id) OVS_REQUIRES(dp
/* look through our list to find the device */
LIST_FOR_EACH (ivshmem, list_node, &dpdk_ring_list) {
if (ivshmem->user_port_id == port_no) {
- VLOG_INFO("Found dpdk ring device %s:\n", dev_name);
+ VLOG_INFO("Found dpdk ring device %s:", dev_name);
*eth_port_id = ivshmem->eth_port_id; /* really all that is needed */
return 0;
}
@@ -1361,9 +1747,9 @@ netdev_dpdk_ring_send(struct netdev *netdev, int qid OVS_UNUSED,
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
/* DPDK Rings have a single TX queue, Therefore needs locking. */
- rte_spinlock_lock(&dev->dpdkr_tx_lock);
+ rte_spinlock_lock(&dev->txq_lock);
netdev_dpdk_send__(dev, 0, pkts, cnt, may_steal);
- rte_spinlock_unlock(&dev->dpdkr_tx_lock);
+ rte_spinlock_unlock(&dev->txq_lock);
return 0;
}
@@ -1384,14 +1770,15 @@ netdev_dpdk_ring_construct(struct netdev *netdev)
goto unlock_dpdk;
}
- err = netdev_dpdk_init(netdev, port_no);
+ err = netdev_dpdk_init(netdev, port_no, DPDK_DEV_ETH);
unlock_dpdk:
ovs_mutex_unlock(&dpdk_mutex);
return err;
}
-#define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, MULTIQ, SEND) \
+#define NETDEV_DPDK_CLASS(NAME, INIT, CONSTRUCT, DESTRUCT, MULTIQ, SEND, \
+ GET_CARRIER, GET_STATS, GET_FEATURES, GET_STATUS, RXQ_RECV) \
{ \
NAME, \
INIT, /* init */ \
@@ -1400,14 +1787,14 @@ unlock_dpdk:
\
netdev_dpdk_alloc, \
CONSTRUCT, \
- netdev_dpdk_destruct, \
+ DESTRUCT, \
netdev_dpdk_dealloc, \
netdev_dpdk_get_config, \
NULL, /* netdev_dpdk_set_config */ \
NULL, /* get_tunnel_config */ \
- NULL, /* build header */ \
- NULL, /* push header */ \
- NULL, /* pop header */ \
+ NULL, /* build header */ \
+ NULL, /* push header */ \
+ NULL, /* pop header */ \
netdev_dpdk_get_numa_id, /* get_numa_id */ \
MULTIQ, /* set_multiq */ \
\
@@ -1419,11 +1806,11 @@ unlock_dpdk:
netdev_dpdk_get_mtu, \
netdev_dpdk_set_mtu, \
netdev_dpdk_get_ifindex, \
- netdev_dpdk_get_carrier, \
+ GET_CARRIER, \
netdev_dpdk_get_carrier_resets, \
netdev_dpdk_set_miimon, \
- netdev_dpdk_get_stats, \
- netdev_dpdk_get_features, \
+ GET_STATS, \
+ GET_FEATURES, \
NULL, /* set_advertisements */ \
\
NULL, /* set_policing */ \
@@ -1445,7 +1832,7 @@ unlock_dpdk:
NULL, /* get_in6 */ \
NULL, /* add_router */ \
NULL, /* get_next_hop */ \
- netdev_dpdk_get_status, \
+ GET_STATUS, \
NULL, /* arp_lookup */ \
\
netdev_dpdk_update_flags, \
@@ -1454,7 +1841,7 @@ unlock_dpdk:
netdev_dpdk_rxq_construct, \
netdev_dpdk_rxq_destruct, \
netdev_dpdk_rxq_dealloc, \
- netdev_dpdk_rxq_recv, \
+ RXQ_RECV, \
NULL, /* rx_wait */ \
NULL, /* rxq_drain */ \
}
@@ -1463,20 +1850,48 @@ int
dpdk_init(int argc, char **argv)
{
int result;
+ int base = 0;
+ char *pragram_name = argv[0];
if (argc < 2 || strcmp(argv[1], "--dpdk"))
return 0;
- /* Make sure program name passed to rte_eal_init() is vswitchd. */
- argv[1] = argv[0];
-
+ /* Remove the --dpdk argument from arg list.*/
argc--;
argv++;
+ /* If the cuse_dev_name parameter has been provided, set 'cuse_dev_name' to
+ * this string if it meets the correct criteria. Otherwise, set it to the
+ * default (vhost-net).
+ */
+ if (!strcmp(argv[1], "--cuse_dev_name") &&
+ (strlen(argv[2]) <= NAME_MAX)) {
+
+ cuse_dev_name = strdup(argv[2]);
+
+ /* Remove the cuse_dev_name configuration parameters from the argument
+ * list, so that the correct elements are passed to the DPDK
+ * initialization function
+ */
+ argc -= 2;
+ argv += 2; /* Increment by two to bypass the cuse_dev_name arguments */
+ base = 2;
+
+ VLOG_ERR("User-provided cuse_dev_name in use: /dev/%s", cuse_dev_name);
+ } else {
+ cuse_dev_name = "vhost-net";
+ VLOG_INFO("No cuse_dev_name provided - defaulting to /dev/vhost-net");
+ }
+
+ /* Keep the program name argument as this is needed for call to
+ * rte_eal_init()
+ */
+ argv[0] = pragram_name;
+
/* Make sure things are initialized ... */
result = rte_eal_init(argc, argv);
if (result < 0) {
- ovs_abort(result, "Cannot init EAL\n");
+ ovs_abort(result, "Cannot init EAL");
}
rte_memzone_dump(stdout);
@@ -1489,7 +1904,7 @@ dpdk_init(int argc, char **argv)
/* We are called from the main thread here */
thread_set_nonpmd();
- return result + 1;
+ return result + 1 + base;
}
const struct netdev_class dpdk_class =
@@ -1497,16 +1912,42 @@ const struct netdev_class dpdk_class =
"dpdk",
NULL,
netdev_dpdk_construct,
+ netdev_dpdk_destruct,
netdev_dpdk_set_multiq,
- netdev_dpdk_eth_send);
+ netdev_dpdk_eth_send,
+ netdev_dpdk_get_carrier,
+ netdev_dpdk_get_stats,
+ netdev_dpdk_get_features,
+ netdev_dpdk_get_status,
+ netdev_dpdk_rxq_recv);
const struct netdev_class dpdk_ring_class =
NETDEV_DPDK_CLASS(
"dpdkr",
NULL,
netdev_dpdk_ring_construct,
+ netdev_dpdk_destruct,
+ NULL,
+ netdev_dpdk_ring_send,
+ netdev_dpdk_get_carrier,
+ netdev_dpdk_get_stats,
+ netdev_dpdk_get_features,
+ netdev_dpdk_get_status,
+ netdev_dpdk_rxq_recv);
+
+const struct netdev_class dpdk_vhost_class =
+ NETDEV_DPDK_CLASS(
+ "dpdkvhost",
+ dpdk_vhost_class_init,
+ netdev_dpdk_vhost_construct,
+ netdev_dpdk_vhost_destruct,
+ netdev_dpdk_vhost_set_multiq,
+ netdev_dpdk_vhost_send,
+ netdev_dpdk_vhost_get_carrier,
+ netdev_dpdk_vhost_get_stats,
+ NULL,
NULL,
- netdev_dpdk_ring_send);
+ netdev_dpdk_vhost_rxq_recv);
void
netdev_dpdk_register(void)
@@ -1521,6 +1962,7 @@ netdev_dpdk_register(void)
dpdk_common_init();
netdev_register_provider(&dpdk_class);
netdev_register_provider(&dpdk_ring_class);
+ netdev_register_provider(&dpdk_vhost_class);
ovsthread_once_done(&once);
}
}
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 7fb103e6c..24c91c203 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2010, 2011, 2012, 2013, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@
#include "odp-util.h"
#include "ofp-print.h"
#include "ofpbuf.h"
+#include "ovs-atomic.h"
#include "packets.h"
#include "pcap-file.h"
#include "poll-loop.h"
diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
index 662ccc975..23f98566d 100644
--- a/lib/netdev-linux.c
+++ b/lib/netdev-linux.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
+#include <sys/utsname.h>
#include <netpacket/packet.h>
#include <net/if.h>
#include <net/if_arp.h>
@@ -376,12 +377,18 @@ tc_destroy(struct tc *tc)
static const struct tc_ops tc_ops_htb;
static const struct tc_ops tc_ops_hfsc;
+static const struct tc_ops tc_ops_codel;
+static const struct tc_ops tc_ops_fqcodel;
+static const struct tc_ops tc_ops_sfq;
static const struct tc_ops tc_ops_default;
static const struct tc_ops tc_ops_other;
static const struct tc_ops *const tcs[] = {
&tc_ops_htb, /* Hierarchy token bucket (see tc-htb(8)). */
&tc_ops_hfsc, /* Hierarchical fair service curve. */
+ &tc_ops_codel, /* Controlled delay */
+ &tc_ops_fqcodel, /* Fair queue controlled delay */
+ &tc_ops_sfq, /* Stochastic fair queueing */
&tc_ops_default, /* Default qdisc (see tc-pfifo_fast(8)). */
&tc_ops_other, /* Some other qdisc. */
NULL
@@ -399,8 +406,8 @@ static struct tcmsg *tc_make_request(const struct netdev *, int type,
unsigned int flags, struct ofpbuf *);
static int tc_transact(struct ofpbuf *request, struct ofpbuf **replyp);
static int tc_add_del_ingress_qdisc(struct netdev *netdev, bool add);
-static int tc_add_policer(struct netdev *netdev, int kbits_rate,
- int kbits_burst);
+static int tc_add_policer(struct netdev *,
+ uint32_t kbits_rate, uint32_t kbits_burst);
static int tc_parse_qdisc(const struct ofpbuf *, const char **kind,
struct nlattr **options);
@@ -2831,9 +2838,666 @@ const struct netdev_class netdev_internal_class =
NULL, /* get_features */
netdev_internal_get_status);
+
+#define CODEL_N_QUEUES 0x0000
+
+/* In sufficiently new kernel headers these are defined as enums in
+ * <linux/pkt_sched.h>. Define them here as macros to help out with older
+ * kernels. (This overrides any enum definition in the header file but that's
+ * harmless.) */
+#define TCA_CODEL_TARGET 1
+#define TCA_CODEL_LIMIT 2
+#define TCA_CODEL_INTERVAL 3
+
+struct codel {
+ struct tc tc;
+ uint32_t target;
+ uint32_t limit;
+ uint32_t interval;
+};
+
+static struct codel *
+codel_get__(const struct netdev *netdev_)
+{
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ return CONTAINER_OF(netdev->tc, struct codel, tc);
+}
+
+static void
+codel_install__(struct netdev *netdev_, uint32_t target, uint32_t limit,
+ uint32_t interval)
+{
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ struct codel *codel;
+
+ codel = xmalloc(sizeof *codel);
+ tc_init(&codel->tc, &tc_ops_codel);
+ codel->target = target;
+ codel->limit = limit;
+ codel->interval = interval;
+
+ netdev->tc = &codel->tc;
+}
+
+static int
+codel_setup_qdisc__(struct netdev *netdev, uint32_t target, uint32_t limit,
+ uint32_t interval)
+{
+ size_t opt_offset;
+ struct ofpbuf request;
+ struct tcmsg *tcmsg;
+ uint32_t otarget, olimit, ointerval;
+ int error;
+
+ tc_del_qdisc(netdev);
+
+ tcmsg = tc_make_request(netdev, RTM_NEWQDISC,
+ NLM_F_EXCL | NLM_F_CREATE, &request);
+ if (!tcmsg) {
+ return ENODEV;
+ }
+ tcmsg->tcm_handle = tc_make_handle(1, 0);
+ tcmsg->tcm_parent = TC_H_ROOT;
+
+ otarget = target ? target : 5000;
+ olimit = limit ? limit : 10240;
+ ointerval = interval ? interval : 100000;
+
+ nl_msg_put_string(&request, TCA_KIND, "codel");
+ opt_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
+ nl_msg_put_u32(&request, TCA_CODEL_TARGET, otarget);
+ nl_msg_put_u32(&request, TCA_CODEL_LIMIT, olimit);
+ nl_msg_put_u32(&request, TCA_CODEL_INTERVAL, ointerval);
+ nl_msg_end_nested(&request, opt_offset);
+
+ error = tc_transact(&request, NULL);
+ if (error) {
+ VLOG_WARN_RL(&rl, "failed to replace %s qdisc, "
+ "target %u, limit %u, interval %u error %d(%s)",
+ netdev_get_name(netdev),
+ otarget, olimit, ointerval,
+ error, ovs_strerror(error));
+ }
+ return error;
+}
+
+static void
+codel_parse_qdisc_details__(struct netdev *netdev OVS_UNUSED,
+ const struct smap *details, struct codel *codel)
+{
+ const char *target_s;
+ const char *limit_s;
+ const char *interval_s;
+
+ target_s = smap_get(details, "target");
+ limit_s = smap_get(details, "limit");
+ interval_s = smap_get(details, "interval");
+
+ codel->target = target_s ? strtoull(target_s, NULL, 10) : 0;
+ codel->limit = limit_s ? strtoull(limit_s, NULL, 10) : 0;
+ codel->interval = interval_s ? strtoull(interval_s, NULL, 10) : 0;
+
+ if (!codel->target) {
+ codel->target = 5000;
+ }
+ if (!codel->limit) {
+ codel->limit = 10240;
+ }
+ if (!codel->interval) {
+ codel->interval = 100000;
+ }
+}
+
+static int
+codel_tc_install(struct netdev *netdev, const struct smap *details)
+{
+ int error;
+ struct codel codel;
+
+ codel_parse_qdisc_details__(netdev, details, &codel);
+ error = codel_setup_qdisc__(netdev, codel.target, codel.limit,
+ codel.interval);
+ if (!error) {
+ codel_install__(netdev, codel.target, codel.limit, codel.interval);
+ }
+ return error;
+}
+
+static int
+codel_parse_tca_options__(struct nlattr *nl_options, struct codel *codel)
+{
+ static const struct nl_policy tca_codel_policy[] = {
+ [TCA_CODEL_TARGET] = { .type = NL_A_U32 },
+ [TCA_CODEL_LIMIT] = { .type = NL_A_U32 },
+ [TCA_CODEL_INTERVAL] = { .type = NL_A_U32 }
+ };
+
+ struct nlattr *attrs[ARRAY_SIZE(tca_codel_policy)];
+
+ if (!nl_parse_nested(nl_options, tca_codel_policy,
+ attrs, ARRAY_SIZE(tca_codel_policy))) {
+ VLOG_WARN_RL(&rl, "failed to parse CoDel class options");
+ return EPROTO;
+ }
+
+ codel->target = nl_attr_get_u32(attrs[TCA_CODEL_TARGET]);
+ codel->limit = nl_attr_get_u32(attrs[TCA_CODEL_LIMIT]);
+ codel->interval = nl_attr_get_u32(attrs[TCA_CODEL_INTERVAL]);
+ return 0;
+}
+
+static int
+codel_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg)
+{
+ struct nlattr *nlattr;
+ const char * kind;
+ int error;
+ struct codel codel;
+
+ error = tc_parse_qdisc(nlmsg, &kind, &nlattr);
+ if (error != 0) {
+ return error;
+ }
+
+ error = codel_parse_tca_options__(nlattr, &codel);
+ if (error != 0) {
+ return error;
+ }
+
+ codel_install__(netdev, codel.target, codel.limit, codel.interval);
+ return 0;
+}
+
+
+static void
+codel_tc_destroy(struct tc *tc)
+{
+ struct codel *codel = CONTAINER_OF(tc, struct codel, tc);
+ tc_destroy(tc);
+ free(codel);
+}
+
+static int
+codel_qdisc_get(const struct netdev *netdev, struct smap *details)
+{
+ const struct codel *codel = codel_get__(netdev);
+ smap_add_format(details, "target", "%u", codel->target);
+ smap_add_format(details, "limit", "%u", codel->limit);
+ smap_add_format(details, "interval", "%u", codel->interval);
+ return 0;
+}
+
+static int
+codel_qdisc_set(struct netdev *netdev, const struct smap *details)
+{
+ struct codel codel;
+
+ codel_parse_qdisc_details__(netdev, details, &codel);
+ codel_install__(netdev, codel.target, codel.limit, codel.interval);
+ codel_get__(netdev)->target = codel.target;
+ codel_get__(netdev)->limit = codel.limit;
+ codel_get__(netdev)->interval = codel.interval;
+ return 0;
+}
+
+static const struct tc_ops tc_ops_codel = {
+ "codel", /* linux_name */
+ "linux-codel", /* ovs_name */
+ CODEL_N_QUEUES, /* n_queues */
+ codel_tc_install,
+ codel_tc_load,
+ codel_tc_destroy,
+ codel_qdisc_get,
+ codel_qdisc_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/* FQ-CoDel traffic control class. */
+
+#define FQCODEL_N_QUEUES 0x0000
+
+/* In sufficiently new kernel headers these are defined as enums in
+ * <linux/pkt_sched.h>. Define them here as macros to help out with older
+ * kernels. (This overrides any enum definition in the header file but that's
+ * harmless.) */
+#define TCA_FQ_CODEL_TARGET 1
+#define TCA_FQ_CODEL_LIMIT 2
+#define TCA_FQ_CODEL_INTERVAL 3
+#define TCA_FQ_CODEL_ECN 4
+#define TCA_FQ_CODEL_FLOWS 5
+#define TCA_FQ_CODEL_QUANTUM 6
+
+struct fqcodel {
+ struct tc tc;
+ uint32_t target;
+ uint32_t limit;
+ uint32_t interval;
+ uint32_t flows;
+ uint32_t quantum;
+};
+
+static struct fqcodel *
+fqcodel_get__(const struct netdev *netdev_)
+{
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ return CONTAINER_OF(netdev->tc, struct fqcodel, tc);
+}
+
+static void
+fqcodel_install__(struct netdev *netdev_, uint32_t target, uint32_t limit,
+ uint32_t interval, uint32_t flows, uint32_t quantum)
+{
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ struct fqcodel *fqcodel;
+
+ fqcodel = xmalloc(sizeof *fqcodel);
+ tc_init(&fqcodel->tc, &tc_ops_fqcodel);
+ fqcodel->target = target;
+ fqcodel->limit = limit;
+ fqcodel->interval = interval;
+ fqcodel->flows = flows;
+ fqcodel->quantum = quantum;
+
+ netdev->tc = &fqcodel->tc;
+}
+
+static int
+fqcodel_setup_qdisc__(struct netdev *netdev, uint32_t target, uint32_t limit,
+ uint32_t interval, uint32_t flows, uint32_t quantum)
+{
+ size_t opt_offset;
+ struct ofpbuf request;
+ struct tcmsg *tcmsg;
+ uint32_t otarget, olimit, ointerval, oflows, oquantum;
+ int error;
+
+ tc_del_qdisc(netdev);
+
+ tcmsg = tc_make_request(netdev, RTM_NEWQDISC,
+ NLM_F_EXCL | NLM_F_CREATE, &request);
+ if (!tcmsg) {
+ return ENODEV;
+ }
+ tcmsg->tcm_handle = tc_make_handle(1, 0);
+ tcmsg->tcm_parent = TC_H_ROOT;
+
+ otarget = target ? target : 5000;
+ olimit = limit ? limit : 10240;
+ ointerval = interval ? interval : 100000;
+ oflows = flows ? flows : 1024;
+ oquantum = quantum ? quantum : 1514; /* fq_codel default quantum is 1514
+ not mtu */
+
+ nl_msg_put_string(&request, TCA_KIND, "fq_codel");
+ opt_offset = nl_msg_start_nested(&request, TCA_OPTIONS);
+ nl_msg_put_u32(&request, TCA_FQ_CODEL_TARGET, otarget);
+ nl_msg_put_u32(&request, TCA_FQ_CODEL_LIMIT, olimit);
+ nl_msg_put_u32(&request, TCA_FQ_CODEL_INTERVAL, ointerval);
+ nl_msg_put_u32(&request, TCA_FQ_CODEL_FLOWS, oflows);
+ nl_msg_put_u32(&request, TCA_FQ_CODEL_QUANTUM, oquantum);
+ nl_msg_end_nested(&request, opt_offset);
+
+ error = tc_transact(&request, NULL);
+ if (error) {
+ VLOG_WARN_RL(&rl, "failed to replace %s qdisc, "
+ "target %u, limit %u, interval %u, flows %u, quantum %u error %d(%s)",
+ netdev_get_name(netdev),
+ otarget, olimit, ointerval, oflows, oquantum,
+ error, ovs_strerror(error));
+ }
+ return error;
+}
+
+static void
+fqcodel_parse_qdisc_details__(struct netdev *netdev OVS_UNUSED,
+ const struct smap *details, struct fqcodel *fqcodel)
+{
+ const char *target_s;
+ const char *limit_s;
+ const char *interval_s;
+ const char *flows_s;
+ const char *quantum_s;
+
+ target_s = smap_get(details, "target");
+ limit_s = smap_get(details, "limit");
+ interval_s = smap_get(details, "interval");
+ flows_s = smap_get(details, "flows");
+ quantum_s = smap_get(details, "quantum");
+ fqcodel->target = target_s ? strtoull(target_s, NULL, 10) : 0;
+ fqcodel->limit = limit_s ? strtoull(limit_s, NULL, 10) : 0;
+ fqcodel->interval = interval_s ? strtoull(interval_s, NULL, 10) : 0;
+ fqcodel->flows = flows_s ? strtoull(flows_s, NULL, 10) : 0;
+ fqcodel->quantum = quantum_s ? strtoull(quantum_s, NULL, 10) : 0;
+ if (!fqcodel->target) {
+ fqcodel->target = 5000;
+ }
+ if (!fqcodel->limit) {
+ fqcodel->limit = 10240;
+ }
+ if (!fqcodel->interval) {
+ fqcodel->interval = 1000000;
+ }
+ if (!fqcodel->flows) {
+ fqcodel->flows = 1024;
+ }
+ if (!fqcodel->quantum) {
+ fqcodel->quantum = 1514;
+ }
+}
+
+static int
+fqcodel_tc_install(struct netdev *netdev, const struct smap *details)
+{
+ int error;
+ struct fqcodel fqcodel;
+
+ fqcodel_parse_qdisc_details__(netdev, details, &fqcodel);
+ error = fqcodel_setup_qdisc__(netdev, fqcodel.target, fqcodel.limit,
+ fqcodel.interval, fqcodel.flows,
+ fqcodel.quantum);
+ if (!error) {
+ fqcodel_install__(netdev, fqcodel.target, fqcodel.limit,
+ fqcodel.interval, fqcodel.flows, fqcodel.quantum);
+ }
+ return error;
+}
+
+static int
+fqcodel_parse_tca_options__(struct nlattr *nl_options, struct fqcodel *fqcodel)
+{
+ static const struct nl_policy tca_fqcodel_policy[] = {
+ [TCA_FQ_CODEL_TARGET] = { .type = NL_A_U32 },
+ [TCA_FQ_CODEL_LIMIT] = { .type = NL_A_U32 },
+ [TCA_FQ_CODEL_INTERVAL] = { .type = NL_A_U32 },
+ [TCA_FQ_CODEL_FLOWS] = { .type = NL_A_U32 },
+ [TCA_FQ_CODEL_QUANTUM] = { .type = NL_A_U32 }
+ };
+
+ struct nlattr *attrs[ARRAY_SIZE(tca_fqcodel_policy)];
+
+ if (!nl_parse_nested(nl_options, tca_fqcodel_policy,
+ attrs, ARRAY_SIZE(tca_fqcodel_policy))) {
+ VLOG_WARN_RL(&rl, "failed to parse FQ_CoDel class options");
+ return EPROTO;
+ }
+
+ fqcodel->target = nl_attr_get_u32(attrs[TCA_FQ_CODEL_TARGET]);
+ fqcodel->limit = nl_attr_get_u32(attrs[TCA_FQ_CODEL_LIMIT]);
+ fqcodel->interval =nl_attr_get_u32(attrs[TCA_FQ_CODEL_INTERVAL]);
+ fqcodel->flows = nl_attr_get_u32(attrs[TCA_FQ_CODEL_FLOWS]);
+ fqcodel->quantum = nl_attr_get_u32(attrs[TCA_FQ_CODEL_QUANTUM]);
+ return 0;
+}
+
+static int
+fqcodel_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg)
+{
+ struct nlattr *nlattr;
+ const char * kind;
+ int error;
+ struct fqcodel fqcodel;
+
+ error = tc_parse_qdisc(nlmsg, &kind, &nlattr);
+ if (error != 0) {
+ return error;
+ }
+
+ error = fqcodel_parse_tca_options__(nlattr, &fqcodel);
+ if (error != 0) {
+ return error;
+ }
+
+ fqcodel_install__(netdev, fqcodel.target, fqcodel.limit, fqcodel.interval,
+ fqcodel.flows, fqcodel.quantum);
+ return 0;
+}
+
+static void
+fqcodel_tc_destroy(struct tc *tc)
+{
+ struct fqcodel *fqcodel = CONTAINER_OF(tc, struct fqcodel, tc);
+ tc_destroy(tc);
+ free(fqcodel);
+}
+
+static int
+fqcodel_qdisc_get(const struct netdev *netdev, struct smap *details)
+{
+ const struct fqcodel *fqcodel = fqcodel_get__(netdev);
+ smap_add_format(details, "target", "%u", fqcodel->target);
+ smap_add_format(details, "limit", "%u", fqcodel->limit);
+ smap_add_format(details, "interval", "%u", fqcodel->interval);
+ smap_add_format(details, "flows", "%u", fqcodel->flows);
+ smap_add_format(details, "quantum", "%u", fqcodel->quantum);
+ return 0;
+}
+
+static int
+fqcodel_qdisc_set(struct netdev *netdev, const struct smap *details)
+{
+ struct fqcodel fqcodel;
+
+ fqcodel_parse_qdisc_details__(netdev, details, &fqcodel);
+ fqcodel_install__(netdev, fqcodel.target, fqcodel.limit, fqcodel.interval,
+ fqcodel.flows, fqcodel.quantum);
+ fqcodel_get__(netdev)->target = fqcodel.target;
+ fqcodel_get__(netdev)->limit = fqcodel.limit;
+ fqcodel_get__(netdev)->interval = fqcodel.interval;
+ fqcodel_get__(netdev)->flows = fqcodel.flows;
+ fqcodel_get__(netdev)->quantum = fqcodel.quantum;
+ return 0;
+}
+
+static const struct tc_ops tc_ops_fqcodel = {
+ "fq_codel", /* linux_name */
+ "linux-fq_codel", /* ovs_name */
+ FQCODEL_N_QUEUES, /* n_queues */
+ fqcodel_tc_install,
+ fqcodel_tc_load,
+ fqcodel_tc_destroy,
+ fqcodel_qdisc_get,
+ fqcodel_qdisc_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/* SFQ traffic control class. */
+
+#define SFQ_N_QUEUES 0x0000
+
+struct sfq {
+ struct tc tc;
+ uint32_t quantum;
+ uint32_t perturb;
+};
+
+static struct sfq *
+sfq_get__(const struct netdev *netdev_)
+{
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ return CONTAINER_OF(netdev->tc, struct sfq, tc);
+}
+
+static void
+sfq_install__(struct netdev *netdev_, uint32_t quantum, uint32_t perturb)
+{
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ struct sfq *sfq;
+
+ sfq = xmalloc(sizeof *sfq);
+ tc_init(&sfq->tc, &tc_ops_sfq);
+ sfq->perturb = perturb;
+ sfq->quantum = quantum;
+
+ netdev->tc = &sfq->tc;
+}
+
+static int
+sfq_setup_qdisc__(struct netdev *netdev, uint32_t quantum, uint32_t perturb)
+{
+ struct tc_sfq_qopt opt;
+ struct ofpbuf request;
+ struct tcmsg *tcmsg;
+ int mtu;
+ int mtu_error, error;
+ mtu_error = netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu);
+
+ tc_del_qdisc(netdev);
+
+ tcmsg = tc_make_request(netdev, RTM_NEWQDISC,
+ NLM_F_EXCL | NLM_F_CREATE, &request);
+ if (!tcmsg) {
+ return ENODEV;
+ }
+ tcmsg->tcm_handle = tc_make_handle(1, 0);
+ tcmsg->tcm_parent = TC_H_ROOT;
+
+ memset(&opt, 0, sizeof opt);
+ if (!quantum) {
+ if (!mtu_error) {
+ opt.quantum = mtu; /* if we cannot find mtu, use default */
+ }
+ } else {
+ opt.quantum = quantum;
+ }
+
+ if (!perturb) {
+ opt.perturb_period = 10;
+ } else {
+ opt.perturb_period = perturb;
+ }
+
+ nl_msg_put_string(&request, TCA_KIND, "sfq");
+ nl_msg_put_unspec(&request, TCA_OPTIONS, &opt, sizeof opt);
+
+ error = tc_transact(&request, NULL);
+ if (error) {
+ VLOG_WARN_RL(&rl, "failed to replace %s qdisc, "
+ "quantum %u, perturb %u error %d(%s)",
+ netdev_get_name(netdev),
+ opt.quantum, opt.perturb_period,
+ error, ovs_strerror(error));
+ }
+ return error;
+}
+
+static void
+sfq_parse_qdisc_details__(struct netdev *netdev,
+ const struct smap *details, struct sfq *sfq)
+{
+ const char *perturb_s;
+ const char *quantum_s;
+ int mtu;
+ int mtu_error;
+
+ perturb_s = smap_get(details, "perturb");
+ quantum_s = smap_get(details, "quantum");
+ sfq->perturb = perturb_s ? strtoull(perturb_s, NULL, 10) : 0;
+ sfq->quantum = quantum_s ? strtoull(quantum_s, NULL, 10) : 0;
+ if (!sfq->perturb) {
+ sfq->perturb = 10;
+ }
+
+ if (!sfq->quantum) {
+ mtu_error = netdev_linux_get_mtu__(netdev_linux_cast(netdev), &mtu);
+ if (!mtu_error) {
+ sfq->quantum = mtu;
+ } else {
+ VLOG_WARN_RL(&rl, "when using SFQ, you must specify quantum on a "
+ "device without mtu");
+ return;
+ }
+ }
+}
+
+static int
+sfq_tc_install(struct netdev *netdev, const struct smap *details)
+{
+ int error;
+ struct sfq sfq;
+
+ sfq_parse_qdisc_details__(netdev, details, &sfq);
+ error = sfq_setup_qdisc__(netdev, sfq.quantum, sfq.perturb);
+ if (!error) {
+ sfq_install__(netdev, sfq.quantum, sfq.perturb);
+ }
+ return error;
+}
+
+static int
+sfq_tc_load(struct netdev *netdev, struct ofpbuf *nlmsg)
+{
+ const struct tc_sfq_qopt *sfq;
+ struct nlattr *nlattr;
+ const char * kind;
+ int error;
+
+ error = tc_parse_qdisc(nlmsg, &kind, &nlattr);
+ if (error == 0) {
+ sfq = nl_attr_get(nlattr);
+ sfq_install__(netdev, sfq->perturb_period, sfq->quantum);
+ return 0;
+ }
+
+ return error;
+}
+
+static void
+sfq_tc_destroy(struct tc *tc)
+{
+ struct sfq *sfq = CONTAINER_OF(tc, struct sfq, tc);
+ tc_destroy(tc);
+ free(sfq);
+}
+
+static int
+sfq_qdisc_get(const struct netdev *netdev, struct smap *details)
+{
+ const struct sfq *sfq = sfq_get__(netdev);
+ smap_add_format(details, "quantum", "%u", sfq->quantum);
+ smap_add_format(details, "perturb", "%u", sfq->perturb);
+ return 0;
+}
+
+static int
+sfq_qdisc_set(struct netdev *netdev, const struct smap *details)
+{
+ struct sfq sfq;
+
+ sfq_parse_qdisc_details__(netdev, details, &sfq);
+ sfq_install__(netdev, sfq.quantum, sfq.perturb);
+ sfq_get__(netdev)->quantum = sfq.quantum;
+ sfq_get__(netdev)->perturb = sfq.perturb;
+ return 0;
+}
+
+static const struct tc_ops tc_ops_sfq = {
+ "sfq", /* linux_name */
+ "linux-sfq", /* ovs_name */
+ SFQ_N_QUEUES, /* n_queues */
+ sfq_tc_install,
+ sfq_tc_load,
+ sfq_tc_destroy,
+ sfq_qdisc_get,
+ sfq_qdisc_set,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
/* HTB traffic control class. */
#define HTB_N_QUEUES 0xf000
+#define HTB_RATE2QUANTUM 10
struct htb {
struct tc tc;
@@ -2892,7 +3556,7 @@ htb_setup_qdisc__(struct netdev *netdev)
nl_msg_put_string(&request, TCA_KIND, "htb");
memset(&opt, 0, sizeof opt);
- opt.rate2quantum = 10;
+ opt.rate2quantum = HTB_RATE2QUANTUM;
opt.version = 3;
opt.defcls = 1;
@@ -2926,6 +3590,11 @@ htb_setup_class__(struct netdev *netdev, unsigned int handle,
memset(&opt, 0, sizeof opt);
tc_fill_rate(&opt.rate, class->min_rate, mtu);
tc_fill_rate(&opt.ceil, class->max_rate, mtu);
+ /* Makes sure the quantum is at least MTU. Setting quantum will
+ * make htb ignore the r2q for this class. */
+ if ((class->min_rate / HTB_RATE2QUANTUM) < mtu) {
+ opt.quantum = mtu;
+ }
opt.buffer = tc_calc_buffer(opt.rate.rate, mtu, class->burst);
opt.cbuffer = tc_calc_buffer(opt.ceil.rate, mtu, class->burst);
opt.prio = class->priority;
@@ -4028,12 +4697,13 @@ tc_add_del_ingress_qdisc(struct netdev *netdev, bool add)
* mtu 65535 drop
*
* The configuration and stats may be seen with the following command:
- * /sbin/tc -s filter show <devname> eth0 parent ffff:
+ * /sbin/tc -s filter show dev <devname> parent ffff:
*
* Returns 0 if successful, otherwise a positive errno value.
*/
static int
-tc_add_policer(struct netdev *netdev, int kbits_rate, int kbits_burst)
+tc_add_policer(struct netdev *netdev,
+ uint32_t kbits_rate, uint32_t kbits_burst)
{
struct tc_police tc_police;
struct ofpbuf request;
@@ -4047,8 +4717,22 @@ tc_add_policer(struct netdev *netdev, int kbits_rate, int kbits_burst)
tc_police.action = TC_POLICE_SHOT;
tc_police.mtu = mtu;
tc_fill_rate(&tc_police.rate, ((uint64_t) kbits_rate * 1000)/8, mtu);
- tc_police.burst = tc_bytes_to_ticks(tc_police.rate.rate,
- kbits_burst * 1024);
+
+ /* The following appears wrong in two ways:
+ *
+ * - tc_bytes_to_ticks() should take "bytes" as quantity for both of its
+ * arguments (or at least consistently "bytes" as both or "bits" as
+ * both), but this supplies bytes for the first argument and bits for the
+ * second.
+ *
+ * - In networking a kilobit is usually 1000 bits but this uses 1024 bits.
+ *
+ * However if you "fix" those problems then "tc filter show ..." shows
+ * "125000b", meaning 125,000 bits, when OVS configures it for 1000 kbit ==
+ * 1,000,000 bits, whereas this actually ends up doing the right thing from
+ * tc's point of view. Whatever. */
+ tc_police.burst = tc_bytes_to_ticks(
+ tc_police.rate.rate, MIN(UINT32_MAX / 1024, kbits_burst) * 1024);
tcmsg = tc_make_request(netdev, RTM_NEWTFILTER,
NLM_F_EXCL | NLM_F_CREATE, &request);
@@ -4390,6 +5074,31 @@ tc_del_qdisc(struct netdev *netdev_)
return error;
}
+static bool
+getqdisc_is_safe(void)
+{
+ static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
+ static bool safe = false;
+
+ if (ovsthread_once_start(&once)) {
+ struct utsname utsname;
+ int major, minor;
+
+ if (uname(&utsname) == -1) {
+ VLOG_WARN("uname failed (%s)", ovs_strerror(errno));
+ } else if (!ovs_scan(utsname.release, "%d.%d", &major, &minor)) {
+ VLOG_WARN("uname reported bad OS release (%s)", utsname.release);
+ } else if (major < 2 || (major == 2 && minor < 35)) {
+ VLOG_INFO("disabling unsafe RTM_GETQDISC in Linux kernel %s",
+ utsname.release);
+ } else {
+ safe = true;
+ }
+ ovsthread_once_done(&once);
+ }
+ return safe;
+}
+
/* If 'netdev''s qdisc type and parameters are not yet known, queries the
* kernel to determine what they are. Returns 0 if successful, otherwise a
* positive errno value. */
@@ -4419,18 +5128,21 @@ tc_query_qdisc(const struct netdev *netdev_)
* create will have a class with handle 1:0. The built-in qdiscs only have
* a class with handle 0:0.
*
- * We could check for Linux 2.6.35+ and use a more straightforward method
- * there. */
+ * On Linux 2.6.35+ we use the straightforward method because it allows us
+ * to handle non-builtin qdiscs without handle 1:0 (e.g. codel). However,
+ * in such a case we get no response at all from the kernel (!) if a
+ * builtin qdisc is in use (which is later caught by "!error &&
+ * !qdisc->size"). */
tcmsg = tc_make_request(netdev_, RTM_GETQDISC, NLM_F_ECHO, &request);
if (!tcmsg) {
return ENODEV;
}
- tcmsg->tcm_handle = tc_make_handle(1, 0);
- tcmsg->tcm_parent = 0;
+ tcmsg->tcm_handle = tc_make_handle(getqdisc_is_safe() ? 0 : 1, 0);
+ tcmsg->tcm_parent = getqdisc_is_safe() ? TC_H_ROOT : 0;
/* Figure out what tc class to instantiate. */
error = tc_transact(&request, &qdisc);
- if (!error) {
+ if (!error && qdisc->size) {
const char *kind;
error = tc_parse_qdisc(qdisc, &kind, NULL);
@@ -4440,15 +5152,15 @@ tc_query_qdisc(const struct netdev *netdev_)
ops = tc_lookup_linux_name(kind);
if (!ops) {
static struct vlog_rate_limit rl2 = VLOG_RATE_LIMIT_INIT(1, 1);
- VLOG_INFO_RL(&rl2, "unknown qdisc \"%s\"", kind);
+ VLOG_DBG_RL(&rl2, "unknown qdisc \"%s\"", kind);
ops = &tc_ops_other;
}
}
- } else if (error == ENOENT) {
- /* Either it's a built-in qdisc, or it's a qdisc set up by some
- * other entity that doesn't have a handle 1:0. We will assume
- * that it's the system default qdisc. */
+ } else if ((!error && !qdisc->size) || error == ENOENT) {
+ /* Either it's a built-in qdisc, or (on Linux pre-2.6.35) it's a qdisc
+ * set up by some other entity that doesn't have a handle 1:0. We will
+ * assume that it's the system default qdisc. */
ops = &tc_ops_default;
error = 0;
} else {
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 915e54a41..734601d84 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -257,20 +257,19 @@ struct netdev_class {
/* Build Partial Tunnel header. Ethernet and ip header is already built,
* build_header() is suppose build protocol specific part of header. */
- int (*build_header)(const struct netdev *, struct ovs_action_push_tnl *data);
+ int (*build_header)(const struct netdev *, struct ovs_action_push_tnl *data,
+ const struct flow *tnl_flow);
/* build_header() can not build entire header for all packets for given
* flow. Push header is called for packet to build header specific to
* a packet on actual transmit. It uses partial header build by
* build_header() which is passed as data. */
- int (*push_header)(const struct netdev *netdev,
- struct dp_packet **buffers, int cnt,
- const struct ovs_action_push_tnl *data);
+ void (*push_header)(struct dp_packet *packet,
+ const struct ovs_action_push_tnl *data);
/* Pop tunnel header from packet, build tunnel metadata and resize packet
* for further processing. */
- int (*pop_header)(struct netdev *netdev,
- struct dp_packet **buffers, int cnt);
+ int (*pop_header)(struct dp_packet *packet);
/* Returns the id of the numa node the 'netdev' is on. If there is no
* such info, returns NETDEV_NUMA_UNSPEC. */
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 8e1b5424a..f228ac219 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -61,6 +61,11 @@ static struct vlog_rate_limit err_rl = VLOG_RATE_LIMIT_INIT(60, 5);
sizeof(struct udp_header) + \
sizeof(struct vxlanhdr))
+#define GENEVE_BASE_HLEN (sizeof(struct eth_header) + \
+ sizeof(struct ip_header) + \
+ sizeof(struct udp_header) + \
+ sizeof(struct genevehdr))
+
#define DEFAULT_TTL 64
struct netdev_vport {
@@ -426,7 +431,8 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
struct netdev_tunnel_config tnl_cfg;
struct smap_node *node;
- has_csum = strstr(type, "gre");
+ has_csum = strstr(type, "gre") || strstr(type, "geneve") ||
+ strstr(type, "vxlan");
ipsec_mech_set = false;
memset(&tnl_cfg, 0, sizeof tnl_cfg);
@@ -611,9 +617,11 @@ set_tunnel_config(struct netdev *dev_, const struct smap *args)
&tnl_cfg.out_key_flow);
ovs_mutex_lock(&dev->mutex);
- dev->tnl_cfg = tnl_cfg;
- tunnel_check_status_change__(dev);
- netdev_change_seq_changed(dev_);
+ if (memcmp(&dev->tnl_cfg, &tnl_cfg, sizeof tnl_cfg)) {
+ dev->tnl_cfg = tnl_cfg;
+ tunnel_check_status_change__(dev);
+ netdev_change_seq_changed(dev_);
+ }
ovs_mutex_unlock(&dev->mutex);
return 0;
@@ -786,9 +794,11 @@ set_patch_config(struct netdev *dev_, const struct smap *args)
}
ovs_mutex_lock(&dev->mutex);
- free(dev->peer);
- dev->peer = xstrdup(peer);
- netdev_change_seq_changed(dev_);
+ if (!dev->peer || strcmp(dev->peer, peer)) {
+ free(dev->peer);
+ dev->peer = xstrdup(peer);
+ netdev_change_seq_changed(dev_);
+ }
ovs_mutex_unlock(&dev->mutex);
return 0;
@@ -837,6 +847,7 @@ ip_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl)
tnl->ip_src = get_16aligned_be32(&nh->ip_src);
tnl->ip_dst = get_16aligned_be32(&nh->ip_dst);
tnl->ip_tos = nh->ip_tos;
+ tnl->ip_ttl = nh->ip_ttl;
return l4;
}
@@ -870,6 +881,95 @@ push_ip_header(struct dp_packet *packet,
return ip + 1;
}
+static void *
+udp_extract_tnl_md(struct dp_packet *packet, struct flow_tnl *tnl)
+{
+ struct udp_header *udp;
+
+ udp = ip_extract_tnl_md(packet, tnl);
+ if (!udp) {
+ return NULL;
+ }
+
+ if (udp->udp_csum) {
+ uint32_t csum = packet_csum_pseudoheader(dp_packet_l3(packet));
+
+ csum = csum_continue(csum, udp, dp_packet_size(packet) -
+ ((const unsigned char *)udp -
+ (const unsigned char *)dp_packet_l2(packet)));
+ if (csum_finish(csum)) {
+ return NULL;
+ }
+ tnl->flags |= FLOW_TNL_F_CSUM;
+ }
+
+ tnl->tp_src = udp->udp_src;
+ tnl->tp_dst = udp->udp_dst;
+
+ return udp + 1;
+}
+
+static ovs_be16
+get_src_port(struct dp_packet *packet)
+{
+ uint32_t hash;
+
+ hash = dp_packet_get_dp_hash(packet);
+
+ return htons((((uint64_t) hash * (tnl_udp_port_max - tnl_udp_port_min)) >> 32) +
+ tnl_udp_port_min);
+}
+
+static void
+push_udp_header(struct dp_packet *packet,
+ const struct ovs_action_push_tnl *data)
+{
+ struct udp_header *udp;
+ int ip_tot_size;
+
+ udp = push_ip_header(packet, data->header, data->header_len, &ip_tot_size);
+
+ /* set udp src port */
+ udp->udp_src = get_src_port(packet);
+ udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header));
+
+ if (udp->udp_csum) {
+ uint32_t csum = packet_csum_pseudoheader(ip_hdr(dp_packet_data(packet)));
+
+ csum = csum_continue(csum, udp,
+ ip_tot_size - sizeof (struct ip_header));
+ udp->udp_csum = csum_finish(csum);
+
+ if (!udp->udp_csum) {
+ udp->udp_csum = htons(0xffff);
+ }
+ }
+}
+
+static void *
+udp_build_header(struct netdev_tunnel_config *tnl_cfg,
+ const struct flow *tnl_flow,
+ struct ovs_action_push_tnl *data)
+{
+ struct ip_header *ip;
+ struct udp_header *udp;
+
+ ip = ip_hdr(data->header);
+ ip->ip_proto = IPPROTO_UDP;
+
+ udp = (struct udp_header *) (ip + 1);
+ udp->udp_dst = tnl_cfg->dst_port;
+
+ if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) {
+ /* Write a value in now to mark that we should compute the checksum
+ * later. 0xffff is handy because it is transparent to the
+ * calculation. */
+ udp->udp_csum = htons(0xffff);
+ }
+
+ return udp + 1;
+}
+
static int
gre_header_len(ovs_be16 flags)
{
@@ -905,6 +1005,10 @@ parse_gre_header(struct dp_packet *packet,
return -EINVAL;
}
+ if (greh->protocol != htons(ETH_TYPE_TEB)) {
+ return -EINVAL;
+ }
+
hlen = gre_header_len(greh->flags);
if (hlen > dp_packet_size(packet)) {
return -EINVAL;
@@ -937,14 +1041,8 @@ parse_gre_header(struct dp_packet *packet,
return hlen;
}
-static void
-reset_tnl_md(struct pkt_metadata *md)
-{
- memset(&md->tunnel, 0, sizeof(md->tunnel));
-}
-
-static void
-gre_extract_md(struct dp_packet *packet)
+static int
+netdev_gre_pop_header(struct dp_packet *packet)
{
struct pkt_metadata *md = &packet->md;
struct flow_tnl *tnl = &md->tunnel;
@@ -953,64 +1051,38 @@ gre_extract_md(struct dp_packet *packet)
memset(md, 0, sizeof *md);
if (hlen > dp_packet_size(packet)) {
- return;
+ return EINVAL;
}
hlen = parse_gre_header(packet, tnl);
if (hlen < 0) {
- reset_tnl_md(md);
+ return -hlen;
}
dp_packet_reset_packet(packet, hlen);
-}
-
-static int
-netdev_gre_pop_header(struct netdev *netdev_ OVS_UNUSED,
- struct dp_packet **pkt, int cnt)
-{
- int i;
- for (i = 0; i < cnt; i++) {
- gre_extract_md(pkt[i]);
- }
return 0;
}
static void
-netdev_gre_push_header__(struct dp_packet *packet,
- const void *header, int size)
+netdev_gre_push_header(struct dp_packet *packet,
+ const struct ovs_action_push_tnl *data)
{
struct gre_base_hdr *greh;
int ip_tot_size;
- greh = push_ip_header(packet, header, size, &ip_tot_size);
+ greh = push_ip_header(packet, data->header, data->header_len, &ip_tot_size);
if (greh->flags & htons(GRE_CSUM)) {
- ovs_16aligned_be32 *options = (ovs_16aligned_be32 *) (greh + 1);
-
- put_16aligned_be32(options,
- (OVS_FORCE ovs_be32) csum(greh, ip_tot_size - sizeof (struct ip_header)));
+ ovs_be16 *csum_opt = (ovs_be16 *) (greh + 1);
+ *csum_opt = csum(greh, ip_tot_size - sizeof (struct ip_header));
}
}
static int
-netdev_gre_push_header(const struct netdev *netdev OVS_UNUSED,
- struct dp_packet **packets, int cnt,
- const struct ovs_action_push_tnl *data)
-{
- int i;
-
- for (i = 0; i < cnt; i++) {
- netdev_gre_push_header__(packets[i], data->header, data->header_len);
- packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port));
- }
- return 0;
-}
-
-
-static int
netdev_gre_build_header(const struct netdev *netdev,
- struct ovs_action_push_tnl *data)
+ struct ovs_action_push_tnl *data,
+ const struct flow *tnl_flow)
{
struct netdev_vport *dev = netdev_vport_cast(netdev);
struct netdev_tunnel_config *tnl_cfg;
@@ -1031,7 +1103,7 @@ netdev_gre_build_header(const struct netdev *netdev,
greh->flags = 0;
options = (ovs_16aligned_be32 *) (greh + 1);
- if (tnl_cfg->csum) {
+ if (tnl_flow->tunnel.flags & FLOW_TNL_F_CSUM) {
greh->flags |= htons(GRE_CSUM);
put_16aligned_be32(options, 0);
options++;
@@ -1040,7 +1112,7 @@ netdev_gre_build_header(const struct netdev *netdev,
if (tnl_cfg->out_key_present) {
greh->flags |= htons(GRE_KEY);
put_16aligned_be32(options, (OVS_FORCE ovs_be32)
- ((OVS_FORCE uint64_t) tnl_cfg->out_key >> 32));
+ ((OVS_FORCE uint64_t) tnl_flow->tunnel.tun_id >> 32));
options++;
}
@@ -1054,75 +1126,55 @@ netdev_gre_build_header(const struct netdev *netdev,
return 0;
}
-static void
-vxlan_extract_md(struct dp_packet *packet)
+static int
+netdev_vxlan_pop_header(struct dp_packet *packet)
{
struct pkt_metadata *md = &packet->md;
struct flow_tnl *tnl = &md->tunnel;
- struct udp_header *udp;
struct vxlanhdr *vxh;
memset(md, 0, sizeof *md);
if (VXLAN_HLEN > dp_packet_size(packet)) {
- return;
+ return EINVAL;
}
- udp = ip_extract_tnl_md(packet, tnl);
- if (!udp) {
- return;
+ vxh = udp_extract_tnl_md(packet, tnl);
+ if (!vxh) {
+ return EINVAL;
}
- vxh = (struct vxlanhdr *) (udp + 1);
if (get_16aligned_be32(&vxh->vx_flags) != htonl(VXLAN_FLAGS) ||
(get_16aligned_be32(&vxh->vx_vni) & htonl(0xff))) {
VLOG_WARN_RL(&err_rl, "invalid vxlan flags=%#x vni=%#x\n",
ntohl(get_16aligned_be32(&vxh->vx_flags)),
ntohl(get_16aligned_be32(&vxh->vx_vni)));
- reset_tnl_md(md);
- return;
+ return EINVAL;
}
- tnl->tp_src = udp->udp_src;
- tnl->tp_dst = udp->udp_dst;
tnl->tun_id = htonll(ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
+ tnl->flags |= FLOW_TNL_F_KEY;
dp_packet_reset_packet(packet, VXLAN_HLEN);
-}
-
-static int
-netdev_vxlan_pop_header(struct netdev *netdev_ OVS_UNUSED,
- struct dp_packet **pkt, int cnt)
-{
- int i;
- for (i = 0; i < cnt; i++) {
- vxlan_extract_md(pkt[i]);
- }
return 0;
}
static int
netdev_vxlan_build_header(const struct netdev *netdev,
- struct ovs_action_push_tnl *data)
+ struct ovs_action_push_tnl *data,
+ const struct flow *tnl_flow)
{
struct netdev_vport *dev = netdev_vport_cast(netdev);
struct netdev_tunnel_config *tnl_cfg;
- struct ip_header *ip;
- struct udp_header *udp;
struct vxlanhdr *vxh;
/* XXX: RCUfy tnl_cfg. */
ovs_mutex_lock(&dev->mutex);
tnl_cfg = &dev->tnl_cfg;
- ip = ip_hdr(data->header);
- ip->ip_proto = IPPROTO_UDP;
-
- udp = (struct udp_header *) (ip + 1);
- udp->udp_dst = tnl_cfg->dst_port;
+ vxh = udp_build_header(tnl_cfg, tnl_flow, data);
- vxh = (struct vxlanhdr *) (udp + 1);
put_16aligned_be32(&vxh->vx_flags, htonl(VXLAN_FLAGS));
- put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_cfg->out_key) << 8));
+ put_16aligned_be32(&vxh->vx_vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
ovs_mutex_unlock(&dev->mutex);
data->header_len = VXLAN_HLEN;
@@ -1130,44 +1182,81 @@ netdev_vxlan_build_header(const struct netdev *netdev,
return 0;
}
-static ovs_be16
-get_src_port(struct dp_packet *packet)
+static int
+netdev_geneve_pop_header(struct dp_packet *packet)
{
- uint32_t hash;
+ struct pkt_metadata *md = &packet->md;
+ struct flow_tnl *tnl = &md->tunnel;
+ struct genevehdr *gnh;
+ unsigned int hlen;
- hash = dp_packet_get_dp_hash(packet);
+ memset(md, 0, sizeof *md);
+ if (GENEVE_BASE_HLEN > dp_packet_size(packet)) {
+ VLOG_WARN_RL(&err_rl, "geneve packet too small: min header=%u packet size=%u\n",
+ (unsigned int)GENEVE_BASE_HLEN, dp_packet_size(packet));
+ return EINVAL;
+ }
- return htons((((uint64_t) hash * (tnl_udp_port_max - tnl_udp_port_min)) >> 32) +
- tnl_udp_port_min);
-}
+ gnh = udp_extract_tnl_md(packet, tnl);
+ if (!gnh) {
+ return EINVAL;
+ }
-static void
-netdev_vxlan_push_header__(struct dp_packet *packet,
- const void *header, int size)
-{
- struct udp_header *udp;
- int ip_tot_size;
+ hlen = GENEVE_BASE_HLEN + gnh->opt_len * 4;
+ if (hlen > dp_packet_size(packet)) {
+ VLOG_WARN_RL(&err_rl, "geneve packet too small: header len=%u packet size=%u\n",
+ hlen, dp_packet_size(packet));
+ return EINVAL;
+ }
- udp = push_ip_header(packet, header, size, &ip_tot_size);
+ if (gnh->ver != 0) {
+ VLOG_WARN_RL(&err_rl, "unknown geneve version: %"PRIu8"\n", gnh->ver);
+ return EINVAL;
+ }
- /* set udp src port */
- udp->udp_src = get_src_port(packet);
- udp->udp_len = htons(ip_tot_size - sizeof (struct ip_header));
- /* udp_csum is zero */
+ if (gnh->opt_len && gnh->critical) {
+ VLOG_WARN_RL(&err_rl, "unknown geneve critical options: %"PRIu8" bytes\n",
+ gnh->opt_len * 4);
+ return EINVAL;
+ }
+
+ if (gnh->proto_type != htons(ETH_TYPE_TEB)) {
+ VLOG_WARN_RL(&err_rl, "unknown geneve encapsulated protocol: %#x\n",
+ ntohs(gnh->proto_type));
+ return EINVAL;
+ }
+
+ tnl->flags |= gnh->oam ? FLOW_TNL_F_OAM : 0;
+ tnl->tun_id = htonll(ntohl(get_16aligned_be32(&gnh->vni)) >> 8);
+ tnl->flags |= FLOW_TNL_F_KEY;
+
+ dp_packet_reset_packet(packet, hlen);
+
+ return 0;
}
static int
-netdev_vxlan_push_header(const struct netdev *netdev OVS_UNUSED,
- struct dp_packet **packets, int cnt,
- const struct ovs_action_push_tnl *data)
+netdev_geneve_build_header(const struct netdev *netdev,
+ struct ovs_action_push_tnl *data,
+ const struct flow *tnl_flow)
{
- int i;
+ struct netdev_vport *dev = netdev_vport_cast(netdev);
+ struct netdev_tunnel_config *tnl_cfg;
+ struct genevehdr *gnh;
- for (i = 0; i < cnt; i++) {
- netdev_vxlan_push_header__(packets[i],
- data->header, VXLAN_HLEN);
- packets[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port));
- }
+ /* XXX: RCUfy tnl_cfg. */
+ ovs_mutex_lock(&dev->mutex);
+ tnl_cfg = &dev->tnl_cfg;
+
+ gnh = udp_build_header(tnl_cfg, tnl_flow, data);
+
+ gnh->oam = !!(tnl_flow->tunnel.flags & FLOW_TNL_F_OAM);
+ gnh->proto_type = htons(ETH_TYPE_TEB);
+ put_16aligned_be32(&gnh->vni, htonl(ntohll(tnl_flow->tunnel.tun_id) << 8));
+
+ ovs_mutex_unlock(&dev->mutex);
+ data->header_len = GENEVE_BASE_HLEN;
+ data->tnl_type = OVS_VPORT_TYPE_GENEVE;
return 0;
}
@@ -1300,7 +1389,9 @@ netdev_vport_tunnel_register(void)
/* The name of the dpif_port should be short enough to accomodate adding
* a port number to the end if one is necessary. */
static const struct vport_class vport_classes[] = {
- TUNNEL_CLASS("geneve", "genev_sys", NULL, NULL, NULL),
+ TUNNEL_CLASS("geneve", "genev_sys", netdev_geneve_build_header,
+ push_udp_header,
+ netdev_geneve_pop_header),
TUNNEL_CLASS("gre", "gre_sys", netdev_gre_build_header,
netdev_gre_push_header,
netdev_gre_pop_header),
@@ -1308,7 +1399,7 @@ netdev_vport_tunnel_register(void)
TUNNEL_CLASS("gre64", "gre64_sys", NULL, NULL, NULL),
TUNNEL_CLASS("ipsec_gre64", "gre64_sys", NULL, NULL, NULL),
TUNNEL_CLASS("vxlan", "vxlan_sys", netdev_vxlan_build_header,
- netdev_vxlan_push_header,
+ push_udp_header,
netdev_vxlan_pop_header),
TUNNEL_CLASS("lisp", "lisp_sys", NULL, NULL, NULL)
};
diff --git a/lib/netdev.c b/lib/netdev.c
index b76da139a..45f7f29a0 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -34,6 +34,7 @@
#include "netdev-dpdk.h"
#include "netdev-provider.h"
#include "netdev-vport.h"
+#include "odp-netlink.h"
#include "openflow/openflow.h"
#include "packets.h"
#include "poll-loop.h"
@@ -43,6 +44,7 @@
#include "sset.h"
#include "svec.h"
#include "openvswitch/vlog.h"
+#include "flow.h"
VLOG_DEFINE_THIS_MODULE(netdev);
@@ -108,7 +110,8 @@ bool
netdev_is_pmd(const struct netdev *netdev)
{
return (!strcmp(netdev->netdev_class->type, "dpdk") ||
- !strcmp(netdev->netdev_class->type, "dpdkr"));
+ !strcmp(netdev->netdev_class->type, "dpdkr") ||
+ !strcmp(netdev->netdev_class->type, "dpdkvhost"));
}
static void
@@ -733,16 +736,30 @@ netdev_send(struct netdev *netdev, int qid, struct dp_packet **buffers,
int
netdev_pop_header(struct netdev *netdev, struct dp_packet **buffers, int cnt)
{
- return (netdev->netdev_class->pop_header
- ? netdev->netdev_class->pop_header(netdev, buffers, cnt)
- : EOPNOTSUPP);
+ int i;
+
+ if (!netdev->netdev_class->pop_header) {
+ return EOPNOTSUPP;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ int err;
+
+ err = netdev->netdev_class->pop_header(buffers[i]);
+ if (err) {
+ dp_packet_clear(buffers[i]);
+ }
+ }
+
+ return 0;
}
int
-netdev_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data)
+netdev_build_header(const struct netdev *netdev, struct ovs_action_push_tnl *data,
+ const struct flow *tnl_flow)
{
if (netdev->netdev_class->build_header) {
- return netdev->netdev_class->build_header(netdev, data);
+ return netdev->netdev_class->build_header(netdev, data, tnl_flow);
}
return EOPNOTSUPP;
}
@@ -752,11 +769,18 @@ netdev_push_header(const struct netdev *netdev,
struct dp_packet **buffers, int cnt,
const struct ovs_action_push_tnl *data)
{
- if (netdev->netdev_class->push_header) {
- return netdev->netdev_class->push_header(netdev, buffers, cnt, data);
- } else {
+ int i;
+
+ if (!netdev->netdev_class->push_header) {
return -EINVAL;
}
+
+ for (i = 0; i < cnt; i++) {
+ netdev->netdev_class->push_header(buffers[i], data);
+ buffers[i]->md = PKT_METADATA_INITIALIZER(u32_to_odp(data->out_port));
+ }
+
+ return 0;
}
/* Registers with the poll loop to wake up from the next call to poll_block()
diff --git a/lib/netdev.h b/lib/netdev.h
index 9a647f0be..71c0af1b5 100644
--- a/lib/netdev.h
+++ b/lib/netdev.h
@@ -22,6 +22,7 @@
#include <stdint.h>
#include "openvswitch/types.h"
#include "packets.h"
+#include "flow.h"
#ifdef __cplusplus
extern "C" {
@@ -184,7 +185,8 @@ int netdev_send(struct netdev *, int qid, struct dp_packet **, int cnt,
bool may_steal);
void netdev_send_wait(struct netdev *, int qid);
-int netdev_build_header(const struct netdev *, struct ovs_action_push_tnl *data);
+int netdev_build_header(const struct netdev *, struct ovs_action_push_tnl *data,
+ const struct flow *tnl_flow);
int netdev_push_header(const struct netdev *netdev,
struct dp_packet **buffers, int cnt,
const struct ovs_action_push_tnl *data);
diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c
index df889d3eb..fab2a6681 100644
--- a/lib/netlink-socket.c
+++ b/lib/netlink-socket.c
@@ -273,63 +273,27 @@ nl_sock_destroy(struct nl_sock *sock)
#ifdef _WIN32
/* Reads the pid for 'sock' generated in the kernel datapath. The function
- * follows a transaction semantic. Eventually this function should call into
- * nl_transact. */
+ * uses a separate IOCTL instead of a transaction semantic to avoid unnecessary
+ * message overhead. */
static int
get_sock_pid_from_kernel(struct nl_sock *sock)
{
- struct nl_transaction txn;
- struct ofpbuf request;
- uint64_t request_stub[128];
- struct ofpbuf reply;
- uint64_t reply_stub[128];
- struct ovs_header *ovs_header;
- struct nlmsghdr *nlmsg;
- uint32_t seq;
- int retval;
- DWORD bytes;
- int ovs_msg_size = sizeof (struct nlmsghdr) + sizeof (struct genlmsghdr) +
- sizeof (struct ovs_header);
-
- ofpbuf_use_stub(&request, request_stub, sizeof request_stub);
- txn.request = &request;
- ofpbuf_use_stub(&reply, reply_stub, sizeof reply_stub);
- txn.reply = &reply;
-
- seq = nl_sock_allocate_seq(sock, 1);
- nl_msg_put_genlmsghdr(&request, 0, OVS_WIN_NL_CTRL_FAMILY_ID, 0,
- OVS_CTRL_CMD_WIN_GET_PID, OVS_WIN_CONTROL_VERSION);
- nlmsg = nl_msg_nlmsghdr(txn.request);
- nlmsg->nlmsg_seq = seq;
-
- ovs_header = ofpbuf_put_uninit(&request, sizeof *ovs_header);
- ovs_header->dp_ifindex = 0;
- ovs_header = ofpbuf_put_uninit(&reply, ovs_msg_size);
+ uint32_t pid = 0;
+ int retval = 0;
+ DWORD bytes = 0;
- if (!DeviceIoControl(sock->handle, OVS_IOCTL_TRANSACT,
- txn.request->data, txn.request->size,
- txn.reply->data, txn.reply->size,
+ if (!DeviceIoControl(sock->handle, OVS_IOCTL_GET_PID,
+ NULL, 0, &pid, sizeof(pid),
&bytes, NULL)) {
retval = EINVAL;
- goto done;
} else {
- if (bytes < ovs_msg_size) {
+ if (bytes < sizeof(pid)) {
retval = EINVAL;
- goto done;
- }
-
- nlmsg = nl_msg_nlmsghdr(txn.reply);
- if (nlmsg->nlmsg_seq != seq) {
- retval = EINVAL;
- goto done;
+ } else {
+ sock->pid = pid;
}
- sock->pid = nlmsg->nlmsg_pid;
}
- retval = 0;
-done:
- ofpbuf_uninit(&request);
- ofpbuf_uninit(&reply);
return retval;
}
#endif /* _WIN32 */
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 721fce526..4b724604f 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -589,6 +589,52 @@ oxm_pull_match_loose(struct ofpbuf *b, struct match *match)
{
return oxm_pull_match__(b, false, match);
}
+
+/* Verify an array of OXM TLVs treating value of each TLV as a mask,
+ * disallowing masks in each TLV and ignoring pre-requisites. */
+enum ofperr
+oxm_pull_field_array(const void *fields_data, size_t fields_len,
+ struct field_array *fa)
+{
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, fields_data, fields_len);
+ while (b.size) {
+ const uint8_t *pos = b.data;
+ const struct mf_field *field;
+ union mf_value value;
+ enum ofperr error;
+ uint64_t header;
+
+ error = nx_pull_entry__(&b, false, &header, &field, &value, NULL);
+ if (error) {
+ VLOG_DBG_RL(&rl, "error pulling field array field");
+ return error;
+ } else if (!field) {
+ VLOG_DBG_RL(&rl, "unknown field array field");
+ error = OFPERR_OFPBMC_BAD_FIELD;
+ } else if (bitmap_is_set(fa->used.bm, field->id)) {
+ VLOG_DBG_RL(&rl, "duplicate field array field '%s'", field->name);
+ error = OFPERR_OFPBMC_DUP_FIELD;
+ } else if (!mf_is_mask_valid(field, &value)) {
+ VLOG_DBG_RL(&rl, "bad mask in field array field '%s'", field->name);
+ return OFPERR_OFPBMC_BAD_MASK;
+ } else {
+ field_array_set(field->id, &value, fa);
+ }
+
+ if (error) {
+ const uint8_t *start = fields_data;
+
+ VLOG_DBG_RL(&rl, "error parsing OXM at offset %"PRIdPTR" "
+ "within field array (%s)", pos - start,
+ ofperr_to_string(error));
+ return error;
+ }
+ }
+
+ return 0;
+}
/* nx_put_match() and helpers.
*
@@ -1021,6 +1067,84 @@ oxm_put_match(struct ofpbuf *b, const struct match *match,
return match_len;
}
+/* Appends to 'b' the nx_match format that expresses the tlv corresponding
+ * to 'id'. If mask is not all-ones then it is also formated as the value
+ * of the tlv. */
+static void
+nx_format_mask_tlv(struct ds *ds, enum mf_field_id id,
+ const union mf_value *mask)
+{
+ const struct mf_field *mf = mf_from_id(id);
+
+ ds_put_format(ds, "%s", mf->name);
+
+ if (!is_all_ones(mask, mf->n_bytes)) {
+ ds_put_char(ds, '=');
+ mf_format(mf, mask, NULL, ds);
+ }
+
+ ds_put_char(ds, ',');
+}
+
+/* Appends a string representation of 'fa_' to 'ds'.
+ * The TLVS value of 'fa_' is treated as a mask and
+ * only the name of fields is formated if it is all ones. */
+void
+oxm_format_field_array(struct ds *ds, const struct field_array *fa)
+{
+ size_t start_len = ds->length;
+ int i;
+
+ for (i = 0; i < MFF_N_IDS; i++) {
+ if (bitmap_is_set(fa->used.bm, i)) {
+ nx_format_mask_tlv(ds, i, &fa->value[i]);
+ }
+ }
+
+ if (ds->length > start_len) {
+ ds_chomp(ds, ',');
+ }
+}
+
+/* Appends to 'b' a series of OXM TLVs corresponding to the series
+ * of enum mf_field_id and value tuples in 'fa_'.
+ *
+ * OXM differs slightly among versions of OpenFlow. Specify the OpenFlow
+ * version in use as 'version'.
+ *
+ * This function can cause 'b''s data to be reallocated.
+ *
+ * Returns the number of bytes appended to 'b'. May return zero. */
+int
+oxm_put_field_array(struct ofpbuf *b, const struct field_array *fa,
+ enum ofp_version version)
+{
+ size_t start_len = b->size;
+ int i;
+
+ /* Field arrays are only used with the group selection method
+ * property and group properties are only available in OpenFlow * 1.5+.
+ * So the following assertion should never fail.
+ *
+ * If support for older OpenFlow versions is desired then some care
+ * will need to be taken of different TLVs that handle the same
+ * flow fields. In particular:
+ * - VLAN_TCI, VLAN_VID and MFF_VLAN_PCP
+ * - IP_DSCP_MASK and DSCP_SHIFTED
+ * - REGS and XREGS
+ */
+ ovs_assert(version >= OFP15_VERSION);
+
+ for (i = 0; i < MFF_N_IDS; i++) {
+ if (bitmap_is_set(fa->used.bm, i)) {
+ nxm_put_unmasked(b, i, version, &fa->value[i],
+ mf_from_id(i)->n_bytes);
+ }
+ }
+
+ return b->size - start_len;
+}
+
static void
nx_put_header__(struct ofpbuf *b, uint64_t header, bool masked)
{
diff --git a/lib/nx-match.h b/lib/nx-match.h
index 9cb64614c..fe0b68c56 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -55,9 +55,14 @@ enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len,
ovs_be64 *cookie_mask);
enum ofperr oxm_pull_match(struct ofpbuf *, struct match *);
enum ofperr oxm_pull_match_loose(struct ofpbuf *, struct match *);
+enum ofperr oxm_pull_field_array(const void *, size_t fields_len,
+ struct field_array *);
int nx_put_match(struct ofpbuf *, const struct match *,
ovs_be64 cookie, ovs_be64 cookie_mask);
int oxm_put_match(struct ofpbuf *, const struct match *, enum ofp_version);
+void oxm_format_field_array(struct ds *, const struct field_array *);
+int oxm_put_field_array(struct ofpbuf *, const struct field_array *,
+ enum ofp_version version);
/* Decoding and encoding OXM/NXM headers (just a field ID) or entries (a field
* ID followed by a value and possibly a mask). */
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 827b91c6e..b82edb700 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -510,6 +510,19 @@ format_odp_hash_action(struct ds *ds, const struct ovs_action_hash *hash_act)
ds_put_format(ds, ")");
}
+static const void *
+format_udp_tnl_push_header(struct ds *ds, const struct ip_header *ip)
+{
+ const struct udp_header *udp;
+
+ udp = (const struct udp_header *) (ip + 1);
+ ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16",csum=0x%"PRIx16"),",
+ ntohs(udp->udp_src), ntohs(udp->udp_dst),
+ ntohs(udp->udp_csum));
+
+ return udp + 1;
+}
+
static void
format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
{
@@ -541,18 +554,20 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
if (data->tnl_type == OVS_VPORT_TYPE_VXLAN) {
const struct vxlanhdr *vxh;
- const struct udp_header *udp;
- /* UDP */
- udp = (const struct udp_header *) (ip + 1);
- ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16"),",
- ntohs(udp->udp_src), ntohs(udp->udp_dst));
+ vxh = format_udp_tnl_push_header(ds, ip);
- /* VxLan */
- vxh = (const struct vxlanhdr *) (udp + 1);
ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")",
ntohl(get_16aligned_be32(&vxh->vx_flags)),
- ntohl(get_16aligned_be32(&vxh->vx_vni)));
+ ntohl(get_16aligned_be32(&vxh->vx_vni)) >> 8);
+ } else if (data->tnl_type == OVS_VPORT_TYPE_GENEVE) {
+ const struct genevehdr *gnh;
+
+ gnh = format_udp_tnl_push_header(ds, ip);
+
+ ds_put_format(ds, "geneve(%svni=0x%"PRIx32")",
+ gnh->oam ? "oam," : "",
+ ntohl(get_16aligned_be32(&gnh->vni)) >> 8);
} else if (data->tnl_type == OVS_VPORT_TYPE_GRE) {
const struct gre_base_hdr *greh;
ovs_16aligned_be32 *options;
@@ -562,10 +577,10 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
greh = (const struct gre_base_hdr *) l4;
ds_put_format(ds, "gre((flags=0x%"PRIx16",proto=0x%"PRIx16")",
- greh->flags, ntohs(greh->protocol));
+ ntohs(greh->flags), ntohs(greh->protocol));
options = (ovs_16aligned_be32 *)(greh + 1);
if (greh->flags & htons(GRE_CSUM)) {
- ds_put_format(ds, ",csum=0x%"PRIx32, ntohl(get_16aligned_be32(options)));
+ ds_put_format(ds, ",csum=0x%"PRIx16, ntohs(*((ovs_be16 *)options)));
options++;
}
if (greh->flags & htons(GRE_KEY)) {
@@ -840,7 +855,7 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
struct ip_header *ip;
struct udp_header *udp;
struct gre_base_hdr *greh;
- uint16_t gre_proto, dl_type, udp_src, udp_dst;
+ uint16_t gre_proto, gre_flags, dl_type, udp_src, udp_dst, csum;
ovs_be32 sip, dip;
uint32_t tnl_type = 0, header_len = 0;
void *l3, *l4;
@@ -885,40 +900,57 @@ ovs_parse_tnl_push(const char *s, struct ovs_action_push_tnl *data)
/* Tunnel header */
udp = (struct udp_header *) l4;
greh = (struct gre_base_hdr *) l4;
- if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16"),",
- &udp_src, &udp_dst)) {
- struct vxlanhdr *vxh;
- uint32_t vx_flags, vx_vni;
+ if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16",csum=0x%"SCNx16"),",
+ &udp_src, &udp_dst, &csum)) {
+ uint32_t vx_flags, vni;
udp->udp_src = htons(udp_src);
udp->udp_dst = htons(udp_dst);
udp->udp_len = 0;
- udp->udp_csum = 0;
-
- vxh = (struct vxlanhdr *) (udp + 1);
- if (!ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))",
- &vx_flags, &vx_vni)) {
+ udp->udp_csum = htons(csum);
+
+ if (ovs_scan_len(s, &n, "vxlan(flags=0x%"SCNx32",vni=0x%"SCNx32"))",
+ &vx_flags, &vni)) {
+ struct vxlanhdr *vxh = (struct vxlanhdr *) (udp + 1);
+
+ put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags));
+ put_16aligned_be32(&vxh->vx_vni, htonl(vni << 8));
+ tnl_type = OVS_VPORT_TYPE_VXLAN;
+ header_len = sizeof *eth + sizeof *ip +
+ sizeof *udp + sizeof *vxh;
+ } else if (ovs_scan_len(s, &n, "geneve(")) {
+ struct genevehdr *gnh = (struct genevehdr *) (udp + 1);
+
+ memset(gnh, 0, sizeof *gnh);
+ if (ovs_scan_len(s, &n, "oam,")) {
+ gnh->oam = 1;
+ }
+ if (!ovs_scan_len(s, &n, "vni=0x%"SCNx32"))", &vni)) {
+ return -EINVAL;
+ }
+ gnh->proto_type = htons(ETH_TYPE_TEB);
+ put_16aligned_be32(&gnh->vni, htonl(vni << 8));
+ tnl_type = OVS_VPORT_TYPE_GENEVE;
+ header_len = sizeof *eth + sizeof *ip +
+ sizeof *udp + sizeof *gnh;
+ } else {
return -EINVAL;
}
- put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags));
- put_16aligned_be32(&vxh->vx_vni, htonl(vx_vni));
- tnl_type = OVS_VPORT_TYPE_VXLAN;
- header_len = sizeof *eth + sizeof *ip +
- sizeof *udp + sizeof *vxh;
} else if (ovs_scan_len(s, &n, "gre((flags=0x%"SCNx16",proto=0x%"SCNx16")",
- &greh->flags, &gre_proto)){
+ &gre_flags, &gre_proto)){
tnl_type = OVS_VPORT_TYPE_GRE;
+ greh->flags = htons(gre_flags);
greh->protocol = htons(gre_proto);
ovs_16aligned_be32 *options = (ovs_16aligned_be32 *) (greh + 1);
if (greh->flags & htons(GRE_CSUM)) {
- uint32_t csum;
-
- if (!ovs_scan_len(s, &n, ",csum=0x%"SCNx32, &csum)) {
+ if (!ovs_scan_len(s, &n, ",csum=0x%"SCNx16, &csum)) {
return -EINVAL;
}
- put_16aligned_be32(options, htonl(csum));
+
+ memset(options, 0, sizeof *options);
+ *((ovs_be16 *)options) = htons(csum);
options++;
}
if (greh->flags & htons(GRE_KEY)) {
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 260d85474..65fa64d08 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -4237,6 +4237,31 @@ format_EXIT(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
ds_put_cstr(s, "exit");
}
+/* Unroll xlate action. */
+
+static void
+encode_UNROLL_XLATE(const struct ofpact_unroll_xlate *unroll OVS_UNUSED,
+ enum ofp_version ofp_version OVS_UNUSED,
+ struct ofpbuf *out OVS_UNUSED)
+{
+ OVS_NOT_REACHED();
+}
+
+static char * OVS_WARN_UNUSED_RESULT
+parse_UNROLL_XLATE(char *arg OVS_UNUSED, struct ofpbuf *ofpacts OVS_UNUSED,
+ enum ofputil_protocol *usable_protocols OVS_UNUSED)
+{
+ OVS_NOT_REACHED();
+ return NULL;
+}
+
+static void
+format_UNROLL_XLATE(const struct ofpact_unroll_xlate *a OVS_UNUSED,
+ struct ds *s)
+{
+ ds_put_cstr(s, "unroll_xlate");
+}
+
/* Action structure for NXAST_SAMPLE.
*
* Samples matching packets with the given probability and sends them
@@ -4726,6 +4751,7 @@ ofpact_is_set_or_move_action(const struct ofpact *a)
case OFPACT_DEC_TTL:
case OFPACT_ENQUEUE:
case OFPACT_EXIT:
+ case OFPACT_UNROLL_XLATE:
case OFPACT_FIN_TIMEOUT:
case OFPACT_GOTO_TABLE:
case OFPACT_GROUP:
@@ -4795,6 +4821,7 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a)
case OFPACT_CONTROLLER:
case OFPACT_ENQUEUE:
case OFPACT_EXIT:
+ case OFPACT_UNROLL_XLATE:
case OFPACT_FIN_TIMEOUT:
case OFPACT_LEARN:
case OFPACT_CONJUNCTION:
@@ -4868,7 +4895,7 @@ ofpacts_copy_all(struct ofpbuf *out, const struct ofpbuf *in,
* "Action Set" and "Action List" terms used in OpenFlow 1.1+.)
*
* In general this involves appending the last instance of each action that is
- * adimissible in the action set in the order described in the OpenFlow
+ * admissible in the action set in the order described in the OpenFlow
* specification.
*
* Exceptions:
@@ -5017,6 +5044,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type)
case OFPACT_MULTIPATH:
case OFPACT_NOTE:
case OFPACT_EXIT:
+ case OFPACT_UNROLL_XLATE:
case OFPACT_SAMPLE:
default:
return OVSINST_OFPIT11_APPLY_ACTIONS;
@@ -5607,6 +5635,11 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a,
case OFPACT_GROUP:
return 0;
+ case OFPACT_UNROLL_XLATE:
+ /* UNROLL is an internal action that should never be seen via
+ * OpenFlow. */
+ return OFPERR_OFPBAC_BAD_TYPE;
+
default:
OVS_NOT_REACHED();
}
@@ -5998,6 +6031,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port)
case OFPACT_MULTIPATH:
case OFPACT_NOTE:
case OFPACT_EXIT:
+ case OFPACT_UNROLL_XLATE:
case OFPACT_PUSH_MPLS:
case OFPACT_POP_MPLS:
case OFPACT_SAMPLE:
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index a1a5bb122..785c8140c 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -105,6 +105,7 @@
OFPACT(NOTE, ofpact_note, data, "note") \
OFPACT(EXIT, ofpact_null, ofpact, "exit") \
OFPACT(SAMPLE, ofpact_sample, ofpact, "sample") \
+ OFPACT(UNROLL_XLATE, ofpact_unroll_xlate, ofpact, "unroll_xlate") \
\
/* Instructions. */ \
OFPACT(METER, ofpact_meter, ofpact, "meter") \
@@ -715,6 +716,17 @@ struct ofpact_group {
uint32_t group_id;
};
+/* OFPACT_UNROLL_XLATE.
+ *
+ * Used only internally. */
+struct ofpact_unroll_xlate {
+ struct ofpact ofpact;
+
+ /* Metadata in xlate context, visible to controller via PACKET_INs. */
+ uint8_t rule_table_id; /* 0xFF if none. */
+ ovs_be64 rule_cookie; /* OVS_BE64_MAX if none. */
+};
+
/* Converting OpenFlow to ofpacts. */
enum ofperr ofpacts_pull_openflow_actions(struct ofpbuf *openflow,
unsigned int actions_len,
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 8d05681d6..8fce546f4 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -1158,6 +1158,67 @@ parse_bucket_str(struct ofputil_bucket *bucket, char *str_,
}
static char * OVS_WARN_UNUSED_RESULT
+parse_select_group_field(char *s, struct field_array *fa,
+ enum ofputil_protocol *usable_protocols)
+{
+ char *save_ptr = NULL;
+ char *name;
+
+ for (name = strtok_r(s, "=, \t\r\n", &save_ptr); name;
+ name = strtok_r(NULL, "=, \t\r\n", &save_ptr)) {
+ const struct mf_field *mf = mf_from_name(name);
+
+ if (mf) {
+ char *error;
+ const char *value_str;
+ union mf_value value;
+
+ if (bitmap_is_set(fa->used.bm, mf->id)) {
+ return xasprintf("%s: duplicate field", name);
+ }
+
+ value_str = strtok_r(NULL, ", \t\r\n", &save_ptr);
+ if (value_str) {
+ error = mf_parse_value(mf, value_str, &value);
+ if (error) {
+ return error;
+ }
+
+ /* The mask cannot be all-zeros */
+ if (is_all_zeros(&value, mf->n_bytes)) {
+ return xasprintf("%s: values are wildcards here "
+ "and must not be all-zeros", s);
+ }
+
+ /* The values parsed are masks for fields used
+ * by the selection method */
+ if (!mf_is_mask_valid(mf, &value)) {
+ return xasprintf("%s: invalid mask for field %s",
+ value_str, mf->name);
+ }
+ } else {
+ memset(&value, 0xff, mf->n_bytes);
+ }
+
+ field_array_set(mf->id, &value, fa);
+
+ if (is_all_ones(&value, mf->n_bytes)) {
+ *usable_protocols &= mf->usable_protocols_exact;
+ } else if (mf->usable_protocols_bitwise == mf->usable_protocols_cidr
+ || ip_is_cidr(value.be32)) {
+ *usable_protocols &= mf->usable_protocols_cidr;
+ } else {
+ *usable_protocols &= mf->usable_protocols_bitwise;
+ }
+ } else {
+ return xasprintf("%s: unknown field %s", s, name);
+ }
+ }
+
+ return NULL;
+}
+
+static char * OVS_WARN_UNUSED_RESULT
parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command,
char *string,
enum ofputil_protocol *usable_protocols)
@@ -1327,6 +1388,39 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command,
} else if (!strcmp(name, "bucket")) {
error = xstrdup("bucket is not needed");
goto out;
+ } else if (!strcmp(name, "selection_method")) {
+ if (!(fields & F_GROUP_TYPE)) {
+ error = xstrdup("selection method is not needed");
+ goto out;
+ }
+ if (strlen(value) >= NTR_MAX_SELECTION_METHOD_LEN) {
+ error = xasprintf("selection method is longer than %u"
+ " bytes long",
+ NTR_MAX_SELECTION_METHOD_LEN - 1);
+ goto out;
+ }
+ memset(gm->props.selection_method, '\0',
+ NTR_MAX_SELECTION_METHOD_LEN);
+ strcpy(gm->props.selection_method, value);
+ *usable_protocols &= OFPUTIL_P_OF15_UP;
+ } else if (!strcmp(name, "selection_method_param")) {
+ if (!(fields & F_GROUP_TYPE)) {
+ error = xstrdup("selection method param is not needed");
+ goto out;
+ }
+ error = str_to_u64(value, &gm->props.selection_method_param);
+ *usable_protocols &= OFPUTIL_P_OF15_UP;
+ } else if (!strcmp(name, "fields")) {
+ if (!(fields & F_GROUP_TYPE)) {
+ error = xstrdup("fields are not needed");
+ goto out;
+ }
+ error = parse_select_group_field(value, &gm->props.fields,
+ usable_protocols);
+ if (error) {
+ goto out;
+ }
+ *usable_protocols &= OFPUTIL_P_OF15_UP;
} else {
error = xasprintf("unknown keyword %s", name);
goto out;
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index b7c9a2641..cec074f1e 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -2156,8 +2156,8 @@ ofp_print_bucket_id(struct ds *s, const char *label, uint32_t bucket_id,
static void
ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type,
- struct ovs_list *p_buckets, enum ofp_version ofp_version,
- bool suppress_type)
+ struct ovs_list *p_buckets, struct ofputil_group_props *props,
+ enum ofp_version ofp_version, bool suppress_type)
{
struct ofputil_bucket *bucket;
@@ -2169,6 +2169,26 @@ ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type,
ds_put_format(s, ",type=%s", type_str[type > 4 ? 4 : type]);
}
+ if (props->selection_method[0]) {
+ size_t mark, start;
+
+ ds_put_format(s, ",selection_method=%s,", props->selection_method);
+ if (props->selection_method_param) {
+ ds_put_format(s, "selection_method_param=%"PRIu64",",
+ props->selection_method_param);
+ }
+
+ /* Allow rewinding to immediately before the trailing ',' */
+ mark = s->length - 1;
+
+ ds_put_cstr(s, "fields=");
+ start = s->length;
+ oxm_format_field_array(s, &props->fields);
+ if (s->length == start) {
+ ds_truncate(s, mark);
+ }
+ }
+
if (!p_buckets) {
return;
}
@@ -2226,8 +2246,8 @@ ofp_print_group_desc(struct ds *s, const struct ofp_header *oh)
ds_put_char(s, '\n');
ds_put_char(s, ' ');
- ofp_print_group(s, gd.group_id, gd.type, &gd.buckets, oh->version,
- false);
+ ofp_print_group(s, gd.group_id, gd.type, &gd.buckets, &gd.props,
+ oh->version, false);
ofputil_bucket_list_destroy(&gd.buckets);
}
}
@@ -2380,8 +2400,8 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
gm.command_bucket_id, oh->version);
}
- ofp_print_group(s, gm.group_id, gm.type, &gm.buckets, oh->version,
- bucket_command);
+ ofp_print_group(s, gm.group_id, gm.type, &gm.buckets, &gm.props,
+ oh->version, bucket_command);
ofputil_bucket_list_destroy(&gm.buckets);
}
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index d5927a9f3..277fdfeb2 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -38,6 +38,7 @@
#include "ofp-msgs.h"
#include "ofp-util.h"
#include "ofpbuf.h"
+#include "openflow/netronome-ext.h"
#include "packets.h"
#include "random.h"
#include "unaligned.h"
@@ -59,6 +60,14 @@ struct ofp_prop_header {
ovs_be16 len;
};
+struct ofp_prop_experimenter {
+ ovs_be16 type; /* OFP*_EXPERIMENTER. */
+ ovs_be16 length; /* Length in bytes of this property. */
+ ovs_be32 experimenter; /* Experimenter ID which takes the same form as
+ * in struct ofp_experimenter_header. */
+ ovs_be32 exp_type; /* Experimenter defined. */
+};
+
/* Pulls a property, beginning with struct ofp_prop_header, from the beginning
* of 'msg'. Stores the type of the property in '*typep' and, if 'property' is
* nonnull, the entire property, including the header, in '*property'. Returns
@@ -6877,10 +6886,9 @@ ofputil_decode_port_stats_request(const struct ofp_header *request,
void
ofputil_bucket_list_destroy(struct ovs_list *buckets)
{
- struct ofputil_bucket *bucket, *next_bucket;
+ struct ofputil_bucket *bucket;
- LIST_FOR_EACH_SAFE (bucket, next_bucket, list_node, buckets) {
- list_remove(&bucket->list_node);
+ LIST_FOR_EACH_POP (bucket, list_node, buckets) {
free(bucket->ofpacts);
free(bucket);
}
@@ -7020,6 +7028,13 @@ ofputil_encode_group_stats_request(enum ofp_version ofp_version,
return request;
}
+void
+ofputil_uninit_group_desc(struct ofputil_group_desc *gd)
+{
+ ofputil_bucket_list_destroy(&gd->buckets);
+ free(&gd->props.fields);
+}
+
/* Decodes the OpenFlow group description request in 'oh', returning the group
* whose description is requested, or OFPG_ALL if stats for all groups was
* requested. */
@@ -7412,6 +7427,26 @@ ofputil_put_ofp15_bucket(const struct ofputil_bucket *bucket,
}
static void
+ofputil_put_group_prop_ntr_selection_method(enum ofp_version ofp_version,
+ const struct ofputil_group_props *gp,
+ struct ofpbuf *openflow)
+{
+ struct ntr_group_prop_selection_method *prop;
+ size_t start;
+
+ start = openflow->size;
+ ofpbuf_put_zeros(openflow, sizeof *prop);
+ oxm_put_field_array(openflow, &gp->fields, ofp_version);
+ prop = ofpbuf_at_assert(openflow, start, sizeof *prop);
+ prop->type = htons(OFPGPT15_EXPERIMENTER);
+ prop->experimenter = htonl(NTR_VENDOR_ID);
+ prop->exp_type = htonl(NTRT_SELECTION_METHOD);
+ strcpy(prop->selection_method, gp->selection_method);
+ prop->selection_method_param = htonll(gp->selection_method_param);
+ end_property(openflow, start);
+}
+
+static void
ofputil_append_ofp11_group_desc_reply(const struct ofputil_group_desc *gds,
const struct ovs_list *buckets,
struct ovs_list *replies,
@@ -7459,6 +7494,12 @@ ofputil_append_ofp15_group_desc_reply(const struct ofputil_group_desc *gds,
ogds->group_id = htonl(gds->group_id);
ogds->bucket_list_len = htons(reply->size - start_buckets);
+ /* Add group properties */
+ if (gds->props.selection_method[0]) {
+ ofputil_put_group_prop_ntr_selection_method(version, &gds->props,
+ reply);
+ }
+
ofpmp_postappend(replies, start_ogds);
}
@@ -7721,6 +7762,196 @@ ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length,
return 0;
}
+static void
+ofputil_init_group_properties(struct ofputil_group_props *gp)
+{
+ memset(gp, 0, sizeof *gp);
+}
+
+static enum ofperr
+parse_group_prop_ntr_selection_method(struct ofpbuf *payload,
+ enum ofp11_group_type group_type,
+ enum ofp15_group_mod_command group_cmd,
+ struct ofputil_group_props *gp)
+{
+ struct ntr_group_prop_selection_method *prop = payload->data;
+ size_t fields_len, method_len;
+ enum ofperr error;
+
+ switch (group_type) {
+ case OFPGT11_SELECT:
+ break;
+ case OFPGT11_ALL:
+ case OFPGT11_INDIRECT:
+ case OFPGT11_FF:
+ log_property(false, "ntr selection method property is only allowed "
+ "for select groups");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ default:
+ OVS_NOT_REACHED();
+ }
+
+ switch (group_cmd) {
+ case OFPGC15_ADD:
+ case OFPGC15_MODIFY:
+ break;
+ case OFPGC15_DELETE:
+ case OFPGC15_INSERT_BUCKET:
+ case OFPGC15_REMOVE_BUCKET:
+ log_property(false, "ntr selection method property is only allowed "
+ "for add and delete group modifications");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ default:
+ OVS_NOT_REACHED();
+ }
+
+ if (payload->size < sizeof *prop) {
+ log_property(false, "ntr selection method property length "
+ "%u is not valid", payload->size);
+ return OFPERR_OFPBPC_BAD_LEN;
+ }
+
+ method_len = strnlen(prop->selection_method, NTR_MAX_SELECTION_METHOD_LEN);
+
+ if (method_len == NTR_MAX_SELECTION_METHOD_LEN) {
+ log_property(false, "ntr selection method is not null terminated");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+
+ if (strcmp("hash", prop->selection_method)) {
+ log_property(false, "ntr selection method '%s' is not supported",
+ prop->selection_method);
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+
+ strcpy(gp->selection_method, prop->selection_method);
+ gp->selection_method_param = ntohll(prop->selection_method_param);
+
+ if (!method_len && gp->selection_method_param) {
+ log_property(false, "ntr selection method parameter is non-zero but "
+ "selection method is empty");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+
+ ofpbuf_pull(payload, sizeof *prop);
+
+ fields_len = ntohs(prop->length) - sizeof *prop;
+ if (!method_len && fields_len) {
+ log_property(false, "ntr selection method parameter is zero "
+ "but fields are provided");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+
+ error = oxm_pull_field_array(payload->data, fields_len,
+ &gp->fields);
+ if (error) {
+ log_property(false, "ntr selection method fields are invalid");
+ return error;
+ }
+
+ return 0;
+}
+
+static enum ofperr
+parse_group_prop_ntr(struct ofpbuf *payload, uint32_t exp_type,
+ enum ofp11_group_type group_type,
+ enum ofp15_group_mod_command group_cmd,
+ struct ofputil_group_props *gp)
+{
+ enum ofperr error;
+
+ switch (exp_type) {
+ case NTRT_SELECTION_METHOD:
+ error = parse_group_prop_ntr_selection_method(payload, group_type,
+ group_cmd, gp);
+ break;
+
+ default:
+ log_property(false, "unknown group property ntr experimenter type "
+ "%"PRIu32, exp_type);
+ error = OFPERR_OFPBPC_BAD_TYPE;
+ break;
+ }
+
+ return error;
+}
+
+static enum ofperr
+parse_ofp15_group_prop_exp(struct ofpbuf *payload,
+ enum ofp11_group_type group_type,
+ enum ofp15_group_mod_command group_cmd,
+ struct ofputil_group_props *gp)
+{
+ struct ofp_prop_experimenter *prop = payload->data;
+ uint16_t experimenter;
+ uint32_t exp_type;
+ enum ofperr error;
+
+ if (payload->size < sizeof *prop) {
+ return OFPERR_OFPBPC_BAD_LEN;
+ }
+
+ experimenter = ntohl(prop->experimenter);
+ exp_type = ntohl(prop->exp_type);
+
+ switch (experimenter) {
+ case NTR_VENDOR_ID:
+ error = parse_group_prop_ntr(payload, exp_type, group_type,
+ group_cmd, gp);
+ break;
+
+ default:
+ log_property(false, "unknown group property experimenter %"PRIu16,
+ experimenter);
+ error = OFPERR_OFPBPC_BAD_EXPERIMENTER;
+ break;
+ }
+
+ return error;
+}
+
+static enum ofperr
+parse_ofp15_group_properties(struct ofpbuf *msg,
+ enum ofp11_group_type group_type,
+ enum ofp15_group_mod_command group_cmd,
+ struct ofputil_group_props *gp,
+ size_t properties_len)
+{
+ struct ofpbuf properties;
+
+ ofpbuf_use_const(&properties, ofpbuf_pull(msg, properties_len),
+ properties_len);
+
+ while (properties.size > 0) {
+ struct ofpbuf payload;
+ enum ofperr error;
+ uint16_t type;
+
+ error = ofputil_pull_property(&properties, &payload, &type);
+ if (error) {
+ return error;
+ }
+
+ switch (type) {
+ case OFPGPT15_EXPERIMENTER:
+ error = parse_ofp15_group_prop_exp(&payload, group_type,
+ group_cmd, gp);
+ break;
+
+ default:
+ log_property(false, "unknown group property %"PRIu16, type);
+ error = OFPERR_OFPBPC_BAD_TYPE;
+ break;
+ }
+
+ if (error) {
+ return error;
+ }
+ }
+
+ return 0;
+}
+
static int
ofputil_decode_ofp11_group_desc_reply(struct ofputil_group_desc *gd,
struct ofpbuf *msg,
@@ -7764,6 +7995,7 @@ ofputil_decode_ofp15_group_desc_reply(struct ofputil_group_desc *gd,
{
struct ofp15_group_desc_stats *ogds;
uint16_t length, bucket_list_len;
+ int error;
if (!msg->header) {
ofpraw_pull_assert(msg);
@@ -7795,9 +8027,22 @@ ofputil_decode_ofp15_group_desc_reply(struct ofputil_group_desc *gd,
"bucket list length %u", bucket_list_len);
return OFPERR_OFPBRC_BAD_LEN;
}
+ error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, version,
+ &gd->buckets);
+ if (error) {
+ return error;
+ }
- return ofputil_pull_ofp15_buckets(msg, bucket_list_len, version,
- &gd->buckets);
+ /* By definition group desc messages don't have a group mod command.
+ * However, parse_group_prop_ntr_selection_method() checks to make sure
+ * that the command is OFPGC15_ADD or OFPGC15_DELETE to guard
+ * against group mod messages with other commands supplying
+ * a NTR selection method group experimenter property.
+ * Such properties are valid for group desc replies so
+ * claim that the group mod command is OFPGC15_ADD to
+ * satisfy the check in parse_group_prop_ntr_selection_method() */
+ return parse_ofp15_group_properties(msg, gd->type, OFPGC15_ADD, &gd->props,
+ msg->size);
}
/* Converts a group description reply in 'msg' into an abstract
@@ -7814,6 +8059,8 @@ int
ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd,
struct ofpbuf *msg, enum ofp_version version)
{
+ ofputil_init_group_properties(&gd->props);
+
switch (version)
{
case OFP11_VERSION:
@@ -7831,6 +8078,12 @@ ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd,
}
}
+void
+ofputil_uninit_group_mod(struct ofputil_group_mod *gm)
+{
+ ofputil_bucket_list_destroy(&gm->buckets);
+}
+
static struct ofpbuf *
ofputil_encode_ofp11_group_mod(enum ofp_version ofp_version,
const struct ofputil_group_mod *gm)
@@ -7907,6 +8160,11 @@ ofputil_encode_ofp15_group_mod(enum ofp_version ofp_version,
ogm->command_bucket_id = htonl(gm->command_bucket_id);
ogm->bucket_array_len = htons(b->size - start_ogm - sizeof *ogm);
+ /* Add group properties */
+ if (gm->props.selection_method[0]) {
+ ofputil_put_group_prop_ntr_selection_method(ofp_version, &gm->props, b);
+ }
+
id_pool_destroy(bucket_ids);
return b;
}
@@ -8064,14 +8322,14 @@ ofputil_pull_ofp15_group_mod(struct ofpbuf *msg, enum ofp_version ofp_version,
}
bucket_list_len = ntohs(ogm->bucket_array_len);
- if (bucket_list_len < msg->size) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "group has %u trailing bytes",
- msg->size - bucket_list_len);
- return OFPERR_OFPGMFC_BAD_BUCKET;
+ error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, ofp_version,
+ &gm->buckets);
+ if (error) {
+ return error;
}
- return ofputil_pull_ofp15_buckets(msg, bucket_list_len, ofp_version,
- &gm->buckets);
+ return parse_ofp15_group_properties(msg, gm->type, gm->command, &gm->props,
+ msg->size);
}
/* Converts OpenFlow group mod message 'oh' into an abstract group mod in
@@ -8088,6 +8346,8 @@ ofputil_decode_group_mod(const struct ofp_header *oh,
ofpbuf_use_const(&msg, oh, ntohs(oh->length));
ofpraw_pull_assert(&msg);
+ ofputil_init_group_properties(&gm->props);
+
switch (ofp_version)
{
case OFP11_VERSION:
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index df4d04465..ee3f1bed6 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -27,6 +27,7 @@
#include "match.h"
#include "meta-flow.h"
#include "netdev.h"
+#include "openflow/netronome-ext.h"
#include "openflow/nicira-ext.h"
#include "openvswitch/types.h"
#include "type-props.h"
@@ -217,6 +218,8 @@ void ofputil_match_to_ofp10_match(const struct match *, struct ofp10_match *);
/* Work with ofp11_match. */
enum ofperr ofputil_pull_ofp11_match(struct ofpbuf *, struct match *,
uint16_t *padded_match_len);
+enum ofperr ofputil_pull_ofp11_mask(struct ofpbuf *, struct match *,
+ struct mf_bitmap *bm);
enum ofperr ofputil_match_from_ofp11_match(const struct ofp11_match *,
struct match *);
int ofputil_put_ofp11_match(struct ofpbuf *, const struct match *,
@@ -994,6 +997,14 @@ struct ofputil_bucket {
};
/* Protocol-independent group_mod. */
+struct ofputil_group_props {
+ /* NTR selection method */
+ char selection_method[NTR_MAX_SELECTION_METHOD_LEN];
+ uint64_t selection_method_param;
+ struct field_array fields;
+};
+
+/* Protocol-independent group_mod. */
struct ofputil_group_mod {
uint16_t command; /* One of OFPGC15_*. */
uint8_t type; /* One of OFPGT11_*. */
@@ -1003,6 +1014,7 @@ struct ofputil_group_mod {
* OFPGC15_REMOVE_BUCKET commands
* execution.*/
struct ovs_list buckets; /* Contains "struct ofputil_bucket"s. */
+ struct ofputil_group_props props; /* Group properties. */
};
/* Group stats reply, independent of protocol. */
@@ -1032,6 +1044,7 @@ struct ofputil_group_desc {
uint8_t type; /* One of OFPGT_*. */
uint32_t group_id; /* Group identifier. */
struct ovs_list buckets; /* Contains "struct ofputil_bucket"s. */
+ struct ofputil_group_props props; /* Group properties. */
};
void ofputil_bucket_list_destroy(struct ovs_list *buckets);
@@ -1062,6 +1075,7 @@ struct ofpbuf *ofputil_encode_group_features_reply(
const struct ofputil_group_features *, const struct ofp_header *request);
void ofputil_decode_group_features_reply(const struct ofp_header *,
struct ofputil_group_features *);
+void ofputil_uninit_group_mod(struct ofputil_group_mod *gm);
struct ofpbuf *ofputil_encode_group_mod(enum ofp_version ofp_version,
const struct ofputil_group_mod *gm);
@@ -1071,6 +1085,7 @@ enum ofperr ofputil_decode_group_mod(const struct ofp_header *,
int ofputil_decode_group_stats_reply(struct ofpbuf *,
struct ofputil_group_stats *);
+void ofputil_uninit_group_desc(struct ofputil_group_desc *gd);
uint32_t ofputil_decode_group_desc_request(const struct ofp_header *);
struct ofpbuf *ofputil_encode_group_desc_request(enum ofp_version,
uint32_t group_id);
diff --git a/lib/ofpbuf.c b/lib/ofpbuf.c
index 7510edb9b..c27c55204 100644
--- a/lib/ofpbuf.c
+++ b/lib/ofpbuf.c
@@ -477,10 +477,9 @@ ofpbuf_to_string(const struct ofpbuf *b, size_t maxbytes)
void
ofpbuf_list_delete(struct ovs_list *list)
{
- struct ofpbuf *b, *next;
+ struct ofpbuf *b;
- LIST_FOR_EACH_SAFE (b, next, list_node, list) {
- list_remove(&b->list_node);
+ LIST_FOR_EACH_POP (b, list_node, list) {
ofpbuf_delete(b);
}
}
diff --git a/lib/ovs-lldp.c b/lib/ovs-lldp.c
index a30eca59a..3edaf429a 100644
--- a/lib/ovs-lldp.c
+++ b/lib/ovs-lldp.c
@@ -421,12 +421,9 @@ aa_get_vlan_queued(struct ovs_list *list)
ovs_mutex_lock(&mutex);
HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
- struct bridge_aa_vlan *node, *node_next;
+ struct bridge_aa_vlan *node;
- LIST_FOR_EACH_SAFE (node,
- node_next,
- list_node,
- &lldp->active_mapping_queue) {
+ LIST_FOR_EACH_POP (node, list_node, &lldp->active_mapping_queue) {
struct bridge_aa_vlan *copy;
copy = xmalloc(sizeof *copy);
@@ -437,7 +434,6 @@ aa_get_vlan_queued(struct ovs_list *list)
list_push_back(list, &copy->list_node);
/* Cleanup */
- list_remove(&node->list_node);
free(node->port_name);
free(node);
}
@@ -483,12 +479,14 @@ aa_configure(const struct aa_settings *s)
LIST_FOR_EACH (chassis, list, &lldp->lldpd->g_chassis) {
/* System Description */
free(chassis->c_descr);
- chassis->c_descr = s->system_description[0] ?
+ chassis->c_descr = s && s->system_description[0] ?
xstrdup(s->system_description) : xstrdup(PACKAGE_STRING);
/* System Name */
- free(chassis->c_name);
- chassis->c_name = xstrdup(s->system_name);
+ if (s) {
+ free(chassis->c_name);
+ chassis->c_name = xstrdup(s->system_name);
+ }
}
}
@@ -822,16 +820,15 @@ lldp_create(const struct netdev *netdev,
hw->h_lport.p_id_len = strlen(netdev_get_name(netdev));
/* Auto Attach element tlv */
- hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
+ hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH;
hw->h_lport.p_element.mgmt_vlan = 0;
memcpy(&hw->h_lport.p_element.system_id.system_mac,
lchassis->c_id, lchassis->c_id_len);
hw->h_lport.p_element.system_id.conn_type =
LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
-
- hw->h_lport.p_element.system_id.smlt_id = 0;
- hw->h_lport.p_element.system_id.mlt_id[0] = 0;
- hw->h_lport.p_element.system_id.mlt_id[1] = 0;
+ hw->h_lport.p_element.system_id.rsvd = 0;
+ hw->h_lport.p_element.system_id.rsvd2[0] = 0;
+ hw->h_lport.p_element.system_id.rsvd2[1] = 0;
list_init(&hw->h_lport.p_isid_vlan_maps);
list_init(&lldp->lldpd->g_hardware);
@@ -908,15 +905,15 @@ lldp_create_dummy(void)
hw->h_lport.p_id_len = strlen(hw->h_lport.p_id);
/* Auto Attach element tlv */
- hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
+ hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH;
hw->h_lport.p_element.mgmt_vlan = 0;
memcpy(&hw->h_lport.p_element.system_id.system_mac,
lchassis->c_id, lchassis->c_id_len);
hw->h_lport.p_element.system_id.conn_type =
LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
- hw->h_lport.p_element.system_id.smlt_id = 0;
- hw->h_lport.p_element.system_id.mlt_id[0] = 0;
- hw->h_lport.p_element.system_id.mlt_id[1] = 0;
+ hw->h_lport.p_element.system_id.rsvd = 0;
+ hw->h_lport.p_element.system_id.rsvd2[0] = 0;
+ hw->h_lport.p_element.system_id.rsvd2[1] = 0;
list_init(&hw->h_lport.p_isid_vlan_maps);
list_init(&lldp->lldpd->g_hardware);
diff --git a/lib/ovs-lldp.h b/lib/ovs-lldp.h
index 825096ba3..66288a577 100644
--- a/lib/ovs-lldp.h
+++ b/lib/ovs-lldp.h
@@ -24,6 +24,7 @@
#include "hmap.h"
#include "list.h"
#include "lldp/lldpd.h"
+#include "ovs-atomic.h"
#include "packets.h"
#include "timer.h"
diff --git a/lib/ovs-numa.c b/lib/ovs-numa.c
index 3aa103694..5bed2b5e2 100644
--- a/lib/ovs-numa.c
+++ b/lib/ovs-numa.c
@@ -380,10 +380,9 @@ ovs_numa_dump_cores_on_numa(int numa_id)
void
ovs_numa_dump_destroy(struct ovs_numa_dump *dump)
{
- struct ovs_numa_info *iter, *next;
+ struct ovs_numa_info *iter;
- LIST_FOR_EACH_SAFE (iter, next, list_node, &dump->dump) {
- list_remove(&iter->list_node);
+ LIST_FOR_EACH_POP (iter, list_node, &dump->dump) {
free(iter);
}
diff --git a/lib/ovs-rcu.c b/lib/ovs-rcu.c
index 5276981c8..76659bbe0 100644
--- a/lib/ovs-rcu.c
+++ b/lib/ovs-rcu.c
@@ -239,7 +239,7 @@ ovsrcu_postpone__(void (*function)(void *aux), void *aux)
static bool
ovsrcu_call_postponed(void)
{
- struct ovsrcu_cbset *cbset, *next_cbset;
+ struct ovsrcu_cbset *cbset;
struct ovs_list cbsets;
guarded_list_pop_all(&flushed_cbsets, &cbsets);
@@ -249,13 +249,12 @@ ovsrcu_call_postponed(void)
ovsrcu_synchronize();
- LIST_FOR_EACH_SAFE (cbset, next_cbset, list_node, &cbsets) {
+ LIST_FOR_EACH_POP (cbset, list_node, &cbsets) {
struct ovsrcu_cb *cb;
for (cb = cbset->cbs; cb < &cbset->cbs[cbset->n_cbs]; cb++) {
cb->function(cb->aux);
}
- list_remove(&cbset->list_node);
free(cbset);
}
diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index 9c25dbcbc..4ec703240 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,11 +28,15 @@
#include "fatal-signal.h"
#include "json.h"
#include "jsonrpc.h"
+#include "ovsdb/ovsdb.h"
+#include "ovsdb/table.h"
#include "ovsdb-data.h"
#include "ovsdb-error.h"
#include "ovsdb-idl-provider.h"
+#include "ovsdb-parser.h"
#include "poll-loop.h"
#include "shash.h"
+#include "sset.h"
#include "util.h"
#include "openvswitch/vlog.h"
@@ -71,16 +75,25 @@ struct ovsdb_idl_arc {
struct ovsdb_idl_row *dst; /* Destination row. */
};
+enum ovsdb_idl_state {
+ IDL_S_SCHEMA_REQUESTED,
+ IDL_S_MONITOR_REQUESTED,
+ IDL_S_MONITORING
+};
+
struct ovsdb_idl {
const struct ovsdb_idl_class *class;
struct jsonrpc_session *session;
struct shash table_by_name;
struct ovsdb_idl_table *tables; /* Contains "struct ovsdb_idl_table *"s.*/
- struct json *monitor_request_id;
- unsigned int last_monitor_request_seqno;
unsigned int change_seqno;
bool verify_write_only;
+ /* Session state. */
+ unsigned int state_seqno;
+ enum ovsdb_idl_state state;
+ struct json *request_id;
+
/* Database locking. */
char *lock_name; /* Name of lock we need, NULL if none. */
bool has_lock; /* Has db server told us we have the lock? */
@@ -124,7 +137,9 @@ static struct vlog_rate_limit syntax_rl = VLOG_RATE_LIMIT_INIT(1, 5);
static struct vlog_rate_limit semantic_rl = VLOG_RATE_LIMIT_INIT(1, 5);
static void ovsdb_idl_clear(struct ovsdb_idl *);
-static void ovsdb_idl_send_monitor_request(struct ovsdb_idl *);
+static void ovsdb_idl_send_schema_request(struct ovsdb_idl *);
+static void ovsdb_idl_send_monitor_request(struct ovsdb_idl *,
+ const struct json *schema_json);
static void ovsdb_idl_parse_update(struct ovsdb_idl *, const struct json *);
static struct ovsdb_error *ovsdb_idl_parse_update__(struct ovsdb_idl *,
const struct json *);
@@ -214,7 +229,10 @@ ovsdb_idl_create(const char *remote, const struct ovsdb_idl_class *class,
hmap_init(&table->rows);
table->idl = idl;
}
- idl->last_monitor_request_seqno = UINT_MAX;
+
+ idl->state_seqno = UINT_MAX;
+ idl->request_id = NULL;
+
hmap_init(&idl->outstanding_txns);
return idl;
@@ -239,7 +257,7 @@ ovsdb_idl_destroy(struct ovsdb_idl *idl)
}
shash_destroy(&idl->table_by_name);
free(idl->tables);
- json_destroy(idl->monitor_request_id);
+ json_destroy(idl->request_id);
free(idl->lock_name);
json_destroy(idl->lock_request_id);
hmap_destroy(&idl->outstanding_txns);
@@ -298,14 +316,17 @@ ovsdb_idl_run(struct ovsdb_idl *idl)
unsigned int seqno;
seqno = jsonrpc_session_get_seqno(idl->session);
- if (idl->last_monitor_request_seqno != seqno) {
- idl->last_monitor_request_seqno = seqno;
+ if (idl->state_seqno != seqno) {
+ idl->state_seqno = seqno;
+ json_destroy(idl->request_id);
+ idl->request_id = NULL;
ovsdb_idl_txn_abort_all(idl);
- ovsdb_idl_send_monitor_request(idl);
+
+ ovsdb_idl_send_schema_request(idl);
+ idl->state = IDL_S_SCHEMA_REQUESTED;
if (idl->lock_name) {
ovsdb_idl_send_lock_request(idl);
}
- break;
}
msg = jsonrpc_session_recv(idl->session);
@@ -321,14 +342,31 @@ ovsdb_idl_run(struct ovsdb_idl *idl)
/* Database contents changed. */
ovsdb_idl_parse_update(idl, msg->params->u.array.elems[1]);
} else if (msg->type == JSONRPC_REPLY
- && idl->monitor_request_id
- && json_equal(idl->monitor_request_id, msg->id)) {
- /* Reply to our "monitor" request. */
- idl->change_seqno++;
- json_destroy(idl->monitor_request_id);
- idl->monitor_request_id = NULL;
- ovsdb_idl_clear(idl);
- ovsdb_idl_parse_update(idl, msg->result);
+ && idl->request_id
+ && json_equal(idl->request_id, msg->id)) {
+ switch (idl->state) {
+ case IDL_S_SCHEMA_REQUESTED:
+ /* Reply to our "get_schema" request. */
+ json_destroy(idl->request_id);
+ idl->request_id = NULL;
+ ovsdb_idl_send_monitor_request(idl, msg->result);
+ idl->state = IDL_S_MONITOR_REQUESTED;
+ break;
+
+ case IDL_S_MONITOR_REQUESTED:
+ /* Reply to our "monitor" request. */
+ idl->change_seqno++;
+ json_destroy(idl->request_id);
+ idl->request_id = NULL;
+ idl->state = IDL_S_MONITORING;
+ ovsdb_idl_clear(idl);
+ ovsdb_idl_parse_update(idl, msg->result);
+ break;
+
+ case IDL_S_MONITORING:
+ default:
+ OVS_NOT_REACHED();
+ }
} else if (msg->type == JSONRPC_REPLY
&& idl->lock_request_id
&& json_equal(idl->lock_request_id, msg->id)) {
@@ -430,12 +468,16 @@ ovsdb_idl_verify_write_only(struct ovsdb_idl *idl)
idl->verify_write_only = true;
}
+/* Returns true if 'idl' is currently connected or trying to connect. */
bool
ovsdb_idl_is_alive(const struct ovsdb_idl *idl)
{
return jsonrpc_session_is_alive(idl->session);
}
+/* Returns the last error reported on a connection by 'idl'. The return value
+ * is 0 only if no connection made by 'idl' has ever encountered an error. See
+ * jsonrpc_get_status() for return value interpretation. */
int
ovsdb_idl_get_last_error(const struct ovsdb_idl *idl)
{
@@ -551,8 +593,107 @@ ovsdb_idl_omit(struct ovsdb_idl *idl, const struct ovsdb_idl_column *column)
}
static void
-ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl)
+ovsdb_idl_send_schema_request(struct ovsdb_idl *idl)
+{
+ struct jsonrpc_msg *msg;
+
+ json_destroy(idl->request_id);
+ msg = jsonrpc_create_request(
+ "get_schema",
+ json_array_create_1(json_string_create(idl->class->database)),
+ &idl->request_id);
+ jsonrpc_session_send(idl->session, msg);
+}
+
+static void
+log_error(struct ovsdb_error *error)
+{
+ char *s = ovsdb_error_to_string(error);
+ VLOG_WARN("error parsing database schema: %s", s);
+ free(s);
+ ovsdb_error_destroy(error);
+}
+
+/* Frees 'schema', which is in the format returned by parse_schema(). */
+static void
+free_schema(struct shash *schema)
+{
+ if (schema) {
+ struct shash_node *node, *next;
+
+ SHASH_FOR_EACH_SAFE (node, next, schema) {
+ struct sset *sset = node->data;
+ sset_destroy(sset);
+ free(sset);
+ shash_delete(schema, node);
+ }
+ shash_destroy(schema);
+ free(schema);
+ }
+}
+
+/* Parses 'schema_json', an OVSDB schema in JSON format as described in RFC
+ * 7047, to obtain the names of its rows and columns. If successful, returns
+ * an shash whose keys are table names and whose values are ssets, where each
+ * sset contains the names of its table's columns. On failure (due to a parse
+ * error), returns NULL.
+ *
+ * It would also be possible to use the general-purpose OVSDB schema parser in
+ * ovsdb-server, but that's overkill, possibly too strict for the current use
+ * case, and would require restructuring ovsdb-server to separate the schema
+ * code from the rest. */
+static struct shash *
+parse_schema(const struct json *schema_json)
+{
+ struct ovsdb_parser parser;
+ const struct json *tables_json;
+ struct ovsdb_error *error;
+ struct shash_node *node;
+ struct shash *schema;
+
+ ovsdb_parser_init(&parser, schema_json, "database schema");
+ tables_json = ovsdb_parser_member(&parser, "tables", OP_OBJECT);
+ error = ovsdb_parser_destroy(&parser);
+ if (error) {
+ log_error(error);
+ return NULL;
+ }
+
+ schema = xmalloc(sizeof *schema);
+ shash_init(schema);
+ SHASH_FOR_EACH (node, json_object(tables_json)) {
+ const char *table_name = node->name;
+ const struct json *json = node->data;
+ const struct json *columns_json;
+
+ ovsdb_parser_init(&parser, json, "table schema for table %s",
+ table_name);
+ columns_json = ovsdb_parser_member(&parser, "columns", OP_OBJECT);
+ error = ovsdb_parser_destroy(&parser);
+ if (error) {
+ log_error(error);
+ free_schema(schema);
+ return NULL;
+ }
+
+ struct sset *columns = xmalloc(sizeof *columns);
+ sset_init(columns);
+
+ struct shash_node *node2;
+ SHASH_FOR_EACH (node2, json_object(columns_json)) {
+ const char *column_name = node2->name;
+ sset_add(columns, column_name);
+ }
+ shash_add(schema, table_name, columns);
+ }
+ return schema;
+}
+
+static void
+ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl,
+ const struct json *schema_json)
{
+ struct shash *schema = parse_schema(schema_json);
struct json *monitor_requests;
struct jsonrpc_msg *msg;
size_t i;
@@ -562,12 +703,25 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl)
const struct ovsdb_idl_table *table = &idl->tables[i];
const struct ovsdb_idl_table_class *tc = table->class;
struct json *monitor_request, *columns;
+ const struct sset *table_schema;
size_t j;
+ table_schema = (schema
+ ? shash_find_data(schema, table->class->name)
+ : NULL);
+
columns = table->need_table ? json_array_create_empty() : NULL;
for (j = 0; j < tc->n_columns; j++) {
const struct ovsdb_idl_column *column = &tc->columns[j];
if (table->modes[j] & OVSDB_IDL_MONITOR) {
+ if (table_schema
+ && !sset_contains(table_schema, column->name)) {
+ VLOG_WARN("%s table in %s database lacks %s column "
+ "(database needs upgrade?)",
+ table->class->name, idl->class->database,
+ column->name);
+ continue;
+ }
if (!columns) {
columns = json_array_create_empty();
}
@@ -576,18 +730,27 @@ ovsdb_idl_send_monitor_request(struct ovsdb_idl *idl)
}
if (columns) {
+ if (schema && !table_schema) {
+ VLOG_WARN("%s database lacks %s table "
+ "(database needs upgrade?)",
+ idl->class->database, table->class->name);
+ json_destroy(columns);
+ continue;
+ }
+
monitor_request = json_object_create();
json_object_put(monitor_request, "columns", columns);
json_object_put(monitor_requests, tc->name, monitor_request);
}
}
+ free_schema(schema);
- json_destroy(idl->monitor_request_id);
+ json_destroy(idl->request_id);
msg = jsonrpc_create_request(
"monitor",
json_array_create_3(json_string_create(idl->class->database),
json_null_create(), monitor_requests),
- &idl->monitor_request_id);
+ &idl->request_id);
jsonrpc_session_send(idl->session, msg);
}
@@ -2385,11 +2548,11 @@ static void
ovsdb_idl_update_has_lock(struct ovsdb_idl *idl, bool new_has_lock)
{
if (new_has_lock && !idl->has_lock) {
- if (!idl->monitor_request_id) {
+ if (idl->state == IDL_S_MONITORING) {
idl->change_seqno++;
} else {
- /* We're waiting for a monitor reply, so don't signal that the
- * database changed. The monitor reply will increment change_seqno
+ /* We're setting up a session, so don't signal that the database
+ * changed. Finalizing the session will increment change_seqno
* anyhow. */
}
idl->is_lock_contended = false;
diff --git a/lib/ovsdb-parser.c b/lib/ovsdb-parser.c
index f4642ad01..3e448332b 100644
--- a/lib/ovsdb-parser.c
+++ b/lib/ovsdb-parser.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2011, 2013 Nicira, Inc.
+/* Copyright (c) 2009, 2011, 2013, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -127,6 +127,15 @@ ovsdb_parser_has_error(const struct ovsdb_parser *parser)
}
struct ovsdb_error *
+ovsdb_parser_destroy(struct ovsdb_parser *parser)
+{
+ free(parser->name);
+ sset_destroy(&parser->used);
+
+ return parser->error;
+}
+
+struct ovsdb_error *
ovsdb_parser_finish(struct ovsdb_parser *parser)
{
if (!parser->error) {
@@ -157,8 +166,5 @@ ovsdb_parser_finish(struct ovsdb_parser *parser)
}
}
- free(parser->name);
- sset_destroy(&parser->used);
-
- return parser->error;
+ return ovsdb_parser_destroy(parser);
}
diff --git a/lib/ovsdb-parser.h b/lib/ovsdb-parser.h
index 8df9d5277..2f9f483d1 100644
--- a/lib/ovsdb-parser.h
+++ b/lib/ovsdb-parser.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, 2011 Nicira, Inc.
+/* Copyright (c) 2009, 2010, 2011, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -72,7 +72,8 @@ bool ovsdb_parser_has_error(const struct ovsdb_parser *);
struct ovsdb_error *ovsdb_parser_get_error(const struct ovsdb_parser *);
struct ovsdb_error *ovsdb_parser_finish(struct ovsdb_parser *)
OVS_WARN_UNUSED_RESULT;
-void ovsdb_parser_destroy(struct ovsdb_parser *);
+struct ovsdb_error *ovsdb_parser_destroy(struct ovsdb_parser *)
+ OVS_WARN_UNUSED_RESULT;
bool ovsdb_parser_is_id(const char *string);
diff --git a/lib/packets.c b/lib/packets.c
index 07cf2eb24..419c6af49 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -1043,3 +1043,17 @@ compose_arp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN],
dp_packet_set_frame(b, eth);
dp_packet_set_l3(b, arp);
}
+
+uint32_t
+packet_csum_pseudoheader(const struct ip_header *ip)
+{
+ uint32_t partial = 0;
+
+ partial = csum_add32(partial, get_16aligned_be32(&ip->ip_src));
+ partial = csum_add32(partial, get_16aligned_be32(&ip->ip_dst));
+ partial = csum_add16(partial, htons(ip->ip_proto));
+ partial = csum_add16(partial, htons(ntohs(ip->ip_tot_len) -
+ IP_IHL(ip->ip_ihl_ver) * 4));
+
+ return partial;
+}
diff --git a/lib/packets.h b/lib/packets.h
index e80de6bc6..b146a5069 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -730,7 +730,26 @@ struct geneve_opt {
uint8_t r2:1;
uint8_t r1:1;
#endif
- uint8_t opt_data[];
+ /* Option data */
+};
+
+struct genevehdr {
+#ifdef WORDS_BIGENDIAN
+ uint8_t ver:2;
+ uint8_t opt_len:6;
+ uint8_t oam:1;
+ uint8_t critical:1;
+ uint8_t rsvd1:6;
+#else
+ uint8_t opt_len:6;
+ uint8_t ver:2;
+ uint8_t rsvd1:6;
+ uint8_t critical:1;
+ uint8_t oam:1;
+#endif
+ ovs_be16 proto_type;
+ ovs_16aligned_be32 vni;
+ struct geneve_opt options[];
};
/* GRE protocol header */
@@ -787,5 +806,6 @@ void packet_format_tcp_flags(struct ds *, uint16_t);
const char *packet_tcp_flag_to_string(uint32_t flag);
void compose_arp(struct dp_packet *b, const uint8_t eth_src[ETH_ADDR_LEN],
ovs_be32 ip_src, ovs_be32 ip_dst);
+uint32_t packet_csum_pseudoheader(const struct ip_header *);
#endif /* packets.h */
diff --git a/lib/sset.c b/lib/sset.c
index 443538d64..33c42989a 100644
--- a/lib/sset.c
+++ b/lib/sset.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -269,21 +269,12 @@ sset_at_position(const struct sset *set, uint32_t *bucketp, uint32_t *offsetp)
return SSET_NODE_FROM_HMAP_NODE(hmap_node);
}
-static int
-compare_string_pointers(const void *a_, const void *b_)
-{
- const char *const *a = a_;
- const char *const *b = b_;
-
- return strcmp(*a, *b);
-}
-
-/* Returns a null-terminated array of pointers to the strings in 'set', sorted
- * alphabetically. The caller must free the returned array when it is no
+/* Returns a null-terminated array of pointers to the strings in 'set', in no
+ * particular order. The caller must free the returned array when it is no
* longer needed, but the strings in the array belong to 'set' and thus must
* not be modified or freed. */
const char **
-sset_sort(const struct sset *set)
+sset_array(const struct sset *set)
{
size_t n = sset_count(set);
const char **array;
@@ -298,7 +289,26 @@ sset_sort(const struct sset *set)
ovs_assert(i == n);
array[n] = NULL;
- qsort(array, n, sizeof *array, compare_string_pointers);
+ return array;
+}
+
+static int
+compare_string_pointers(const void *a_, const void *b_)
+{
+ const char *const *a = a_;
+ const char *const *b = b_;
+
+ return strcmp(*a, *b);
+}
+/* Returns a null-terminated array of pointers to the strings in 'set', sorted
+ * alphabetically. The caller must free the returned array when it is no
+ * longer needed, but the strings in the array belong to 'set' and thus must
+ * not be modified or freed. */
+const char **
+sset_sort(const struct sset *set)
+{
+ const char **array = sset_array(set);
+ qsort(array, sset_count(set), sizeof *array, compare_string_pointers);
return array;
}
diff --git a/lib/sset.h b/lib/sset.h
index 1e864efce..35bf46320 100644
--- a/lib/sset.h
+++ b/lib/sset.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -80,6 +80,7 @@ struct sset_node *sset_at_position(const struct sset *,
: false); \
(NAME) = (NEXT))
+const char **sset_array(const struct sset *);
const char **sset_sort(const struct sset *);
/* Implementation helper macros. */
diff --git a/lib/vconn.c b/lib/vconn.c
index a59829d52..c033b48d8 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -881,13 +881,11 @@ int
vconn_transact_multiple_noreply(struct vconn *vconn, struct ovs_list *requests,
struct ofpbuf **replyp)
{
- struct ofpbuf *request, *next;
+ struct ofpbuf *request;
- LIST_FOR_EACH_SAFE (request, next, list_node, requests) {
+ LIST_FOR_EACH_POP (request, list_node, requests) {
int error;
- list_remove(&request->list_node);
-
error = vconn_transact_noreply(vconn, request, replyp);
if (error || *replyp) {
ofpbuf_list_delete(requests);
diff --git a/ofproto/bond.c b/ofproto/bond.c
index 7831fa41e..2e3ad2957 100644
--- a/ofproto/bond.c
+++ b/ofproto/bond.c
@@ -28,6 +28,7 @@
#include "ofpbuf.h"
#include "ofproto/ofproto-provider.h"
#include "ofproto/ofproto-dpif.h"
+#include "ofproto/ofproto-dpif-rid.h"
#include "connectivity.h"
#include "coverage.h"
#include "dynamic-string.h"
@@ -289,7 +290,7 @@ bond_unref(struct bond *bond)
hmap_destroy(&bond->pr_rule_ops);
if (bond->recirc_id) {
- ofproto_dpif_free_recirc_id(bond->ofproto, bond->recirc_id);
+ recirc_free_id(bond->recirc_id);
}
free(bond);
@@ -446,10 +447,10 @@ bond_reconfigure(struct bond *bond, const struct bond_settings *s)
if (bond->balance != BM_AB) {
if (!bond->recirc_id) {
- bond->recirc_id = ofproto_dpif_alloc_recirc_id(bond->ofproto);
+ bond->recirc_id = recirc_alloc_id(bond->ofproto);
}
} else if (bond->recirc_id) {
- ofproto_dpif_free_recirc_id(bond->ofproto, bond->recirc_id);
+ recirc_free_id(bond->recirc_id);
bond->recirc_id = 0;
}
diff --git a/ofproto/bundles.c b/ofproto/bundles.c
index 4d9deacf9..c40909150 100644
--- a/ofproto/bundles.c
+++ b/ofproto/bundles.c
@@ -100,11 +100,10 @@ ofp_bundle_create(uint32_t id, uint16_t flags)
static void
ofp_bundle_remove(struct ofconn *ofconn, struct ofp_bundle *item)
{
- struct bundle_message *msg, *next;
+ struct bundle_message *msg;
struct hmap *bundles;
- LIST_FOR_EACH_SAFE (msg, next, node, &item->msg_list) {
- list_remove(&msg->node);
+ LIST_FOR_EACH_POP (msg, node, &item->msg_list) {
free(msg->msg);
free(msg);
}
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index f34652bfa..707385f00 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -1093,10 +1093,9 @@ ofconn_send_reply(const struct ofconn *ofconn, struct ofpbuf *msg)
void
ofconn_send_replies(const struct ofconn *ofconn, struct ovs_list *replies)
{
- struct ofpbuf *reply, *next;
+ struct ofpbuf *reply;
- LIST_FOR_EACH_SAFE (reply, next, list_node, replies) {
- list_remove(&reply->list_node);
+ LIST_FOR_EACH_POP (reply, list_node, replies) {
ofconn_send_reply(ofconn, reply);
}
}
@@ -1724,11 +1723,9 @@ connmgr_send_packet_in(struct connmgr *mgr,
static void
do_send_packet_ins(struct ofconn *ofconn, struct ovs_list *txq)
{
- struct ofpbuf *pin, *next_pin;
-
- LIST_FOR_EACH_SAFE (pin, next_pin, list_node, txq) {
- list_remove(&pin->list_node);
+ struct ofpbuf *pin;
+ LIST_FOR_EACH_POP (pin, list_node, txq) {
if (rconn_send_with_limit(ofconn->rconn, pin,
ofconn->packet_in_counter, 100) == EAGAIN) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5);
@@ -2255,12 +2252,11 @@ ofmonitor_flush(struct connmgr *mgr)
struct ofconn *ofconn;
LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
- struct ofpbuf *msg, *next;
+ struct ofpbuf *msg;
- LIST_FOR_EACH_SAFE (msg, next, list_node, &ofconn->updates) {
+ LIST_FOR_EACH_POP (msg, list_node, &ofconn->updates) {
unsigned int n_bytes;
- list_remove(&msg->list_node);
ofconn_send(ofconn, msg, ofconn->monitor_counter);
n_bytes = rconn_packet_counter_n_bytes(ofconn->monitor_counter);
if (!ofconn->monitor_paused && n_bytes > 128 * 1024) {
diff --git a/ofproto/ofproto-dpif-rid.c b/ofproto/ofproto-dpif-rid.c
index afad3ce34..f1b3bdcf8 100644
--- a/ofproto/ofproto-dpif-rid.c
+++ b/ofproto/ofproto-dpif-rid.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Nicira, Inc.
+ * Copyright (c) 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,59 +16,350 @@
#include <config.h>
-#include "id-pool.h"
-#include "ovs-thread.h"
+#include "ofpbuf.h"
+#include "ofproto-dpif.h"
#include "ofproto-dpif-rid.h"
+#include "ofproto-provider.h"
+#include "openvswitch/vlog.h"
-struct recirc_id_pool {
- struct ovs_mutex lock;
- struct id_pool *rids;
-};
+VLOG_DEFINE_THIS_MODULE(ofproto_dpif_rid);
-#define RECIRC_ID_BASE 300
-#define RECIRC_ID_N_IDS 1024
+static struct ovs_mutex mutex;
-struct recirc_id_pool *
-recirc_id_pool_create(void)
+static struct cmap id_map;
+static struct cmap metadata_map;
+
+static struct ovs_list expiring OVS_GUARDED_BY(mutex);
+static struct ovs_list expired OVS_GUARDED_BY(mutex);
+
+static uint32_t next_id OVS_GUARDED_BY(mutex); /* Possible next free id. */
+
+#define RECIRC_POOL_STATIC_IDS 1024
+
+void
+recirc_init(void)
{
- struct recirc_id_pool *pool;
+ static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
- pool = xmalloc(sizeof *pool);
- pool->rids = id_pool_create(RECIRC_ID_BASE, RECIRC_ID_N_IDS);
- ovs_mutex_init(&pool->lock);
+ if (ovsthread_once_start(&once)) {
+ ovs_mutex_init(&mutex);
+ ovs_mutex_lock(&mutex);
+ next_id = 1; /* 0 is not a valid ID. */
+ cmap_init(&id_map);
+ cmap_init(&metadata_map);
+ list_init(&expiring);
+ list_init(&expired);
+ ovs_mutex_unlock(&mutex);
+
+ ovsthread_once_done(&once);
+ }
- return pool;
}
+/* This should be called by the revalidator once at each round (every 500ms or
+ * more). */
void
-recirc_id_pool_destroy(struct recirc_id_pool *pool)
+recirc_run(void)
+{
+ static long long int last = 0;
+ long long int now = time_msec();
+
+ /* Do maintenance at most 4 times / sec. */
+ ovs_mutex_lock(&mutex);
+ if (now - last > 250) {
+ struct recirc_id_node *node;
+
+ last = now;
+
+ /* Nodes in 'expiring' and 'expired' lists have the refcount of zero,
+ * which means that while they can still be found (by id), no new
+ * references can be taken on them. We have removed the entry from the
+ * 'metadata_map', at the time when refcount reached zero, causing any
+ * new translations to allocate a new ID. This allows the expiring
+ * entry to be safely deleted while any sudden new use of the similar
+ * recirculation will safely start using a new recirculation ID. When
+ * the refcount gets to zero, the node is also added to the 'expiring'
+ * list. At any time after that the nodes in the 'expiring' list can
+ * be moved to the 'expired' list, from which they are deleted at least
+ * 250ms afterwards. */
+
+ /* Delete the expired. These have been lingering for at least 250 ms,
+ * which should be enough for any ongoing recirculations to be
+ * finished. */
+ LIST_FOR_EACH_POP (node, exp_node, &expired) {
+ cmap_remove(&id_map, &node->id_node, node->id);
+ ovsrcu_postpone(free, node);
+ }
+
+ if (!list_is_empty(&expiring)) {
+ /* 'expired' is now empty, move nodes in 'expiring' to it. */
+ list_splice(&expired, list_front(&expiring), &expiring);
+ }
+ }
+ ovs_mutex_unlock(&mutex);
+}
+
+/* We use the id as the hash value, which works due to cmap internal rehashing.
+ * We also only insert nodes with unique IDs, so all possible hash collisions
+ * remain internal to the cmap. */
+static struct recirc_id_node *
+recirc_find__(uint32_t id)
+ OVS_REQUIRES(mutex)
+{
+ struct cmap_node *node = cmap_find_protected(&id_map, id);
+
+ return node ? CONTAINER_OF(node, struct recirc_id_node, id_node) : NULL;
+}
+
+/* Lockless RCU protected lookup. If node is needed accross RCU quiescent
+ * state, caller should copy the contents. */
+const struct recirc_id_node *
+recirc_id_node_find(uint32_t id)
+{
+ const struct cmap_node *node = cmap_find(&id_map, id);
+
+ return node
+ ? CONTAINER_OF(node, const struct recirc_id_node, id_node)
+ : NULL;
+}
+
+static uint32_t
+recirc_metadata_hash(struct ofproto_dpif *ofproto, uint8_t table_id,
+ struct recirc_metadata *md, struct ofpbuf *stack,
+ uint32_t action_set_len, uint32_t ofpacts_len,
+ const struct ofpact *ofpacts)
+{
+ uint32_t hash;
+
+ BUILD_ASSERT(OFPACT_ALIGNTO == sizeof(uint64_t));
+
+ hash = hash_pointer(ofproto, 0);
+ hash = hash_int(table_id, hash);
+ hash = hash_words64((const uint64_t *)md, sizeof *md / sizeof(uint64_t),
+ hash);
+ if (stack && stack->size != 0) {
+ hash = hash_words64((const uint64_t *)stack->data,
+ stack->size / sizeof(uint64_t), hash);
+ }
+ hash = hash_int(action_set_len, hash);
+ if (ofpacts_len) {
+ hash = hash_words64(ALIGNED_CAST(const uint64_t *, ofpacts),
+ OFPACT_ALIGN(ofpacts_len) / sizeof(uint64_t),
+ hash);
+ }
+ return hash;
+}
+
+static bool
+recirc_metadata_equal(const struct recirc_id_node *node,
+ struct ofproto_dpif *ofproto, uint8_t table_id,
+ struct recirc_metadata *md, struct ofpbuf *stack,
+ uint32_t action_set_len, uint32_t ofpacts_len,
+ const struct ofpact *ofpacts)
+{
+ return node->ofproto == ofproto
+ && node->table_id == table_id
+ && !memcmp(&node->metadata, md, sizeof *md)
+ && ((!node->stack && (!stack || stack->size == 0))
+ || (node->stack && stack && ofpbuf_equal(node->stack, stack)))
+ && node->action_set_len == action_set_len
+ && node->ofpacts_len == ofpacts_len
+ && (ofpacts_len == 0 || !memcmp(node->ofpacts, ofpacts, ofpacts_len));
+}
+
+/* Lockless RCU protected lookup. If node is needed accross RCU quiescent
+ * state, caller should take a reference. */
+static struct recirc_id_node *
+recirc_find_equal(struct ofproto_dpif *ofproto, uint8_t table_id,
+ struct recirc_metadata *md, struct ofpbuf *stack,
+ uint32_t action_set_len, uint32_t ofpacts_len,
+ const struct ofpact *ofpacts, uint32_t hash)
+{
+ struct recirc_id_node *node;
+
+ CMAP_FOR_EACH_WITH_HASH(node, metadata_node, hash, &metadata_map) {
+ if (recirc_metadata_equal(node, ofproto, table_id, md, stack,
+ action_set_len, ofpacts_len, ofpacts)) {
+ return node;
+ }
+ }
+ return NULL;
+}
+
+static struct recirc_id_node *
+recirc_ref_equal(struct ofproto_dpif *ofproto, uint8_t table_id,
+ struct recirc_metadata *md, struct ofpbuf *stack,
+ uint32_t action_set_len, uint32_t ofpacts_len,
+ const struct ofpact *ofpacts, uint32_t hash)
+{
+ struct recirc_id_node *node;
+
+ do {
+ node = recirc_find_equal(ofproto, table_id, md, stack, action_set_len,
+ ofpacts_len, ofpacts, hash);
+
+ /* Try again if the node was released before we get the reference. */
+ } while (node && !ovs_refcount_try_ref_rcu(&node->refcount));
+
+ return node;
+}
+
+/* Allocate a unique recirculation id for the given set of flow metadata.
+ * The ID space is 2^^32, so there should never be a situation in which all
+ * the IDs are used up. We loop until we find a free one.
+ * hash is recomputed if it is passed in as 0. */
+static struct recirc_id_node *
+recirc_alloc_id__(struct ofproto_dpif *ofproto, uint8_t table_id,
+ struct recirc_metadata *md, struct ofpbuf *stack,
+ uint32_t action_set_len, uint32_t ofpacts_len,
+ const struct ofpact *ofpacts, uint32_t hash)
+{
+ struct recirc_id_node *node = xzalloc(sizeof *node +
+ OFPACT_ALIGN(ofpacts_len));
+ node->hash = hash;
+ ovs_refcount_init(&node->refcount);
+
+ node->ofproto = ofproto;
+ node->table_id = table_id;
+ memcpy(&node->metadata, md, sizeof node->metadata);
+ node->stack = (stack && stack->size) ? ofpbuf_clone(stack) : NULL;
+ node->action_set_len = action_set_len;
+ node->ofpacts_len = ofpacts_len;
+ if (ofpacts_len) {
+ memcpy(node->ofpacts, ofpacts, ofpacts_len);
+ }
+
+ ovs_mutex_lock(&mutex);
+ for (;;) {
+ /* Claim the next ID. The ID space should be sparse enough for the
+ allocation to succeed at the first try. We do skip the first
+ RECIRC_POOL_STATIC_IDS IDs on the later rounds, though, as some of
+ the initial allocations may be for long term uses (like bonds). */
+ node->id = next_id++;
+ if (OVS_UNLIKELY(!node->id)) {
+ next_id = RECIRC_POOL_STATIC_IDS + 1;
+ node->id = next_id++;
+ }
+ /* Find if the id is free. */
+ if (OVS_LIKELY(!recirc_find__(node->id))) {
+ break;
+ }
+ }
+ cmap_insert(&id_map, &node->id_node, node->id);
+ cmap_insert(&metadata_map, &node->metadata_node, node->hash);
+ ovs_mutex_unlock(&mutex);
+ return node;
+}
+
+/* Look up an existing ID for the given flow's metadata and optional actions.
+ */
+uint32_t
+recirc_find_id(struct ofproto_dpif *ofproto, uint8_t table_id,
+ struct recirc_metadata *md, struct ofpbuf *stack,
+ uint32_t action_set_len, uint32_t ofpacts_len,
+ const struct ofpact *ofpacts)
+{
+ /* Check if an ID with the given metadata already exists. */
+ struct recirc_id_node *node;
+ uint32_t hash;
+
+ hash = recirc_metadata_hash(ofproto, table_id, md, stack, action_set_len,
+ ofpacts_len, ofpacts);
+ node = recirc_find_equal(ofproto, table_id, md, stack, action_set_len,
+ ofpacts_len, ofpacts, hash);
+
+ return node ? node->id : 0;
+}
+
+/* Allocate a unique recirculation id for the given set of flow metadata and
+ optional actions. */
+uint32_t
+recirc_alloc_id_ctx(struct ofproto_dpif *ofproto, uint8_t table_id,
+ struct recirc_metadata *md, struct ofpbuf *stack,
+ uint32_t action_set_len, uint32_t ofpacts_len,
+ const struct ofpact *ofpacts)
{
- id_pool_destroy(pool->rids);
- ovs_mutex_destroy(&pool->lock);
- free(pool);
+ struct recirc_id_node *node;
+ uint32_t hash;
+
+ /* Look up an existing ID. */
+ hash = recirc_metadata_hash(ofproto, table_id, md, stack, action_set_len,
+ ofpacts_len, ofpacts);
+ node = recirc_ref_equal(ofproto, table_id, md, stack, action_set_len,
+ ofpacts_len, ofpacts, hash);
+
+ /* Allocate a new recirc ID if needed. */
+ if (!node) {
+ ovs_assert(action_set_len <= ofpacts_len);
+
+ node = recirc_alloc_id__(ofproto, table_id, md, stack, action_set_len,
+ ofpacts_len, ofpacts, hash);
+ }
+
+ return node->id;
}
+/* Allocate a unique recirculation id. */
uint32_t
-recirc_id_alloc(struct recirc_id_pool *pool)
+recirc_alloc_id(struct ofproto_dpif *ofproto)
{
- uint32_t id;
- bool ret;
+ struct recirc_metadata md;
+ struct recirc_id_node *node;
+ uint32_t hash;
- ovs_mutex_lock(&pool->lock);
- ret = id_pool_alloc_id(pool->rids, &id);
- ovs_mutex_unlock(&pool->lock);
+ memset(&md, 0, sizeof md);
+ md.in_port = OFPP_NONE;
+ hash = recirc_metadata_hash(ofproto, TBL_INTERNAL, &md, NULL, 0, 0, NULL);
+ node = recirc_alloc_id__(ofproto, TBL_INTERNAL, &md, NULL, 0, 0, NULL,
+ hash);
+ return node->id;
+}
- if (!ret) {
- return 0;
+void
+recirc_id_node_unref(const struct recirc_id_node *node_)
+ OVS_EXCLUDED(mutex)
+{
+ struct recirc_id_node *node = CONST_CAST(struct recirc_id_node *, node_);
+
+ if (node && ovs_refcount_unref(&node->refcount) == 1) {
+ ovs_mutex_lock(&mutex);
+ /* Prevent re-use of this node by removing the node from 'metadata_map'
+ */
+ cmap_remove(&metadata_map, &node->metadata_node, node->hash);
+ /* We keep the node in the 'id_map' so that it can be found as long
+ * as it lingers, and add it to the 'expiring' list. */
+ list_insert(&expiring, &node->exp_node);
+ ovs_mutex_unlock(&mutex);
}
+}
- return id;
+void
+recirc_free_id(uint32_t id)
+{
+ const struct recirc_id_node *node;
+
+ node = recirc_id_node_find(id);
+ if (node) {
+ recirc_id_node_unref(node);
+ } else {
+ VLOG_ERR("Freeing nonexistent recirculation ID: %"PRIu32, id);
+ }
}
+/* Called when 'ofproto' is destructed. Checks for and clears any
+ * recirc_id leak.
+ * No other thread may have access to the 'ofproto' being destructed.
+ * All related datapath flows must be deleted before calling this. */
void
-recirc_id_free(struct recirc_id_pool *pool, uint32_t id)
+recirc_free_ofproto(struct ofproto_dpif *ofproto, const char *ofproto_name)
{
- ovs_mutex_lock(&pool->lock);
- id_pool_free_id(pool->rids, id);
- ovs_mutex_unlock(&pool->lock);
+ struct recirc_id_node *n;
+
+ CMAP_FOR_EACH (n, metadata_node, &metadata_map) {
+ if (n->ofproto == ofproto) {
+ VLOG_ERR("recirc_id %"PRIu32
+ " left allocated when ofproto (%s)"
+ " is destructed", n->id, ofproto_name);
+ }
+ }
}
diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h
index 3344e2a53..81a61a236 100644
--- a/ofproto/ofproto-dpif-rid.h
+++ b/ofproto/ofproto-dpif-rid.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Nicira, Inc.
+ * Copyright (c) 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,29 +20,164 @@
#include <stddef.h>
#include <stdint.h>
-struct recirc_id_pool;
+#include "cmap.h"
+#include "list.h"
+#include "ofp-actions.h"
+#include "ovs-thread.h"
+
+struct ofproto_dpif;
+struct rule;
/*
- * Recirculation ID pool.
- * ======================
+ * Recirculation
+ * =============
+ *
+ * Recirculation is a technique to allow a frame to re-enter the datapath
+ * packet processing path for one or multiple times to achieve more flexible
+ * packet processing, such modifying header fields after MPLS POP action and
+ * selecting bond a slave port for bond ports.
+ *
+ * Data path and user space interface
+ * -----------------------------------
+ *
+ * Recirculation uses two uint32_t fields, recirc_id and dp_hash, and a RECIRC
+ * action. The value recirc_id is used to select the next packet processing
+ * steps among multiple instances of recirculation. When a packet initially
+ * enters the data path it is assigned with recirc_id 0, which indicates no
+ * recirculation. Recirc_ids are managed by the user space, opaque to the
+ * data path.
+ *
+ * On the other hand, dp_hash can only be computed by the data path, opaque to
+ * the user space. In fact, user space may not able to recompute the hash
+ * value. The dp_hash value should be wildcarded for a newly received
+ * packet. HASH action specifies whether the hash is computed, and if
+ * computed, how many fields are to be included in the hash computation. The
+ * computed hash value is stored into the dp_hash field prior to recirculation.
+ *
+ * The RECIRC action sets the recirc_id field and then reprocesses the packet
+ * as if it was received on the same input port. RECIRC action works like a
+ * function call; actions listed behind the RECIRC action will be executed
+ * after its execution. RECIRC action can be nested, data path implementation
+ * limits the number of recirculation executed to prevent unreasonable nesting
+ * depth or infinite loop.
+ *
+ * User space recirculation context
+ * ---------------------------------
*
- * Recirculation ID needs to be unique for each datapath. Recirculation
- * ID pool keeps track recirculation ids.
+ * Recirculation is hidden from the OpenFlow controllers. Action translation
+ * code deduces when recirculation is necessary and issues a data path
+ * recirculation action. All OpenFlow actions to be performed after
+ * recirculation are derived from the OpenFlow pipeline and are stored with the
+ * recirculation ID. When the OpenFlow tables are changed in a way affecting
+ * the recirculation flows, new recirculation ID with new metadata and actions
+ * is allocated and the old one is timed out.
*
- * Typically, there is one recirculation ID pool for each backer.
+ * Recirculation ID pool
+ * ----------------------
*
- * In theory, Recirculation ID can be any uint32_t value, except 0.
- * The implementation usually limits it to a smaller range to ease
- * debugging.
+ * Recirculation ID needs to be unique for all data paths. Recirculation ID
+ * pool keeps track recirculation ids and stores OpenFlow pipeline translation
+ * context so that flow processing may continue after recirculation.
+ *
+ * A Recirculation ID can be any uint32_t value, except for that the value 0 is
+ * reserved for 'no recirculation' case.
*
* Thread-safety
- * =============
+ * --------------
*
* All APIs are thread safe.
- *
*/
-struct recirc_id_pool *recirc_id_pool_create(void);
-void recirc_id_pool_destroy(struct recirc_id_pool *pool);
-uint32_t recirc_id_alloc(struct recirc_id_pool *pool);
-void recirc_id_free(struct recirc_id_pool *pool, uint32_t recirc_id);
+
+/* Metadata for restoring pipeline context after recirculation. Helpers
+ * are inlined below to keep them together with the definition for easier
+ * updates. */
+BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31);
+
+struct recirc_metadata {
+ /* Metadata in struct flow. */
+ struct flow_tnl tunnel; /* Encapsulating tunnel parameters. */
+ ovs_be64 metadata; /* OpenFlow Metadata. */
+ uint64_t regs[FLOW_N_XREGS]; /* Registers. */
+ ofp_port_t in_port; /* Incoming port. */
+ ofp_port_t actset_output; /* Output port in action set. */
+};
+
+static inline void
+recirc_metadata_from_flow(struct recirc_metadata *md,
+ const struct flow *flow)
+{
+ memset(md, 0, sizeof *md);
+ md->tunnel = flow->tunnel;
+ md->metadata = flow->metadata;
+ memcpy(md->regs, flow->regs, sizeof md->regs);
+ md->in_port = flow->in_port.ofp_port;
+ md->actset_output = flow->actset_output;
+}
+
+static inline void
+recirc_metadata_to_flow(const struct recirc_metadata *md,
+ struct flow *flow)
+{
+ flow->tunnel = md->tunnel;
+ flow->metadata = md->metadata;
+ memcpy(flow->regs, md->regs, sizeof flow->regs);
+ flow->in_port.ofp_port = md->in_port;
+ flow->actset_output = md->actset_output;
+}
+
+/* Pool node fields should NOT be modified after placing the node in the pool.
+ */
+struct recirc_id_node {
+ struct ovs_list exp_node OVS_GUARDED;
+ struct cmap_node id_node;
+ struct cmap_node metadata_node;
+ uint32_t id;
+ uint32_t hash;
+ struct ovs_refcount refcount;
+
+ /* Initial table for post-recirculation processing. */
+ uint8_t table_id;
+
+ /* Pipeline context for post-recirculation processing. */
+ struct ofproto_dpif *ofproto; /* Post-recirculation bridge. */
+ struct recirc_metadata metadata; /* Flow metadata. */
+ struct ofpbuf *stack; /* Stack if any. */
+
+ /* Actions to be translated on recirculation. */
+ uint32_t action_set_len; /* How much of 'ofpacts' consists of an
+ * action set? */
+ uint32_t ofpacts_len; /* Size of 'ofpacts', in bytes. */
+ struct ofpact ofpacts[]; /* Sequence of "struct ofpacts". */
+};
+
+void recirc_init(void);
+
+/* This is only used for bonds and will go away when bonds implementation is
+ * updated to use this mechanism instead of internal rules. */
+uint32_t recirc_alloc_id(struct ofproto_dpif *);
+
+uint32_t recirc_alloc_id_ctx(struct ofproto_dpif *, uint8_t table_id,
+ struct recirc_metadata *, struct ofpbuf *stack,
+ uint32_t action_set_len, uint32_t ofpacts_len,
+ const struct ofpact *);
+uint32_t recirc_find_id(struct ofproto_dpif *, uint8_t table_id,
+ struct recirc_metadata *, struct ofpbuf *stack,
+ uint32_t action_set_len, uint32_t ofpacts_len,
+ const struct ofpact *);
+void recirc_free_id(uint32_t recirc_id);
+void recirc_free_ofproto(struct ofproto_dpif *, const char *ofproto_name);
+
+const struct recirc_id_node *recirc_id_node_find(uint32_t recirc_id);
+
+static inline bool recirc_id_node_try_ref_rcu(const struct recirc_id_node *n_)
+{
+ struct recirc_id_node *node = CONST_CAST(struct recirc_id_node *, n_);
+
+ return node ? ovs_refcount_try_ref_rcu(&node->refcount) : false;
+}
+
+void recirc_id_node_unref(const struct recirc_id_node *);
+
+void recirc_run(void);
+
#endif
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 3c80a0c03..01bc382b5 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -152,6 +152,8 @@ enum upcall_type {
struct upcall {
struct ofproto_dpif *ofproto; /* Parent ofproto. */
+ const struct recirc_id_node *recirc; /* Recirculation context. */
+ bool have_recirc_ref; /* Reference held on recirc ctx? */
/* The flow and packet are only required to be constant when using
* dpif-netdev. If a modification is absolutely necessary, a const cast
@@ -229,6 +231,10 @@ struct udpif_key {
struct odputil_keybuf buf;
struct nlattr nla;
} keybuf, maskbuf;
+
+ /* Recirculation IDs with references held by the ukey. */
+ unsigned n_recircs;
+ uint32_t recircs[]; /* 'n_recircs' id's for which references are held. */
};
/* Datapath operation with optional ukey attached. */
@@ -271,7 +277,7 @@ static void upcall_unixctl_dump_wait(struct unixctl_conn *conn, int argc,
static void upcall_unixctl_purge(struct unixctl_conn *conn, int argc,
const char *argv[], void *aux);
-static struct udpif_key *ukey_create_from_upcall(const struct upcall *);
+static struct udpif_key *ukey_create_from_upcall(struct upcall *);
static int ukey_create_from_dpif_flow(const struct udpif *,
const struct dpif_flow *,
struct udpif_key **);
@@ -737,6 +743,8 @@ udpif_revalidator(void *arg)
if (leader) {
uint64_t reval_seq;
+ recirc_run(); /* Recirculation cleanup. */
+
reval_seq = seq_read(udpif->reval_seq);
last_reval_seq = reval_seq;
@@ -903,6 +911,8 @@ upcall_receive(struct upcall *upcall, const struct dpif_backer *backer,
return error;
}
+ upcall->recirc = NULL;
+ upcall->have_recirc_ref = false;
upcall->flow = flow;
upcall->packet = packet;
upcall->ufid = ufid;
@@ -942,9 +952,21 @@ upcall_xlate(struct udpif *udpif, struct upcall *upcall,
if (upcall->type == DPIF_UC_MISS) {
xin.resubmit_stats = &stats;
+
+ if (xin.recirc) {
+ /* We may install a datapath flow only if we get a reference to the
+ * recirculation context (otherwise we could have recirculation
+ * upcalls using recirculation ID for which no context can be
+ * found). We may still execute the flow's actions even if we
+ * don't install the flow. */
+ upcall->recirc = xin.recirc;
+ upcall->have_recirc_ref = recirc_id_node_try_ref_rcu(xin.recirc);
+ }
} else {
- /* For non-miss upcalls, there's a flow in the datapath which this
- * packet was accounted to. Presumably the revalidators will deal
+ /* For non-miss upcalls, we are either executing actions (one of which
+ * is an userspace action) for an upcall, in which case the stats have
+ * already been taken care of, or there's a flow in the datapath which
+ * this packet was accounted to. Presumably the revalidators will deal
* with pushing its stats eventually. */
}
@@ -1005,8 +1027,13 @@ upcall_uninit(struct upcall *upcall)
xlate_out_uninit(&upcall->xout);
}
ofpbuf_uninit(&upcall->put_actions);
- if (!upcall->ukey_persists) {
- ukey_delete__(upcall->ukey);
+ if (upcall->ukey) {
+ if (!upcall->ukey_persists) {
+ ukey_delete__(upcall->ukey);
+ }
+ } else if (upcall->have_recirc_ref) {
+ /* The reference was transferred to the ukey if one was created. */
+ recirc_id_node_unref(upcall->recirc);
}
}
}
@@ -1056,10 +1083,16 @@ upcall_cb(const struct dp_packet *packet, const struct flow *flow, ovs_u128 *ufi
goto out;
}
- if (upcall.ukey && !ukey_install(udpif, upcall.ukey)) {
+ /* Prevent miss flow installation if the key has recirculation ID but we
+ * were not able to get a reference on it. */
+ if (type == DPIF_UC_MISS && upcall.recirc && !upcall.have_recirc_ref) {
error = ENOSPC;
+ goto out;
}
+ if (upcall.ukey && !ukey_install(udpif, upcall.ukey)) {
+ error = ENOSPC;
+ }
out:
if (!error) {
upcall.ukey_persists = true;
@@ -1189,8 +1222,12 @@ handle_upcalls(struct udpif *udpif, struct upcall *upcalls,
* - The datapath already has too many flows.
*
* - We received this packet via some flow installed in the kernel
- * already. */
- if (may_put && upcall->type == DPIF_UC_MISS) {
+ * already.
+ *
+ * - Upcall was a recirculation but we do not have a reference to
+ * to the recirculation ID. */
+ if (may_put && upcall->type == DPIF_UC_MISS &&
+ (!upcall->recirc || upcall->have_recirc_ref)) {
struct udpif_key *ukey = upcall->ukey;
upcall->ukey_persists = true;
@@ -1277,10 +1314,13 @@ ukey_create__(const struct nlattr *key, size_t key_len,
const struct nlattr *mask, size_t mask_len,
bool ufid_present, const ovs_u128 *ufid,
const int pmd_id, const struct ofpbuf *actions,
- uint64_t dump_seq, uint64_t reval_seq, long long int used)
+ uint64_t dump_seq, uint64_t reval_seq, long long int used,
+ const struct recirc_id_node *key_recirc, struct xlate_out *xout)
OVS_NO_THREAD_SAFETY_ANALYSIS
{
- struct udpif_key *ukey = xmalloc(sizeof *ukey);
+ unsigned n_recircs = (key_recirc ? 1 : 0) + (xout ? xout->n_recircs : 0);
+ struct udpif_key *ukey = xmalloc(sizeof *ukey +
+ n_recircs * sizeof *ukey->recircs);
memcpy(&ukey->keybuf, key, key_len);
ukey->key = &ukey->keybuf.nla;
@@ -1303,11 +1343,22 @@ ukey_create__(const struct nlattr *key, size_t key_len,
ukey->stats.used = used;
ukey->xcache = NULL;
+ ukey->n_recircs = n_recircs;
+ if (key_recirc) {
+ ukey->recircs[0] = key_recirc->id;
+ }
+ if (xout && xout->n_recircs) {
+ const uint32_t *act_recircs = xlate_out_get_recircs(xout);
+
+ memcpy(ukey->recircs + (key_recirc ? 1 : 0), act_recircs,
+ xout->n_recircs * sizeof *ukey->recircs);
+ xlate_out_take_recircs(xout);
+ }
return ukey;
}
static struct udpif_key *
-ukey_create_from_upcall(const struct upcall *upcall)
+ukey_create_from_upcall(struct upcall *upcall)
{
struct odputil_keybuf keystub, maskstub;
struct ofpbuf keybuf, maskbuf;
@@ -1337,7 +1388,9 @@ ukey_create_from_upcall(const struct upcall *upcall)
return ukey_create__(keybuf.data, keybuf.size, maskbuf.data, maskbuf.size,
true, upcall->ufid, upcall->pmd_id,
&upcall->put_actions, upcall->dump_seq,
- upcall->reval_seq, 0);
+ upcall->reval_seq, 0,
+ upcall->have_recirc_ref ? upcall->recirc : NULL,
+ &upcall->xout);
}
static int
@@ -1349,12 +1402,15 @@ ukey_create_from_dpif_flow(const struct udpif *udpif,
struct ofpbuf actions;
uint64_t dump_seq, reval_seq;
uint64_t stub[DPIF_FLOW_BUFSIZE / 8];
+ const struct nlattr *a;
+ unsigned int left;
- if (!flow->key_len) {
+ if (!flow->key_len || !flow->actions_len) {
struct ofpbuf buf;
int err;
- /* If the key was not provided by the datapath, fetch the full flow. */
+ /* If the key or actions were not provided by the datapath, fetch the
+ * full flow. */
ofpbuf_use_stack(&buf, &stub, sizeof stub);
err = dpif_flow_get(udpif->dpif, NULL, 0, &flow->ufid,
flow->pmd_id, &buf, &full_flow);
@@ -1363,13 +1419,23 @@ ukey_create_from_dpif_flow(const struct udpif *udpif,
}
flow = &full_flow;
}
+
+ /* Check the flow actions for recirculation action. As recirculation
+ * relies on OVS userspace internal state, we need to delete all old
+ * datapath flows with recirculation upon OVS restart. */
+ NL_ATTR_FOR_EACH_UNSAFE (a, left, flow->actions, flow->actions_len) {
+ if (nl_attr_type(a) == OVS_ACTION_ATTR_RECIRC) {
+ return EINVAL;
+ }
+ }
+
dump_seq = seq_read(udpif->dump_seq);
reval_seq = seq_read(udpif->reval_seq);
ofpbuf_use_const(&actions, &flow->actions, flow->actions_len);
*ukey = ukey_create__(flow->key, flow->key_len,
flow->mask, flow->mask_len, flow->ufid_present,
&flow->ufid, flow->pmd_id, &actions, dump_seq,
- reval_seq, flow->stats.used);
+ reval_seq, flow->stats.used, NULL, NULL);
return 0;
}
@@ -1512,6 +1578,9 @@ ukey_delete__(struct udpif_key *ukey)
OVS_NO_THREAD_SAFETY_ANALYSIS
{
if (ukey) {
+ for (int i = 0; i < ukey->n_recircs; i++) {
+ recirc_free_id(ukey->recircs[i]);
+ }
xlate_cache_delete(ukey->xcache);
ofpbuf_delete(ukey->actions);
ovs_mutex_destroy(&ukey->mutex);
@@ -1776,8 +1845,8 @@ push_ukey_ops__(struct udpif *udpif, struct ukey_op *ops, size_t n_ops)
continue;
}
- error = xlate_lookup(udpif->backer, &flow, &ofproto,
- NULL, NULL, &netflow, &ofp_in_port);
+ error = xlate_lookup(udpif->backer, &flow, &ofproto, NULL, NULL,
+ &netflow, &ofp_in_port);
if (!error) {
struct xlate_in xin;
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 3691d728b..55ae6831a 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -71,9 +71,6 @@ VLOG_DEFINE_THIS_MODULE(ofproto_dpif_xlate);
#define MAX_INTERNAL_RESUBMITS 1 /* Max resbmits allowed using rules in
internal table. */
-/* Timeout for internal rules created to handle recirculation */
-#define RECIRC_TIMEOUT 60
-
/* Maximum number of resubmit actions in a flow translation, whether they are
* recursive or not. */
#define MAX_RESUBMITS (MAX_RESUBMIT_RECURSION * MAX_RESUBMIT_RECURSION)
@@ -208,9 +205,90 @@ struct xlate_ctx {
uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */
bool exit; /* No further actions should be processed. */
- bool use_recirc; /* Should generate recirc? */
- struct xlate_recirc recirc; /* Information used for generating
- * recirculation actions */
+ /* These are used for non-bond recirculation. The recirculation IDs are
+ * stored in xout and must be associated with a datapath flow (ukey),
+ * otherwise they will be freed when the xout is uninitialized.
+ *
+ *
+ * Steps in Recirculation Translation
+ * ==================================
+ *
+ * At some point during translation, the code recognizes the need for
+ * recirculation. For example, recirculation is necessary when, after
+ * popping the last MPLS label, an action or a match tries to examine or
+ * modify a field that has been newly revealed following the MPLS label.
+ *
+ * The simplest part of the work to be done is to commit existing changes to
+ * the packet, which produces datapath actions corresponding to the changes,
+ * and after this, add an OVS_ACTION_ATTR_RECIRC datapath action.
+ *
+ * The main problem here is preserving state. When the datapath executes
+ * OVS_ACTION_ATTR_RECIRC, it will upcall to userspace to get a translation
+ * for the post-recirculation actions. At this point userspace has to
+ * resume the translation where it left off, which means that it has to
+ * execute the following:
+ *
+ * - The action that prompted recirculation, and any actions following
+ * it within the same flow.
+ *
+ * - If the action that prompted recirculation was invoked within a
+ * NXAST_RESUBMIT, then any actions following the resubmit. These
+ * "resubmit"s can be nested, so this has to go all the way up the
+ * control stack.
+ *
+ * - The OpenFlow 1.1+ action set.
+ *
+ * State that actions and flow table lookups can depend on, such as the
+ * following, must also be preserved:
+ *
+ * - Metadata fields (input port, registers, OF1.1+ metadata, ...).
+ *
+ * - Action set, stack
+ *
+ * - The table ID and cookie of the flow being translated at each level
+ * of the control stack (since OFPAT_CONTROLLER actions send these to
+ * the controller).
+ *
+ * Translation allows for the control of this state preservation via these
+ * members. When a need for recirculation is identified, the translation
+ * process:
+ *
+ * 1. Sets 'recirc_action_offset' to the current size of 'action_set'. The
+ * action set is part of what needs to be preserved, so this allows the
+ * action set and the additional state to share the 'action_set' buffer.
+ * Later steps can tell that setup for recirculation is in progress from
+ * the nonnegative value of 'recirc_action_offset'.
+ *
+ * 2. Sets 'exit' to true to tell later steps that we're exiting from the
+ * translation process.
+ *
+ * 3. Adds an OFPACT_UNROLL_XLATE action to 'action_set'. This action
+ * holds the current table ID and cookie so that they can be restored
+ * during a post-recirculation upcall translation.
+ *
+ * 4. Adds the action that prompted recirculation and any actions following
+ * it within the same flow to 'action_set', so that they can be executed
+ * during a post-recirculation upcall translation.
+ *
+ * 5. Returns.
+ *
+ * 6. The action that prompted recirculation might be nested in a stack of
+ * nested "resubmit"s that have actions remaining. Each of these notices
+ * that we're exiting (from 'exit') and that recirculation setup is in
+ * progress (from 'recirc_action_offset') and responds by adding more
+ * OFPACT_UNROLL_XLATE actions to 'action_set', as necessary, and any
+ * actions that were yet unprocessed.
+ *
+ * The caller stores all the state produced by this process associated with
+ * the recirculation ID. For post-recirculation upcall translation, the
+ * caller passes it back in for the new translation to execute. The
+ * process yielded a set of ofpacts that can be translated directly, so it
+ * is not much of a special case at that point.
+ */
+ int recirc_action_offset; /* Offset in 'action_set' to actions to be
+ * executed after recirculation, or -1. */
+ int last_unroll_offset; /* Offset in 'action_set' to the latest unroll
+ * action, or -1. */
/* True if a packet was but is no longer MPLS (due to an MPLS pop action).
* This is a trigger for recirculation in cases where translating an action
@@ -223,12 +301,37 @@ struct xlate_ctx {
* 'action_set' accumulates "struct ofpact"s added by OFPACT_WRITE_ACTIONS.
* When translation is otherwise complete, ofpacts_execute_action_set()
* converts it to a set of "struct ofpact"s that can be translated into
- * datapath actions. */
+ * datapath actions. */
bool action_set_has_group; /* Action set contains OFPACT_GROUP? */
struct ofpbuf action_set; /* Action set. */
uint64_t action_set_stub[1024 / 8];
};
+static void xlate_action_set(struct xlate_ctx *ctx);
+
+static void
+ctx_trigger_recirculation(struct xlate_ctx *ctx)
+{
+ ctx->exit = true;
+ ctx->recirc_action_offset = ctx->action_set.size;
+}
+
+static bool
+ctx_first_recirculation_action(const struct xlate_ctx *ctx)
+{
+ return ctx->recirc_action_offset == ctx->action_set.size;
+}
+
+static inline bool
+exit_recirculates(const struct xlate_ctx *ctx)
+{
+ /* When recirculating the 'recirc_action_offset' has a non-negative value.
+ */
+ return ctx->recirc_action_offset >= 0;
+}
+
+static void compose_recirculate_action(struct xlate_ctx *ctx);
+
/* A controller may use OFPP_NONE as the ingress port to indicate that
* it did not arrive on a "real" port. 'ofpp_none_bundle' exists for
* when an input bundle is needed for validation (e.g., mirroring or
@@ -351,7 +454,16 @@ static bool input_vid_is_valid(uint16_t vid, struct xbundle *, bool warn);
static uint16_t input_vid_to_vlan(const struct xbundle *, uint16_t vid);
static void output_normal(struct xlate_ctx *, const struct xbundle *,
uint16_t vlan);
-static void compose_output_action(struct xlate_ctx *, ofp_port_t ofp_port);
+
+/* Optional bond recirculation parameter to compose_output_action(). */
+struct xlate_bond_recirc {
+ uint32_t recirc_id; /* !0 Use recirculation instead of output. */
+ uint8_t hash_alg; /* !0 Compute hash for recirc before. */
+ uint32_t hash_basis; /* Compute hash for recirc before. */
+};
+
+static void compose_output_action(struct xlate_ctx *, ofp_port_t ofp_port,
+ const struct xlate_bond_recirc *xr);
static struct xbridge *xbridge_lookup(struct xlate_cfg *,
const struct ofproto_dpif *);
@@ -837,14 +949,13 @@ xlate_bundle_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle,
static void
xlate_xbundle_remove(struct xlate_cfg *xcfg, struct xbundle *xbundle)
{
- struct xport *xport, *next;
+ struct xport *xport;
if (!xbundle) {
return;
}
- LIST_FOR_EACH_SAFE (xport, next, bundle_node, &xbundle->xports) {
- list_remove(&xport->bundle_node);
+ LIST_FOR_EACH_POP (xport, bundle_node, &xbundle->xports) {
xport->xbundle = NULL;
}
@@ -975,64 +1086,24 @@ xlate_ofport_remove(struct ofport_dpif *ofport)
xlate_xport_remove(new_xcfg, xport);
}
-/* Given a datapath and flow metadata ('backer', and 'flow' respectively)
- * returns the corresponding struct xport, or NULL if none is found. */
-static struct xport *
-xlate_lookup_xport(const struct dpif_backer *backer, const struct flow *flow)
-{
- struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
-
- return xport_lookup(xcfg, tnl_port_should_receive(flow)
- ? tnl_port_receive(flow)
- : odp_port_to_ofport(backer, flow->in_port.odp_port));
-}
-
static struct ofproto_dpif *
xlate_lookup_ofproto_(const struct dpif_backer *backer, const struct flow *flow,
ofp_port_t *ofp_in_port, const struct xport **xportp)
{
- struct ofproto_dpif *recv_ofproto = NULL;
- struct ofproto_dpif *recirc_ofproto = NULL;
+ struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
const struct xport *xport;
- ofp_port_t in_port = OFPP_NONE;
-
- *xportp = xport = xlate_lookup_xport(backer, flow);
-
- if (xport) {
- recv_ofproto = xport->xbridge->ofproto;
- in_port = xport->ofp_port;
- }
- /* When recirc_id is set in 'flow', checks whether the ofproto_dpif that
- * corresponds to the recirc_id is same as the receiving bridge. If they
- * are the same, uses the 'recv_ofproto' and keeps the 'ofp_in_port' as
- * assigned. Otherwise, uses the 'recirc_ofproto' that owns recirc_id and
- * assigns OFPP_NONE to 'ofp_in_port'. Doing this is in that, the
- * recirculated flow must be processced by the ofproto which originates
- * the recirculation, and as bridges can only see their own ports, the
- * in_port of the 'recv_ofproto' should not be passed to the
- * 'recirc_ofproto'.
- *
- * Admittedly, setting the 'ofp_in_port' to OFPP_NONE limits the
- * 'recirc_ofproto' from meaningfully matching on in_port of recirculated
- * flow, and should be fixed in the near future.
- *
- * TODO: Restore the original patch port.
- */
- if (recv_ofproto && flow->recirc_id) {
- recirc_ofproto = ofproto_dpif_recirc_get_ofproto(backer,
- flow->recirc_id);
- if (recv_ofproto != recirc_ofproto) {
- *xportp = xport = NULL;
- in_port = OFPP_NONE;
- }
+ xport = xport_lookup(xcfg, tnl_port_should_receive(flow)
+ ? tnl_port_receive(flow)
+ : odp_port_to_ofport(backer, flow->in_port.odp_port));
+ if (OVS_UNLIKELY(!xport)) {
+ return NULL;
}
-
+ *xportp = xport;
if (ofp_in_port) {
- *ofp_in_port = in_port;
+ *ofp_in_port = xport->ofp_port;
}
-
- return xport ? recv_ofproto : recirc_ofproto;
+ return xport->xbridge->ofproto;
}
/* Given a datapath and flow metadata ('backer', and 'flow' respectively)
@@ -1668,28 +1739,28 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
uint16_t vid;
ovs_be16 tci, old_tci;
struct xport *xport;
+ struct xlate_bond_recirc xr;
+ bool use_recirc = false;
vid = output_vlan_to_vid(out_xbundle, vlan);
if (list_is_empty(&out_xbundle->xports)) {
/* Partially configured bundle with no slaves. Drop the packet. */
return;
} else if (!out_xbundle->bond) {
- ctx->use_recirc = false;
xport = CONTAINER_OF(list_front(&out_xbundle->xports), struct xport,
bundle_node);
} else {
struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
struct flow_wildcards *wc = &ctx->xout->wc;
- struct xlate_recirc *xr = &ctx->recirc;
struct ofport_dpif *ofport;
if (ctx->xbridge->enable_recirc) {
- ctx->use_recirc = bond_may_recirc(
- out_xbundle->bond, &xr->recirc_id, &xr->hash_basis);
+ use_recirc = bond_may_recirc(
+ out_xbundle->bond, &xr.recirc_id, &xr.hash_basis);
- if (ctx->use_recirc) {
+ if (use_recirc) {
/* Only TCP mode uses recirculation. */
- xr->hash_alg = OVS_HASH_ALG_L4;
+ xr.hash_alg = OVS_HASH_ALG_L4;
bond_update_post_recirc_rules(out_xbundle->bond, false);
/* Recirculation does not require unmasking hash fields. */
@@ -1706,9 +1777,9 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
return;
}
- /* If ctx->xout->use_recirc is set, the main thread will handle stats
+ /* If use_recirc is set, the main thread will handle stats
* accounting for this bond. */
- if (!ctx->use_recirc) {
+ if (!use_recirc) {
if (ctx->xin->resubmit_stats) {
bond_account(out_xbundle->bond, &ctx->xin->flow, vid,
ctx->xin->resubmit_stats->n_bytes);
@@ -1736,7 +1807,7 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
}
*flow_tci = tci;
- compose_output_action(ctx, xport->ofp_port);
+ compose_output_action(ctx, xport->ofp_port, use_recirc ? &xr : NULL);
*flow_tci = old_tci;
}
@@ -2671,7 +2742,7 @@ build_tunnel_send(const struct xlate_ctx *ctx, const struct xport *xport,
static void
compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
- bool check_stp)
+ const struct xlate_bond_recirc *xr, bool check_stp)
{
const struct xport *xport = get_ofp_port(ctx->xbridge, ofp_port);
struct flow_wildcards *wc = &ctx->xout->wc;
@@ -2729,12 +2800,15 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
if (xport->peer) {
const struct xport *peer = xport->peer;
struct flow old_flow = ctx->xin->flow;
+ bool old_was_mpls = ctx->was_mpls;
enum slow_path_reason special;
- uint8_t table_id = rule_dpif_lookup_get_init_table_id(&ctx->xin->flow);
struct ofpbuf old_stack = ctx->stack;
union mf_subvalue new_stack[1024 / sizeof(union mf_subvalue)];
+ struct ofpbuf old_action_set = ctx->action_set;
+ uint64_t actset_stub[1024 / 8];
ofpbuf_use_stub(&ctx->stack, new_stack, sizeof new_stack);
+ ofpbuf_use_stub(&ctx->action_set, actset_stub, sizeof actset_stub);
ctx->xbridge = peer->xbridge;
flow->in_port.ofp_port = peer->ofp_port;
flow->metadata = htonll(0);
@@ -2748,27 +2822,57 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
ctx->xout->slow |= special;
} else if (may_receive(peer, ctx)) {
if (xport_stp_forward_state(peer) && xport_rstp_forward_state(peer)) {
- xlate_table_action(ctx, flow->in_port.ofp_port, table_id,
- true, true);
+ xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true);
+ if (ctx->action_set.size) {
+ /* Translate action set only if not dropping the packet and
+ * not recirculating. */
+ if (!exit_recirculates(ctx)) {
+ xlate_action_set(ctx);
+ }
+ }
+ /* Check if need to recirculate. */
+ if (exit_recirculates(ctx)) {
+ compose_recirculate_action(ctx);
+ }
} else {
/* Forwarding is disabled by STP and RSTP. Let OFPP_NORMAL and
* the learning action look at the packet, then drop it. */
struct flow old_base_flow = ctx->base_flow;
size_t old_size = ctx->xout->odp_actions->size;
mirror_mask_t old_mirrors = ctx->xout->mirrors;
- xlate_table_action(ctx, flow->in_port.ofp_port, table_id,
- true, true);
+
+ xlate_table_action(ctx, flow->in_port.ofp_port, 0, true, true);
ctx->xout->mirrors = old_mirrors;
ctx->base_flow = old_base_flow;
ctx->xout->odp_actions->size = old_size;
+
+ /* Undo changes that may have been done for recirculation. */
+ if (exit_recirculates(ctx)) {
+ ctx->action_set.size = ctx->recirc_action_offset;
+ ctx->recirc_action_offset = -1;
+ ctx->last_unroll_offset = -1;
+ }
}
}
ctx->xin->flow = old_flow;
ctx->xbridge = xport->xbridge;
+ ofpbuf_uninit(&ctx->action_set);
+ ctx->action_set = old_action_set;
ofpbuf_uninit(&ctx->stack);
ctx->stack = old_stack;
+ /* The peer bridge popping MPLS should have no effect on the original
+ * bridge. */
+ ctx->was_mpls = old_was_mpls;
+
+ /* The fact that the peer bridge exits (for any reason) does not mean
+ * that the original bridge should exit. Specifically, if the peer
+ * bridge recirculates (which typically modifies the packet), the
+ * original bridge must continue processing with the original, not the
+ * recirculated packet! */
+ ctx->exit = false;
+
if (ctx->xin->resubmit_stats) {
netdev_vport_inc_tx(xport->netdev, ctx->xin->resubmit_stats);
netdev_vport_inc_rx(peer->netdev, ctx->xin->resubmit_stats);
@@ -2854,9 +2958,8 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
wc,
ctx->xbridge->masked_set_action);
- if (ctx->use_recirc) {
+ if (xr) {
struct ovs_action_hash *act_hash;
- struct xlate_recirc *xr = &ctx->recirc;
/* Hash action. */
act_hash = nl_msg_put_unspec_uninit(ctx->xout->odp_actions,
@@ -2912,9 +3015,10 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port,
}
static void
-compose_output_action(struct xlate_ctx *ctx, ofp_port_t ofp_port)
+compose_output_action(struct xlate_ctx *ctx, ofp_port_t ofp_port,
+ const struct xlate_bond_recirc *xr)
{
- compose_output_action__(ctx, ofp_port, true);
+ compose_output_action__(ctx, ofp_port, xr, true);
}
static void
@@ -2964,6 +3068,11 @@ static void
xlate_table_action(struct xlate_ctx *ctx, ofp_port_t in_port, uint8_t table_id,
bool may_packet_in, bool honor_table_miss)
{
+ /* Check if we need to recirculate before matching in a table. */
+ if (ctx->was_mpls) {
+ ctx_trigger_recirculation(ctx);
+ return;
+ }
if (xlate_resubmit_resource_check(ctx)) {
struct flow_wildcards *wc;
uint8_t old_table_id = ctx->table_id;
@@ -3025,6 +3134,8 @@ xlate_group_bucket(struct xlate_ctx *ctx, struct ofputil_bucket *bucket)
{
uint64_t action_list_stub[1024 / 8];
struct ofpbuf action_list, action_set;
+ struct flow old_flow = ctx->xin->flow;
+ bool old_was_mpls = ctx->was_mpls;
ofpbuf_use_const(&action_set, bucket->ofpacts, bucket->ofpacts_len);
ofpbuf_use_stub(&action_list, action_list_stub, sizeof action_list_stub);
@@ -3036,6 +3147,38 @@ xlate_group_bucket(struct xlate_ctx *ctx, struct ofputil_bucket *bucket)
ofpbuf_uninit(&action_set);
ofpbuf_uninit(&action_list);
+
+ /* Check if need to recirculate. */
+ if (exit_recirculates(ctx)) {
+ compose_recirculate_action(ctx);
+ }
+
+ /* Roll back flow to previous state.
+ * This is equivalent to cloning the packet for each bucket.
+ *
+ * As a side effect any subsequently applied actions will
+ * also effectively be applied to a clone of the packet taken
+ * just before applying the all or indirect group.
+ *
+ * Note that group buckets are action sets, hence they cannot modify the
+ * main action set. Also any stack actions are ignored when executing an
+ * action set, so group buckets cannot change the stack either.
+ * However, we do allow resubmit actions in group buckets, which could
+ * break the above assumptions. It is up to the controller to not mess up
+ * with the action_set and stack in the tables resubmitted to from
+ * group buckets. */
+ ctx->xin->flow = old_flow;
+
+ /* The group bucket popping MPLS should have no effect after bucket
+ * execution. */
+ ctx->was_mpls = old_was_mpls;
+
+ /* The fact that the group bucket exits (for any reason) does not mean that
+ * the translation after the group action should exit. Specifically, if
+ * the group bucket recirculates (which typically modifies the packet), the
+ * actions after the group action must continue processing with the
+ * original, not the recirculated packet! */
+ ctx->exit = false;
}
static void
@@ -3043,19 +3186,11 @@ xlate_all_group(struct xlate_ctx *ctx, struct group_dpif *group)
{
struct ofputil_bucket *bucket;
const struct ovs_list *buckets;
- struct flow old_flow = ctx->xin->flow;
group_dpif_get_buckets(group, &buckets);
LIST_FOR_EACH (bucket, list_node, buckets) {
xlate_group_bucket(ctx, bucket);
- /* Roll back flow to previous state.
- * This is equivalent to cloning the packet for each bucket.
- *
- * As a side effect any subsequently applied actions will
- * also effectively be applied to a clone of the packet taken
- * just before applying the all or indirect group. */
- ctx->xin->flow = old_flow;
}
xlate_group_stats(ctx, group, NULL);
}
@@ -3073,31 +3208,102 @@ xlate_ff_group(struct xlate_ctx *ctx, struct group_dpif *group)
}
static void
-xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
+xlate_default_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
{
struct flow_wildcards *wc = &ctx->xout->wc;
struct ofputil_bucket *bucket;
uint32_t basis;
basis = flow_hash_symmetric_l4(&ctx->xin->flow, 0);
+ flow_mask_hash_fields(&ctx->xin->flow, wc, NX_HASH_FIELDS_SYMMETRIC_L4);
bucket = group_best_live_bucket(ctx, group, basis);
if (bucket) {
- memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
- memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
- memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type);
- memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
- memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
- memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
- memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
- memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
- memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
+ xlate_group_bucket(ctx, bucket);
+ xlate_group_stats(ctx, group, bucket);
+ }
+}
+
+static void
+xlate_hash_fields_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
+{
+ struct mf_bitmap hash_fields = MF_BITMAP_INITIALIZER;
+ struct flow_wildcards *wc = &ctx->xout->wc;
+ const struct field_array *fields;
+ struct ofputil_bucket *bucket;
+ uint32_t basis;
+ int i;
+
+ fields = group_dpif_get_fields(group);
+ basis = hash_uint64(group_dpif_get_selection_method_param(group));
+
+ /* Determine which fields to hash */
+ for (i = 0; i < MFF_N_IDS; i++) {
+ if (bitmap_is_set(fields->used.bm, i)) {
+ const struct mf_field *mf;
+
+ /* If the field is already present in 'hash_fields' then
+ * this loop has already checked that it and its pre-requisites
+ * are present in the flow and its pre-requisites have
+ * already been added to 'hash_fields'. There is nothing more
+ * to do here and as an optimisation the loop can continue. */
+ if (bitmap_is_set(hash_fields.bm, i)) {
+ continue;
+ }
+
+ mf = mf_from_id(i);
+
+ /* Only hash a field if it and its pre-requisites are present
+ * in the flow. */
+ if (!mf_are_prereqs_ok(mf, &ctx->xin->flow)) {
+ continue;
+ }
+
+ /* Hash both the field and its pre-requisites */
+ mf_bitmap_set_field_and_prereqs(mf, &hash_fields);
+ }
+ }
+
+ /* Hash the fields */
+ for (i = 0; i < MFF_N_IDS; i++) {
+ if (bitmap_is_set(hash_fields.bm, i)) {
+ const struct mf_field *mf = mf_from_id(i);
+ union mf_value value;
+ int j;
+ mf_get_value(mf, &ctx->xin->flow, &value);
+ /* This seems inefficient but so does apply_mask() */
+ for (j = 0; j < mf->n_bytes; j++) {
+ ((uint8_t *) &value)[j] &= ((uint8_t *) &fields->value[i])[j];
+ }
+ basis = hash_bytes(&value, mf->n_bytes, basis);
+
+ mf_mask_field(mf, &wc->masks);
+ }
+ }
+
+ bucket = group_best_live_bucket(ctx, group, basis);
+ if (bucket) {
xlate_group_bucket(ctx, bucket);
xlate_group_stats(ctx, group, bucket);
}
}
static void
+xlate_select_group(struct xlate_ctx *ctx, struct group_dpif *group)
+{
+ const char *selection_method = group_dpif_get_selection_method(group);
+
+ if (selection_method[0] == '\0') {
+ xlate_default_select_group(ctx, group);
+ } else if (!strcasecmp("hash", selection_method)) {
+ xlate_hash_fields_select_group(ctx, group);
+ } else {
+ /* Parsing of groups should ensure this never happens */
+ OVS_NOT_REACHED();
+ }
+}
+
+static void
xlate_group_action__(struct xlate_ctx *ctx, struct group_dpif *group)
{
ctx->in_group = true;
@@ -3204,9 +3410,9 @@ flood_packets(struct xlate_ctx *ctx, bool all)
}
if (all) {
- compose_output_action__(ctx, xport->ofp_port, false);
+ compose_output_action__(ctx, xport->ofp_port, NULL, false);
} else if (!(xport->config & OFPUTIL_PC_NO_FLOOD)) {
- compose_output_action(ctx, xport->ofp_port);
+ compose_output_action(ctx, xport->ofp_port, NULL);
}
}
@@ -3268,69 +3474,53 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
dp_packet_delete(packet);
}
+/* Called only when ctx->recirc_action_offset is set. */
static void
-compose_recirculate_action(struct xlate_ctx *ctx,
- const struct ofpact *ofpacts_base,
- const struct ofpact *ofpact_current,
- size_t ofpacts_base_len)
+compose_recirculate_action(struct xlate_ctx *ctx)
{
+ struct recirc_metadata md;
uint32_t id;
- int error;
- unsigned ofpacts_len;
- struct match match;
- struct rule *rule;
- struct ofpbuf ofpacts;
- ctx->exit = true;
+ ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
+ ctx->xout->odp_actions,
+ &ctx->xout->wc,
+ ctx->xbridge->masked_set_action);
- ofpacts_len = ofpacts_base_len -
- ((uint8_t *)ofpact_current - (uint8_t *)ofpacts_base);
+ recirc_metadata_from_flow(&md, &ctx->xin->flow);
- if (ctx->rule) {
- id = rule_dpif_get_recirc_id(ctx->rule);
- } else {
- /* In the case where ctx has no rule then allocate a recirc id.
- * The life-cycle of this recirc id is managed by associating it
- * with the internal rule that is created to to handle
- * recirculation below.
- *
- * The known use-case of this is packet_out which
- * translates actions without a rule */
- id = ofproto_dpif_alloc_recirc_id(ctx->xbridge->ofproto);
- }
- if (!id) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_ERR_RL(&rl, "Failed to allocate recirculation id");
- return;
- }
+ ovs_assert(ctx->recirc_action_offset >= 0);
- match_init_catchall(&match);
- match_set_recirc_id(&match, id);
- ofpbuf_use_const(&ofpacts, ofpact_current, ofpacts_len);
- error = ofproto_dpif_add_internal_flow(ctx->xbridge->ofproto, &match,
- RECIRC_RULE_PRIORITY,
- RECIRC_TIMEOUT, &ofpacts, &rule);
- if (error) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_ERR_RL(&rl, "Failed to add post recirculation flow %s",
- match_to_string(&match, 0));
- if (!ctx->rule) {
- ofproto_dpif_free_recirc_id(ctx->xbridge->ofproto, id);
+ /* Only allocate recirculation ID if we have a packet. */
+ if (ctx->xin->packet) {
+ /* Allocate a unique recirc id for the given metadata state in the
+ * flow. The life-cycle of this recirc id is managed by associating it
+ * with the udpif key ('ukey') created for each new datapath flow. */
+ id = recirc_alloc_id_ctx(ctx->xbridge->ofproto, 0, &md, &ctx->stack,
+ ctx->recirc_action_offset,
+ ctx->action_set.size, ctx->action_set.data);
+ if (!id) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ VLOG_ERR_RL(&rl, "Failed to allocate recirculation id");
+ return;
}
- return;
- }
- /* If ctx has no rule then associate the recirc id, which
- * was allocated above, with the internal rule. This allows
- * the recirc id to be released when the internal rule times out. */
- if (!ctx->rule) {
- rule_set_recirc_id(rule, id);
+ xlate_out_add_recirc(ctx->xout, id);
+ } else {
+ /* Look up an existing recirc id for the given metadata state in the
+ * flow. No new reference is taken, as the ID is RCU protected and is
+ * only required temporarily for verification. */
+ id = recirc_find_id(ctx->xbridge->ofproto, 0, &md, &ctx->stack,
+ ctx->recirc_action_offset,
+ ctx->action_set.size, ctx->action_set.data);
+ /* We let zero 'id' to be used in the RECIRC action below, which will
+ * fail all revalidations as zero is not a valid recirculation ID. */
}
- ctx->xout->slow |= commit_odp_actions(&ctx->xin->flow, &ctx->base_flow,
- ctx->xout->odp_actions,
- &ctx->xout->wc,
- ctx->xbridge->masked_set_action);
nl_msg_put_u32(ctx->xout->odp_actions, OVS_ACTION_ATTR_RECIRC, id);
+
+ /* Undo changes done by recirculation. */
+ ctx->action_set.size = ctx->recirc_action_offset;
+ ctx->recirc_action_offset = -1;
+ ctx->last_unroll_offset = -1;
}
static void
@@ -3473,7 +3663,7 @@ xlate_output_action(struct xlate_ctx *ctx,
switch (port) {
case OFPP_IN_PORT:
- compose_output_action(ctx, ctx->xin->flow.in_port.ofp_port);
+ compose_output_action(ctx, ctx->xin->flow.in_port.ofp_port, NULL);
break;
case OFPP_TABLE:
xlate_table_action(ctx, ctx->xin->flow.in_port.ofp_port,
@@ -3500,7 +3690,7 @@ xlate_output_action(struct xlate_ctx *ctx,
case OFPP_LOCAL:
default:
if (port != ctx->xin->flow.in_port.ofp_port) {
- compose_output_action(ctx, port);
+ compose_output_action(ctx, port, NULL);
} else {
xlate_report(ctx, "skipping output to input port");
}
@@ -3559,7 +3749,7 @@ xlate_enqueue_action(struct xlate_ctx *ctx,
/* Add datapath actions. */
flow_priority = ctx->xin->flow.skb_priority;
ctx->xin->flow.skb_priority = priority;
- compose_output_action(ctx, ofp_port);
+ compose_output_action(ctx, ofp_port, NULL);
ctx->xin->flow.skb_priority = flow_priority;
/* Update NetFlow output port. */
@@ -3778,89 +3968,121 @@ xlate_action_set(struct xlate_ctx *ctx)
ctx->in_action_set = true;
ofpbuf_use_stub(&action_list, action_list_stub, sizeof action_list_stub);
ofpacts_execute_action_set(&action_list, &ctx->action_set);
+ /* Clear the action set, as it is not needed any more. */
+ ofpbuf_clear(&ctx->action_set);
do_xlate_actions(action_list.data, action_list.size, ctx);
ctx->in_action_set = false;
ofpbuf_uninit(&action_list);
}
-static bool
-ofpact_needs_recirculation_after_mpls(const struct ofpact *a, struct xlate_ctx *ctx)
+static void
+recirc_put_unroll_xlate(struct xlate_ctx *ctx)
{
- struct flow_wildcards *wc = &ctx->xout->wc;
- struct flow *flow = &ctx->xin->flow;
+ struct ofpact_unroll_xlate *unroll;
- if (!ctx->was_mpls) {
- return false;
+ unroll = ctx->last_unroll_offset < 0
+ ? NULL
+ : ALIGNED_CAST(struct ofpact_unroll_xlate *,
+ (char *)ctx->action_set.data + ctx->last_unroll_offset);
+
+ /* Restore the table_id and rule cookie for a potential PACKET
+ * IN if needed. */
+ if (!unroll ||
+ (ctx->table_id != unroll->rule_table_id
+ || ctx->rule_cookie != unroll->rule_cookie)) {
+
+ ctx->last_unroll_offset = ctx->action_set.size;
+ unroll = ofpact_put_UNROLL_XLATE(&ctx->action_set);
+ unroll->rule_table_id = ctx->table_id;
+ unroll->rule_cookie = ctx->rule_cookie;
}
+}
- switch (a->type) {
- case OFPACT_OUTPUT:
- case OFPACT_GROUP:
- case OFPACT_CONTROLLER:
- case OFPACT_STRIP_VLAN:
- case OFPACT_SET_VLAN_PCP:
- case OFPACT_SET_VLAN_VID:
- case OFPACT_ENQUEUE:
- case OFPACT_PUSH_VLAN:
- case OFPACT_SET_ETH_SRC:
- case OFPACT_SET_ETH_DST:
- case OFPACT_SET_TUNNEL:
- case OFPACT_SET_QUEUE:
- case OFPACT_POP_QUEUE:
- case OFPACT_CONJUNCTION:
- case OFPACT_NOTE:
- case OFPACT_OUTPUT_REG:
- case OFPACT_EXIT:
- case OFPACT_METER:
- case OFPACT_WRITE_METADATA:
- case OFPACT_WRITE_ACTIONS:
- case OFPACT_CLEAR_ACTIONS:
- case OFPACT_SAMPLE:
- return false;
- case OFPACT_POP_MPLS:
- case OFPACT_DEC_MPLS_TTL:
- case OFPACT_SET_MPLS_TTL:
- case OFPACT_SET_MPLS_TC:
- case OFPACT_SET_MPLS_LABEL:
- case OFPACT_SET_IPV4_SRC:
- case OFPACT_SET_IPV4_DST:
- case OFPACT_SET_IP_DSCP:
- case OFPACT_SET_IP_ECN:
- case OFPACT_SET_IP_TTL:
- case OFPACT_SET_L4_SRC_PORT:
- case OFPACT_SET_L4_DST_PORT:
- case OFPACT_RESUBMIT:
- case OFPACT_STACK_PUSH:
- case OFPACT_STACK_POP:
- case OFPACT_DEC_TTL:
- case OFPACT_MULTIPATH:
- case OFPACT_BUNDLE:
- case OFPACT_LEARN:
- case OFPACT_FIN_TIMEOUT:
- case OFPACT_GOTO_TABLE:
- return true;
+/* Copy remaining actions to the action_set to be executed after recirculation.
+ * UNROLL_XLATE action is inserted, if not already done so, before actions that
+ * may generate PACKET_INs from the current table and without matching another
+ * rule. */
+static void
+recirc_unroll_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
+ struct xlate_ctx *ctx)
+{
+ const struct ofpact *a;
- case OFPACT_REG_MOVE:
- return (mf_is_l3_or_higher(ofpact_get_REG_MOVE(a)->dst.field) ||
- mf_is_l3_or_higher(ofpact_get_REG_MOVE(a)->src.field));
+ OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
+ switch (a->type) {
+ /* May generate PACKET INs. */
+ case OFPACT_OUTPUT_REG:
+ case OFPACT_GROUP:
+ case OFPACT_OUTPUT:
+ case OFPACT_CONTROLLER:
+ case OFPACT_DEC_MPLS_TTL:
+ case OFPACT_DEC_TTL:
+ recirc_put_unroll_xlate(ctx);
+ break;
- case OFPACT_SET_FIELD:
- return mf_is_l3_or_higher(ofpact_get_SET_FIELD(a)->field);
+ /* These may not generate PACKET INs. */
+ case OFPACT_SET_TUNNEL:
+ case OFPACT_REG_MOVE:
+ case OFPACT_SET_FIELD:
+ case OFPACT_STACK_PUSH:
+ case OFPACT_STACK_POP:
+ case OFPACT_LEARN:
+ case OFPACT_WRITE_METADATA:
+ case OFPACT_RESUBMIT: /* May indirectly generate PACKET INs, */
+ case OFPACT_GOTO_TABLE: /* but from a different table and rule. */
+ case OFPACT_ENQUEUE:
+ case OFPACT_SET_VLAN_VID:
+ case OFPACT_SET_VLAN_PCP:
+ case OFPACT_STRIP_VLAN:
+ case OFPACT_PUSH_VLAN:
+ case OFPACT_SET_ETH_SRC:
+ case OFPACT_SET_ETH_DST:
+ case OFPACT_SET_IPV4_SRC:
+ case OFPACT_SET_IPV4_DST:
+ case OFPACT_SET_IP_DSCP:
+ case OFPACT_SET_IP_ECN:
+ case OFPACT_SET_IP_TTL:
+ case OFPACT_SET_L4_SRC_PORT:
+ case OFPACT_SET_L4_DST_PORT:
+ case OFPACT_SET_QUEUE:
+ case OFPACT_POP_QUEUE:
+ case OFPACT_PUSH_MPLS:
+ case OFPACT_POP_MPLS:
+ case OFPACT_SET_MPLS_LABEL:
+ case OFPACT_SET_MPLS_TC:
+ case OFPACT_SET_MPLS_TTL:
+ case OFPACT_MULTIPATH:
+ case OFPACT_BUNDLE:
+ case OFPACT_EXIT:
+ case OFPACT_UNROLL_XLATE:
+ case OFPACT_FIN_TIMEOUT:
+ case OFPACT_CLEAR_ACTIONS:
+ case OFPACT_WRITE_ACTIONS:
+ case OFPACT_METER:
+ case OFPACT_SAMPLE:
+ break;
- case OFPACT_PUSH_MPLS:
- /* Recirculate if it is an IP packet with a zero ttl. This may
- * indicate that the packet was previously MPLS and an MPLS pop action
- * converted it to IP. In this case recirculating should reveal the IP
- * TTL which is used as the basis for a new MPLS LSE. */
- return (!flow_count_mpls_labels(flow, wc)
- && flow->nw_ttl == 0
- && is_ip_any(flow));
+ /* These need not be copied for restoration. */
+ case OFPACT_NOTE:
+ case OFPACT_CONJUNCTION:
+ continue;
+ }
+ /* Copy the action over. */
+ ofpbuf_put(&ctx->action_set, a, OFPACT_ALIGN(a->len));
}
-
- OVS_NOT_REACHED();
}
+#define CHECK_MPLS_RECIRCULATION() \
+ if (ctx->was_mpls) { \
+ ctx_trigger_recirculation(ctx); \
+ break; \
+ }
+#define CHECK_MPLS_RECIRCULATION_IF(COND) \
+ if (COND) { \
+ CHECK_MPLS_RECIRCULATION(); \
+ }
+
static void
do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
struct xlate_ctx *ctx)
@@ -3881,14 +4103,17 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
const struct mf_field *mf;
if (ctx->exit) {
+ /* Check if need to store the remaining actions for later
+ * execution. */
+ if (exit_recirculates(ctx)) {
+ recirc_unroll_actions(a, OFPACT_ALIGN(ofpacts_len -
+ ((uint8_t *)a -
+ (uint8_t *)ofpacts)),
+ ctx);
+ }
break;
}
- if (ofpact_needs_recirculation_after_mpls(a, ctx)) {
- compose_recirculate_action(ctx, ofpacts, a, ofpacts_len);
- return;
- }
-
switch (a->type) {
case OFPACT_OUTPUT:
xlate_output_action(ctx, ofpact_get_OUTPUT(a)->port,
@@ -3897,6 +4122,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
case OFPACT_GROUP:
if (xlate_group_action(ctx, ofpact_get_GROUP(a)->group_id)) {
+ /* Group could not be found. */
return;
}
break;
@@ -3956,6 +4182,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_SET_IPV4_SRC:
+ CHECK_MPLS_RECIRCULATION();
if (flow->dl_type == htons(ETH_TYPE_IP)) {
memset(&wc->masks.nw_src, 0xff, sizeof wc->masks.nw_src);
flow->nw_src = ofpact_get_SET_IPV4_SRC(a)->ipv4;
@@ -3963,6 +4190,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_SET_IPV4_DST:
+ CHECK_MPLS_RECIRCULATION();
if (flow->dl_type == htons(ETH_TYPE_IP)) {
memset(&wc->masks.nw_dst, 0xff, sizeof wc->masks.nw_dst);
flow->nw_dst = ofpact_get_SET_IPV4_DST(a)->ipv4;
@@ -3970,6 +4198,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_SET_IP_DSCP:
+ CHECK_MPLS_RECIRCULATION();
if (is_ip_any(flow)) {
wc->masks.nw_tos |= IP_DSCP_MASK;
flow->nw_tos &= ~IP_DSCP_MASK;
@@ -3978,6 +4207,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_SET_IP_ECN:
+ CHECK_MPLS_RECIRCULATION();
if (is_ip_any(flow)) {
wc->masks.nw_tos |= IP_ECN_MASK;
flow->nw_tos &= ~IP_ECN_MASK;
@@ -3986,6 +4216,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_SET_IP_TTL:
+ CHECK_MPLS_RECIRCULATION();
if (is_ip_any(flow)) {
wc->masks.nw_ttl = 0xff;
flow->nw_ttl = ofpact_get_SET_IP_TTL(a)->ttl;
@@ -3993,6 +4224,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_SET_L4_SRC_PORT:
+ CHECK_MPLS_RECIRCULATION();
if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
memset(&wc->masks.tp_src, 0xff, sizeof wc->masks.tp_src);
@@ -4001,6 +4233,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_SET_L4_DST_PORT:
+ CHECK_MPLS_RECIRCULATION();
if (is_ip_any(flow) && !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
memset(&wc->masks.tp_dst, 0xff, sizeof wc->masks.tp_dst);
@@ -4029,10 +4262,15 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_REG_MOVE:
+ CHECK_MPLS_RECIRCULATION_IF(
+ mf_is_l3_or_higher(ofpact_get_REG_MOVE(a)->dst.field) ||
+ mf_is_l3_or_higher(ofpact_get_REG_MOVE(a)->src.field));
nxm_execute_reg_move(ofpact_get_REG_MOVE(a), flow, wc);
break;
case OFPACT_SET_FIELD:
+ CHECK_MPLS_RECIRCULATION_IF(
+ mf_is_l3_or_higher(ofpact_get_SET_FIELD(a)->field));
set_field = ofpact_get_SET_FIELD(a);
mf = set_field->field;
@@ -4058,43 +4296,62 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_STACK_PUSH:
+ CHECK_MPLS_RECIRCULATION_IF(
+ mf_is_l3_or_higher(ofpact_get_STACK_PUSH(a)->subfield.field));
nxm_execute_stack_push(ofpact_get_STACK_PUSH(a), flow, wc,
&ctx->stack);
break;
case OFPACT_STACK_POP:
+ CHECK_MPLS_RECIRCULATION_IF(
+ mf_is_l3_or_higher(ofpact_get_STACK_POP(a)->subfield.field));
nxm_execute_stack_pop(ofpact_get_STACK_POP(a), flow, wc,
&ctx->stack);
break;
case OFPACT_PUSH_MPLS:
+ /* Recirculate if it is an IP packet with a zero ttl. This may
+ * indicate that the packet was previously MPLS and an MPLS pop
+ * action converted it to IP. In this case recirculating should
+ * reveal the IP TTL which is used as the basis for a new MPLS
+ * LSE. */
+ CHECK_MPLS_RECIRCULATION_IF(
+ !flow_count_mpls_labels(flow, wc)
+ && flow->nw_ttl == 0
+ && is_ip_any(flow));
compose_mpls_push_action(ctx, ofpact_get_PUSH_MPLS(a));
break;
case OFPACT_POP_MPLS:
+ CHECK_MPLS_RECIRCULATION();
compose_mpls_pop_action(ctx, ofpact_get_POP_MPLS(a)->ethertype);
break;
case OFPACT_SET_MPLS_LABEL:
+ CHECK_MPLS_RECIRCULATION();
compose_set_mpls_label_action(
ctx, ofpact_get_SET_MPLS_LABEL(a)->label);
- break;
+ break;
case OFPACT_SET_MPLS_TC:
+ CHECK_MPLS_RECIRCULATION();
compose_set_mpls_tc_action(ctx, ofpact_get_SET_MPLS_TC(a)->tc);
break;
case OFPACT_SET_MPLS_TTL:
+ CHECK_MPLS_RECIRCULATION();
compose_set_mpls_ttl_action(ctx, ofpact_get_SET_MPLS_TTL(a)->ttl);
break;
case OFPACT_DEC_MPLS_TTL:
+ CHECK_MPLS_RECIRCULATION();
if (compose_dec_mpls_ttl_action(ctx)) {
return;
}
break;
case OFPACT_DEC_TTL:
+ CHECK_MPLS_RECIRCULATION();
wc->masks.nw_ttl = 0xff;
if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
return;
@@ -4106,10 +4363,12 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_MULTIPATH:
+ CHECK_MPLS_RECIRCULATION();
multipath_execute(ofpact_get_MULTIPATH(a), flow, wc);
break;
case OFPACT_BUNDLE:
+ CHECK_MPLS_RECIRCULATION();
xlate_bundle_action(ctx, ofpact_get_BUNDLE(a));
break;
@@ -4118,6 +4377,7 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
break;
case OFPACT_LEARN:
+ CHECK_MPLS_RECIRCULATION();
xlate_learn_action(ctx, ofpact_get_LEARN(a));
break;
@@ -4135,7 +4395,16 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
ctx->exit = true;
break;
+ case OFPACT_UNROLL_XLATE: {
+ struct ofpact_unroll_xlate *unroll = ofpact_get_UNROLL_XLATE(a);
+
+ /* Restore translation context data that was stored earlier. */
+ ctx->table_id = unroll->rule_table_id;
+ ctx->rule_cookie = unroll->rule_cookie;
+ break;
+ }
case OFPACT_FIN_TIMEOUT:
+ CHECK_MPLS_RECIRCULATION();
memset(&wc->masks.nw_proto, 0xff, sizeof wc->masks.nw_proto);
ctx->xout->has_fin_timeout = true;
xlate_fin_timeout(ctx, ofpact_get_FIN_TIMEOUT(a));
@@ -4179,6 +4448,16 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len,
xlate_sample_action(ctx, ofpact_get_SAMPLE(a));
break;
}
+
+ /* Check if need to store this and the remaining actions for later
+ * execution. */
+ if (ctx->exit && ctx_first_recirculation_action(ctx)) {
+ recirc_unroll_actions(a, OFPACT_ALIGN(ofpacts_len -
+ ((uint8_t *)a -
+ (uint8_t *)ofpacts)),
+ ctx);
+ break;
+ }
}
}
@@ -4204,13 +4483,21 @@ xlate_in_init(struct xlate_in *xin, struct ofproto_dpif *ofproto,
xin->resubmit_stats = NULL;
xin->skip_wildcards = false;
xin->odp_actions = NULL;
+
+ /* Do recirc lookup. */
+ xin->recirc = flow->recirc_id
+ ? recirc_id_node_find(flow->recirc_id)
+ : NULL;
}
void
xlate_out_uninit(struct xlate_out *xout)
{
- if (xout && xout->odp_actions == &xout->odp_actions_buf) {
- ofpbuf_uninit(xout->odp_actions);
+ if (xout) {
+ if (xout->odp_actions == &xout->odp_actions_buf) {
+ ofpbuf_uninit(xout->odp_actions);
+ }
+ xlate_out_free_recircs(xout);
}
}
@@ -4372,9 +4659,8 @@ too_many_output_actions(const struct ofpbuf *odp_actions OVS_UNUSED)
#endif
}
-/* Translates the 'ofpacts_len' bytes of "struct ofpacts" starting at 'ofpacts'
- * into datapath actions in 'odp_actions', using 'ctx'.
- *
+/* Translates the flow, actions, or rule in 'xin' into datapath actions in
+ * 'xout'.
* The caller must take responsibility for eventually freeing 'xout', with
* xlate_out_uninit(). */
void
@@ -4387,6 +4673,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
enum slow_path_reason special;
const struct ofpact *ofpacts;
+ struct xbridge *xbridge;
struct xport *in_port;
struct flow orig_flow;
struct xlate_ctx ctx;
@@ -4425,6 +4712,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
ctx.xout->has_fin_timeout = false;
ctx.xout->nf_output_iface = NF_OUT_DROP;
ctx.xout->mirrors = 0;
+ ctx.xout->n_recircs = 0;
xout->odp_actions = xin->odp_actions;
if (!xout->odp_actions) {
@@ -4434,10 +4722,13 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
}
ofpbuf_reserve(xout->odp_actions, NL_A_U32_SIZE);
- ctx.xbridge = xbridge_lookup(xcfg, xin->ofproto);
- if (!ctx.xbridge) {
+ xbridge = xbridge_lookup(xcfg, xin->ofproto);
+ if (!xbridge) {
return;
}
+ /* 'ctx.xbridge' may be changed by action processing, whereas 'xbridge'
+ * will remain set on the original input bridge. */
+ ctx.xbridge = xbridge;
ctx.rule = xin->rule;
ctx.base_flow = *flow;
@@ -4452,12 +4743,12 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
if (is_ip_any(flow)) {
wc->masks.nw_frag |= FLOW_NW_FRAG_MASK;
}
- if (ctx.xbridge->enable_recirc) {
+ if (xbridge->enable_recirc) {
/* Always exactly match recirc_id when datapath supports
* recirculation. */
wc->masks.recirc_id = UINT32_MAX;
}
- if (ctx.xbridge->netflow) {
+ if (xbridge->netflow) {
netflow_mask_wc(flow, wc);
}
}
@@ -4473,13 +4764,97 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
ctx.table_id = 0;
ctx.rule_cookie = OVS_BE64_MAX;
ctx.exit = false;
- ctx.use_recirc = false;
ctx.was_mpls = false;
+ ctx.recirc_action_offset = -1;
+ ctx.last_unroll_offset = -1;
+
+ ctx.action_set_has_group = false;
+ ofpbuf_use_stub(&ctx.action_set,
+ ctx.action_set_stub, sizeof ctx.action_set_stub);
+
+ ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack);
+
+ /* The in_port of the original packet before recirculation. */
+ in_port = get_ofp_port(xbridge, flow->in_port.ofp_port);
+
+ if (xin->recirc) {
+ const struct recirc_id_node *recirc = xin->recirc;
+
+ if (xin->ofpacts_len > 0 || ctx.rule) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+
+ VLOG_WARN_RL(&rl, "Recirculation conflict (%s)!",
+ xin->ofpacts_len > 0
+ ? "actions"
+ : "rule");
+ return;
+ }
+
+ /* Set the bridge for post-recirculation processing if needed. */
+ if (ctx.xbridge->ofproto != recirc->ofproto) {
+ struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
+ const struct xbridge *new_bridge = xbridge_lookup(xcfg,
+ recirc->ofproto);
+
+ if (OVS_UNLIKELY(!new_bridge)) {
+ /* Drop the packet if the bridge cannot be found. */
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+ VLOG_WARN_RL(&rl, "Recirculation bridge no longer exists.");
+ return;
+ }
+ ctx.xbridge = new_bridge;
+ }
+
+ /* Set the post-recirculation table id. Note: A table lookup is done
+ * only if there are no post-recirculation actions. */
+ ctx.table_id = recirc->table_id;
+
+ /* Restore pipeline metadata. May change flow's in_port and other
+ * metadata to the values that existed when recirculation was
+ * triggered. */
+ recirc_metadata_to_flow(&recirc->metadata, flow);
+
+ /* Restore stack, if any. */
+ if (recirc->stack) {
+ ofpbuf_put(&ctx.stack, recirc->stack->data, recirc->stack->size);
+ }
+
+ /* Restore action set, if any. */
+ if (recirc->action_set_len) {
+ const struct ofpact *a;
+
+ ofpbuf_put(&ctx.action_set, recirc->ofpacts,
+ recirc->action_set_len);
+
+ OFPACT_FOR_EACH(a, recirc->ofpacts, recirc->action_set_len) {
+ if (a->type == OFPACT_GROUP) {
+ ctx.action_set_has_group = true;
+ break;
+ }
+ }
+ }
+
+ /* Restore recirculation actions. If there are no actions, processing
+ * will start with a lookup in the table set above. */
+ if (recirc->ofpacts_len > recirc->action_set_len) {
+ xin->ofpacts_len = recirc->ofpacts_len - recirc->action_set_len;
+ xin->ofpacts = recirc->ofpacts +
+ recirc->action_set_len / sizeof *recirc->ofpacts;
+ }
+ } else if (OVS_UNLIKELY(flow->recirc_id)) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+
+ VLOG_WARN_RL(&rl, "Recirculation context not found for ID %"PRIx32,
+ flow->recirc_id);
+ return;
+ }
if (!xin->ofpacts && !ctx.rule) {
- rule = rule_dpif_lookup(ctx.xbridge->ofproto, flow, wc,
- ctx.xin->xcache != NULL,
- ctx.xin->resubmit_stats, &ctx.table_id);
+ rule = rule_dpif_lookup_from_table(ctx.xbridge->ofproto, flow, wc,
+ ctx.xin->xcache != NULL,
+ ctx.xin->resubmit_stats,
+ &ctx.table_id,
+ flow->in_port.ofp_port, true, true);
if (ctx.xin->resubmit_stats) {
rule_dpif_credit_stats(rule, ctx.xin->resubmit_stats);
}
@@ -4511,20 +4886,14 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
OVS_NOT_REACHED();
}
- ofpbuf_use_stub(&ctx.stack, ctx.init_stack, sizeof ctx.init_stack);
-
- ctx.action_set_has_group = false;
- ofpbuf_use_stub(&ctx.action_set,
- ctx.action_set_stub, sizeof ctx.action_set_stub);
-
- if (mbridge_has_mirrors(ctx.xbridge->mbridge)) {
+ if (mbridge_has_mirrors(xbridge->mbridge)) {
/* Do this conditionally because the copy is expensive enough that it
* shows up in profiles. */
orig_flow = *flow;
}
- in_port = get_ofp_port(ctx.xbridge, flow->in_port.ofp_port);
- if (in_port && in_port->is_tunnel) {
+ /* Tunnel stats only for non-recirculated packets. */
+ if (!xin->recirc && in_port && in_port->is_tunnel) {
if (ctx.xin->resubmit_stats) {
netdev_vport_inc_rx(in_port->netdev, ctx.xin->resubmit_stats);
if (in_port->bfd) {
@@ -4540,22 +4909,29 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
}
}
- special = process_special(&ctx, flow, in_port, ctx.xin->packet);
- if (special) {
+ /* Do not perform special processing on recirculated packets,
+ * as recirculated packets are not really received by the bridge. */
+ if (!xin->recirc &&
+ (special = process_special(&ctx, flow, in_port, ctx.xin->packet))) {
ctx.xout->slow |= special;
} else {
size_t sample_actions_len;
if (flow->in_port.ofp_port
- != vsp_realdev_to_vlandev(ctx.xbridge->ofproto,
+ != vsp_realdev_to_vlandev(xbridge->ofproto,
flow->in_port.ofp_port,
flow->vlan_tci)) {
ctx.base_flow.vlan_tci = 0;
}
- add_sflow_action(&ctx);
- add_ipfix_action(&ctx);
- sample_actions_len = ctx.xout->odp_actions->size;
+ /* Sampling is done only for packets really received by the bridge. */
+ if (!xin->recirc) {
+ add_sflow_action(&ctx);
+ add_ipfix_action(&ctx);
+ sample_actions_len = ctx.xout->odp_actions->size;
+ } else {
+ sample_actions_len = 0;
+ }
if (tnl_may_send && (!in_port || may_receive(in_port, &ctx))) {
do_xlate_actions(ofpacts, ofpacts_len, &ctx);
@@ -4566,21 +4942,40 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
!xport_rstp_forward_state(in_port))) {
/* Drop all actions added by do_xlate_actions() above. */
ctx.xout->odp_actions->size = sample_actions_len;
+
+ /* Undo changes that may have been done for recirculation. */
+ if (exit_recirculates(&ctx)) {
+ ctx.action_set.size = ctx.recirc_action_offset;
+ ctx.recirc_action_offset = -1;
+ ctx.last_unroll_offset = -1;
+ }
} else if (ctx.action_set.size) {
- /* Translate action set only if not dropping the packet. */
- xlate_action_set(&ctx);
+ /* Translate action set only if not dropping the packet and
+ * not recirculating. */
+ if (!exit_recirculates(&ctx)) {
+ xlate_action_set(&ctx);
+ }
+ }
+ /* Check if need to recirculate. */
+ if (exit_recirculates(&ctx)) {
+ compose_recirculate_action(&ctx);
}
}
- if (ctx.xbridge->has_in_band
+ /* Output only fully processed packets. */
+ if (!exit_recirculates(&ctx)
+ && xbridge->has_in_band
&& in_band_must_output_to_local_port(flow)
&& !actions_output_to_local_port(&ctx)) {
- compose_output_action(&ctx, OFPP_LOCAL);
+ compose_output_action(&ctx, OFPP_LOCAL, NULL);
}
- fix_sflow_action(&ctx);
-
- if (mbridge_has_mirrors(ctx.xbridge->mbridge)) {
+ if (!xin->recirc) {
+ fix_sflow_action(&ctx);
+ }
+ /* Only mirror fully processed packets. */
+ if (!exit_recirculates(&ctx)
+ && mbridge_has_mirrors(xbridge->mbridge)) {
add_mirror_actions(&ctx, &orig_flow);
}
}
@@ -4597,9 +4992,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
ctx.xout->slow |= SLOW_ACTION;
}
- if (mbridge_has_mirrors(ctx.xbridge->mbridge)) {
+ /* Update mirror stats only for packets really received by the bridge. */
+ if (!xin->recirc && mbridge_has_mirrors(xbridge->mbridge)) {
if (ctx.xin->resubmit_stats) {
- mirror_update_stats(ctx.xbridge->mbridge, xout->mirrors,
+ mirror_update_stats(xbridge->mbridge, xout->mirrors,
ctx.xin->resubmit_stats->n_packets,
ctx.xin->resubmit_stats->n_bytes);
}
@@ -4607,12 +5003,13 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
struct xc_entry *entry;
entry = xlate_cache_add_entry(ctx.xin->xcache, XC_MIRROR);
- entry->u.mirror.mbridge = mbridge_ref(ctx.xbridge->mbridge);
+ entry->u.mirror.mbridge = mbridge_ref(xbridge->mbridge);
entry->u.mirror.mirrors = xout->mirrors;
}
}
- if (ctx.xbridge->netflow) {
+ /* Do netflow only for packets really received by the bridge. */
+ if (!xin->recirc && xbridge->netflow) {
/* Only update netflow if we don't have controller flow. We don't
* report NetFlow expiration messages for such facets because they
* are just part of the control logic for the network, not real
@@ -4621,7 +5018,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
|| ofpacts->type != OFPACT_CONTROLLER
|| ofpact_next(ofpacts) < ofpact_end(ofpacts, ofpacts_len)) {
if (ctx.xin->resubmit_stats) {
- netflow_flow_update(ctx.xbridge->netflow, flow,
+ netflow_flow_update(xbridge->netflow, flow,
xout->nf_output_iface,
ctx.xin->resubmit_stats);
}
@@ -4629,7 +5026,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
struct xc_entry *entry;
entry = xlate_cache_add_entry(ctx.xin->xcache, XC_NETFLOW);
- entry->u.nf.netflow = netflow_ref(ctx.xbridge->netflow);
+ entry->u.nf.netflow = netflow_ref(xbridge->netflow);
entry->u.nf.flow = xmemdup(flow, sizeof *flow);
entry->u.nf.iface = xout->nf_output_iface;
}
diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
index a53fa8e4d..6c8ade308 100644
--- a/ofproto/ofproto-dpif-xlate.h
+++ b/ofproto/ofproto-dpif-xlate.h
@@ -21,6 +21,7 @@
#include "odp-util.h"
#include "ofpbuf.h"
#include "ofproto-dpif-mirror.h"
+#include "ofproto-dpif-rid.h"
#include "ofproto-dpif.h"
#include "ofproto.h"
#include "stp.h"
@@ -36,12 +37,6 @@ struct mac_learning;
struct mcast_snooping;
struct xlate_cache;
-struct xlate_recirc {
- uint32_t recirc_id; /* !0 Use recirculation instead of output. */
- uint8_t hash_alg; /* !0 Compute hash for recirc before. */
- uint32_t hash_basis; /* Compute hash for recirc before. */
-};
-
struct xlate_out {
/* Wildcards relevant in translation. Any fields that were used to
* calculate the action must be set for caching and kernel
@@ -60,11 +55,72 @@ struct xlate_out {
ofp_port_t nf_output_iface; /* Output interface index for NetFlow. */
mirror_mask_t mirrors; /* Bitmap of associated mirrors. */
+ /* Recirculation IDs on which references are held. */
+ unsigned n_recircs;
+ union {
+ uint32_t recirc[2]; /* When n_recircs == 1 or 2 */
+ uint32_t *recircs; /* When 'n_recircs' > 2 */
+ };
+
uint64_t odp_actions_stub[256 / 8];
struct ofpbuf odp_actions_buf;
struct ofpbuf *odp_actions;
};
+/* Helpers to abstract the recirculation union away. */
+static inline void
+xlate_out_add_recirc(struct xlate_out *xout, uint32_t id)
+{
+ if (OVS_LIKELY(xout->n_recircs < ARRAY_SIZE(xout->recirc))) {
+ xout->recirc[xout->n_recircs++] = id;
+ } else {
+ if (xout->n_recircs == ARRAY_SIZE(xout->recirc)) {
+ uint32_t *recircs = xmalloc(sizeof xout->recirc + sizeof id);
+
+ memcpy(recircs, xout->recirc, sizeof xout->recirc);
+ xout->recircs = recircs;
+ } else {
+ xout->recircs = xrealloc(xout->recircs,
+ (xout->n_recircs + 1) * sizeof id);
+ }
+ xout->recircs[xout->n_recircs++] = id;
+ }
+}
+
+static inline const uint32_t *
+xlate_out_get_recircs(const struct xlate_out *xout)
+{
+ if (OVS_LIKELY(xout->n_recircs <= ARRAY_SIZE(xout->recirc))) {
+ return xout->recirc;
+ } else {
+ return xout->recircs;
+ }
+}
+
+static inline void
+xlate_out_take_recircs(struct xlate_out *xout)
+{
+ if (OVS_UNLIKELY(xout->n_recircs > ARRAY_SIZE(xout->recirc))) {
+ free(xout->recircs);
+ }
+ xout->n_recircs = 0;
+}
+
+static inline void
+xlate_out_free_recircs(struct xlate_out *xout)
+{
+ if (OVS_LIKELY(xout->n_recircs <= ARRAY_SIZE(xout->recirc))) {
+ for (int i = 0; i < xout->n_recircs; i++) {
+ recirc_free_id(xout->recirc[i]);
+ }
+ } else {
+ for (int i = 0; i < xout->n_recircs; i++) {
+ recirc_free_id(xout->recircs[i]);
+ }
+ free(xout->recircs);
+ }
+}
+
struct xlate_in {
struct ofproto_dpif *ofproto;
@@ -143,6 +199,10 @@ struct xlate_in {
* odp_actions stored in xlate_out. If NULL, the default buffer will be
* used. */
struct ofpbuf *odp_actions;
+
+ /* The recirculation context related to this translation, as returned by
+ * xlate_lookup. */
+ const struct recirc_id_node *recirc;
};
void xlate_ofproto_set(struct ofproto_dpif *, const char *name, struct dpif *,
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 38ad6e253..01d99c54a 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -255,13 +255,6 @@ COVERAGE_DEFINE(rev_flow_table);
COVERAGE_DEFINE(rev_mac_learning);
COVERAGE_DEFINE(rev_mcast_snooping);
-/* Stores mapping between 'recirc_id' and 'ofproto-dpif'. */
-struct dpif_backer_recirc_node {
- struct cmap_node cmap_node;
- struct ofproto_dpif *ofproto;
- uint32_t recirc_id;
-};
-
/* All datapaths of a given type share a single dpif backer instance. */
struct dpif_backer {
char *type;
@@ -279,9 +272,6 @@ struct dpif_backer {
bool recv_set_enable; /* Enables or disables receiving packets. */
/* Recirculation. */
- struct recirc_id_pool *rid_pool; /* Recirculation ID pool. */
- struct cmap recirc_map; /* Map of 'recirc_id's to 'ofproto's. */
- struct ovs_mutex recirc_mutex; /* Protects 'recirc_map'. */
bool enable_recirc; /* True if the datapath supports recirculation */
/* True if the datapath supports unique flow identifiers */
@@ -395,8 +385,6 @@ ofproto_dpif_get_enable_ufid(struct dpif_backer *backer)
return backer->enable_ufid;
}
-static struct ofport_dpif *get_ofp_port(const struct ofproto_dpif *ofproto,
- ofp_port_t ofp_port);
static void ofproto_trace(struct ofproto_dpif *, struct flow *,
const struct dp_packet *packet,
const struct ofpact[], size_t ofpacts_len,
@@ -857,27 +845,6 @@ dealloc(struct ofproto *ofproto_)
free(ofproto);
}
-/* Called when 'ofproto' is destructed. Checks for and clears any
- * recirc_id leak. */
-static void
-dpif_backer_recirc_clear_ofproto(struct dpif_backer *backer,
- struct ofproto_dpif *ofproto)
-{
- struct dpif_backer_recirc_node *node;
-
- ovs_mutex_lock(&backer->recirc_mutex);
- CMAP_FOR_EACH (node, cmap_node, &backer->recirc_map) {
- if (node->ofproto == ofproto) {
- VLOG_ERR("recirc_id %"PRIu32", not freed when ofproto (%s) "
- "is destructed", node->recirc_id, ofproto->up.name);
- cmap_remove(&backer->recirc_map, &node->cmap_node,
- node->recirc_id);
- ovsrcu_postpone(free, node);
- }
- }
- ovs_mutex_unlock(&backer->recirc_mutex);
-}
-
static void
close_dpif_backer(struct dpif_backer *backer)
{
@@ -893,9 +860,6 @@ close_dpif_backer(struct dpif_backer *backer)
ovs_rwlock_destroy(&backer->odp_to_ofport_lock);
hmap_destroy(&backer->odp_to_ofport_map);
shash_find_and_delete(&all_dpif_backers, backer->type);
- recirc_id_pool_destroy(backer->rid_pool);
- cmap_destroy(&backer->recirc_map);
- ovs_mutex_destroy(&backer->recirc_mutex);
free(backer->type);
free(backer->dp_version_string);
dpif_close(backer->dpif);
@@ -922,13 +886,15 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
struct dpif_port port;
struct shash_node *node;
struct ovs_list garbage_list;
- struct odp_garbage *garbage, *next;
+ struct odp_garbage *garbage;
struct sset names;
char *backer_name;
const char *name;
int error;
+ recirc_init();
+
backer = shash_find_data(&all_dpif_backers, type);
if (backer) {
backer->refcount++;
@@ -998,9 +964,8 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
}
dpif_port_dump_done(&port_dump);
- LIST_FOR_EACH_SAFE (garbage, next, list_node, &garbage_list) {
+ LIST_FOR_EACH_POP (garbage, list_node, &garbage_list) {
dpif_port_del(backer->dpif, garbage->odp_port);
- list_remove(&garbage->list_node);
free(garbage);
}
@@ -1010,9 +975,6 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp)
backer->max_mpls_depth = check_max_mpls_depth(backer);
backer->masked_set_action = check_masked_set_action(backer);
backer->enable_ufid = check_ufid(backer);
- backer->rid_pool = recirc_id_pool_create();
- ovs_mutex_init(&backer->recirc_mutex);
- cmap_init(&backer->recirc_map);
backer->enable_tnl_push_pop = dpif_supports_tnl_push_pop(backer->dpif);
atomic_count_init(&backer->tnl_count, 0);
@@ -1365,7 +1327,6 @@ add_internal_flows(struct ofproto_dpif *ofproto)
uint64_t ofpacts_stub[128 / 8];
struct ofpbuf ofpacts;
struct rule *unused_rulep OVS_UNUSED;
- struct ofpact_resubmit *resubmit;
struct match match;
int error;
int id;
@@ -1408,22 +1369,6 @@ add_internal_flows(struct ofproto_dpif *ofproto)
match_set_recirc_id(&match, 0);
error = ofproto_dpif_add_internal_flow(ofproto, &match, 2, 0, &ofpacts,
&unused_rulep);
- if (error) {
- return error;
- }
-
- /* Continue rule lookups for not-matched recirc rules from table 0.
- *
- * (priority=1), actions=resubmit(, 0)
- */
- resubmit = ofpact_put_RESUBMIT(&ofpacts);
- resubmit->in_port = OFPP_IN_PORT;
- resubmit->table_id = 0;
-
- match_init_catchall(&match);
- error = ofproto_dpif_add_internal_flow(ofproto, &match, 1, 0, &ofpacts,
- &unused_rulep);
-
return error;
}
@@ -1431,7 +1376,7 @@ static void
destruct(struct ofproto *ofproto_)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- struct ofproto_packet_in *pin, *next_pin;
+ struct ofproto_packet_in *pin;
struct rule_dpif *rule;
struct oftable *table;
struct ovs_list pins;
@@ -1454,14 +1399,13 @@ destruct(struct ofproto *ofproto_)
}
guarded_list_pop_all(&ofproto->pins, &pins);
- LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) {
- list_remove(&pin->list_node);
+ LIST_FOR_EACH_POP (pin, list_node, &pins) {
free(CONST_CAST(void *, pin->up.packet));
free(pin);
}
guarded_list_destroy(&ofproto->pins);
- dpif_backer_recirc_clear_ofproto(ofproto->backer, ofproto);
+ recirc_free_ofproto(ofproto, ofproto->up.name);
mbridge_unref(ofproto->mbridge);
@@ -1510,13 +1454,12 @@ run(struct ofproto *ofproto_)
/* Do not perform any periodic activity required by 'ofproto' while
* waiting for flow restore to complete. */
if (!ofproto_get_flow_restore_wait()) {
- struct ofproto_packet_in *pin, *next_pin;
+ struct ofproto_packet_in *pin;
struct ovs_list pins;
guarded_list_pop_all(&ofproto->pins, &pins);
- LIST_FOR_EACH_SAFE (pin, next_pin, list_node, &pins) {
+ LIST_FOR_EACH_POP (pin, list_node, &pins) {
connmgr_send_packet_in(ofproto->up.connmgr, pin);
- list_remove(&pin->list_node);
free(CONST_CAST(void *, pin->up.packet));
free(pin);
}
@@ -1969,14 +1912,12 @@ static int
set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
{
struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
+ struct cfm *old = ofport->cfm;
int error = 0;
if (s) {
if (!ofport->cfm) {
- struct ofproto_dpif *ofproto;
-
- ofproto = ofproto_dpif_cast(ofport->up.ofproto);
- ofproto->backer->need_revalidate = REV_RECONFIGURE;
ofport->cfm = cfm_create(ofport->up.netdev);
}
@@ -1990,6 +1931,9 @@ set_cfm(struct ofport *ofport_, const struct cfm_settings *s)
cfm_unref(ofport->cfm);
ofport->cfm = NULL;
out:
+ if (ofport->cfm != old) {
+ ofproto->backer->need_revalidate = REV_RECONFIGURE;
+ }
ofproto_dpif_monitor_port_update(ofport, ofport->bfd, ofport->cfm,
ofport->lldp, ofport->up.pp.hw_addr);
return error;
@@ -2743,7 +2687,7 @@ bundle_add_port(struct ofbundle *bundle, ofp_port_t ofp_port,
{
struct ofport_dpif *port;
- port = get_ofp_port(bundle->ofproto, ofp_port);
+ port = ofp_port_to_ofport(bundle->ofproto, ofp_port);
if (!port) {
return false;
}
@@ -3249,8 +3193,8 @@ set_mcast_snooping_port(struct ofproto *ofproto_, void *aux,
/* Ports. */
-static struct ofport_dpif *
-get_ofp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port)
+struct ofport_dpif *
+ofp_port_to_ofport(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port)
{
struct ofport *ofport = ofproto_get_port(&ofproto->up, ofp_port);
return ofport ? ofport_dpif_cast(ofport) : NULL;
@@ -3444,7 +3388,7 @@ static int
port_del(struct ofproto *ofproto_, ofp_port_t ofp_port)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port);
+ struct ofport_dpif *ofport = ofp_port_to_ofport(ofproto, ofp_port);
int error = 0;
if (!ofport) {
@@ -3756,21 +3700,13 @@ static void
rule_dpif_set_recirc_id(struct rule_dpif *rule, uint32_t id)
OVS_REQUIRES(rule->up.mutex)
{
- ovs_assert(!rule->recirc_id);
- rule->recirc_id = id;
-}
-
-/* Returns 'rule''s recirculation id. */
-uint32_t
-rule_dpif_get_recirc_id(struct rule_dpif *rule)
- OVS_REQUIRES(rule->up.mutex)
-{
- if (!rule->recirc_id) {
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
-
- rule_dpif_set_recirc_id(rule, ofproto_dpif_alloc_recirc_id(ofproto));
+ ovs_assert(!rule->recirc_id || rule->recirc_id == id);
+ if (rule->recirc_id == id) {
+ /* Release the new reference to the same id. */
+ recirc_free_id(id);
+ } else {
+ rule->recirc_id = id;
}
- return rule->recirc_id;
}
/* Sets 'rule''s recirculation id. */
@@ -3784,32 +3720,6 @@ rule_set_recirc_id(struct rule *rule_, uint32_t id)
ovs_mutex_unlock(&rule->up.mutex);
}
-/* Lookup 'flow' in table 0 of 'ofproto''s classifier.
- * If 'wc' is non-null, sets the fields that were relevant as part of
- * the lookup. Returns the table id where a match or miss occurred via
- * 'table_id'. This will be zero unless there was a miss and
- * OFPTC11_TABLE_MISS_CONTINUE is in effect for the sequence of tables
- * where misses occur, or TBL_INTERNAL if the rule has a non-zero
- * recirculation ID, and a match was found in the internal table, or if
- * there was no match and one of the special rules (drop_frags_rule,
- * miss_rule, or no_packet_in_rule) was returned.
- *
- * The return value is the found rule, which is valid at least until the next
- * RCU quiescent period. If the rule needs to stay around longer,
- * a non-zero 'take_ref' must be passed in to cause a reference to be taken
- * on it before this returns. */
-struct rule_dpif *
-rule_dpif_lookup(struct ofproto_dpif *ofproto, struct flow *flow,
- struct flow_wildcards *wc, bool take_ref,
- const struct dpif_flow_stats *stats, uint8_t *table_id)
-{
- *table_id = rule_dpif_lookup_get_init_table_id(flow);
-
- return rule_dpif_lookup_from_table(ofproto, flow, wc, take_ref, stats,
- table_id, flow->in_port.ofp_port, true,
- true);
-}
-
/* The returned rule (if any) is valid at least until the next RCU quiescent
* period. If the rule needs to stay around longer, a non-zero 'take_ref'
* must be passed in to cause a reference to be taken on it.
@@ -3943,7 +3853,7 @@ rule_dpif_lookup_from_table(struct ofproto_dpif *ofproto, struct flow *flow,
|| miss_config == OFPUTIL_TABLE_MISS_CONTROLLER) {
struct ofport_dpif *port;
- port = get_ofp_port(ofproto, old_in_port);
+ port = ofp_port_to_ofport(ofproto, old_in_port);
if (!port) {
VLOG_WARN_RL(&rl, "packet-in on unknown OpenFlow port %"PRIu16,
old_in_port);
@@ -4034,9 +3944,7 @@ rule_destruct(struct rule *rule_)
ovs_mutex_destroy(&rule->stats_mutex);
if (rule->recirc_id) {
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
-
- ofproto_dpif_free_recirc_id(ofproto, rule->recirc_id);
+ recirc_free_id(rule->recirc_id);
}
}
@@ -4241,6 +4149,12 @@ group_dpif_get_type(const struct group_dpif *group)
{
return group->up.type;
}
+
+const char *
+group_dpif_get_selection_method(const struct group_dpif *group)
+{
+ return group->up.props.selection_method;
+}
/* Sends 'packet' out 'ofport'.
* May modify 'packet'.
@@ -4259,6 +4173,18 @@ ofproto_dpif_send_packet(const struct ofport_dpif *ofport, struct dp_packet *pac
ovs_mutex_unlock(&ofproto->stats_mutex);
return error;
}
+
+uint64_t
+group_dpif_get_selection_method_param(const struct group_dpif *group)
+{
+ return group->up.props.selection_method_param;
+}
+
+const struct field_array *
+group_dpif_get_fields(const struct group_dpif *group)
+{
+ return &group->up.props.fields;
+}
/* Return the version string of the datapath that backs up
* this 'ofproto'.
@@ -5458,7 +5384,7 @@ vsp_add(struct ofport_dpif *port, ofp_port_t realdev_ofp_port, int vid)
static odp_port_t
ofp_port_to_odp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port)
{
- const struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port);
+ const struct ofport_dpif *ofport = ofp_port_to_ofport(ofproto, ofp_port);
return ofport ? ofport->odp_port : ODPP_NONE;
}
@@ -5493,61 +5419,6 @@ odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, odp_port_t odp_port)
}
}
-struct ofproto_dpif *
-ofproto_dpif_recirc_get_ofproto(const struct dpif_backer *backer,
- uint32_t recirc_id)
-{
- struct dpif_backer_recirc_node *node;
-
- node = CONTAINER_OF(cmap_find(&backer->recirc_map, recirc_id),
- struct dpif_backer_recirc_node, cmap_node);
-
- return node ? node->ofproto : NULL;
-}
-
-uint32_t
-ofproto_dpif_alloc_recirc_id(struct ofproto_dpif *ofproto)
-{
- struct dpif_backer *backer = ofproto->backer;
- uint32_t recirc_id = recirc_id_alloc(backer->rid_pool);
-
- if (recirc_id) {
- struct dpif_backer_recirc_node *node = xmalloc(sizeof *node);
-
- node->recirc_id = recirc_id;
- node->ofproto = ofproto;
-
- ovs_mutex_lock(&backer->recirc_mutex);
- cmap_insert(&backer->recirc_map, &node->cmap_node, node->recirc_id);
- ovs_mutex_unlock(&backer->recirc_mutex);
- }
-
- return recirc_id;
-}
-
-void
-ofproto_dpif_free_recirc_id(struct ofproto_dpif *ofproto, uint32_t recirc_id)
-{
- struct dpif_backer *backer = ofproto->backer;
- struct dpif_backer_recirc_node *node;
-
- node = CONTAINER_OF(cmap_find(&backer->recirc_map, recirc_id),
- struct dpif_backer_recirc_node, cmap_node);
- if (node) {
- ovs_mutex_lock(&backer->recirc_mutex);
- cmap_remove(&backer->recirc_map, &node->cmap_node, node->recirc_id);
- ovs_mutex_unlock(&backer->recirc_mutex);
- recirc_id_free(backer->rid_pool, node->recirc_id);
-
- /* 'recirc_id' should never be freed by non-owning 'ofproto'. */
- ovs_assert(node->ofproto == ofproto);
-
- /* RCU postpone the free, since other threads may be referring
- * to 'node' at same time. */
- ovsrcu_postpone(free, node);
- }
-}
-
int
ofproto_dpif_add_internal_flow(struct ofproto_dpif *ofproto,
const struct match *match, int priority,
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index e2359cd06..956692422 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -77,11 +77,6 @@ size_t ofproto_dpif_get_max_mpls_depth(const struct ofproto_dpif *);
bool ofproto_dpif_get_enable_recirc(const struct ofproto_dpif *);
bool ofproto_dpif_get_enable_ufid(struct dpif_backer *backer);
-struct rule_dpif *rule_dpif_lookup(struct ofproto_dpif *, struct flow *,
- struct flow_wildcards *, bool take_ref,
- const struct dpif_flow_stats *,
- uint8_t *table_id);
-
struct rule_dpif *rule_dpif_lookup_from_table(struct ofproto_dpif *,
struct flow *,
struct flow_wildcards *,
@@ -92,14 +87,6 @@ struct rule_dpif *rule_dpif_lookup_from_table(struct ofproto_dpif *,
bool may_packet_in,
bool honor_table_miss);
-/* If 'recirc_id' is set, starts looking up from internal table for
- * post recirculation flows or packets. Otherwise, starts from table 0. */
-static inline uint8_t
-rule_dpif_lookup_get_init_table_id(const struct flow *flow)
-{
- return flow->recirc_id ? TBL_INTERNAL : 0;
-}
-
static inline void rule_dpif_ref(struct rule_dpif *);
static inline void rule_dpif_unref(struct rule_dpif *);
@@ -115,7 +102,6 @@ uint8_t rule_dpif_get_table(const struct rule_dpif *);
bool table_is_internal(uint8_t table_id);
const struct rule_actions *rule_dpif_get_actions(const struct rule_dpif *);
-uint32_t rule_dpif_get_recirc_id(struct rule_dpif *);
void rule_set_recirc_id(struct rule *, uint32_t id);
ovs_be64 rule_dpif_get_flow_cookie(const struct rule_dpif *rule);
@@ -137,6 +123,9 @@ bool group_dpif_lookup(struct ofproto_dpif *ofproto, uint32_t group_id,
void group_dpif_get_buckets(const struct group_dpif *group,
const struct ovs_list **buckets);
enum ofp11_group_type group_dpif_get_type(const struct group_dpif *group);
+const char *group_dpif_get_selection_method(const struct group_dpif *group);
+uint64_t group_dpif_get_selection_method_param(const struct group_dpif *group);
+const struct field_array *group_dpif_get_fields(const struct group_dpif *group);
bool ofproto_has_vlan_splinters(const struct ofproto_dpif *);
ofp_port_t vsp_realdev_to_vlandev(const struct ofproto_dpif *,
@@ -156,83 +145,9 @@ void ofproto_dpif_flow_mod(struct ofproto_dpif *, struct ofputil_flow_mod *);
struct rule_dpif *ofproto_dpif_refresh_rule(struct rule_dpif *);
struct ofport_dpif *odp_port_to_ofport(const struct dpif_backer *, odp_port_t);
+struct ofport_dpif *ofp_port_to_ofport(const struct ofproto_dpif *,
+ ofp_port_t);
-/*
- * Recirculation
- * =============
- *
- * Recirculation is a technique to allow a frame to re-enter the packet
- * processing path for one or multiple times to achieve more flexible packet
- * processing in the data path. MPLS handling and selecting bond slave port
- * of a bond ports.
- *
- * Data path and user space interface
- * -----------------------------------
- *
- * Two new fields, recirc_id and dp_hash, are added to the current flow data
- * structure. They are both of type uint32_t. In addition, a new action,
- * RECIRC, are added.
- *
- * The value recirc_id is used to distinguish a packet from multiple
- * iterations of recirculation. A packet initially received is considered of
- * having recirc_id of 0. Recirc_id is managed by the user space, opaque to
- * the data path.
- *
- * On the other hand, dp_hash can only be computed by the data path, opaque to
- * the user space. In fact, user space may not able to recompute the hash
- * value. The dp_hash value should be wildcarded when for a newly received
- * packet. RECIRC action specifies whether the hash is computed. If computed,
- * how many fields to be included in the hash computation. The computed hash
- * value is stored into the dp_hash field prior to recirculation.
- *
- * The RECIRC action computes and set the dp_hash field, set the recirc_id
- * field and then reprocess the packet as if it was received on the same input
- * port. RECIRC action works like a function call; actions listed behind the
- * RECIRC action will be executed after its execution. RECIRC action can be
- * nested, data path implementation limits the number of recirculation executed
- * to prevent unreasonable nesting depth or infinite loop.
- *
- * Both flow fields and the RECIRC action are exposed as OpenFlow fields via
- * Nicira extensions.
- *
- * Post recirculation flow
- * ------------------------
- *
- * At the OpenFlow level, post recirculation rules are always hidden from the
- * controller. They are installed in table 254 which is set up as a hidden
- * table during boot time. Those rules are managed by the local user space
- * program only.
- *
- * To speed up the classifier look up process, recirc_id is always reflected
- * into the metadata field, since recirc_id is required to be exactly matched.
- *
- * Classifier look up always starts with table 254. A post recirculation flow
- * lookup should find its hidden rule within this table. On the other hand, A
- * newly received packet should miss all post recirculation rules because its
- * recirc_id is zero, then hit a pre-installed lower priority rule to redirect
- * classifier to look up starting from table 0:
- *
- * * , actions=resubmit(,0)
- *
- * Post recirculation data path flows are managed like other data path flows.
- * They are created on demand. Miss handling, stats collection and revalidation
- * work the same way as regular flows.
- *
- * If the bridge which originates the recirculation is different from the bridge
- * that receives the post recirculation packet (e.g. when patch port is used),
- * the packet will be processed directly by the recirculation bridge with
- * in_port set to OFPP_NONE. Admittedly, doing this limits the recirculation
- * bridge from matching on in_port of post recirculation packets, and will be
- * fixed in the near future.
- *
- * TODO: Always restore the correct in_port.
- *
- */
-
-struct ofproto_dpif *ofproto_dpif_recirc_get_ofproto(const struct dpif_backer *ofproto,
- uint32_t recirc_id);
-uint32_t ofproto_dpif_alloc_recirc_id(struct ofproto_dpif *ofproto);
-void ofproto_dpif_free_recirc_id(struct ofproto_dpif *ofproto, uint32_t recirc_id);
int ofproto_dpif_add_internal_flow(struct ofproto_dpif *,
const struct match *, int priority,
uint16_t idle_timeout,
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 7208541b1..9222fe431 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -499,6 +499,8 @@ struct ofgroup {
struct ovs_list buckets; /* Contains "struct ofputil_bucket"s. */
const uint32_t n_buckets;
+
+ const struct ofputil_group_props props;
};
bool ofproto_group_lookup(const struct ofproto *ofproto, uint32_t group_id,
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 07a1f5d5d..927521bb2 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2961,9 +2961,9 @@ static void
learned_cookies_flush(struct ofproto *ofproto, struct ovs_list *dead_cookies)
OVS_REQUIRES(ofproto_mutex)
{
- struct learned_cookie *c, *next;
+ struct learned_cookie *c;
- LIST_FOR_EACH_SAFE (c, next, u.list_node, dead_cookies) {
+ LIST_FOR_EACH_POP (c, u.list_node, dead_cookies) {
struct rule_criteria criteria;
struct rule_collection rules;
struct match match;
@@ -2977,7 +2977,6 @@ learned_cookies_flush(struct ofproto *ofproto, struct ovs_list *dead_cookies)
rule_criteria_destroy(&criteria);
rule_collection_destroy(&rules);
- list_remove(&c->u.list_node);
free(c);
}
}
@@ -5827,6 +5826,8 @@ append_group_desc(struct ofgroup *group, struct ovs_list *replies)
gds.group_id = group->group_id;
gds.type = group->type;
+ gds.props = group->props;
+
ofputil_append_group_desc_reply(&gds, &group->buckets, replies);
}
@@ -5929,6 +5930,9 @@ init_group(struct ofproto *ofproto, struct ofputil_group_mod *gm,
*CONST_CAST(uint32_t *, &(*ofgroup)->n_buckets) =
list_size(&(*ofgroup)->buckets);
+ memcpy(CONST_CAST(struct ofputil_group_props *, &(*ofgroup)->props),
+ &gm->props, sizeof (struct ofputil_group_props));
+
/* Construct called BEFORE any locks are held. */
error = ofproto->ofproto_class->group_construct(*ofgroup);
if (error) {
diff --git a/ofproto/tunnel.c b/ofproto/tunnel.c
index f621efbe9..3ea0eb44f 100644
--- a/ofproto/tunnel.c
+++ b/ofproto/tunnel.c
@@ -709,7 +709,7 @@ tnl_port_build_header(const struct ofport_dpif *ofport,
put_16aligned_be32(&ip->ip_src, ip_src);
put_16aligned_be32(&ip->ip_dst, tnl_flow->tunnel.ip_dst);
- res = netdev_build_header(tnl_port->netdev, data);
+ res = netdev_build_header(tnl_port->netdev, data, tnl_flow);
ip->ip_csum = csum(ip, sizeof *ip);
fat_rwlock_unlock(&rwlock);
diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c
index 2ba5ddd45..95b49958f 100644
--- a/ovsdb/jsonrpc-server.c
+++ b/ovsdb/jsonrpc-server.c
@@ -78,8 +78,9 @@ static void ovsdb_jsonrpc_trigger_complete_done(
struct ovsdb_jsonrpc_session *);
/* Monitors. */
-static struct json *ovsdb_jsonrpc_monitor_create(
- struct ovsdb_jsonrpc_session *, struct ovsdb *, struct json *params);
+static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_create(
+ struct ovsdb_jsonrpc_session *, struct ovsdb *, struct json *params,
+ const struct json *request_id);
static struct jsonrpc_msg *ovsdb_jsonrpc_monitor_cancel(
struct ovsdb_jsonrpc_session *,
struct json_array *params,
@@ -674,7 +675,7 @@ ovsdb_jsonrpc_lookup_db(const struct ovsdb_jsonrpc_session *s,
return db;
error:
- *replyp = jsonrpc_create_reply(ovsdb_error_to_json(error), request->id);
+ *replyp = jsonrpc_create_error(ovsdb_error_to_json(error), request->id);
ovsdb_error_destroy(error);
return NULL;
}
@@ -752,7 +753,7 @@ ovsdb_jsonrpc_session_lock(struct ovsdb_jsonrpc_session *s,
return jsonrpc_create_reply(result, request->id);
error:
- reply = jsonrpc_create_reply(ovsdb_error_to_json(error), request->id);
+ reply = jsonrpc_create_error(ovsdb_error_to_json(error), request->id);
ovsdb_error_destroy(error);
return reply;
}
@@ -812,7 +813,7 @@ ovsdb_jsonrpc_session_unlock(struct ovsdb_jsonrpc_session *s,
return jsonrpc_create_reply(json_object_create(), request->id);
error:
- reply = jsonrpc_create_reply(ovsdb_error_to_json(error), request->id);
+ reply = jsonrpc_create_error(ovsdb_error_to_json(error), request->id);
ovsdb_error_destroy(error);
return reply;
}
@@ -842,9 +843,8 @@ ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *s,
} else if (!strcmp(request->method, "monitor")) {
struct ovsdb *db = ovsdb_jsonrpc_lookup_db(s, request, &reply);
if (!reply) {
- reply = jsonrpc_create_reply(
- ovsdb_jsonrpc_monitor_create(s, db, request->params),
- request->id);
+ reply = ovsdb_jsonrpc_monitor_create(s, db, request->params,
+ request->id);
}
} else if (!strcmp(request->method, "monitor_cancel")) {
reply = ovsdb_jsonrpc_monitor_cancel(s, json_array(request->params),
@@ -1221,9 +1221,10 @@ ovsdb_jsonrpc_parse_monitor_request(struct ovsdb_jsonrpc_monitor_table *mt,
return NULL;
}
-static struct json *
+static struct jsonrpc_msg *
ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
- struct json *params)
+ struct json *params,
+ const struct json *request_id)
{
struct ovsdb_jsonrpc_monitor *m = NULL;
struct json *monitor_id, *monitor_requests;
@@ -1310,7 +1311,8 @@ ovsdb_jsonrpc_monitor_create(struct ovsdb_jsonrpc_session *s, struct ovsdb *db,
}
}
- return ovsdb_jsonrpc_monitor_get_initial(m);
+ return jsonrpc_create_reply(ovsdb_jsonrpc_monitor_get_initial(m),
+ request_id);
error:
if (m) {
@@ -1319,7 +1321,7 @@ error:
json = ovsdb_error_to_json(error);
ovsdb_error_destroy(error);
- return json;
+ return jsonrpc_create_error(json, request_id);
}
static struct jsonrpc_msg *
diff --git a/ovsdb/ovsdb-server.1.in b/ovsdb/ovsdb-server.1.in
index 0fafc49a9..e33d718cb 100644
--- a/ovsdb/ovsdb-server.1.in
+++ b/ovsdb/ovsdb-server.1.in
@@ -251,7 +251,34 @@ vSwitch 2.4 and later extend <condition> to allow the use of \fB<\fR,
of 0 or 1 integer'' and ``set of 0 or 1 real''. These conditions
evaluate to false when the column is empty, and otherwise as described
in RFC 7047 for integer and real types.
-
+.
+.SH "BUGS"
+.
+In Open vSwitch before version 2.4, when \fBovsdb\-server\fR sent
+JSON-RPC error responses to some requests, it incorrectly formulated
+them with the \fBresult\fR and \fBerror\fR swapped, so that the
+response appeared to indicate success (with a nonsensical result)
+rather than an error. The requests that suffered from this problem
+were:
+.
+.IP \fBtransact\fR
+.IQ \fBget_schema\fR
+Only if the request names a nonexistent database.
+.IP \fBmonitor\fR
+.IQ \fBlock\fR
+.IQ \fBunlock\fR
+In all error cases.
+.
+.PP
+Of these cases, the only error that a well-written application is
+likely to encounter in practice is \fBmonitor\fR of tables or columns
+that do not exist, in an situation where the application has been
+upgraded but the old database schema is still temporarily in use. To
+handle this situation gracefully, we recommend that clients should
+treat a \fBmonitor\fR response with a \fBresult\fR that contains an
+\fBerror\fR key-value pair as an error (assuming that the database
+being monitored does not contain a table named \fBerror\fR).
+.
.SH "SEE ALSO"
.
.BR ovsdb\-tool (1).
diff --git a/rhel/openvswitch-fedora.spec.in b/rhel/openvswitch-fedora.spec.in
index 5a3af4a15..f3dbebfcf 100644
--- a/rhel/openvswitch-fedora.spec.in
+++ b/rhel/openvswitch-fedora.spec.in
@@ -38,7 +38,7 @@ BuildRequires: groff graphviz
Requires: openssl iproute module-init-tools
#Upstream kernel commit 4f647e0a3c37b8d5086214128614a136064110c3
-Requires: kernel >= 3.15.0-0
+#Requires: kernel >= 3.15.0-0
Requires(post): systemd-units
Requires(preun): systemd-units
@@ -200,6 +200,8 @@ rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
+%{_sysconfdir}/bash_completion.d/ovs-appctl-bashcomp.bash
+%{_sysconfdir}/bash_completion.d/ovs-vsctl-bashcomp.bash
%dir %{_sysconfdir}/openvswitch
%config %ghost %{_sysconfdir}/openvswitch/conf.db
%config %ghost %{_sysconfdir}/openvswitch/system-id.conf
diff --git a/rhel/openvswitch-kmod-fedora.spec.in b/rhel/openvswitch-kmod-fedora.spec.in
index ed3800226..ecea16c8b 100644
--- a/rhel/openvswitch-kmod-fedora.spec.in
+++ b/rhel/openvswitch-kmod-fedora.spec.in
@@ -1,6 +1,6 @@
# Spec file for Open vSwitch.
-# Copyright (C) 2009, 2010 Nicira Networks, Inc.
+# Copyright (C) 2009, 2010, 2015 Nicira Networks, Inc.
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
@@ -55,7 +55,7 @@ depmod %{kernel}
%files
%defattr(-,root,root)
-/lib/modules/%{kernel}/kernel/extra/openvswitch/openvswitch.ko
+/lib/modules/%{kernel}/kernel/extra/openvswitch/*.ko
%changelog
* Wed Sep 21 2011 Kyle Mestery <kmestery@cisco.com>
diff --git a/rhel/openvswitch.spec.in b/rhel/openvswitch.spec.in
index 56603ccbb..1ea685d3b 100644
--- a/rhel/openvswitch.spec.in
+++ b/rhel/openvswitch.spec.in
@@ -123,6 +123,8 @@ exit 0
%files
%defattr(-,root,root)
+/etc/bash_completion.d/ovs-appctl-bashcomp.bash
+/etc/bash_completion.d/ovs-vsctl-bashcomp.bash
/etc/init.d/openvswitch
%config(noreplace) /etc/logrotate.d/openvswitch
/etc/sysconfig/network-scripts/ifup-ovs
diff --git a/tests/automake.mk b/tests/automake.mk
index abbfcb540..fdc3118c6 100644
--- a/tests/automake.mk
+++ b/tests/automake.mk
@@ -200,9 +200,9 @@ clean-local:
AUTOTEST = $(AUTOM4TE) --language=autotest
$(TESTSUITE): package.m4 $(TESTSUITE_AT) $(COMMON_MACROS_AT) $(TESTSUITE_PATCH)
- $(AM_V_GEN)$(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
- patch -p0 $@.tmp $(TESTSUITE_PATCH)
- $(AM_V_at)mv $@.tmp $@
+ $(AM_V_GEN)$(AUTOTEST) -I '$(srcdir)' -o testsuite.tmp $@.at
+ patch -p0 testsuite.tmp $(TESTSUITE_PATCH)
+ $(AM_V_at)mv testsuite.tmp $@
$(KMOD_TESTSUITE): package.m4 $(KMOD_TESTSUITE_AT) $(COMMON_MACROS_AT)
$(AM_V_GEN)$(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at
@@ -235,7 +235,7 @@ tests_test_lib_LDADD = lib/libopenvswitch.la
# idltest schema and IDL
OVSIDL_BUILT += tests/idltest.c tests/idltest.h tests/idltest.ovsidl
IDLTEST_IDL_FILES = tests/idltest.ovsschema tests/idltest.ann
-EXTRA_DIST += $(IDLTEST_IDL_FILES)
+EXTRA_DIST += $(IDLTEST_IDL_FILES) tests/idltest2.ovsschema
tests/idltest.ovsidl: $(IDLTEST_IDL_FILES)
$(AM_V_GEN)$(OVSDB_IDLC) -C $(srcdir) annotate $(IDLTEST_IDL_FILES) > $@.tmp && \
mv $@.tmp $@
diff --git a/tests/completion.at b/tests/completion.at
index d3b280046..0aca7aabb 100644
--- a/tests/completion.at
+++ b/tests/completion.at
@@ -608,7 +608,7 @@ AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "add Bridge br0 other_config ran
[0], [dnl
${MATCH}
])
-MATCH="$(PREPARE_MATCH_NOSPACE(random_key=abc))"
+MATCH="$(PREPARE_MATCH_NOSPACE(abc))"
AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "add Bridge br0 other_config random_key=abc"],
[0], [dnl
${MATCH}
@@ -638,14 +638,14 @@ AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set Bridge br0 other"],
${MATCH}
])
# then, with the ':' we should complete on key.
-TMP="$(ovs-vsctl --no-heading --columns=other_config list Bridge br0 | tr -d '{\"}' | tr -s ', ' '\n' | cut -d'=' -f1 | xargs printf "other_config:%s\n")"
+TMP="$(ovs-vsctl --no-heading --columns=other_config list Bridge br0 | tr -d '{\"}' | tr -s ', ' '\n' | cut -d'=' -f1)"
MATCH="$(PREPARE_MATCH_NOSPACE(${TMP}))"
AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set Bridge br0 other_config:"],
[0], [dnl
${MATCH}
])
# finally, if user fill in some value, we should just complete on user input.
-MATCH="$(PREPARE_MATCH_NOSPACE(other_config:random_val1=12345))"
+MATCH="$(PREPARE_MATCH_NOSPACE(random_val1))"
AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set Bridge br0 other_config:random_val1=12345"],
[0], [dnl
${MATCH}
@@ -677,14 +677,14 @@ AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set-manager "],
${MATCH}
])
# filename completion on unix, punix.
-MATCH="$(PREPARE_MATCH_NOSPACE(unix:testsuite.log))"
+MATCH="$(PREPARE_MATCH_NOSPACE(testsuite.log))"
AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set-manager unix:test"],
[0], [dnl
${MATCH}
])
# no completion on other type, just return available types.
# in real environment, bash will not complete on anything.
-MATCH="$(PREPARE_MATCH_NOSPACE(pssl: ptcp: punix: ssl: tcp: unix:))"
+MATCH="$(PREPARE_MATCH_NOSPACE(pssl: ptcp: punix: tcp: unix:))"
AT_CHECK_UNQUOTED([ovs-vsctl-bashcomp.bash test "set-manager ssl:something"],
[0], [dnl
${MATCH}
diff --git a/tests/idltest2.ovsschema b/tests/idltest2.ovsschema
new file mode 100644
index 000000000..312c9cc9e
--- /dev/null
+++ b/tests/idltest2.ovsschema
@@ -0,0 +1,85 @@
+{
+ "name": "idltest",
+ "version": "1.2.3",
+ "tables": {
+ "link1": {
+ "columns": {
+ "i": {
+ "type": "integer"
+ },
+ "k": {
+ "type": {
+ "key": {
+ "type": "uuid",
+ "refTable": "link1"
+ }
+ }
+ },
+ "ka": {
+ "type": {
+ "key": {
+ "type": "uuid",
+ "refTable": "link1"
+ },
+ "max": "unlimited",
+ "min": 0
+ }
+ }
+ }
+ },
+ "simple": {
+ "columns": {
+ "b": {
+ "type": "boolean"
+ },
+ "ba": {
+ "type": {
+ "key": "boolean",
+ "max": 1,
+ "min": 0
+ }
+ },
+ "i": {
+ "type": "integer"
+ },
+ "ia": {
+ "type": {
+ "key": "integer",
+ "max": "unlimited",
+ "min": 0
+ }
+ },
+ "r": {
+ "type": "real"
+ },
+ "ra": {
+ "type": {
+ "key": "real",
+ "max": "unlimited",
+ "min": 0
+ }
+ },
+ "s": {
+ "type": "string"
+ },
+ "sa": {
+ "type": {
+ "key": "string",
+ "max": "unlimited",
+ "min": 0
+ }
+ },
+ "u": {
+ "type": "uuid"
+ },
+ "ua": {
+ "type": {
+ "key": "uuid",
+ "max": "unlimited",
+ "min": 0
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/library.at b/tests/library.at
index 250768815..9bd6d81d5 100644
--- a/tests/library.at
+++ b/tests/library.at
@@ -7,7 +7,7 @@ AT_CHECK([ovstest test-flows flows pcap], [0], [checked 247 packets, 0 errors
AT_CLEANUP
AT_SETUP([test TCP/IP checksumming])
-AT_CHECK([ovstest test-csum], [0], [....#....#....###................................#................................#
+AT_CHECK([ovstest test-csum], [0], [....#....#....####................................#................................#
])
AT_CLEANUP
@@ -38,7 +38,7 @@ AT_CHECK([ovstest test-atomic])
AT_CLEANUP
AT_SETUP([test linked lists])
-AT_CHECK([ovstest test-list], [0], [..
+AT_CHECK([ovstest test-list], [0], [...
])
AT_CLEANUP
diff --git a/tests/mpls-xlate.at b/tests/mpls-xlate.at
index e2ef2e7c6..571b8ce45 100644
--- a/tests/mpls-xlate.at
+++ b/tests/mpls-xlate.at
@@ -31,8 +31,12 @@ dnl Setup multiple MPLS tags.
AT_CHECK([ovs-ofctl del-flows br0])
AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 in_port=local,dl_type=0x0800,action=push_mpls:0x8847,set_field:10-\>mpls_label,push_mpls:0x8847,set_field:20-\>mpls_label,output:1])
-AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 table=0,dl_type=0x8847,in_port=1,mpls_label=60,action=pop_mpls:0x8847,goto_table:1])
-AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 table=1,dl_type=0x8847,in_port=1,mpls_label=50,action=pop_mpls:0x0800,output:LOCAL])
+# The resubmits will be executed after recirculation, which preserves the
+# register values.
+AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 cookie=0xa,table=0,dl_type=0x8847,in_port=1,mpls_label=60,action=set_field:10-\>reg0,pop_mpls:0x8847,goto_table:1])
+# The pop_mpls below recirculates from within a resubmit
+# After recirculation the (restored) register value is moved to IP ttl.
+AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br0 cookie=0xb,table=1,dl_type=0x8847,in_port=1,mpls_label=50,action=push:NXM_NX_REG0[[0..7]],pop_mpls:0x0800,set_field:0-\>nw_ttl,pop:NXM_NX_REG1[[0..7]],move:NXM_NX_REG1[[0..7]]-\>NXM_NX_IP_TTL[[]],output:LOCAL])
dnl Double MPLS push
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(100),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x0800),ipv4(src=1.1.2.92,dst=1.1.2.88,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
@@ -41,9 +45,19 @@ AT_CHECK([tail -1 stdout], [0],
])
dnl Double MPLS pop
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x8847),mpls(label=60,tc=0/0,ttl=64,bos=0)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x8847),mpls(label=60,tc=0/0,ttl=64,bos=0)' -generate], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
- [Datapath actions: pop_mpls(eth_type=0x8847),recirc(300)
+ [Datapath actions: pop_mpls(eth_type=0x8847),recirc(1)
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(1),in_port(1),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x8847),mpls(label=50,tc=0/0,ttl=64,bos=0)' -generate], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: pop_mpls(eth_type=0x800),recirc(2)
+])
+
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(2),in_port(1),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x0800),ipv4(src=1.1.2.92,dst=1.1.2.88,proto=47,tos=0,ttl=64,frag=no)' -generate], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: set(ipv4(ttl=10)),100
])
OVS_VSWITCHD_STOP
diff --git a/tests/odp.at b/tests/odp.at
index de08771d2..c35648711 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -279,9 +279,11 @@ sample(sample=9.7%,actions(1,2,3,push_vlan(vid=1,pcp=2)))
set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,csum,key)))
set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)))
tnl_pop(4)
-tnl_push(tnl_port(4),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x20,proto=0x6558),key=0x1e241)),out_port(1))
-tnl_push(tnl_port(4),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0xa0,proto=0x6558),csum=0x0,key=0x1e241)),out_port(1))
-tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x1c700)),out_port(1))
+tnl_push(tnl_port(4),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x2000,proto=0x6558),key=0x1e241)),out_port(1))
+tnl_push(tnl_port(4),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0xa000,proto=0x6558),csum=0x0,key=0x1e241)),out_port(1))
+tnl_push(tnl_port(6),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x1c7)),out_port(1))
+tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0x0),geneve(oam,vni=0x1c7)),out_port(1))
+tnl_push(tnl_port(6),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x1c7)),out_port(1))
])
AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0],
[`cat actions.txt`
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index dc809e252..c2250d08a 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -447,7 +447,7 @@ c0 a8 00 02 27 2f 00 00 78 50 cc 5b 57 af 42 1e \
50 02 02 00 26 e8 00 00 00 00 00 00 00 00 \
"], [0], [dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=3 (via no_match) data_len=60 buffer=0x00000111
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=syn tcp_csum:26e8
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=syn tcp_csum:26e8
])
AT_CLEANUP
@@ -461,7 +461,7 @@ c0 a8 00 02 27 2f 00 00 78 50 cc 5b 57 af 42 1e \
50 10 02 00 26 e8 00 00 00 00 00 00 00 00 \
" 3], [0], [dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=3 (via no_match) data_len=60 buffer=0x00000111
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=ack tcp_csum:26e8
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=ack tcp_csum:26e8
00000000 50 54 00 00 00 06 50 54-00 00 00 05 08 00 45 00
00000010 00 28 bd 12 00 00 40 06-3c 6a c0 a8 00 01 c0 a8
00000020 00 02 27 2f 00 00 78 50-cc 5b 57 af 42 1e 50 10
@@ -480,7 +480,7 @@ c0 a8 00 02 27 2f 00 00 78 50 cc 5b 57 af 42 1e \
50 02 02 00 26 e8 00 00 00 00 00 00 00 00 \
"], [0], [dnl
OFPT_PACKET_IN (OF1.1) (xid=0x0): total_len=60 in_port=3 (via no_match) data_len=60 buffer=0x00000111
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=syn tcp_csum:26e8
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=10031,tp_dst=0,tcp_flags=syn tcp_csum:26e8
])
AT_CLEANUP
@@ -494,7 +494,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
00 00 00 23 20 83 c1 5f 00 00 00 00 \
"], [0], [dnl
OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00
-rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=1,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
+rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=1,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
])
AT_CLEANUP
@@ -508,7 +508,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
00 00 00 23 20 83 c1 5f 00 00 00 00 \
" 3], [0], [dnl
OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00
-rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
+rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
00000000 ff ff ff ff ff ff 00 23-20 83 c1 5f 80 35 00 01
00000010 08 00 06 04 00 03 00 23-20 83 c1 5f 00 00 00 00
00000020 00 23 20 83 c1 5f 00 00-00 00
@@ -526,7 +526,7 @@ ff ff ff fe 00 00 00 00 00 00 ff ff ff ff ff ff \
00 00 00 00 \
"], [0], [dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x102030405060708 total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00
-rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
+rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
])
AT_CLEANUP
@@ -541,7 +541,7 @@ ff ff ff fe 00 00 00 00 00 00 ff ff ff ff ff ff \
00 00 00 00 \
"], [0], [dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x102030405060708 total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00
-rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
+rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
])
AT_CLEANUP
@@ -556,7 +556,7 @@ ff ff ff fe 00 00 00 00 00 00 ff ff ff ff ff ff \
00 00 00 00 \
"], [0], [dnl
OFPT_PACKET_IN (OF1.5) (xid=0x0): cookie=0x102030405060708 total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00
-rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
+rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
])
AT_CLEANUP
@@ -571,7 +571,7 @@ ff ff ff fe 00 00 00 00 00 00 ff ff ff ff ff ff \
00 00 00 00 \
" 3], [0], [dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x102030405060708 total_len=42 in_port=LOCAL (via no_match) data_len=42 buffer=0xffffff00
-rarp,in_port=0,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
+rarp,vlan_tci=0x0000,dl_src=00:23:20:83:c1:5f,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=0.0.0.0,arp_tpa=0.0.0.0,arp_op=3,arp_sha=00:23:20:83:c1:5f,arp_tha=00:23:20:83:c1:5f
00000000 ff ff ff ff ff ff 00 23-20 83 c1 5f 80 35 00 01
00000010 08 00 06 04 00 03 00 23-20 83 c1 5f 00 00 00 00
00000020 00 23 20 83 c1 5f 00 00-00 00
@@ -696,7 +696,7 @@ b9 7c c0 a8 00 02 c0 a8 00 01 00 00 2b 60 00 00 \
00 00 00 00 \
"], [0], [dnl
OFPT_PACKET_OUT (xid=0x0): in_port=1 actions=output:3 data_len=60
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75
])
AT_CLEANUP
@@ -711,7 +711,7 @@ b9 7c c0 a8 00 02 c0 a8 00 01 00 00 2b 60 00 00 \
00 00 00 00 \
" 3], [0], [dnl
OFPT_PACKET_OUT (xid=0x0): in_port=1 actions=output:3 data_len=60
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75
00000000 50 54 00 00 00 05 50 54-00 00 00 06 08 00 45 00
00000010 00 28 00 00 40 00 40 06-b9 7c c0 a8 00 02 c0 a8
00000020 00 01 00 00 2b 60 00 00-00 00 6a 4f 2b 58 50 14
@@ -742,7 +742,7 @@ b9 7c c0 a8 00 02 c0 a8 00 01 00 00 2b 60 00 00 \
00 00 00 00 \
"], [0], [dnl
OFPT_PACKET_OUT (OF1.2) (xid=0x8858dfc5): in_port=LOCAL actions=FLOOD data_len=60
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:06,dl_dst=50:54:00:00:00:05,nw_src=192.168.0.2,nw_dst=192.168.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=11104,tcp_flags=rst|ack tcp_csum:6d75
])
AT_CLEANUP
@@ -2026,7 +2026,7 @@ AT_CLEANUP
AT_SETUP([OFPST_GROUP_DESC reply - OF1.5])
AT_KEYWORDS([ofp-print OFPT_STATS_REPLY])
AT_CHECK([ovs-ofctl ofp-print "\
-06 13 00 98 00 00 00 02 00 07 00 00 00 00 00 00 \
+06 13 00 d8 00 00 00 02 00 07 00 00 00 00 00 00 \
00 88 01 00 00 00 20 00 00 78 00 00 00 00 00 00 \
00 28 00 10 00 00 00 00 00 00 00 10 00 00 00 01 \
00 00 00 00 00 00 00 00 00 00 00 08 00 64 00 00 \
@@ -2037,9 +2037,14 @@ AT_CHECK([ovs-ofctl ofp-print "\
00 28 00 10 00 00 00 02 00 00 00 10 00 00 00 03 \
00 00 00 00 00 00 00 00 00 00 00 08 00 c8 00 00 \
00 01 00 08 00 00 00 03 \
+ff ff 00 3b 00 00 15 40 00 00 00 01 00 00 00 00 \
+68 61 73 68 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 00 \
+80 00 18 04 ff ff ff 00 80 00 1a 02 ff ff 80 00 \
+14 01 ff 00 00 00 00 00 \
"], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5) (xid=0x2):
- group_id=8192,type=select,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3
+ group_id=8192,type=select,selection_method=hash,fields=ip_dst=255.255.255.0,nw_proto,tcp_src,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3
])
AT_CLEANUP
@@ -2698,7 +2703,7 @@ ff ff ff ff ff ff 00 00 00 00 82 82 82 82 82 82 \
31 6d 00 00 00 00 00 00 00 00 \
"], [0], [dnl
NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 metadata=0x5a5a5a5a5a5a5a5a reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86,tcp_flags=syn tcp_csum:316d
+tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86,tcp_flags=syn tcp_csum:316d
])
AT_CLEANUP
@@ -2719,7 +2724,7 @@ ff ff ff ff ff ff 00 00 00 00 82 82 82 82 82 82 \
31 6d 00 00 00 00 00 00 00 00 \
" 3], [0], [dnl
NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 metadata=0x5a5a5a5a5a5a5a5a reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d
+tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d
00000000 82 82 82 82 82 82 80 81-81 81 81 81 81 00 00 50
00000010 08 00 45 00 00 28 00 00-00 00 00 06 32 05 53 53
00000020 53 53 54 54 54 54 00 55-00 56 00 00 00 00 00 00
@@ -2845,7 +2850,7 @@ AT_CLEANUP
AT_SETUP([OFPT_GROUP_MOD add - OF1.5])
AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print "\
-06 0f 00 90 11 22 33 44 00 00 01 00 87 65 43 21 \
+06 0f 00 b8 11 22 33 44 00 00 01 00 87 65 43 21 \
00 78 00 00 ff ff ff ff 00 28 00 10 00 00 00 00 \
00 00 00 10 00 00 00 01 00 00 00 00 00 00 00 00 \
00 00 00 08 00 64 00 00 00 01 00 08 00 00 00 01 \
@@ -2854,9 +2859,12 @@ AT_CHECK([ovs-ofctl ofp-print "\
00 01 00 08 00 00 00 02 00 28 00 10 00 00 00 02 \
00 00 00 10 00 00 00 03 00 00 00 00 00 00 00 00 \
00 00 00 08 00 c8 00 00 00 01 00 08 00 00 00 03 \
+ff ff 00 28 00 00 15 40 00 00 00 01 00 00 00 00 \
+68 61 73 68 00 00 00 00 00 00 00 00 00 00 00 00 \
+00 00 00 00 00 00 00 07 \
"], [0], [dnl
OFPT_GROUP_MOD (OF1.5) (xid=0x11223344):
- ADD group_id=2271560481,type=select,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3
+ ADD group_id=2271560481,type=select,selection_method=hash,selection_method_param=7,bucket=bucket_id:0,weight:100,watch_port:1,actions=output:1,bucket=bucket_id:1,weight:200,watch_port:2,actions=output:2,bucket=bucket_id:2,weight:200,watch_port:3,actions=output:3
])
AT_CLEANUP
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 897df4e62..139dfdd6b 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -6,7 +6,7 @@ AT_CHECK([ovs-appctl revalidator/wait])
OVS_VSWITCHD_STOP
AT_CLEANUP
-AT_SETUP([ofproto-dpif, active-backup bonding])
+AT_SETUP([ofproto-dpif - active-backup bonding])
# Create br0 with interfaces p1, p2 and p7, creating bond0 with p1 and p2
# and br1 with interfaces p3, p4 and p8.
# toggle p1,p2 of bond0 up and down to test bonding in active-backup mode.
@@ -53,7 +53,7 @@ recirc_id=0,rarp,in_port=4,vlan_tci=0x0000/0x1fff,dl_src=50:54:00:00:00:0b,dl_ds
OVS_VSWITCHD_STOP
AT_CLEANUP
-AT_SETUP([ofproto-dpif, balance-slb bonding])
+AT_SETUP([ofproto-dpif - balance-slb bonding])
# Create br0 with interfaces bond0(p1, p2, p3) and p7,
# and br1 with interfaces p4, p5, p6 and p8.
# p1 <-> p4, p2 <-> p5, p3 <-> p6
@@ -96,7 +96,7 @@ AT_CHECK([test `egrep 'in_port\(6\)' br1_flows.txt |wc -l` -gt 3])
OVS_VSWITCHD_STOP
AT_CLEANUP
-AT_SETUP([ofproto-dpif, balance-tcp bonding])
+AT_SETUP([ofproto-dpif - balance-tcp bonding])
# Create br0 with interfaces bond0(p1, p2, p3) and p7,
# and br1 with interfaces bond1(p4, p5, p6) and p8.
# bond0 <-> bond1
@@ -149,7 +149,7 @@ OVS_VSWITCHD_STOP()
AT_CLEANUP
# Makes sure recirculation does not change the way packet is handled.
-AT_SETUP([ofproto-dpif, balance-tcp bonding, different recirc flow ])
+AT_SETUP([ofproto-dpif - balance-tcp bonding, different recirc flow ])
OVS_VSWITCHD_START(
[add-bond br0 bond0 p1 p2 bond_mode=balance-tcp lacp=active \
other-config:lacp-time=fast other-config:bond-rebalance-interval=0 -- \
@@ -186,7 +186,7 @@ table=0 priority=2 in_port=5 dl_vlan=1 actions=drop
AT_CHECK([ovs-ofctl add-flows br-int flows.txt])
# Sends a packet to trigger recirculation.
-# Should generate recirc_id(0x12d),dp_hash(0xc1261ba2/0xff).
+# Should generate recirc_id(0x2),dp_hash(0xc1261ba2/0xff).
AT_CHECK([ovs-appctl netdev-dummy/receive p5 "in_port(5),eth(src=50:54:00:00:00:05,dst=50:54:00:00:01:00),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1)"])
# Collects flow stats.
@@ -195,7 +195,7 @@ AT_CHECK([ovs-appctl revalidator/purge], [0])
# Checks the flow stats in br1, should only be one flow with non-zero
# 'n_packets' from internal table.
AT_CHECK([ovs-appctl bridge/dump-flows br1 | ofctl_strip | grep -- "n_packets" | grep -- "table_id" | sed -e 's/dp_hash=0x[[0-9a-f]][[0-9a-f]]*/dp_hash=0x0/' -e 's/output:[[0-9]][[0-9]]*/output/'], [0], [dnl
-table_id=254, n_packets=1, n_bytes=64, priority=20,recirc_id=0x12d,dp_hash=0x0/0xff,actions=output
+table_id=254, n_packets=1, n_bytes=64, priority=20,recirc_id=0x2,dp_hash=0x0/0xff,actions=output
])
# Checks the flow stats in br-int, should be only one match.
@@ -332,6 +332,18 @@ AT_CHECK([tail -1 stdout], [0],
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([ofproto-dpif - group actions have no effect afterwards])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1], [10])
+AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=select,bucket=set_field:192.168.3.90->ip_src,output:10'])
+AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=group:1234,output:10'])
+AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: set(ipv4(src=192.168.3.90,dst=192.168.0.2)),10,set(ipv4(src=192.168.0.1,dst=192.168.0.2)),10
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
AT_SETUP([ofproto-dpif - all group in action set])
OVS_VSWITCHD_START
ADD_OF_PORTS([br0], [1], [10], [11])
@@ -403,6 +415,39 @@ AT_CHECK([tail -1 stdout], [0],
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([ofproto-dpif - select group with hash selection method])
+OVS_VSWITCHD_START
+ADD_OF_PORTS([br0], [1], [10], [11])
+AT_CHECK([ovs-ofctl -O OpenFlow15 add-group br0 'group_id=1234,type=select,selection_method=hash,fields=eth_dst,bucket=output:10,bucket=output:11'])
+AT_CHECK([ovs-ofctl -O OpenFlow15 add-flow br0 'ip actions=write_actions(group:1234)'])
+
+# Try a bunch of different flows and make sure that they get distributed
+# at least somewhat.
+for d in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
+ AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=1,dl_src=50:54:00:00:00:07,dl_dst=50:54:00:00:00:0$d,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0"], [0], [stdout])
+ tail -1 stdout >> results
+done
+sort results | uniq -c
+AT_CHECK([sort results | uniq], [0],
+ [Datapath actions: 10
+Datapath actions: 11
+])
+
+> results
+# Try a bunch of different flows and make sure that they are not distributed
+# as they only vary a field that is not hashed
+for d in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
+ AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=1,dl_src=50:54:00:00:00:$d,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0"], [0], [stdout])
+ tail -1 stdout >> results
+done
+sort results | uniq -c
+AT_CHECK([sort results | uniq], [0],
+ [Datapath actions: 10
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
AT_SETUP([ofproto-dpif - fast failover group])
OVS_VSWITCHD_START
ADD_OF_PORTS([br0], [1], [10], [11])
@@ -680,7 +725,7 @@ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:
OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=34 in_port=1 (via invalid_ttl) data_len=34 (unbuffered)
-ip,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=1
+ip,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=111,nw_tos=0,nw_ecn=0,nw_ttl=1
])
OVS_VSWITCHD_STOP
AT_CLEANUP
@@ -856,13 +901,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=syn tcp_csum:0
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -919,13 +964,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0
dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0
dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=rst|urg tcp_csum:0
])
AT_CHECK([ovs-appctl revalidator/purge], [0])
@@ -986,13 +1031,13 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
])
dnl Hit table 0, Miss all other tables, sent to controller
@@ -1006,13 +1051,13 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
])
AT_CHECK([ovs-appctl revalidator/purge], [0])
@@ -1049,13 +1094,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
])
dnl Hit table 1, Miss all other tables, sent to controller
@@ -1069,13 +1114,13 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=253 cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
])
AT_CHECK([ovs-appctl revalidator/purge], [0])
@@ -1259,13 +1304,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=9,tcp_flags=ack tcp_csum:0
])
dnl Singleton controller action.
@@ -1279,13 +1324,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
])
dnl Modified controller action.
@@ -1299,13 +1344,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0
+tcp,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0
dnl
OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0
+tcp,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0
dnl
OFPT_PACKET_IN (xid=0x0): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0
+tcp,dl_vlan=15,dl_vlan_pcp=0,dl_src=30:33:33:33:33:33,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=fin tcp_csum:0
])
dnl Modified VLAN controller action.
@@ -1319,13 +1364,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-ip,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
+ip,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-ip,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
+ip,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-ip,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
+ip,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:44:41,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
])
dnl Checksum TCP.
@@ -1339,31 +1384,31 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 reg0=0x1 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0
+tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 reg0=0x1 reg1=0x2 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0
+tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0
+tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:0
dnl
NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:1a03
+tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:1a03
dnl
NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:3205
+tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=11,tcp_flags=fin tcp_csum:3205
dnl
NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=11,tcp_flags=fin tcp_csum:31b8
+tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=11,tcp_flags=fin tcp_csum:31b8
dnl
NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d
+tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d
dnl
NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-tcp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d
+tcp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=85,tp_dst=86,tcp_flags=fin tcp_csum:316d
])
dnl Checksum UDP.
@@ -1377,31 +1422,31 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-udp,in_port=0,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
+udp,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=64 in_port=1 reg0=0x1 (via action) data_len=64 (unbuffered)
-udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
+udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
dnl
NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=64 in_port=1 reg0=0x1 reg1=0x2 (via action) data_len=64 (unbuffered)
-udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
+udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
dnl
NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 (via action) data_len=64 (unbuffered)
-udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
+udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:1234
dnl
NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=64 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 (via action) data_len=64 (unbuffered)
-udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:2c37
+udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:2c37
dnl
NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:4439
+udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=8,tp_dst=11 udp_csum:4439
dnl
NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=11 udp_csum:43ec
+udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=11 udp_csum:43ec
dnl
NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1
+udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1
dnl
NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=64 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=64 (unbuffered)
-udp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1
+udp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 udp_csum:43a1
])
dnl Modified ARP controller action.
@@ -1415,23 +1460,23 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 18])
OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-arp,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.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00
+arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-arp,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=00:00:00:00:00:00
+arp,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=00:00:00:00:00:00
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41
+arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-arp,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.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00
+arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-arp,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=00:00:00:00:00:00
+arp,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=00:00:00:00:00:00
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41
+arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-arp,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.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00
+arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=192.168.0.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=00:00:00:00:00:00
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-arp,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=00:00:00:00:00:00
+arp,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=00:00:00:00:00:00
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-arp,in_port=0,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41
+arp,vlan_tci=0x0000,dl_src=80:88:88:88:88:88,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=1.1.1.1,arp_tpa=2.2.2.2,arp_op=2,arp_sha=50:54:00:00:00:05,arp_tha=40:44:44:44:44:41
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -1448,31 +1493,31 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 18])
OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0x1 total_len=98 in_port=1 (via action) data_len=98 (unbuffered)
-sctp,in_port=0,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
+sctp,vlan_tci=0x0000,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x3 total_len=102 in_port=1 reg0=0x1 (via action) data_len=102 (unbuffered)
-sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
+sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=20:22:22:22:22:22,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
dnl
NXT_PACKET_IN (xid=0x0): table_id=2 cookie=0x4 total_len=102 in_port=1 reg0=0x1 reg1=0x2 (via action) data_len=102 (unbuffered)
-sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
+sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
dnl
NXT_PACKET_IN (xid=0x0): table_id=3 cookie=0x5 total_len=102 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 (via action) data_len=102 (unbuffered)
-sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
+sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
dnl
NXT_PACKET_IN (xid=0x0): table_id=4 cookie=0x6 total_len=102 in_port=1 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 (via action) data_len=102 (unbuffered)
-sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
+sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
dnl
NXT_PACKET_IN (xid=0x0): table_id=5 cookie=0x7 total_len=102 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=102 (unbuffered)
-sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
+sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=1112,tp_dst=2223 sctp_csum:d9d79157
dnl
NXT_PACKET_IN (xid=0x0): table_id=6 cookie=0x8 total_len=102 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=102 (unbuffered)
-sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=2223 sctp_csum:dd778f5f
+sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=2223 sctp_csum:dd778f5f
dnl
NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=102 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=102 (unbuffered)
-sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 sctp_csum:62051f56
+sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 sctp_csum:62051f56
dnl
NXT_PACKET_IN (xid=0x0): table_id=7 cookie=0x9 total_len=102 in_port=1 tun_id=0x6 reg0=0x1 reg1=0x2 reg2=0x3 reg3=0x4 reg4=0x5 (via action) data_len=102 (unbuffered)
-sctp,in_port=0,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 sctp_csum:62051f56
+sctp,dl_vlan=80,dl_vlan_pcp=0,dl_src=80:81:81:81:81:81,dl_dst=82:82:82:82:82:82,nw_src=83.83.83.83,nw_dst=84.84.84.84,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=85,tp_dst=86 sctp_csum:62051f56
])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
@@ -1526,7 +1571,8 @@ cookie=0xd dl_src=60:66:66:66:00:07 actions=pop_mpls:0x0800,learn(table=1,hard_t
cookie=0xd dl_src=60:66:66:66:00:08 actions=pop_mpls:0x0806,resubmit(1,1)
cookie=0xd table=1 arp actions=controller
-cookie=0xd dl_src=60:66:66:66:00:09 actions=pop_mpls:0x0800,mod_nw_tos:48,controller
+cookie=0xdeadbeef table=2 dl_src=60:66:66:66:00:09 actions=pop_mpls:0x0800,mod_nw_tos:48
+cookie=0xd dl_src=60:66:66:66:00:09 actions=resubmit(,2),controller
cookie=0xd dl_src=60:66:66:66:00:0a actions=pop_mpls:0x0800,mod_nw_dst:10.0.0.1,controller
cookie=0xd dl_src=60:66:66:66:00:0b actions=pop_mpls:0x0800,mod_nw_src:10.0.0.1,controller
@@ -1535,20 +1581,20 @@ cookie=0xd dl_src=60:66:66:66:01:01 actions=pop_mpls:0x8847,dec_mpls_ttl,control
cookie=0xd dl_src=60:66:66:66:01:02 actions=pop_mpls:0x8848,load:3->OXM_OF_MPLS_TC[[]],controller
cookie=0xd dl_src=60:66:66:66:02:00 actions=pop_mpls:0x8847,pop_mpls:0x0800,controller
-cookie=0xd dl_src=60:66:66:66:02:01 actions=pop_mpls:0x8848,pop_mpls:0x0800,dec_ttl,controller
-cookie=0xd dl_src=60:66:66:66:02:10 actions=pop_mpls:0x8847,dec_mpls_ttl,pop_mpls:0x0800,dec_ttl,controller
+cookie=0xe dl_src=60:66:66:66:02:01 actions=pop_mpls:0x8848,pop_mpls:0x0800,dec_ttl,controller
+cookie=0xe dl_src=60:66:66:66:02:10 actions=pop_mpls:0x8847,dec_mpls_ttl,pop_mpls:0x0800,dec_ttl,controller
-cookie=0xd dl_src=60:66:66:66:03:00 actions=pop_mpls:0x8848,pop_mpls:0x8848,controller
-cookie=0xd dl_src=60:66:66:66:03:01 actions=pop_mpls:0x8847,pop_mpls:0x8847,dec_mpls_ttl,controller
-cookie=0xd dl_src=60:66:66:66:03:10 actions=pop_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8848,dec_mpls_ttl,controller
+cookie=0xe dl_src=60:66:66:66:03:00 actions=pop_mpls:0x8848,pop_mpls:0x8848,controller
+cookie=0xe dl_src=60:66:66:66:03:01 actions=pop_mpls:0x8847,pop_mpls:0x8847,dec_mpls_ttl,controller
+cookie=0xe dl_src=60:66:66:66:03:10 actions=pop_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8848,dec_mpls_ttl,controller
-cookie=0xd dl_src=60:66:66:66:04:00 actions=pop_mpls:0x0800,push_mpls:0x8847,controller
-cookie=0xd dl_src=60:66:66:66:04:01 actions=pop_mpls:0x0800,push_mpls:0x8848,dec_mpls_ttl,controller
-cookie=0xd dl_src=60:66:66:66:04:10 actions=pop_mpls:0x0800,dec_ttl,push_mpls:0x8848,dec_mpls_ttl,controller
+cookie=0xf dl_src=60:66:66:66:04:00 actions=pop_mpls:0x0800,push_mpls:0x8847,controller
+cookie=0xf dl_src=60:66:66:66:04:01 actions=pop_mpls:0x0800,push_mpls:0x8848,dec_mpls_ttl,controller
+cookie=0xf dl_src=60:66:66:66:04:10 actions=pop_mpls:0x0800,dec_ttl,push_mpls:0x8848,dec_mpls_ttl,controller
-cookie=0xd dl_src=60:66:66:66:05:00 actions=push_mpls:0x8848,pop_mpls:0x8847,controller
-cookie=0xd dl_src=60:66:66:66:05:01 actions=push_mpls:0x8847,pop_mpls:0x8848,dec_mpls_ttl,controller
-cookie=0xd dl_src=60:66:66:66:05:10 actions=push_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8847,dec_mpls_ttl,controller
+cookie=0x5 dl_src=60:66:66:66:05:00 actions=push_mpls:0x8848,pop_mpls:0x8847,controller
+cookie=0x5 dl_src=60:66:66:66:05:01 actions=push_mpls:0x8847,pop_mpls:0x8848,dec_mpls_ttl,controller
+cookie=0x5 dl_src=60:66:66:66:05:10 actions=push_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8847,dec_mpls_ttl,controller
])
AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
@@ -1563,13 +1609,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:42,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
])
dnl Modified MPLS controller action.
@@ -1583,13 +1629,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-ip,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
+ip,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-ip,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
+ip,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-ip,in_port=0,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
+ip,vlan_tci=0x0000,dl_src=41:44:44:44:44:42,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=16,nw_tos=0,nw_ecn=0,nw_ttl=64
])
dnl Modified MPLS controller action.
@@ -1605,13 +1651,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:43,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=46912
])
dnl Modified MPLS controller action.
@@ -1625,13 +1671,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=7,dl_src=40:44:44:44:44:44,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=1
])
dnl Modified MPLS controller action.
@@ -1645,13 +1691,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:45,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=63,mpls_bos=1
])
dnl Modified MPLS controller action.
@@ -1665,13 +1711,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:46,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
])
dnl Modified MPLS controller action.
@@ -1685,13 +1731,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:47,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=10,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -1707,13 +1753,13 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816
+mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816
+mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816
+mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:44:49,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=64,mpls_bos=0,mpls_lse1=42816
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -1729,13 +1775,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xa total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:44:48,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=3,mpls_ttl=9,mpls_bos=1
])
dnl Modified MPLS actions.
@@ -1749,13 +1795,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xb total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=50:55:55:55:55:55,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=64,mpls_bos=1
])
dnl Modified MPLS ipv6 controller action.
@@ -1769,13 +1815,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
+mplsm,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
+mplsm,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xc total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
+mplsm,vlan_tci=0x0000,dl_src=70:77:77:77:77:77,dl_dst=50:54:00:00:00:07,mpls_label=1000,mpls_tc=7,mpls_ttl=128,mpls_bos=1
])
@@ -1797,13 +1843,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:66:66,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -1822,14 +1868,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -1848,14 +1894,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:02,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -1874,14 +1920,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:03,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -1900,14 +1946,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:04,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.2,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7743
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -1926,14 +1972,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:05,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.106,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:76db
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -1952,14 +1998,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:06,dl_dst=50:54:00:00:00:07,nw_src=192.168.255.255,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7745
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -1978,14 +2024,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:07,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2003,13 +2049,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered)
-arp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff
+arp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff
dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered)
-arp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff
+arp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff
dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0xd total_len=56 in_port=1 (via action) data_len=56 (unbuffered)
-arp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff
+arp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=ff:ff:ff:ff:ff:ff,arp_spa=192.168.0.1,arp_tpa=255.255.255.255,arp_op=2,arp_sha=60:66:66:66:00:08,arp_tha=ff:ff:ff:ff:ff:ff
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2028,14 +2074,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:09,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=48,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2054,14 +2100,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0a,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=10.0.0.1,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2dee
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2080,14 +2126,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:0b,dl_dst=50:54:00:00:00:07,nw_src=10.0.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:2ded
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2108,13 +2154,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2134,14 +2180,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:01:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2162,13 +2208,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1
dnl
NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:01:02,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=3,mpls_ttl=31,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2188,14 +2234,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:00,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2211,25 +2257,26 @@ AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor
for i in 1 2 3; do
ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 60 66 66 66 02 01 88 48 00 01 40 20 00 01 41 1f 45 00 00 2c 00 00 00 00 ff 06 3b 78 c0 a8 00 01 c0 a8 00 02 00 50 00 00 00 00 00 2a 00 00 00 2a 50 00 27 10 77 44 00 00 48 4f 47 45'
done
+
OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:01,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
dnl Modified MPLS pop action.
dnl The input is a frame with two MPLS label stack entries which tcpdump -vve shows as:
-dnl 60:66:66:66:02:10 > 50:54:00:00:02:10, ethertype MPLS unicast (0x8847), length 66: MPLS (label 20, exp 0, ttl 32)
+dnl 60:66:66:66:02:10 > 50:54:00:00:00:07, ethertype MPLS unicast (0x8847), length 66: MPLS (label 20, exp 0, ttl 32)
dnl (label 20, exp 0, [S], ttl 31)
dnl (tos 0x0, ttl 254, id 0, offset 0, flags [none], proto TCP (6), length 44)
dnl 192.168.0.1.80 > 192.168.0.2.0: Flags [none], cksum 0x7744 (correct), seq 42:46, win 10000, length 4
@@ -2242,21 +2289,21 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:02:10,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
dnl Modified MPLS pop action.
dnl The input is a frame with three MPLS label stack entries which tcpdump -vve shows as:
-dnl 60:66:66:66:03:00 > 50:54:00:00:00:00, ethertype MPLS unicast (0x8847), length 66: MPLS (label 20, exp 0, ttl 32)
+dnl 60:66:66:66:03:00 > 50:54:00:00:00:07, ethertype MPLS unicast (0x8847), length 66: MPLS (label 20, exp 0, ttl 32)
dnl (label 20, exp 0, ttl 31)
dnl (label 20, exp 0, [S], ttl 30)
dnl (tos 0x0, ttl 254, id 0, offset 0, flags [none], proto TCP (6), length 44)
@@ -2270,14 +2317,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=30,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2298,14 +2345,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:03:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2326,14 +2373,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xe total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:03:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=29,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2352,14 +2399,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:04:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=255,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2378,14 +2425,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:01,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=254,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2404,14 +2451,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0xf total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:04:10,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=253,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2426,18 +2473,19 @@ AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor
for i in 1 2 3; do
ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 60 66 66 66 05 00 88 47 00 01 41 20 45 00 00 2c 00 00 00 00 ff 06 3a 78 c0 a8 00 01 c0 a8 00 02 00 50 00 00 00 00 00 2a 00 00 00 2a 50 00 27 10 77 44 00 00 48 4f 47 45'
done
+
OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): cookie=0xd total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:00,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=32,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2456,14 +2504,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mplsm,vlan_tci=0x0000,dl_src=60:66:66:66:05:01,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2478,22 +2526,26 @@ AT_CHECK([ovs-ofctl monitor br0 65534 -P nxm --detach --pidfile 2> ofctl_monitor
for i in 1 2 3; do
ovs-appctl netdev-dummy/receive p1 '50 54 00 00 00 07 60 66 66 66 05 10 88 47 00 01 41 20 45 00 00 2c 00 00 00 00 ff 06 3a 78 c0 a8 00 01 c0 a8 00 02 00 50 00 00 00 00 00 2a 00 00 00 2a 50 00 27 10 77 44 00 00 48 4f 47 45'
done
+
OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
dnl
-NXT_PACKET_IN (xid=0x0): table_id=254 cookie=0x0 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
+NXT_PACKET_IN (xid=0x0): cookie=0x5 total_len=62 in_port=1 (via action) data_len=62 (unbuffered)
+mpls,vlan_tci=0x0000,dl_src=60:66:66:66:05:10,dl_dst=50:54:00:00:00:07,mpls_label=20,mpls_tc=0,mpls_ttl=31,mpls_bos=1
])
AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ cookie=0x5, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:00 actions=push_mpls:0x8848,pop_mpls:0x8847,CONTROLLER:65535
+ cookie=0x5, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:01 actions=push_mpls:0x8847,pop_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535
+ cookie=0x5, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:10 actions=push_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8847,dec_mpls_ttl,CONTROLLER:65535
cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:42 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:43 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
cookie=0xa, n_packets=3, n_bytes=180, dl_src=40:44:44:44:44:44 actions=push_mpls:0x8847,load:0xa->OXM_OF_MPLS_LABEL[[]],load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
@@ -2513,26 +2565,24 @@ AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:05 actions=pop_mpls:0x0800,multipath(eth_src,50,modulo_n,256,0,NXM_OF_IP_SRC[[0..7]]),CONTROLLER:65535
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:06 actions=pop_mpls:0x0800,bundle_load(eth_src,50,hrw,ofport,NXM_OF_IP_SRC[[0..15]],slaves:1,2),CONTROLLER:65535
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:07 actions=pop_mpls:0x0800,learn(table=1,hard_timeout=60,eth_type=0x800,nw_proto=6,NXM_OF_IP_SRC[[]]=NXM_OF_IP_DST[[]]),CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:09 actions=pop_mpls:0x0800,mod_nw_tos:48,CONTROLLER:65535
+ cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:09 actions=resubmit(,2),CONTROLLER:65535
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:0a actions=pop_mpls:0x0800,mod_nw_dst:10.0.0.1,CONTROLLER:65535
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:0b actions=pop_mpls:0x0800,mod_nw_src:10.0.0.1,CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:00 actions=pop_mpls:0x0800,push_mpls:0x8847,CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:01 actions=pop_mpls:0x0800,push_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:10 actions=pop_mpls:0x0800,dec_ttl,push_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:00 actions=push_mpls:0x8848,pop_mpls:0x8847,CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:01 actions=push_mpls:0x8847,pop_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:05:10 actions=push_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8847,dec_mpls_ttl,CONTROLLER:65535
cookie=0xd, n_packets=3, n_bytes=186, dl_src=60:66:66:66:66:66 actions=pop_mpls:0x0800,CONTROLLER:65535
cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:01:00 actions=pop_mpls:0x8848,CONTROLLER:65535
cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:01:01 actions=pop_mpls:0x8847,dec_mpls_ttl,CONTROLLER:65535
cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:01:02 actions=pop_mpls:0x8848,load:0x3->OXM_OF_MPLS_TC[[]],CONTROLLER:65535
cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:02:00 actions=pop_mpls:0x8847,pop_mpls:0x0800,CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:02:01 actions=pop_mpls:0x8848,pop_mpls:0x0800,dec_ttl,CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=198, dl_src=60:66:66:66:02:10 actions=pop_mpls:0x8847,dec_mpls_ttl,pop_mpls:0x0800,dec_ttl,CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:00 actions=pop_mpls:0x8848,pop_mpls:0x8848,CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:01 actions=pop_mpls:0x8847,pop_mpls:0x8847,dec_mpls_ttl,CONTROLLER:65535
- cookie=0xd, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:10 actions=pop_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535
cookie=0xd, table=1, n_packets=3, n_bytes=168, arp actions=CONTROLLER:65535
+ cookie=0xdeadbeef, table=2, n_packets=3, n_bytes=186, dl_src=60:66:66:66:00:09 actions=pop_mpls:0x0800,mod_nw_tos:48
+ cookie=0xe, n_packets=3, n_bytes=198, dl_src=60:66:66:66:02:01 actions=pop_mpls:0x8848,pop_mpls:0x0800,dec_ttl,CONTROLLER:65535
+ cookie=0xe, n_packets=3, n_bytes=198, dl_src=60:66:66:66:02:10 actions=pop_mpls:0x8847,dec_mpls_ttl,pop_mpls:0x0800,dec_ttl,CONTROLLER:65535
+ cookie=0xe, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:00 actions=pop_mpls:0x8848,pop_mpls:0x8848,CONTROLLER:65535
+ cookie=0xe, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:01 actions=pop_mpls:0x8847,pop_mpls:0x8847,dec_mpls_ttl,CONTROLLER:65535
+ cookie=0xe, n_packets=3, n_bytes=210, dl_src=60:66:66:66:03:10 actions=pop_mpls:0x8848,dec_mpls_ttl,pop_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535
+ cookie=0xf, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:00 actions=pop_mpls:0x0800,push_mpls:0x8847,CONTROLLER:65535
+ cookie=0xf, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:01 actions=pop_mpls:0x0800,push_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535
+ cookie=0xf, n_packets=3, n_bytes=186, dl_src=60:66:66:66:04:10 actions=pop_mpls:0x0800,dec_ttl,push_mpls:0x8848,dec_mpls_ttl,CONTROLLER:65535
NXST_FLOW reply:
])
@@ -2568,13 +2618,13 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=1 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=1 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=1 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=255,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
])
AT_CHECK([ovs-appctl revalidator/purge], [0])
@@ -2616,14 +2666,14 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([STRIP_METADATA ofctl_monitor.log], [0], [dnl
-OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=254 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=254 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
dnl
-OFPT_PACKET_IN (OF1.2) (xid=0x0): table_id=254 total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
+OFPT_PACKET_IN (OF1.2) (xid=0x0): total_len=58 in_port=1 (via action) data_len=58 (unbuffered)
+tcp,vlan_tci=0x0000,dl_src=60:66:66:66:00:08,dl_dst=50:54:00:00:00:01,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=32,nw_ecn=0,nw_ttl=254,tp_src=80,tp_dst=0,tcp_flags=0 tcp_csum:7744
])
AT_CHECK([ovs-appctl revalidator/purge], [0])
@@ -2656,13 +2706,13 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (xid=0x0): total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
])
AT_CHECK([ovs-appctl revalidator/purge], [0])
@@ -2698,13 +2748,13 @@ AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
])
AT_CHECK([ovs-appctl revalidator/purge], [0])
@@ -2764,13 +2814,13 @@ send: OFPT_SET_ASYNC (OF1.3) (xid=0x2):
FLOW_REMOVED: (off)
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2806,13 +2856,13 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([ovs-appctl revalidator/purge], [0])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via no_match) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2854,31 +2904,31 @@ AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.3) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -2922,31 +2972,31 @@ AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via group) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action_set) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via group) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action_set) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): table_id=2 cookie=0x0 total_len=60 in_port=1 (via group) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
dnl
OFPT_PACKET_IN (OF1.4) (xid=0x0): cookie=0x0 total_len=60 in_port=1 (via action_set) data_len=60 (unbuffered)
-tcp,in_port=0,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
+tcp,vlan_tci=0x0000,dl_src=10:11:11:11:11:11,dl_dst=50:54:00:00:00:07,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=8,tp_dst=10,tcp_flags=syn tcp_csum:0
])
AT_CHECK([ovs-appctl time/warp 5000], [0], [ignore])
@@ -3150,21 +3200,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 00 00 88 47 00 00
00000010 01 40 45 00 00 28 00 00-00 00 40 06 f9 7c c0 a8
00000020 00 01 c0 a8 00 02 00 00-00 00 00 00 00 00 00 00
00000030 00 00 50 00 00 00 00 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 00 00 88 47 00 00
00000010 01 40 45 00 00 28 00 00-00 00 40 06 f9 7c c0 a8
00000020 00 01 c0 a8 00 02 00 00-00 00 00 00 00 00 00 00
00000030 00 00 50 00 00 00 00 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:00,dl_dst=50:54:00:00:00:07,mpls_label=0,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 00 00 88 47 00 00
00000010 01 40 45 00 00 28 00 00-00 00 40 06 f9 7c c0 a8
00000020 00 01 c0 a8 00 02 00 00-00 00 00 00 00 00 00 00
@@ -3183,21 +3233,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
00000000 50 54 00 00 00 07 40 44-44 44 00 01 88 47 00 00
00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00
00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
00000030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
00000000 50 54 00 00 00 07 40 44-44 44 00 01 88 47 00 00
00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00
00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
00000030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
+mpls,vlan_tci=0x0000,dl_src=40:44:44:44:00:01,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
00000000 50 54 00 00 00 07 40 44-44 44 00 01 88 47 00 00
00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00
00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
@@ -3218,21 +3268,21 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
+mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
00000000 50 54 00 00 00 07 40 44-44 44 00 02 88 48 00 00
00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00
00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
00000030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
+mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
00000000 50 54 00 00 00 07 40 44-44 44 00 02 88 48 00 00
00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00
00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
00000030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mplsm,in_port=0,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
+mplsm,vlan_tci=0x0000,dl_src=40:44:44:44:00:02,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=0,mpls_lse1=41280
00000000 50 54 00 00 00 07 40 44-44 44 00 02 88 48 00 00
00000010 a0 40 00 00 a1 40 00 00-00 00 00 00 00 00 00 00
00000020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00
@@ -3276,7 +3326,7 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 50 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3284,7 +3334,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00
00000040 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 50 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3292,7 +3342,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00
00000040 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:50,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 50 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3313,21 +3363,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 51 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 51 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:51,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 51 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3347,7 +3397,7 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 52 54 00 00 00 07 40 44-44 44 54 52 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3355,7 +3405,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00
00000040 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 52 54 00 00 00 07 40 44-44 44 54 52 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3363,7 +3413,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00
00000040 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:52,dl_dst=52:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 52 54 00 00 00 07 40 44-44 44 54 52 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3384,21 +3434,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 53 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 53 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:53,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 53 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3418,7 +3468,7 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 54 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3426,7 +3476,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00
00000040 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 54 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3434,7 +3484,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00
00000040 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:54,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 54 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3455,21 +3505,21 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 55 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 55 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:55,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 55 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3489,7 +3539,7 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 56 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3497,7 +3547,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00
00000040 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 56 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3505,7 +3555,7 @@ mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00
00000040 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=68 in_port=1 (via action) data_len=68 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:56,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 56 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3526,21 +3576,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 57 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 57 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:57,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 57 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3560,21 +3610,21 @@ OVS_APP_EXIT_AND_WAIT(ovs-ofctl)
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 58 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 58 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:58,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 58 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -3594,21 +3644,21 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([cat ofctl_monitor.log | ofctl_strip], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 59 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 59 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
00000030 00 00 00 00 00 00 50 00-00 00 00 00 00 00 00 00
dnl
OFPT_PACKET_IN (OF1.2): total_len=64 in_port=1 (via action) data_len=64 (unbuffered)
-mpls,in_port=0,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
+mpls,dl_vlan=99,dl_vlan_pcp=1,dl_src=40:44:44:44:54:59,dl_dst=50:54:00:00:00:07,mpls_label=10,mpls_tc=0,mpls_ttl=64,mpls_bos=1
00000000 50 54 00 00 00 07 40 44-44 44 54 59 81 00 20 63
00000010 88 47 00 00 a1 40 45 00-00 28 00 00 00 00 40 06
00000020 f9 7c c0 a8 00 01 c0 a8-00 02 00 00 00 00 00 00
@@ -5164,7 +5214,7 @@ AT_CHECK([STRIP_XIDS stdout | sed -n 's/duration=[[0-9]]*\.[[0-9]]*s/duration=0.
OVS_VSWITCHD_STOP
AT_CLEANUP
-AT_SETUP([idle_age and hard_age increase over time])
+AT_SETUP([ofproto-dpif - idle_age and hard_age increase over time])
OVS_VSWITCHD_START
# get_ages DURATION HARD IDLE
@@ -6341,13 +6391,13 @@ done
OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
dnl
NXT_PACKET_IN (xid=0x0): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
dnl
NXT_PACKET_IN (xid=0x0): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
])
AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip | sort], [0], [dnl
@@ -6392,13 +6442,13 @@ done
OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=14 in_port=1 (via no_match) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
dnl
NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=14 in_port=1 (via no_match) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
dnl
NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=14 in_port=1 (via no_match) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
])
(printf "OFPST_TABLE reply (OF1.3) (xid=0x2):"
@@ -6448,13 +6498,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
])
AT_CHECK([ovs-appctl revalidator/purge], [0])
@@ -6501,13 +6551,13 @@ OVS_WAIT_UNTIL([test `wc -l < ofctl_monitor.log` -ge 6])
OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
dnl
NXT_PACKET_IN (xid=0x0): table_id=1 cookie=0x0 total_len=60 in_port=1 (via action) data_len=60 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
+vlan_tci=0x0000,dl_src=50:54:00:00:00:09,dl_dst=50:54:00:00:00:0a,dl_type=0x1234
])
AT_CHECK([ovs-appctl revalidator/purge], [0])
@@ -6548,7 +6598,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 in_port=1 (via no_match) data_len=86 (unbuffered)
-icmp6,in_port=0,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::260:97ff:fe07:69ea,nd_sll=00:00:86:05:80:da,nd_tll=00:00:00:00:00:00 icmp6_csum:68bd
+icmp6,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::260:97ff:fe07:69ea,nd_sll=00:00:86:05:80:da,nd_tll=00:00:00:00:00:00 icmp6_csum:68bd
])
OVS_VSWITCHD_STOP
@@ -6569,7 +6619,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 in_port=1 (via action) data_len=86 (unbuffered)
-icmp6,in_port=0,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::1,nd_sll=32:21:14:86:11:74,nd_tll=00:00:00:00:00:00 icmp6_csum:19d3
+icmp6,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::1,nd_sll=32:21:14:86:11:74,nd_tll=00:00:00:00:00:00 icmp6_csum:19d3
])
OVS_VSWITCHD_STOP
diff --git a/tests/ofproto.at b/tests/ofproto.at
index a3f5e2a1d..5ae313998 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -338,14 +338,14 @@ dnl Actions definition listed in both supported formats (w/ actions=)
AT_SETUP([ofproto - del group (OpenFlow 1.5)])
OVS_VSWITCHD_START
AT_DATA([groups.txt], [dnl
-group_id=1234,type=all,bucket=output:10,bucket=output:11
+group_id=1234,type=select,selection_method=hash,bucket=output:10,bucket=output:11
group_id=1235,type=all,bucket=actions=output:12,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn add-groups br0 groups.txt])
AT_CHECK([ovs-ofctl -F OXM-OpenFlow15 -O OpenFlow15 -vwarn dump-groups br0 1234], [0], [stdout])
AT_CHECK([STRIP_XIDS stdout], [0], [dnl
OFPST_GROUP_DESC reply (OF1.5):
- group_id=1234,type=all,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
+ group_id=1234,type=select,selection_method=hash,bucket=bucket_id:0,actions=output:10,bucket=bucket_id:1,actions=output:11
])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn del-groups br0 group_id=1234])
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-groups br0], [0], [stdout])
@@ -2037,21 +2037,21 @@ check_async () {
ovs-ofctl -v packet-out br0 controller controller '0001020304050010203040501234'
if test X"$1" = X"OFPR_ACTION"; then shift;
echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
fi
# OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123)
ovs-ofctl -v packet-out br0 controller 'controller(reason=no_match,id=123)' '0001020304050010203040501234'
if test X"$1" = X"OFPR_NO_MATCH"; then shift;
echo >>expout "OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via no_match) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
fi
# OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
ovs-ofctl packet-out br0 controller dec_ttl '002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00'
if test X"$1" = X"OFPR_INVALID_TTL"; then shift;
echo >>expout "OFPT_PACKET_IN: total_len=76 in_port=CONTROLLER (via invalid_ttl) data_len=76 (unbuffered)
-udp,in_port=0,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d"
+udp,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d"
fi
# OFPT_PORT_STATUS, OFPPR_ADD
@@ -2141,21 +2141,21 @@ check_async () {
ovs-ofctl -O OpenFlow12 -v packet-out br0 none controller '0001020304050010203040501234'
if test X"$1" = X"OFPR_ACTION"; then shift;
echo >>expout "OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
fi
# OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123)
ovs-ofctl -O OpenFlow12 -v packet-out br0 none 'controller(reason=no_match,id=123)' '0001020304050010203040501234'
if test X"$1" = X"OFPR_NO_MATCH"; then shift;
echo >>expout "OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY (via no_match) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
fi
# OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
ovs-ofctl -O OpenFlow12 packet-out br0 none dec_ttl '002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00'
if test X"$1" = X"OFPR_INVALID_TTL"; then shift;
echo >>expout "OFPT_PACKET_IN (OF1.2): total_len=76 in_port=ANY (via invalid_ttl) data_len=76 (unbuffered)
-udp,in_port=0,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d"
+udp,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d"
fi
# OFPT_PORT_STATUS, OFPPR_ADD
@@ -2245,21 +2245,21 @@ check_async () {
ovs-ofctl -O OpenFlow13 -v packet-out br0 none controller '0001020304050010203040501234'
if test X"$1" = X"OFPR_ACTION"; then shift;
echo >>expout "OFPT_PACKET_IN (OF1.3): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
fi
# OFPT_PACKET_IN, OFPR_NO_MATCH (controller_id=123)
ovs-ofctl -O OpenFlow13 -v packet-out br0 none 'controller(reason=no_match,id=123)' '0001020304050010203040501234'
if test X"$1" = X"OFPR_NO_MATCH"; then shift;
echo >>expout "OFPT_PACKET_IN (OF1.3): total_len=14 in_port=ANY (via no_match) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234"
fi
# OFPT_PACKET_IN, OFPR_INVALID_TTL (controller_id=0)
ovs-ofctl -O OpenFlow13 packet-out br0 none dec_ttl '002583dfb4000026b98cb0f908004500003eb7e200000011339bac11370dac100002d7730035002b8f6d86fb0100000100000000000006626c702d7873066e696369726103636f6d00000f00'
if test X"$1" = X"OFPR_INVALID_TTL"; then shift;
echo >>expout "OFPT_PACKET_IN (OF1.3): total_len=76 in_port=ANY (via invalid_ttl) data_len=76 (unbuffered)
-udp,in_port=0,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d"
+udp,vlan_tci=0x0000,dl_src=00:26:b9:8c:b0:f9,dl_dst=00:25:83:df:b4:00,nw_src=172.17.55.13,nw_dst=172.16.0.2,nw_tos=0,nw_ecn=0,nw_ttl=0,tp_src=55155,tp_dst=53 udp_csum:8f6d"
fi
# OFPT_PORT_STATUS, OFPPR_ADD
@@ -2567,9 +2567,9 @@ ovs-ofctl dump-ports br0
AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN: total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_PACKET_IN: total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
OFPT_BARRIER_REPLY:
])
@@ -2600,9 +2600,9 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_PACKET_IN (OF1.2): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
OFPT_BARRIER_REPLY (OF1.2):
])
@@ -2633,9 +2633,9 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.1): total_len=14 in_port=ANY (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_PACKET_IN (OF1.1): total_len=14 in_port=CONTROLLER (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x5678
OFPT_BARRIER_REPLY (OF1.1):
])
@@ -2663,7 +2663,7 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
NXT_PACKET_IN: total_len=14 in_port=CONTROLLER metadata=0xfafafafa5a5a5a5a pkt_mark=0xaa (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_BARRIER_REPLY:
])
@@ -2691,7 +2691,7 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY metadata=0xfafafafa5a5a5a5a (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_BARRIER_REPLY (OF1.2):
])
@@ -2719,7 +2719,7 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.3): total_len=14 in_port=ANY metadata=0x6b (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_BARRIER_REPLY (OF1.3):
])
@@ -2746,7 +2746,7 @@ ovs-appctl -t ovs-ofctl exit
AT_CHECK([sed 's/ (xid=0x[[0-9a-fA-F]]*)//' monitor.log], [0], [dnl
OFPT_PACKET_IN (OF1.2): total_len=14 in_port=ANY tun_id=0x1020304 tun_src=127.0.0.1 tun_dst=192.168.0.1 (via action) data_len=14 (unbuffered)
-in_port=0,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
+vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=00:01:02:03:04:05,dl_type=0x1234
OFPT_BARRIER_REPLY (OF1.2):
])
diff --git a/tests/ovsdb-idl.at b/tests/ovsdb-idl.at
index 89752f0f6..57642be68 100644
--- a/tests/ovsdb-idl.at
+++ b/tests/ovsdb-idl.at
@@ -496,3 +496,78 @@ OVSDB_CHECK_IDL_PY([getattr idl, insert ops],
002: i=2 k=2 ka=[] l2= uuid=<0>
003: done
]])
+
+AT_SETUP([idl handling of missing tables and columns - C])
+AT_KEYWORDS([ovsdb server idl positive])
+OVS_RUNDIR=`pwd`; export OVS_RUNDIR
+
+# idltest2.ovsschema is the same as idltest.ovsschema, except that
+# table link2 and column l2 have been deleted. But the IDL still
+# expects them to be there, so this test checks that it properly
+# tolerates them being missing.
+AT_CHECK([ovsdb-tool create db $abs_srcdir/idltest2.ovsschema],
+ [0], [stdout], [ignore])
+AT_CHECK([ovsdb-server '-vPATTERN:console:ovsdb-server|%c|%m' --detach --no-chdir --pidfile="`pwd`"/pid --remote=punix:socket --unixctl="`pwd`"/unixctl db], [0], [ignore], [ignore])
+AT_CHECK([test-ovsdb '-vPATTERN:console:test-ovsdb|%c|%m' -vjsonrpc -t10 idl unix:socket ['["idltest",
+ {"op": "insert",
+ "table": "link1",
+ "row": {"i": 0, "k": ["named-uuid", "self"]},
+ "uuid-name": "self"}]' \
+ '["idltest",
+ {"op": "insert",
+ "table": "link1",
+ "row": {"i": 1, "k": ["named-uuid", "row2"]},
+ "uuid-name": "row1"},
+ {"op": "insert",
+ "table": "link1",
+ "row": {"i": 2, "k": ["named-uuid", "row1"]},
+ "uuid-name": "row2"}]' \
+ '["idltest",
+ {"op": "update",
+ "table": "link1",
+ "where": [["i", "==", 1]],
+ "row": {"k": ["uuid", "#1#"]}}]' \
+ '["idltest",
+ {"op": "update",
+ "table": "link1",
+ "where": [],
+ "row": {"k": ["uuid", "#0#"]}}]']],
+ [0], [stdout], [stderr], [kill `cat pid`])
+AT_CHECK([sort stdout | ${PERL} $srcdir/uuidfilt.pl], [0],
+ [[000: empty
+001: {"error":null,"result":[{"uuid":["uuid","<0>"]}]}
+002: i=0 k=0 ka=[] l2= uuid=<0>
+003: {"error":null,"result":[{"uuid":["uuid","<1>"]},{"uuid":["uuid","<2>"]}]}
+004: i=0 k=0 ka=[] l2= uuid=<0>
+004: i=1 k=2 ka=[] l2= uuid=<1>
+004: i=2 k=1 ka=[] l2= uuid=<2>
+005: {"error":null,"result":[{"count":1}]}
+006: i=0 k=0 ka=[] l2= uuid=<0>
+006: i=1 k=1 ka=[] l2= uuid=<1>
+006: i=2 k=1 ka=[] l2= uuid=<2>
+007: {"error":null,"result":[{"count":3}]}
+008: i=0 k=0 ka=[] l2= uuid=<0>
+008: i=1 k=0 ka=[] l2= uuid=<1>
+008: i=2 k=0 ka=[] l2= uuid=<2>
+009: done
+]], [], [kill `cat pid`])
+
+# Check that ovsdb-idl figured out that table link2 and column l2 are missing.
+AT_CHECK([grep ovsdb_idl stderr | sort], [0], [dnl
+test-ovsdb|ovsdb_idl|idltest database lacks link2 table (database needs upgrade?)
+test-ovsdb|ovsdb_idl|link1 table in idltest database lacks l2 column (database needs upgrade?)
+])
+
+# Check that ovsdb-idl sent on "monitor" request and that it didn't
+# mention that table or column, and (for paranoia) that it did mention another
+# table and column.
+AT_CHECK([grep -c '"monitor"' stderr], [0], [1
+])
+AT_CHECK([grep '"monitor"' stderr | grep link2], [1])
+AT_CHECK([grep '"monitor"' stderr | grep l2], [1])
+AT_CHECK([grep '"monitor"' stderr | grep -c '"link1"'], [0], [1
+])
+AT_CHECK([grep '"monitor"' stderr | grep -c '"ua"'], [0], [1
+])
+OVSDB_SERVER_SHUTDOWN
+AT_CLEANUP
diff --git a/tests/ovsdb-server.at b/tests/ovsdb-server.at
index 35f0d118d..c9ce4b1fd 100644
--- a/tests/ovsdb-server.at
+++ b/tests/ovsdb-server.at
@@ -163,7 +163,7 @@ ordinals
], [ignore], [test ! -e pid || kill `cat pid`])
AT_CHECK(
[[ovstest test-jsonrpc request unix:socket get_schema [\"nonexistent\"]]], [0],
- [[{"error":null,"id":0,"result":{"details":"get_schema request specifies unknown database nonexistent","error":"unknown database","syntax":"[\"nonexistent\"]"}}
+ [[{"error":{"details":"get_schema request specifies unknown database nonexistent","error":"unknown database","syntax":"[\"nonexistent\"]"},"id":0,"result":null}
]], [], [test ! -e pid || kill `cat pid`])
OVSDB_SERVER_SHUTDOWN
AT_CLEANUP
diff --git a/tests/test-aa.c b/tests/test-aa.c
index 4fb26188f..9dabce16d 100644
--- a/tests/test-aa.c
+++ b/tests/test-aa.c
@@ -98,12 +98,12 @@ check_received_aa(struct lldpd_port *sport,
sport->p_element.system_id.system_mac[5]);
assert(rport->p_element.system_id.conn_type ==
sport->p_element.system_id.conn_type);
- assert(rport->p_element.system_id.smlt_id ==
- sport->p_element.system_id.smlt_id);
- assert(rport->p_element.system_id.mlt_id[0] ==
- sport->p_element.system_id.mlt_id[0]);
- assert(rport->p_element.system_id.mlt_id[1] ==
- sport->p_element.system_id.mlt_id[1]);
+ assert(rport->p_element.system_id.rsvd ==
+ sport->p_element.system_id.rsvd);
+ assert(rport->p_element.system_id.rsvd2[0] ==
+ sport->p_element.system_id.rsvd2[0]);
+ assert(rport->p_element.system_id.rsvd2[1] ==
+ sport->p_element.system_id.rsvd2[1]);
/* Should receive 2 mappings */
assert(!list_is_empty(&rport->p_isid_vlan_maps));
@@ -160,7 +160,8 @@ test_aa_send(void)
hardware.h_lport.p_mfs = 1516;
/* Auto attach element discovery info */
- hardware.h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
+ hardware.h_lport.p_element.type =
+ LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH;
hardware.h_lport.p_element.mgmt_vlan = 0xCDC;
hardware.h_lport.p_element.system_id.system_mac[0] = 0x1;
hardware.h_lport.p_element.system_id.system_mac[1] = 0x2;
@@ -170,9 +171,9 @@ test_aa_send(void)
hardware.h_lport.p_element.system_id.system_mac[5] = 0x6;
hardware.h_lport.p_element.system_id.conn_type = 0x5;
- hardware.h_lport.p_element.system_id.smlt_id = 0x3CC;
- hardware.h_lport.p_element.system_id.mlt_id[0] = 0xB;
- hardware.h_lport.p_element.system_id.mlt_id[1] = 0xE;
+ hardware.h_lport.p_element.system_id.rsvd = 0x3CC;
+ hardware.h_lport.p_element.system_id.rsvd2[0] = 0xB;
+ hardware.h_lport.p_element.system_id.rsvd2[1] = 0xE;
/* Local chassis info */
chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
@@ -242,12 +243,12 @@ test_aa_send(void)
hw->h_lport.p_element.system_id.conn_type =
hardware.h_lport.p_element.system_id.conn_type;
- hw->h_lport.p_element.system_id.smlt_id =
- hardware.h_lport.p_element.system_id.smlt_id;
- hw->h_lport.p_element.system_id.mlt_id[0] =
- hardware.h_lport.p_element.system_id.mlt_id[0];
- hw->h_lport.p_element.system_id.mlt_id[1] =
- hardware.h_lport.p_element.system_id.mlt_id[1];
+ hw->h_lport.p_element.system_id.rsvd =
+ hardware.h_lport.p_element.system_id.rsvd;
+ hw->h_lport.p_element.system_id.rsvd2[0] =
+ hardware.h_lport.p_element.system_id.rsvd2[0];
+ hw->h_lport.p_element.system_id.rsvd2[1] =
+ hardware.h_lport.p_element.system_id.rsvd2[1];
/* Populate instance with two auto attach isid/vlan mappings */
map[0].isid_vlan_data.status = map_init[0].isid_vlan_data.status;
diff --git a/tests/test-csum.c b/tests/test-csum.c
index e25fb3d67..97638b916 100644
--- a/tests/test-csum.c
+++ b/tests/test-csum.c
@@ -20,11 +20,13 @@
#include <assert.h>
#include <inttypes.h>
#include <netinet/in.h>
+#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "crc32c.h"
#include "ovstest.h"
+#include "packets.h"
#include "random.h"
#include "unaligned.h"
#include "util.h"
@@ -175,6 +177,37 @@ test_crc32c(void)
mark('#');
}
+/* Check the IP pseudoheader calculation. */
+static void
+test_pseudo(void)
+{
+ ovs_be16 csum;
+ /* Try an IP header similar to one that the tunnel code
+ * might generate. */
+ struct ip_header ip = {
+ .ip_ihl_ver = IP_IHL_VER(5, 4),
+ .ip_tos = 0,
+ .ip_tot_len = htons(134),
+ .ip_id = 0,
+ .ip_frag_off = htons(IP_DF),
+ .ip_ttl = 64,
+ .ip_proto = IPPROTO_UDP,
+ .ip_csum = htons(0x1265),
+ .ip_src = { .hi = htons(0x1400), .lo = htons(0x0002) },
+ .ip_dst = { .hi = htons(0x1400), .lo = htons(0x0001) }
+ };
+
+ csum = csum_finish(packet_csum_pseudoheader(&ip));
+ assert(csum == htons(0xd779));
+
+ /* And also test something totally different to check for
+ * corner cases. */
+ memset(&ip, 0xff, sizeof ip);
+ csum = csum_finish(packet_csum_pseudoheader(&ip));
+ assert(csum == htons(0xff3c));
+
+ mark('#');
+}
static void
test_csum_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
@@ -239,6 +272,7 @@ test_csum_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
test_rfc1624();
test_crc32c();
+ test_pseudo();
/* Test recalc_csum16(). */
for (i = 0; i < 32; i++) {
diff --git a/tests/test-list.c b/tests/test-list.c
index 5fd7149c7..9b6b0bde9 100644
--- a/tests/test-list.c
+++ b/tests/test-list.c
@@ -159,6 +159,31 @@ test_list_for_each_safe(void)
}
}
+/* Tests that LIST_FOR_EACH_POP removes the elements of a list. */
+static void
+test_list_for_each_pop(void)
+{
+ enum { MAX_ELEMS = 10 };
+ size_t n;
+
+ for (n = 0; n <= MAX_ELEMS; n++) {
+ struct element elements[MAX_ELEMS];
+ int values[MAX_ELEMS];
+ struct ovs_list list;
+ struct element *e;
+ size_t n_remaining;
+
+ make_list(&list, elements, values, n);
+
+ n_remaining = n;
+ LIST_FOR_EACH_POP (e, node, &list) {
+ n_remaining--;
+ memmove(values, values + 1, sizeof *values * n_remaining);
+ check_list(&list, values, n_remaining);
+ }
+ }
+}
+
static void
run_test(void (*function)(void))
{
@@ -171,6 +196,7 @@ test_list_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
{
run_test(test_list_construction);
run_test(test_list_for_each_safe);
+ run_test(test_list_for_each_pop);
printf("\n");
}
diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
index f1fac7f89..877e417ad 100644
--- a/tests/tunnel-push-pop.at
+++ b/tests/tunnel-push-pop.at
@@ -7,7 +7,12 @@ AT_CHECK([ovs-vsctl add-br int-br -- set bridge int-br datapath_type=dummy], [0]
AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=vxlan \
options:remote_ip=1.1.2.92 options:key=123 ofport_request=2\
-- add-port int-br t1 -- set Interface t1 type=gre \
- options:remote_ip=1.1.2.92 options:key=456 ofport_request=3], [0])
+ options:remote_ip=1.1.2.92 options:key=456 ofport_request=3\
+ -- add-port int-br t3 -- set Interface t3 type=vxlan \
+ options:remote_ip=1.1.2.93 options:out_key=flow options:csum=true ofport_request=4\
+ -- add-port int-br t4 -- set Interface t4 type=geneve \
+ options:remote_ip=1.1.2.92 options:key=123 ofport_request=5\
+ ], [0])
AT_CHECK([ovs-appctl dpif/show], [0], [dnl
dummy@ovs-dummy: hit:0 missed:0
@@ -18,6 +23,8 @@ dummy@ovs-dummy: hit:0 missed:0
int-br 65534/2: (dummy)
t1 3/3: (gre: key=456, remote_ip=1.1.2.92)
t2 2/4789: (vxlan: key=123, remote_ip=1.1.2.92)
+ t3 4/4789: (vxlan: csum=true, out_key=flow, remote_ip=1.1.2.93)
+ t4 5/6081: (geneve: key=123, remote_ip=1.1.2.92)
])
AT_CHECK([ovs-appctl ovs/route/add 1.1.2.92/24 br0], [0], [OK
@@ -29,11 +36,13 @@ AT_CHECK([ovs-ofctl add-flow br0 action=normal])
dnl Check ARP Snoop
AT_CHECK([ovs-appctl netdev-dummy/receive br0 'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:34:b6,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.92,tip=1.1.2.88,op=1,sha=f8:bc:12:44:34:b6,tha=00:00:00:00:00:00)'])
+AT_CHECK([ovs-appctl netdev-dummy/receive br0 'recirc_id(0),in_port(100),eth(src=f8:bc:12:44:34:b7,dst=ff:ff:ff:ff:ff:ff),eth_type(0x0806),arp(sip=1.1.2.93,tip=1.1.2.88,op=1,sha=f8:bc:12:44:34:b7,tha=00:00:00:00:00:00)'])
AT_CHECK([ovs-appctl tnl/arp/show], [0], [dnl
IP MAC Bridge
=============================================
1.1.2.92 f8:bc:12:44:34:b6 br0
+1.1.2.93 f8:bc:12:44:34:b7 br0
])
dnl Check VXLAN tunnel pop
@@ -48,18 +57,54 @@ AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_pop(3)
])
+dnl Check Geneve tunnel pop
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x0800),ipv4(src=1.1.2.92,dst=1.1.2.88,proto=17,tos=0,ttl=64,frag=no),udp(src=51283,dst=6081)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_pop(6081)
+])
+
dnl Check VXLAN tunnel push
AT_CHECK([ovs-ofctl add-flow int-br action=2])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
- [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789),vxlan(flags=0x8000000,vni=0x7b00)),out_port(100))
+ [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789,csum=0x0),vxlan(flags=0x8000000,vni=0x7b)),out_port(100))
+])
+
+dnl Check VXLAN tunnel push set tunnel id by flow and checksum
+AT_CHECK([ovs-ofctl add-flow int-br "actions=set_tunnel:124,4"])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_push(tnl_port(4789),header(size=50,type=4,eth(dst=f8:bc:12:44:34:b7,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.93,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=4789,csum=0xffff),vxlan(flags=0x8000000,vni=0x7c)),out_port(100))
])
dnl Check GRE tunnel push
AT_CHECK([ovs-ofctl add-flow int-br action=3])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
- [Datapath actions: tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x20,proto=0x6558),key=0x1c8)),out_port(100))
+ [Datapath actions: tnl_push(tnl_port(3),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100))
+])
+
+dnl Check Geneve tunnel push
+AT_CHECK([ovs-ofctl add-flow int-br action=5])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_push(tnl_port(6081),header(size=50,type=5,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=17,tos=0,ttl=64,frag=0x40),udp(src=0,dst=6081,csum=0x0),geneve(vni=0x7b)),out_port(100))
+])
+
+dnl Check decapsulation of GRE packet
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 '001b213cac30001b213cab6408004500007e79464000402f99080101025c0101025820006558000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 3'], [0], [dnl
+ port 3: rx pkts=1, bytes=98, drop=0, errs=0, frame=0, over=0, crc=0
+])
+
+dnl Check GRE only accepts encapsulated Ethernet frames
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 '001b213cac30001b213cab6408004500007e79464000402f99080101025c0101025820000800000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
+ovs-appctl time/warp 1000
+
+AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 3'], [0], [dnl
+ port 3: rx pkts=1, bytes=98, drop=0, errs=0, frame=0, over=0, crc=0
])
OVS_VSWITCHD_STOP
diff --git a/tutorial/ovs-sandbox b/tutorial/ovs-sandbox
index 9e8ead004..133585e49 100755
--- a/tutorial/ovs-sandbox
+++ b/tutorial/ovs-sandbox
@@ -1,6 +1,6 @@
#! /bin/sh
#
-# Copyright (c) 2013 Nicira, Inc.
+# Copyright (c) 2013, 2015 Nicira, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@ rungdb() {
if $under_gdb && [ "$DISPLAY" ]; then
args=`echo $@ |sed s/--detach//g | sed s/--vconsole:off//g`
xterm_title=$1
- run_xterm $xterm_title gdb --args $args
+ run_xterm $xterm_title gdb -ex run --args $args
else
run $@
fi
@@ -279,6 +279,9 @@ fi
rungdb $gdb_ovsdb ovsdb-server --detach --no-chdir --pidfile -vconsole:off --log-file \
--remote=punix:"$sandbox"/db.sock $ovsdb_server_args
+# Initialize database.
+run ovs-vsctl --no-wait -- init
+
# Start ovs-vswitchd.
rungdb $gdb_vswitchd ovs-vswitchd --detach --no-chdir --pidfile -vconsole:off --log-file \
--enable-dummy=override -vvconn -vnetdev_dummy
diff --git a/utilities/automake.mk b/utilities/automake.mk
index 55bf44967..a06630f1f 100644
--- a/utilities/automake.mk
+++ b/utilities/automake.mk
@@ -22,6 +22,10 @@ scripts_SCRIPTS += \
utilities/ovs-save
scripts_DATA += utilities/ovs-lib
+completion_SCRIPTS += \
+ utilities/ovs-appctl-bashcomp.bash \
+ utilities/ovs-vsctl-bashcomp.bash
+
check_SCRIPTS += \
utilities/ovs-appctl-bashcomp.bash \
utilities/ovs-vsctl-bashcomp.bash
@@ -46,7 +50,8 @@ EXTRA_DIST += \
utilities/ovs-save \
utilities/ovs-tcpundump.in \
utilities/ovs-test.in \
- utilities/ovs-vlan-test.in
+ utilities/ovs-vlan-test.in \
+ utilities/qemu-wrap.py
MAN_ROOTS += \
utilities/ovs-appctl.8.in \
utilities/ovs-benchmark.1.in \
diff --git a/utilities/ovs-appctl-bashcomp.bash b/utilities/ovs-appctl-bashcomp.bash
index 0d83549ad..67a268eda 100755
--- a/utilities/ovs-appctl-bashcomp.bash
+++ b/utilities/ovs-appctl-bashcomp.bash
@@ -589,8 +589,9 @@ _ovs_command_complete() {
COMPREPLY=( $(compgen -W "$(echo $_COMP_WORDLIST | tr ' ' '\n' \
| sort -u | sed -e '/NO_EXPAN/d')" -- $cur) )
else
+ compopt -o nospace
# If there is no completions, just complete on file path.
- COMPREPLY=( $(compgen -o filenames -A file -- $cur) )
+ _filedir
fi
fi
diff --git a/utilities/ovs-command-bashcomp.INSTALL.md b/utilities/ovs-command-bashcomp.INSTALL.md
index 411f42fe6..9bdef40f3 100644
--- a/utilities/ovs-command-bashcomp.INSTALL.md
+++ b/utilities/ovs-command-bashcomp.INSTALL.md
@@ -65,9 +65,16 @@ ovs-vsctl-bashcomp
How to use:
-----------
- To use the scripts, either copy them inside /etc/bash_completion.d/ or
- manually run it directly in bash via . ovs-appctl-bashcomp.bash or
- . ovs-vsctl-bashcomp.bash.
+ The bashcomp scripts should be placed at /etc/bash_completion.d/
+ to be available for all bash sessions. Running 'make install'
+ will place the scripts to $(sysconfdir)/bash_completion.d/. So user
+ should specify --sysconfdir=/etc at configuration. Meanwhile, if OVS is
+ installed from packages, the scripts will automatically be placed inside
+ /etc/bash_completion.d/.
+
+ If you just want to run the scripts in one bash, you can remove them from
+ /etc/bash_completion.d/ and run the scripts via '. ovs-appctl-bashcomp.bash'
+ or '. ovs-vsctl-bashcomp.bash'.
Test:
-----
diff --git a/utilities/ovs-dev.py b/utilities/ovs-dev.py
index 869d89e81..9467df521 100755
--- a/utilities/ovs-dev.py
+++ b/utilities/ovs-dev.py
@@ -1,5 +1,5 @@
#!/usr/bin/python
-# Copyright (c) 2013, 2014 Nicira, Inc.
+# Copyright (c) 2013, 2014, 2015 Nicira, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -269,7 +269,8 @@ def modinst():
pass # Module isn't loaded
try:
- _sh("rm /lib/modules/%s/extra/openvswitch.ko" % uname())
+ _sh("rm -f /lib/modules/%s/extra/openvswitch.ko" % uname())
+ _sh("rm -f /lib/modules/%s/extra/vport-*.ko" % uname())
except subprocess.CalledProcessError, e:
pass # Module isn't installed
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 7aee788b0..ea3337b93 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -2248,6 +2248,40 @@ remove the in the group whose \fBbucket_id\fR is \fIid\fR.
It is an error if there is no bucket persent group in whose \fBbucket_id\fR is
\fIid\fR.
+.IP \fBselection_method\fR=\fImethod\fR
+The selection method used to select a bucket for a select group.
+This is a string of 1 to 15 bytes in length known to lower layers.
+This field is optional for \fBadd\-group\fR, \fBadd\-groups\fR and
+\fBmod\-group\fR commands on groups of type \fBselect\fR. Prohibited
+otherwise. The default value is the empty string.
+.IP
+This option will use a Netronome OpenFlow extension which is only supported
+when using Open vSwitch 2.4 and later with OpenFlow 1.5 and later.
+
+.IP \fBselection_method_param\fR=\fIparam\fR
+64-bit integer parameter to the selection method selected by the
+\fBselection_method\fR field. The parameter's use is defined by the
+lower-layer that implements the \fBselection_method\fR. It is optional if
+the \fBselection_method\fR field is specified as a non-empty string.
+Prohibited otherwise. The default value is zero.
+.IP
+This option will use a Netronome OpenFlow extension which is only supported
+when using Open vSwitch 2.4 and later with OpenFlow 1.5 and later.
+
+.IP \fBfields\fR=\fIparam\fR
+The field parameters to selection method selected by the
+\fBselection_method\fR field. The syntax is described in \fBFlow Syntax\fR
+with the additional restrictions that if a value is provided it is
+treated as a wildcard mask and wildcard masks following a slash are
+prohibited. The pre-requisites of fields must be provided by any flows that
+output to the group. The use of the fields is defined by the lower-layer
+that implements the \fBselection_method\fR. They are optional if the
+\fBselection_method\fR field is specified as a non-empty string.
+Prohibited otherwise. The default is no fields.
+.IP
+This option will use a Netronome OpenFlow extension which is only supported
+when using Open vSwitch 2.4 and later with OpenFlow 1.5 and later.
+
.IP \fBbucket\fR=\fIbucket_parameters\fR
The \fBadd-group\fR, \fBadd-groups\fR and \fBmod-group\fR commands
require at least one bucket field. Bucket fields must appear after
diff --git a/utilities/ovs-vsctl-bashcomp.bash b/utilities/ovs-vsctl-bashcomp.bash
index e79c6a217..a3273f8ee 100755
--- a/utilities/ovs-vsctl-bashcomp.bash
+++ b/utilities/ovs-vsctl-bashcomp.bash
@@ -202,7 +202,7 @@ _ovs_vsctl_complete_key_given_table_column () {
keys=$(_ovs_vsctl --no-heading --columns="$3" list \
"$2" \
| tr -d '{\"}' | tr -s ', ' '\n' | cut -d'=' -f1 \
- | xargs printf "$4%s\n" | _ovs_vsctl_check_startswith_string "$1")
+ | xargs printf "$4%s\n" | _ovs_vsctl_check_startswith_string "$4$1")
result="${keys}"
printf -- "%s\n" "${result}"
}
@@ -604,6 +604,43 @@ _ovs_vsctl_process_messages () {
fi
}
+# colon, equal sign will mess up the completion output, just
+# removes the colon-word and equal-word prefix from COMPREPLY items.
+#
+# Implementation of this function refers to the __ltrim_colon_completions
+# function defined in bash_completion module.
+#
+# $1: Current argument
+# $2: $COMP_WORDBREAKS
+# $3: ${COMPREPLY[@]}
+_ovs_vsctl_trim_compreply() {
+ local cur comp_wordbreaks
+ local compreply
+
+ cur=$1 && shift
+ comp_wordbreaks=$1 && shift
+ compreply=( $@ )
+
+ if [[ "$cur" == *:* && "$comp_wordbreaks" == *:* ]]; then
+ local colon_word=${cur%${cur##*:}}
+ local i=${#compreply[*]}
+ cur=${cur##*:}
+ while [ $((--i)) -ge 0 ]; do
+ compreply[$i]=${compreply[$i]#"$colon_word"}
+ done
+ fi
+
+ if [[ "$cur" == *=* && "$comp_wordbreaks" == *=* ]]; then
+ local equal_word=${cur%${cur##*=}}
+ local i=${#compreply[*]}
+ while [ $((--i)) -ge 0 ]; do
+ compreply[$i]=${compreply[$i]#"$equal_word"}
+ done
+ fi
+
+ printf "%s " "${compreply[@]}"
+}
+
# The general strategy here is that the same functions that decide
# completions can also capture the necessary context for later
# completions. This means that there is no distinction between the
@@ -627,7 +664,7 @@ _ovs_vsctl_process_messages () {
# status of the function _ovs_vsctl_complete_argument represents where
# it has determined that the next argument will be.
_ovs_vsctl_bashcomp () {
- local cur valid_globals cmd_args raw_cmd cmd_pos valid_globals valid_opts
+ local words cword valid_globals cmd_args raw_cmd cmd_pos valid_globals valid_opts
local test="false"
# Does not support BASH_VERSION < 4.0
@@ -645,6 +682,12 @@ _ovs_vsctl_bashcomp () {
<<< "$tmp"
export COMP_WORDS
export COMP_CWORD="$((${#COMP_WORDS[@]}-1))"
+ else
+ # If not in test mode, reassembles the COMP_WORDS and COMP_CWORD
+ # using just space as word break.
+ _get_comp_words_by_ref -n "\"'><=;|&(:" -w words -i cword
+ COMP_WORDS=( "${words[@]}" )
+ COMP_CWORD=${cword}
fi
# Extract the conf.db path.
@@ -654,20 +697,18 @@ _ovs_vsctl_bashcomp () {
fi
# If having trouble accessing the database, return.
- if ! _ovs_vsctl get-manager 2>/dev/null; then
+ if ! _ovs_vsctl get-manager 1>/dev/null 2>/dev/null; then
return 1;
fi
_OVS_VSCTL_PARSED_ARGS=()
_OVS_VSCTL_NEW_RECORDS=()
cmd_pos=-1
- cur=${COMP_WORDS[COMP_CWORD]}
valid_globals=true
valid_opts=true
valid_commands=true
given_opts=""
index=1
- export COMP_WORDBREAKS=" "
for word in "${COMP_WORDS[@]:1:${COMP_CWORD}} "; do
_OVS_VSCTL_COMP_NOSPACE=false
local completion
@@ -753,6 +794,8 @@ _ovs_vsctl_bashcomp () {
completion="$(sort -u <<< "$(tr ' ' '\n' <<< ${completion})")"
if [ $index -eq $COMP_CWORD ]; then
if [ "$test" = "true" ]; then
+ completion="$(_ovs_vsctl_trim_compreply "$word" ":=" ${completion} | \
+ tr ' ' '\n')"
if [ "${_OVS_VSCTL_COMP_NOSPACE}" = "true" ]; then
printf "%s" "$completion" | sed -e '/^$/d'
else
@@ -767,6 +810,8 @@ _ovs_vsctl_bashcomp () {
compopt +o nospace
COMPREPLY=( $(compgen -W "${completion}" -- $word) )
fi
+ COMPREPLY=( $(_ovs_vsctl_trim_compreply "$word" \
+ "${COMP_WORDBREAKS}" ${COMPREPLY[@]}) )
fi
fi
index=$(($index+1))
diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c
index 1abefb440..009a8caad 100644
--- a/utilities/ovs-vsctl.c
+++ b/utilities/ovs-vsctl.c
@@ -1185,7 +1185,6 @@ pre_get_info(struct vsctl_context *ctx)
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_controller);
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_fail_mode);
ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_ports);
- ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_auto_attach);
ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_name);
ovsdb_idl_add_column(ctx->idl, &ovsrec_port_col_fake_bridge);
@@ -1194,7 +1193,6 @@ pre_get_info(struct vsctl_context *ctx)
ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_name);
- ovsdb_idl_add_column(ctx->idl, &ovsrec_autoattach_col_mappings);
ovsdb_idl_add_column(ctx->idl, &ovsrec_interface_col_ofport);
}
@@ -1807,7 +1805,6 @@ cmd_add_br(struct vsctl_context *ctx)
if (!parent_name) {
struct ovsrec_port *port;
- struct ovsrec_autoattach *aa;
struct ovsrec_bridge *br;
iface = ovsrec_interface_insert(ctx->txn);
@@ -1818,12 +1815,9 @@ cmd_add_br(struct vsctl_context *ctx)
ovsrec_port_set_name(port, br_name);
ovsrec_port_set_interfaces(port, &iface, 1);
- aa = ovsrec_autoattach_insert(ctx->txn);
-
br = ovsrec_bridge_insert(ctx->txn);
ovsrec_bridge_set_name(br, br_name);
ovsrec_bridge_set_ports(br, &port, 1);
- ovsrec_bridge_set_auto_attach(br, aa);
ovs_insert_bridge(ctx->ovs, br);
} else {
@@ -2732,6 +2726,10 @@ cmd_add_aa_mapping(struct vsctl_context *ctx)
}
if (br && br->br_cfg) {
+ if (!br->br_cfg->auto_attach) {
+ struct ovsrec_autoattach *aa = ovsrec_autoattach_insert(ctx->txn);
+ ovsrec_bridge_set_auto_attach(br->br_cfg, aa);
+ }
autoattach_insert_mapping(br->br_cfg->auto_attach, isid, vlan);
}
}
@@ -2806,6 +2804,7 @@ pre_aa_mapping(struct vsctl_context *ctx)
{
pre_get_info(ctx);
+ ovsdb_idl_add_column(ctx->idl, &ovsrec_bridge_col_auto_attach);
ovsdb_idl_add_column(ctx->idl, &ovsrec_autoattach_col_mappings);
}
@@ -4678,7 +4677,7 @@ static const struct vsctl_command_syntax all_commands[] = {
cmd_set_ssl, NULL, "--bootstrap", RW},
/* Auto Attach commands. */
- {"add-aa-mapping", 3, 3, "BRIDGE ARG ARG", pre_get_info, cmd_add_aa_mapping,
+ {"add-aa-mapping", 3, 3, "BRIDGE ARG ARG", pre_aa_mapping, cmd_add_aa_mapping,
NULL, "", RW},
{"del-aa-mapping", 3, 3, "BRIDGE ARG ARG", pre_aa_mapping, cmd_del_aa_mapping,
NULL, "", RW},
diff --git a/utilities/qemu-wrap.py b/utilities/qemu-wrap.py
new file mode 100755
index 000000000..5cee849ae
--- /dev/null
+++ b/utilities/qemu-wrap.py
@@ -0,0 +1,389 @@
+#!/usr/bin/python
+#
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+#####################################################################
+# This script is designed to modify the call to the QEMU emulator
+# to support userspace vhost when starting a guest machine through
+# libvirt with vhost enabled. The steps to enable this are as follows
+# and should be run as root:
+#
+# 1. Place this script in a libvirtd's binary search PATH ($PATH)
+# A good location would be in the same directory that the QEMU
+# binary is located
+#
+# 2. Ensure that the script has the same owner/group and file
+# permissions as the QEMU binary
+#
+# 3. Update the VM xml file using "virsh edit VM.xml"
+#
+# 3.a) Set the VM to use the launch script
+#
+# Set the emulator path contained in the
+# <emulator><emulator/> tags
+#
+# e.g replace <emulator>/usr/bin/qemu-kvm<emulator/>
+# with <emulator>/usr/bin/qemu-wrap.py<emulator/>
+#
+# 3.b) Set the VM's device's to use vhost-net offload
+#
+# <interface type="network">
+# <model type="virtio"/>
+# <driver name="vhost"/>
+# <interface/>
+#
+# 4. Enable libvirt to access our userpace device file by adding it to
+# controllers cgroup for libvirtd using the following steps
+#
+# 4.a) In /etc/libvirt/qemu.conf add/edit the following lines:
+# 1) cgroup_controllers = [ ... "devices", ... ]
+# 2) clear_emulator_capabilities = 0
+# 3) user = "root"
+# 4) group = "root"
+# 5) cgroup_device_acl = [
+# "/dev/null", "/dev/full", "/dev/zero",
+# "/dev/random", "/dev/urandom",
+# "/dev/ptmx", "/dev/kvm", "/dev/kqemu",
+# "/dev/rtc", "/dev/hpet", "/dev/net/tun",
+# "/dev/<devbase-name>-<index>",
+# "/dev/hugepages"
+# ]
+#
+# 4.b) Disable SELinux or set to permissive mode
+#
+# 4.c) Mount cgroup device controller
+# "mkdir /dev/cgroup"
+# "mount -t cgroup none /dev/cgroup -o devices"
+#
+# 4.d) Set hugetlbfs_mount variable - ( Optional )
+# VMs using userspace vhost must use hugepage backed
+# memory. This can be enabled in the libvirt XML
+# config by adding a memory backing section to the
+# XML config e.g.
+# <memoryBacking>
+# <hugepages/>
+# </memoryBacking>
+# This memory backing section should be added after the
+# <memory> and <currentMemory> sections. This will add
+# flags "-mem-prealloc -mem-path <path>" to the QEMU
+# command line. The hugetlbfs_mount variable can be used
+# to override the default <path> passed through by libvirt.
+#
+# if "-mem-prealloc" or "-mem-path <path>" are not passed
+# through and a vhost device is detected then these options will
+# be automatically added by this script. This script will detect
+# the system hugetlbfs mount point to be used for <path>. The
+# default <path> for this script can be overidden by the
+# hugetlbfs_dir variable in the configuration section of this script.
+#
+#
+# 4.e) Restart the libvirtd system process
+# e.g. on Fedora "systemctl restart libvirtd.service"
+#
+#
+# 4.f) Edit the Configuration Parameters section of this script
+# to point to the correct emulator location and set any
+# addition options
+#
+# The script modifies the libvirtd Qemu call by modifying/adding
+# options based on the configuration parameters below.
+# NOTE:
+# emul_path and us_vhost_path must be set
+# All other parameters are optional
+#####################################################################
+
+
+#############################################
+# Configuration Parameters
+#############################################
+#Path to QEMU binary
+emul_path = "/usr/local/bin/qemu-system-x86_64"
+
+#Path to userspace vhost device file
+# This filename should match the --dev-basename --dev-index parameters of
+# the command used to launch the userspace vhost sample application e.g.
+# if the sample app lauch command is:
+# ./build/vhost-switch ..... --dev-basename usvhost --dev-index 1
+# then this variable should be set to:
+# us_vhost_path = "/dev/usvhost-1"
+us_vhost_path = "/dev/usvhost-1"
+
+#List of additional user defined emulation options. These options will
+#be added to all Qemu calls
+emul_opts_user = []
+
+#List of additional user defined emulation options for vhost only.
+#These options will only be added to vhost enabled guests
+emul_opts_user_vhost = []
+
+#For all VHOST enabled VMs, the VM memory is preallocated from hugetlbfs
+# Set this variable to one to enable this option for all VMs
+use_huge_all = 0
+
+#Instead of autodetecting, override the hugetlbfs directory by setting
+#this variable
+hugetlbfs_dir = ""
+
+#############################################
+
+
+#############################################
+# ****** Do Not Modify Below this Line ******
+#############################################
+
+import sys, os, subprocess
+import time
+import signal
+
+
+#List of open userspace vhost file descriptors
+fd_list = []
+
+#additional virtio device flags when using userspace vhost
+vhost_flags = [ "csum=off",
+ "gso=off",
+ "guest_tso4=off",
+ "guest_tso6=off",
+ "guest_ecn=off"
+ ]
+
+#String of the path to the Qemu process pid
+qemu_pid = "/tmp/%d-qemu.pid" % os.getpid()
+
+#############################################
+# Signal haldler to kill Qemu subprocess
+#############################################
+def kill_qemu_process(signum, stack):
+ pidfile = open(qemu_pid, 'r')
+ pid = int(pidfile.read())
+ os.killpg(pid, signal.SIGTERM)
+ pidfile.close()
+
+
+#############################################
+# Find the system hugefile mount point.
+# Note:
+# if multiple hugetlbfs mount points exist
+# then the first one found will be used
+#############################################
+def find_huge_mount():
+
+ if (len(hugetlbfs_dir)):
+ return hugetlbfs_dir
+
+ huge_mount = ""
+
+ if (os.access("/proc/mounts", os.F_OK)):
+ f = open("/proc/mounts", "r")
+ line = f.readline()
+ while line:
+ line_split = line.split(" ")
+ if line_split[2] == 'hugetlbfs':
+ huge_mount = line_split[1]
+ break
+ line = f.readline()
+ else:
+ print "/proc/mounts not found"
+ exit (1)
+
+ f.close
+ if len(huge_mount) == 0:
+ print "Failed to find hugetlbfs mount point"
+ exit (1)
+
+ return huge_mount
+
+
+#############################################
+# Get a userspace Vhost file descriptor
+#############################################
+def get_vhost_fd():
+
+ if (os.access(us_vhost_path, os.F_OK)):
+ fd = os.open( us_vhost_path, os.O_RDWR)
+ else:
+ print ("US-Vhost file %s not found" %us_vhost_path)
+ exit (1)
+
+ return fd
+
+
+#############################################
+# Check for vhostfd. if found then replace
+# with our own vhost fd and append any vhost
+# flags onto the end
+#############################################
+def modify_netdev_arg(arg):
+
+ global fd_list
+ vhost_in_use = 0
+ s = ''
+ new_opts = []
+ netdev_opts = arg.split(",")
+
+ for opt in netdev_opts:
+ #check if vhost is used
+ if "vhost" == opt[:5]:
+ vhost_in_use = 1
+ else:
+ new_opts.append(opt)
+
+ #if using vhost append vhost options
+ if vhost_in_use == 1:
+ #append vhost on option
+ new_opts.append('vhost=on')
+ #append vhostfd ption
+ new_fd = get_vhost_fd()
+ new_opts.append('vhostfd=' + str(new_fd))
+ fd_list.append(new_fd)
+
+ #concatenate all options
+ for opt in new_opts:
+ if len(s) > 0:
+ s+=','
+
+ s+=opt
+
+ return s
+
+
+#############################################
+# Main
+#############################################
+def main():
+
+ global fd_list
+ global vhost_in_use
+ new_args = []
+ num_cmd_args = len(sys.argv)
+ emul_call = ''
+ mem_prealloc_set = 0
+ mem_path_set = 0
+ num = 0;
+
+ #parse the parameters
+ while (num < num_cmd_args):
+ arg = sys.argv[num]
+
+ #Check netdev +1 parameter for vhostfd
+ if arg == '-netdev':
+ num_vhost_devs = len(fd_list)
+ new_args.append(arg)
+
+ num+=1
+ arg = sys.argv[num]
+ mod_arg = modify_netdev_arg(arg)
+ new_args.append(mod_arg)
+
+ #append vhost flags if this is a vhost device
+ # and -device is the next arg
+ # i.e -device -opt1,-opt2,...,-opt3,%vhost
+ if (num_vhost_devs < len(fd_list)):
+ num+=1
+ arg = sys.argv[num]
+ if arg == '-device':
+ new_args.append(arg)
+ num+=1
+ new_arg = sys.argv[num]
+ for flag in vhost_flags:
+ new_arg = ''.join([new_arg,',',flag])
+ new_args.append(new_arg)
+ else:
+ new_args.append(arg)
+ elif arg == '-mem-prealloc':
+ mem_prealloc_set = 1
+ new_args.append(arg)
+ elif arg == '-mem-path':
+ mem_path_set = 1
+ new_args.append(arg)
+
+ else:
+ new_args.append(arg)
+
+ num+=1
+
+ #Set Qemu binary location
+ emul_call+=emul_path
+ emul_call+=" "
+
+ #Add prealloc mem options if using vhost and not already added
+ if ((len(fd_list) > 0) and (mem_prealloc_set == 0)):
+ emul_call += "-mem-prealloc "
+
+ #Add mempath mem options if using vhost and not already added
+ if ((len(fd_list) > 0) and (mem_path_set == 0)):
+ #Detect and add hugetlbfs mount point
+ mp = find_huge_mount()
+ mp = "".join(["-mem-path ", mp])
+ emul_call += mp
+ emul_call += " "
+
+ #add user options
+ for opt in emul_opts_user:
+ emul_call += opt
+ emul_call += " "
+
+ #Add add user vhost only options
+ if len(fd_list) > 0:
+ for opt in emul_opts_user_vhost:
+ emul_call += opt
+ emul_call += " "
+
+ #Add updated libvirt options
+ iter_args = iter(new_args)
+ #skip 1st arg i.e. call to this script
+ next(iter_args)
+ for arg in iter_args:
+ emul_call+=str(arg)
+ emul_call+= " "
+
+ emul_call += "-pidfile %s " % qemu_pid
+ #Call QEMU
+ process = subprocess.Popen(emul_call, shell=True, preexec_fn=os.setsid)
+
+ for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGHUP, signal.SIGQUIT]:
+ signal.signal(sig, kill_qemu_process)
+
+ process.wait()
+
+ #Close usvhost files
+ for fd in fd_list:
+ os.close(fd)
+ #Cleanup temporary files
+ if os.access(qemu_pid, os.F_OK):
+ os.remove(qemu_pid)
+
+
+
+if __name__ == "__main__":
+ main()
diff --git a/vswitchd/automake.mk b/vswitchd/automake.mk
index 2f07c0fc7..81f201a45 100644
--- a/vswitchd/automake.mk
+++ b/vswitchd/automake.mk
@@ -63,7 +63,7 @@ vswitchd/vswitch.ovsschema.stamp: vswitchd/vswitch.ovsschema
touch $@; \
else \
ln=`sed -n '/"cksum":/=' $?`; \
- echo >&2 "$?:$$ln: checksum \"$$sum\" does not match (you should probably update the version number and fix the checksum)"; \
+ echo >&2 "$?:$$ln: The checksum \"$$sum\" was calculated from the schema file and does not match cksum field in the schema file - you should probably update the version number and the checksum in the schema file with the value listed here."; \
exit 1; \
fi
CLEANFILES += vswitchd/vswitch.ovsschema.stamp
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 85bbfa3f2..ea7d78838 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -18,6 +18,7 @@
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
+
#include "async-append.h"
#include "bfd.h"
#include "bitmap.h"
@@ -26,6 +27,7 @@
#include "coverage.h"
#include "daemon.h"
#include "dirs.h"
+#include "dpif.h"
#include "dynamic-string.h"
#include "hash.h"
#include "hmap.h"
@@ -201,6 +203,9 @@ static bool status_txn_try_again;
* timeout in 'STATUS_CHECK_AGAIN_MSEC' to check again. */
#define STATUS_CHECK_AGAIN_MSEC 100
+/* Statistics update to database. */
+static struct ovsdb_idl_txn *stats_txn;
+
/* Each time this timer expires, the bridge fetches interface and mirror
* statistics and pushes them into the database. */
static int stats_timer_interval;
@@ -317,6 +322,7 @@ static ofp_port_t iface_get_requested_ofp_port(
const struct ovsrec_interface *);
static ofp_port_t iface_pick_ofport(const struct ovsrec_interface *);
+
/* Linux VLAN device support (e.g. "eth0.10" for VLAN 10.)
*
* This is deprecated. It is only for compatibility with broken device drivers
@@ -335,6 +341,8 @@ static void add_vlan_splinter_ports(struct bridge *,
const unsigned long int *splinter_vlans,
struct shash *ports);
+static void discover_types(const struct ovsrec_open_vswitch *cfg);
+
static void
bridge_init_ofproto(const struct ovsrec_open_vswitch *cfg)
{
@@ -394,6 +402,8 @@ bridge_init(const char *remote)
ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_cur_cfg);
ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_statistics);
+ ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_datapath_types);
+ ovsdb_idl_omit_alert(idl, &ovsrec_open_vswitch_col_iface_types);
ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_external_ids);
ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_ovs_version);
ovsdb_idl_omit(idl, &ovsrec_open_vswitch_col_db_version);
@@ -571,6 +581,10 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
smap_get_int(&ovs_cfg->other_config, "n-handler-threads", 0),
smap_get_int(&ovs_cfg->other_config, "n-revalidator-threads", 0));
+ if (ovs_cfg) {
+ discover_types(ovs_cfg);
+ }
+
/* Destroy "struct bridge"s, "struct port"s, and "struct iface"s according
* to 'ovs_cfg', with only very minimal configuration otherwise.
*
@@ -2682,7 +2696,6 @@ refresh_controller_status(void)
static void
run_stats_update(void)
{
- static struct ovsdb_idl_txn *stats_txn;
const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(idl);
int stats_interval;
@@ -2737,6 +2750,18 @@ run_stats_update(void)
}
}
+static void
+stats_update_wait(void)
+{
+ /* If the 'stats_txn' is non-null (transaction incomplete), waits for the
+ * transaction to complete. Otherwise, waits for the 'stats_timer'. */
+ if (stats_txn) {
+ ovsdb_idl_txn_wait(stats_txn);
+ } else {
+ poll_timer_wait_until(stats_timer);
+ }
+}
+
/* Update bridge/port/interface status if necessary. */
static void
run_status_update(void)
@@ -2815,12 +2840,6 @@ run_status_update(void)
static void
status_update_wait(void)
{
- /* This prevents the process from constantly waking up on
- * connectivity seq, when there is no connection to ovsdb. */
- if (!ovsdb_idl_has_lock(idl)) {
- return;
- }
-
/* If the 'status_txn' is non-null (transaction incomplete), waits for the
* transaction to complete. If the status update to database needs to be
* run again (transaction fails), registers a timeout in
@@ -2884,7 +2903,10 @@ bridge_run(void)
* disable system stats collection. */
system_stats_enable(false);
return;
- } else if (!ovsdb_idl_has_lock(idl)) {
+ } else if (!ovsdb_idl_has_lock(idl)
+ || !ovsdb_idl_has_ever_connected(idl)) {
+ /* Returns if not holding the lock or not done retrieving db
+ * contents. */
return;
}
cfg = ovsrec_open_vswitch_first(idl);
@@ -2940,6 +2962,7 @@ bridge_run(void)
if (cfg) {
ovsrec_open_vswitch_set_cur_cfg(cfg, cfg->next_cfg);
+ discover_types(cfg);
}
/* If we are completing our initial configuration for this run
@@ -3002,11 +3025,10 @@ bridge_wait(void)
HMAP_FOR_EACH (br, node, &all_bridges) {
ofproto_wait(br->ofproto);
}
-
- poll_timer_wait_until(stats_timer);
+ stats_update_wait();
+ status_update_wait();
}
- status_update_wait();
system_stats_wait();
}
@@ -4382,7 +4404,7 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos)
ofpbuf_init(&queues_buf, 0);
- if (!qos || qos->type[0] == '\0' || qos->n_queues < 1) {
+ if (!qos || qos->type[0] == '\0') {
netdev_set_qos(iface->netdev, NULL, NULL);
} else {
const struct ovsdb_datum *queues;
@@ -4445,8 +4467,8 @@ iface_configure_qos(struct iface *iface, const struct ovsrec_qos *qos)
}
netdev_set_policing(iface->netdev,
- iface->cfg->ingress_policing_rate,
- iface->cfg->ingress_policing_burst);
+ MIN(UINT32_MAX, iface->cfg->ingress_policing_rate),
+ MIN(UINT32_MAX, iface->cfg->ingress_policing_burst));
ofpbuf_uninit(&queues_buf);
}
@@ -5023,3 +5045,31 @@ mirror_refresh_stats(struct mirror *m)
ovsrec_mirror_set_statistics(m->cfg, keys, values, stat_cnt);
}
+
+/*
+ * Add registered netdev and dpif types to ovsdb to allow external
+ * applications to query the capabilities of the Open vSwitch instance
+ * running on the node.
+ */
+static void
+discover_types(const struct ovsrec_open_vswitch *cfg)
+{
+ struct sset types;
+
+ /* Datapath types. */
+ sset_init(&types);
+ dp_enumerate_types(&types);
+ const char **datapath_types = sset_array(&types);
+ ovsrec_open_vswitch_set_datapath_types(cfg, datapath_types,
+ sset_count(&types));
+ free(datapath_types);
+ sset_destroy(&types);
+
+ /* Port types. */
+ sset_init(&types);
+ netdev_enumerate_types(&types);
+ const char **iface_types = sset_array(&types);
+ ovsrec_open_vswitch_set_iface_types(cfg, iface_types, sset_count(&types));
+ free(iface_types);
+ sset_destroy(&types);
+}
diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c
index eda4aab21..44d44f043 100644
--- a/vswitchd/ovs-vswitchd.c
+++ b/vswitchd/ovs-vswitchd.c
@@ -252,11 +252,13 @@ usage(void)
daemon_usage();
vlog_usage();
printf("\nDPDK options:\n"
- " --dpdk options Initialize DPDK datapath.\n");
+ " --dpdk options Initialize DPDK datapath.\n"
+ " --cuse_dev_name BASENAME override default character device name\n"
+ " for use with userspace vHost.\n");
printf("\nOther options:\n"
- " --unixctl=SOCKET override default control socket name\n"
- " -h, --help display this help message\n"
- " -V, --version display version information\n");
+ " --unixctl=SOCKET override default control socket name\n"
+ " -h, --help display this help message\n"
+ " -V, --version display version information\n");
exit(EXIT_SUCCESS);
}
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
index 4898b16d0..35f145f5d 100644
--- a/vswitchd/vswitch.ovsschema
+++ b/vswitchd/vswitch.ovsschema
@@ -1,6 +1,6 @@
{"name": "Open_vSwitch",
- "version": "7.11.2",
- "cksum": "320332148 22294",
+ "version": "7.12.1",
+ "cksum": "2211824403 22535",
"tables": {
"Open_vSwitch": {
"columns": {
@@ -39,7 +39,13 @@
"min": 0, "max": 1}},
"system_version": {
"type": {"key": {"type": "string"},
- "min": 0, "max": 1}}},
+ "min": 0, "max": 1}},
+ "datapath_types": {
+ "type": {"key": {"type": "string"},
+ "min": 0, "max": "unlimited"}},
+ "iface_types": {
+ "type": {"key": {"type": "string"},
+ "min": 0, "max": "unlimited"}}},
"isRoot": true,
"maxRows": 1},
"Bridge": {
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 1bd652217..3256ce0a4 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -423,6 +423,28 @@
</group>
+ <group title="Capabilities">
+ <p>
+ These columns report capabilities of the Open vSwitch instance.
+ </p>
+ <column name="datapath_types">
+ <p>
+ This column reports the different dpifs registered with the system.
+ These are the values that this instance supports in the <ref
+ column="datapath_type" table="Bridge"/> column of the <ref
+ table="Bridge"/> table.
+ </p>
+ </column>
+ <column name="iface_types">
+ <p>
+ This column reports the different netdevs registered with the system.
+ These are the values that this instance supports in the <ref
+ column="type" table="Interface"/> column of the <ref
+ table="Interface"/> table.
+ </p>
+ </column>
+ </group>
+
<group title="Database Configuration">
<p>
These columns primarily configure the Open vSwitch database
@@ -928,9 +950,12 @@
<group title="Other Features">
<column name="datapath_type">
- Name of datapath provider. The kernel datapath has
- type <code>system</code>. The userspace datapath has
- type <code>netdev</code>.
+ Name of datapath provider. The kernel datapath has type
+ <code>system</code>. The userspace datapath has type
+ <code>netdev</code>. A manager may refer to the <ref
+ table="Open_vSwitch" column="datapath_types"/> column of the <ref
+ table="Open_vSwitch"/> table for a list of the types accepted by this
+ Open vSwitch instance.
</column>
<column name="external_ids" key="bridge-id">
@@ -955,18 +980,47 @@
<column name="other_config" key="forward-bpdu"
type='{"type": "boolean"}'>
- Option to allow forwarding of BPDU frames when NORMAL action is
- invoked. Frames with reserved Ethernet addresses (e.g. STP
- BPDU) will be forwarded when this option is enabled and the
- switch is not providing that functionality. If STP is enabled
- on the port, STP BPDUs will never be forwarded. If the Open
- vSwitch bridge is used to connect different Ethernet networks,
- and if Open vSwitch node does not run STP, then this option
- should be enabled. Default is disabled, set to
- <code>true</code> to enable.
-
- The following destination MAC addresss will not be forwarded when this
- option is enabled.
+
+ <p>
+ Controls forwarding of BPDUs and other network control frames when
+ NORMAL action is invoked. When this option is <code>false</code> or
+ unset, frames with reserved Ethernet addresses (see table below) will
+ not be forwarded. When this option is <code>true</code>, such frames
+ will not be treated specially.
+ </p>
+
+ <p>
+ The above general rule has the following exceptions:
+ </p>
+
+ <ul>
+ <li>
+ If STP is enabled on the bridge (see the <ref column="stp_enable"
+ table="Bridge"/> column in the <ref table="Bridge"/> table), the
+ bridge processes all received STP packets and never passes them to
+ OpenFlow or forwards them. This is true even if STP is disabled on
+ an individual port.
+ </li>
+
+ <li>
+ If LLDP is enabled on an interface (see the <ref column="lldp"
+ table="Interface"/> column in the <ref table="Interface"/> table),
+ the interface processes received LLDP packets and never passes them
+ to OpenFlow or forwards them.
+ </li>
+ </ul>
+
+ <p>
+ Set this option to <code>true</code> if the Open vSwitch bridge
+ connects different Ethernet networks and is not configured to
+ participate in STP.
+ </p>
+
+ <p>
+ This option affects packets with the following destination MAC
+ addresses:
+ </p>
+
<dl>
<dt><code>01:80:c2:00:00:00</code></dt>
<dd>IEEE 802.1D Spanning Tree Protocol (STP).</dd>
@@ -1747,7 +1801,10 @@
<group title="System-Specific Details">
<column name="type">
<p>
- The interface type, one of:
+ The interface type. The types supported by a particular instance of
+ Open vSwitch are listed in the <ref table="Open_vSwitch"
+ column="iface_types"/> column in the <ref table="Open_vSwitch"/>
+ table. The following types are defined:
</p>
<dl>
@@ -2029,24 +2086,28 @@
</group>
- <group title="Tunnel Options: gre and ipsec_gre only">
+ <group title="Tunnel Options: gre, ipsec_gre, geneve, and vxlan">
<p>
- Only <code>gre</code> and <code>ipsec_gre</code> interfaces support
- these options.
+ <code>gre</code>, <code>ipsec_gre</code>, <code>geneve</code>, and
+ <code>vxlan</code> interfaces support these options.
</p>
<column name="options" key="csum" type='{"type": "boolean"}'>
<p>
- Optional. Compute GRE checksums on outgoing packets. Default is
- disabled, set to <code>true</code> to enable. Checksums present on
- incoming packets will be validated regardless of this setting.
+ Optional. Compute encapsulation header (either GRE or UDP)
+ checksums on outgoing packets. Default is disabled, set to
+ <code>true</code> to enable. Checksums present on incoming
+ packets will be validated regardless of this setting.
</p>
- <p>
- GRE checksums impose a significant performance penalty because they
- cover the entire packet. The encapsulated L3, L4, and L7 packet
- contents typically have their own checksums, so this additional
- checksum only adds value for the GRE and encapsulated L2 headers.
+ <p>
+ When using the upstream Linux kernel module, computation of
+ checksums for <code>geneve</code> and <code>vxlan</code> requires
+ Linux kernel version 4.0 or higher. <code>gre</code> supports
+ checksums for all versions of Open vSwitch that support GRE.
+ The out of tree kernel module distributed as part of OVS
+ can compute all tunnel checksums on any kernel version that it
+ is compatible with.
</p>
<p>
@@ -3149,6 +3210,33 @@
information on how this classifier works.
</dd>
</dl>
+ <dl>
+ <dt><code>linux-sfq</code></dt>
+ <dd>
+ Linux ``Stochastic Fairness Queueing'' classifier. See
+ <code>tc-sfq</code>(8) (also at
+ <code>http://linux.die.net/man/8/tc-sfq</code>) for information on
+ how this classifier works.
+ </dd>
+ </dl>
+ <dl>
+ <dt><code>linux-codel</code></dt>
+ <dd>
+ Linux ``Controlled Delay'' classifier. See <code>tc-codel</code>(8)
+ (also at
+ <code>http://man7.org/linux/man-pages/man8/tc-codel.8.html</code>)
+ for information on how this classifier works.
+ </dd>
+ </dl>
+ <dl>
+ <dt><code>linux-fq_codel</code></dt>
+ <dd>
+ Linux ``Fair Queuing with Controlled Delay'' classifier. See
+ <code>tc-fq_codel</code>(8) (also at
+ <code>http://man7.org/linux/man-pages/man8/tc-fq_codel.8.html</code>)
+ for information on how this classifier works.
+ </dd>
+ </dl>
</column>
<column name="queues">
diff --git a/vtep/automake.mk b/vtep/automake.mk
index 184d85f61..c712b0c91 100644
--- a/vtep/automake.mk
+++ b/vtep/automake.mk
@@ -87,7 +87,7 @@ vtep/vtep.ovsschema.stamp: vtep/vtep.ovsschema
touch $@; \
else \
ln=`sed -n '/"cksum":/=' $?`; \
- echo >&2 "$?:$$ln: checksum \"$$sum\" does not match (you should probably update the version number and fix the checksum)"; \
+ echo >&2 "$?:$$ln: The checksum \"$$sum\" was calculated from the schema file and does not match cksum field in the schema file - you should probably update the version number and the checksum in the schema file with the value listed here."; \
exit 1; \
fi
CLEANFILES += vtep/vtep.ovsschema.stamp
diff --git a/xenserver/openvswitch-xen.spec.in b/xenserver/openvswitch-xen.spec.in
index 3bae86a51..2902372e8 100644
--- a/xenserver/openvswitch-xen.spec.in
+++ b/xenserver/openvswitch-xen.spec.in
@@ -1,6 +1,6 @@
# Spec file for Open vSwitch.
-# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+# Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
#
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
@@ -430,6 +430,8 @@ exit 0
%files
%defattr(-,root,root)
+/etc/bash_completion.d/ovs-appctl-bashcomp.bash
+/etc/bash_completion.d/ovs-vsctl-bashcomp.bash
/etc/init.d/openvswitch
/etc/init.d/openvswitch-xapi-update
/etc/xapi.d/plugins/openvswitch-cfg-update
@@ -500,3 +502,4 @@ exit 0
%files %{module_package}
/lib/modules/%{xen_version}/extra/openvswitch/openvswitch.ko
+/lib/modules/%{xen_version}/extra/openvswitch/vport-*.ko