[ovs-dev,ovn,1/4] Documentation cleanup: tutorial section
diff mbox series

Message ID 20190612071822.24182-1-nusiddiq@redhat.com
State Accepted
Headers show
Series
  • [ovs-dev,ovn,1/4] Documentation cleanup: tutorial section
Related show

Commit Message

Numan Siddique June 12, 2019, 7:18 a.m. UTC
From: Numan Siddique <nusiddiq@redhat.com>

Also deleted the contents of Documentation/howto/ipsec.rst
and Documentation/howto/ssl.rst and instead updated them
to refer to the Open vSwitch documentation.

Signed-off-by: Numan Siddique <nusiddiq@redhat.com>
---
 Documentation/automake.mk                 |    4 -
 Documentation/howto/ipsec.rst             |  167 +--
 Documentation/howto/ssl.rst               |  311 +----
 Documentation/index.rst                   |    6 +-
 Documentation/tutorials/faucet.rst        | 1436 ---------------------
 Documentation/tutorials/index.rst         |    4 -
 Documentation/tutorials/ipsec.rst         |  347 -----
 Documentation/tutorials/ovn-ipsec.rst     |    4 +-
 Documentation/tutorials/ovn-sandbox.rst   |    8 +-
 Documentation/tutorials/ovs-advanced.rst  |  941 --------------
 Documentation/tutorials/ovs-conntrack.rst |  572 --------
 11 files changed, 9 insertions(+), 3791 deletions(-)
 delete mode 100644 Documentation/tutorials/faucet.rst
 delete mode 100644 Documentation/tutorials/ipsec.rst
 delete mode 100644 Documentation/tutorials/ovs-advanced.rst
 delete mode 100644 Documentation/tutorials/ovs-conntrack.rst

Comments

Ben Pfaff June 12, 2019, 6:14 p.m. UTC | #1
On Wed, Jun 12, 2019 at 12:48:22PM +0530, nusiddiq@redhat.com wrote:
> From: Numan Siddique <nusiddiq@redhat.com>
> 
> Also deleted the contents of Documentation/howto/ipsec.rst
> and Documentation/howto/ssl.rst and instead updated them
> to refer to the Open vSwitch documentation.
> 
> Signed-off-by: Numan Siddique <nusiddiq@redhat.com>

I'm a little surprised that you left ipsec.rst there at all, but I don't
object.

Acked-by: Ben Pfaff <blp@ovn.org>
Numan Siddique June 13, 2019, 6:02 a.m. UTC | #2
On Wed, Jun 12, 2019 at 11:44 PM Ben Pfaff <blp@ovn.org> wrote:

> On Wed, Jun 12, 2019 at 12:48:22PM +0530, nusiddiq@redhat.com wrote:
> > From: Numan Siddique <nusiddiq@redhat.com>
> >
> > Also deleted the contents of Documentation/howto/ipsec.rst
> > and Documentation/howto/ssl.rst and instead updated them
> > to refer to the Open vSwitch documentation.
> >
> > Signed-off-by: Numan Siddique <nusiddiq@redhat.com>
>
> I'm a little surprised that you left ipsec.rst there at all, but I don't
> object.
>

Thank for the review. I pushed the patches 1 - 3  of this series to the
master.

Since we have Documentation/tutorial/ovn-ipsec.rst, I thought of keeping
ipsec.rst.

If that file doesn't add much value, I will submit a patch later to remove
it.

Thanks for the review.

Numan


> Acked-by: Ben Pfaff <blp@ovn.org>
>

Patch
diff mbox series

diff --git a/Documentation/automake.mk b/Documentation/automake.mk
index a5ef29252..181a69cab 100644
--- a/Documentation/automake.mk
+++ b/Documentation/automake.mk
@@ -22,12 +22,8 @@  DOC_SOURCE = \
 	Documentation/intro/install/windows.rst \
 	Documentation/intro/install/xenserver.rst \
 	Documentation/tutorials/index.rst \
-	Documentation/tutorials/faucet.rst \
-	Documentation/tutorials/ovs-advanced.rst \
 	Documentation/tutorials/ovn-openstack.rst \
 	Documentation/tutorials/ovn-sandbox.rst \
-	Documentation/tutorials/ovs-conntrack.rst \
-	Documentation/tutorials/ipsec.rst \
 	Documentation/tutorials/ovn-ipsec.rst \
 	Documentation/tutorials/ovn-rbac.rst \
 	Documentation/topics/index.rst \
diff --git a/Documentation/howto/ipsec.rst b/Documentation/howto/ipsec.rst
index 17153ac2b..7730b5050 100644
--- a/Documentation/howto/ipsec.rst
+++ b/Documentation/howto/ipsec.rst
@@ -25,170 +25,5 @@ 
 Encrypt Open vSwitch Tunnels with IPsec
 =======================================
 
-This document gives detailed description on the OVS IPsec tunnel and its
-configuration modes.  If you want to follow a step-by-step guide to run and
-test IPsec tunnel, please refer to :doc:`/tutorials/ipsec`.
+Please refer to the Open vSwitch documentation on ipsec.
 
-Overview
---------
-
-Why do encryption?
-~~~~~~~~~~~~~~~~~~
-
-OVS tunnel packets are transported from one machine to another. Along the path,
-the packets are processed by physical routers and physical switches.  There are
-risks that these physical devices might read or write the contents of the
-tunnel packets. IPsec encrypts IP payload and prevents the malicious party
-sniffing or manipulating the tunnel traffic.
-
-OVS IPsec
-~~~~~~~~~
-
-OVS IPsec aims to provide a simple interface for user to add encryption on OVS
-tunnels. It supports GRE, GENEVE, VXLAN, and STT tunnel. The IPsec
-configuration is done by setting options of the tunnel interface and
-other_config of Open_vSwitch. You can choose different authentication methods
-and plaintext tunnel policies based on your requirements.
-
-OVS does not currently provide any support for IPsec encryption for traffic not
-encapsulated in a tunnel.
-
-Configuration
--------------
-
-Authentication Methods
-~~~~~~~~~~~~~~~~~~~~~~
-
-Hosts of the IPsec tunnel need to authenticate each other to build a secure
-channel. There are three authentication methods:
-
-1) You can use a pre-shared key (PSK) to do authentication. In both hosts, set
-   the same PSK value. This PSK is like your password. You should never reveal
-   it to untrusted parties. This method is easier to use but less secure than
-   the certificate-based methods::
-
-      $ ovs-vsctl add-port br0 ipsec_gre0 -- \
-                  set interface ipsec_gre0 type=gre \
-                                     options:remote_ip=2.2.2.2 \
-                                     options:psk=swordfish
-
-2) You can use a self-signed certificate to do authentication. In each host,
-   generate a certificate and the paired private key. Copy the certificate of
-   the remote host to the local host and configure the OVS as following::
-
-      $ ovs-vsctl set Open_vSwitch . \
-                  other_config:certificate=/path/to/local_cert.pem \
-                  other_config:private_key=/path/to/priv_key.pem
-      $ ovs-vsctl add-port br0 ipsec_gre0 -- \
-                  set interface ipsec_gre0 type=gre \
-                                 options:remote_ip=2.2.2.2 \
-                                 options:remote_cert=/path/to/remote_cert.pem
-
-   `local_cert.pem` is the certificate of the local host. `priv_key.pem`
-   is the private key of the local host. `priv_key.pem` needs to be stored in
-   a secure location. `remote_cert.pem` is the certificate of the remote host.
-
-   .. note::
-
-      OVS IPsec requires x.509 version 3 certificate with the subjectAltName
-      DNS field setting the same string as the common name (CN) field. You can
-      follow the tutorial in :doc:`/tutorials/ipsec` and use ovs-pki(8) to
-      generate compatible certificate and key.
-
-      (Before OVS version 2.10.90, ovs-pki(8) did not generate x.509 v3
-      certificates, so if your existing PKI was generated by an older version,
-      it is not suitable for this purpose.)
-
-3) You can also use CA-signed certificate to do authentication. First, you need
-   to create a CA certificate and sign each host certificate with the CA key
-   (please see :doc:`/tutorials/ipsec`). Copy the CA certificate to each
-   host and configure the OVS as following::
-
-      $ ovs-vsctl set Open_vSwitch . \
-                  other_config:certificate=/path/to/local_cert.pem \
-                  other_config:private_key=/path/to/priv_key.pem \
-                  other_config:ca_cert=/path/to/ca_cert.pem
-      $ ovs-vsctl add-port br0 ipsec_gre0 -- \
-                  set interface ipsec_gre0 type=gre \
-                                     options:remote_ip=2.2.2.2 \
-                                     options:remote_name=remote_cn
-
-   `ca_cert.pem` is the CA certificate.  You need to set `remote_cn` as the
-   common name (CN) of the remote host's certificate so that only the
-   certificate with the expected CN can be trusted in this connection. It is
-   preferable to use this method than 2) if there are many remote hosts since
-   you don't have to copy every remote certificate to the local host.
-
-   .. note::
-
-      When using certificate-based authentication, you should not set psk in
-      the interface options. When using psk-based authentication, you should
-      not set certificate, private_key, ca_cert, remote_cert, and remote_name.
-
-Plaintext Policies
-~~~~~~~~~~~~~~~~~~
-
-When an IPsec tunnel is configured in this database, multiple independent
-components take responsibility for implementing it.  ``ovs-vswitchd`` and its
-datapath handle packet forwarding to the tunnel and a separate daemon pushes
-the tunnel's IPsec policy configuration to the kernel or other entity that
-implements it.  There is a race: if the former configuration completes before
-the latter, then packets sent by the local host over the tunnel can be
-transmitted in plaintext.  Using this setting, OVS users can avoid this
-undesirable situation.
-
-1) The default setting allows unencrypted packets to be sent before IPsec
-   completes negotiation::
-
-     $ ovs-vsctl add-port br0 ipsec_gre0 -- \
-                  set interface ipsec_gre0 type=gre \
-                                     options:remote_ip=2.2.2.2 \
-                                     options:psk=swordfish
-
-   This setting should be used only and only if tunnel configuration is static
-   and/or if there is firewall that can drop the plain packets that
-   occasionally leak the tunnel unencrypted on OVSDB (re)configuration events.
-
-2) Setiing ipsec_skb_mark drops unencrypted packets by using skb_mark of
-   tunnel packets::
-
-     $ ovs-vsctl set Open_vSwitch . other_config:ipsec_skb_mark=0/1
-     $ ovs-vsctl add-port br0 ipsec_gre0 -- \
-                 set interface ipsec_gre0 type=gre \
-                                    options:remote_ip=2.2.2.2 \
-                                    options:psk=swordfish
-
-   OVS IPsec drops unencrypted packets which carry the same skb_mark as
-   `ipsec_skb_mark`. By setting the ipsec_skb_mark as 0/1, OVS IPsec prevents
-   all unencrypted tunnel packets leaving the host since the default skb_mark
-   value for tunnel packets are 0. This affects all OVS tunnels including those
-   without IPsec being set up. You can install OpenFlow rules to whitelist
-   those non-IPsec tunnels by setting the skb_mark of the tunnel traffic as
-   non-zero value.
-
-3) Setting `ipsec_skb_mark` as 1/1 only drops tunnel packets with skb_mark
-   value being 1::
-
-     $ ovs-vsctl set Open_vSwitch . other_config:ipsec_skb_mark=1/1
-     $ ovs-vsctl add-port br0 ipsec_gre0 -- \
-                 set interface ipsec_gre0 type=gre \
-                                    options:remote_ip=2.2.2.2 \
-                                    options:psk=swordfish
-
-   Opposite to 2), this setting passes through unencrypted tunnel packets by
-   default. To drop unencrypted IPsec tunnel traffic, you need to explicitly
-   set skb_mark to a non-zero value for those tunnel traffic by installing
-   OpenFlow rules.
-
-Bug Reporting
--------------
-
-If you think you may have found a bug with security implications, like
-
-1) IPsec protected tunnel accepted packets that came unencrypted; OR
-2) IPsec protected tunnel allowed packets to leave unencrypted
-
-then please report such bugs according to :doc:`/internals/security`.
-
-If the bug does not have security implications, then report it according to
-instructions in :doc:`/internals/bugs`.
diff --git a/Documentation/howto/ssl.rst b/Documentation/howto/ssl.rst
index 3085206fb..c2c540435 100644
--- a/Documentation/howto/ssl.rst
+++ b/Documentation/howto/ssl.rst
@@ -25,314 +25,5 @@ 
 Open vSwitch with SSL
 =====================
 
-If you plan to configure Open vSwitch to connect across the network to an
-OpenFlow controller, then we recommend that you build Open vSwitch with
-OpenSSL. SSL support ensures integrity and confidentiality of the OpenFlow
-connections, increasing network security.
+Please refer to the Open vSwitch documentation on SSL.
 
-This document describes how to configure an Open vSwitch to connect to an
-OpenFlow controller over SSL.  Refer to :doc:`/intro/install/general`. for
-instructions on building Open vSwitch with SSL support.
-
-Open vSwitch uses TLS version 1.0 or later (TLSv1), as specified by RFC 2246,
-which is very similar to SSL version 3.0.  TLSv1 was released in January 1999,
-so all current software and hardware should implement it.
-
-This document assumes basic familiarity with public-key cryptography and
-public-key infrastructure.
-
-SSL Concepts for OpenFlow
--------------------------
-
-This section is an introduction to the public-key infrastructure architectures
-that Open vSwitch supports for SSL authentication.
-
-To connect over SSL, every Open vSwitch must have a unique private/public key
-pair and a certificate that signs that public key.  Typically, the Open vSwitch
-generates its own public/private key pair.  There are two common ways to obtain
-a certificate for a switch:
-
-* Self-signed certificates: The Open vSwitch signs its certificate with its own
-  private key.  In this case, each switch must be individually approved by the
-  OpenFlow controller(s), since there is no central authority.
-
-  This is the only switch PKI model currently supported by NOX
-  (http://noxrepo.org).
-
-* Switch certificate authority: A certificate authority (the "switch CA") signs
-  each Open vSwitch's public key.  The OpenFlow controllers then check that any
-  connecting switches' certificates are signed by that certificate authority.
-
-  This is the only switch PKI model supported by the simple OpenFlow controller
-  included with Open vSwitch.
-
-Each Open vSwitch must also have a copy of the CA certificate for the
-certificate authority that signs OpenFlow controllers' keys (the "controller
-CA" certificate).  Typically, the same controller CA certificate is installed
-on all of the switches within a given administrative unit.  There are two
-common ways for a switch to obtain the controller CA certificate:
-
-* Manually copy the certificate to the switch through some secure means, e.g.
-  using a USB flash drive, or over the network with "scp", or even FTP or HTTP
-  followed by manual verification.
-
-* Open vSwitch "bootstrap" mode, in which Open vSwitch accepts and saves the
-  controller CA certificate that it obtains from the OpenFlow controller on its
-  first connection.  Thereafter the switch will only connect to controllers
-  signed by the same CA certificate.
-
-Establishing a Public Key Infrastructure
-----------------------------------------
-
-Open vSwitch can make use of your existing public key infrastructure.  If you
-already have a PKI, you may skip forward to the next section.  Otherwise, if
-you do not have a PKI, the ovs-pki script included with Open vSwitch can help.
-To create an initial PKI structure, invoke it as:
-
-::
-
-    $ ovs-pki init
-
-This will create and populate a new PKI directory.  The default location for
-the PKI directory depends on how the Open vSwitch tree was configured (to see
-the configured default, look for the ``--dir`` option description in the output
-of ``ovs-pki --help``).
-
-The pki directory contains two important subdirectories.  The `controllerca`
-subdirectory contains controller CA files, including the following:
-
-`cacert.pem`
-  Root certificate for the controller certificate authority.  Each Open vSwitch
-  must have a copy of this file to allow it to authenticate valid controllers.
-
-`private/cakey.pem`
-  Private signing key for the controller certificate authority.  This file must
-  be kept secret.  There is no need for switches or controllers to have a copy
-  of it.
-
-The `switchca` subdirectory contains switch CA files, analogous to those in the
-`controllerca` subdirectory:
-
-`cacert.pem`
-  Root certificate for the switch certificate authority.  The OpenFlow
-  controller must have this file to enable it to authenticate valid switches.
-
-`private/cakey.pem`
-  Private signing key for the switch certificate authority.  This file must be
-  kept secret.  There is no need for switches or controllers to have a copy of
-  it.
-
-After you create the initial structure, you can create keys and certificates
-for switches and controllers with ovs-pki.  Refer to the ovs-pki(8) manage for
-complete details.  A few examples of its use follow:
-
-Controller Key Generation
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-To create a controller private key and certificate in files named
-ctl-privkey.pem and ctl-cert.pem, run the following on the machine that
-contains the PKI structure:
-
-::
-
-    $ ovs-pki req+sign ctl controller
-
-ctl-privkey.pem and ctl-cert.pem would need to be copied to the controller for
-its use at runtime.  If, for testing purposes, you were to use
-ovs-testcontroller, the simple OpenFlow controller included with Open vSwitch,
-then the --private-key and --certificate options, respectively, would point to
-these files.
-
-It is very important to make sure that no stray copies of ctl-privkey.pem are
-created, because they could be used to impersonate the controller.
-
-Switch Key Generation with Self-Signed Certificates
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you are using self-signed certificates (see "SSL Concepts for OpenFlow"),
-this is one way to create an acceptable certificate for your controller to
-approve.
-
-1. Run the following command on the Open vSwitch itself::
-
-       $ ovs-pki self-sign sc
-
-   .. note::
-     This command does not require a copy of any of the PKI files generated by
-     ``ovs-pki init``, and you should not copy them to the switch because some
-     of them have contents that must remain secret for security.)
-
-   The ``ovs-pki self-sign`` command has the following output:
-
-   sc-privkey.pem
-     the switch private key file.  For security, the contents of this file must
-     remain secret.  There is ordinarily no need to copy this file off the Open
-     vSwitch.
-
-   sc-cert.pem
-     the switch certificate, signed by the switch's own private key.  Its
-     contents are not a secret.
-
-2. Optionally, copy `controllerca/cacert.pem` from the machine that has the
-   OpenFlow PKI structure and verify that it is correct.  (Otherwise, you will
-   have to use CA certificate bootstrapping when you configure Open vSwitch in
-   the next step.)
-
-3. Configure Open vSwitch to use the keys and certificates (see "Configuring
-   SSL Support", below).
-
-Switch Key Generation with a Switch PKI (Easy Method)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you are using a switch PKI (see "SSL Concepts for OpenFlow", above), this
-method of switch key generation is a little easier than the alternate method
-described below, but it is also a little less secure because it requires
-copying a sensitive private key from file from the machine hosting the PKI to
-the switch.
-
-1. Run the following on the machine that contains the PKI structure::
-
-       $ ovs-pki req+sign sc switch
-
-   This command has the following output:
-
-   sc-privkey.pem
-     the switch private key file.  For security, the contents of this file must
-     remain secret.
-
-   sc-cert.pem
-     the switch certificate.  Its contents are not a secret.
-
-2. Copy sc-privkey.pem and sc-cert.pem, plus controllerca/cacert.pem, to the
-   Open vSwitch.
-
-3. Delete the copies of sc-privkey.pem and sc-cert.pem on the PKI machine and
-   any other copies that may have been made in transit.  It is very important
-   to make sure that there are no stray copies of sc-privkey.pem, because they
-   could be used to impersonate the switch.
-
-   .. warning::
-     Don't delete controllerca/cacert.pem!  It is not security-sensitive and
-     you will need it to configure additional switches.
-
-4. Configure Open vSwitch to use the keys and certificates (see "Configuring
-   SSL Support", below).
-
-Switch Key Generation with a Switch PKI (More Secure)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-If you are using a switch PKI (see "SSL Concepts for OpenFlow", above), then,
-compared to the previous method, the method described here takes a little more
-work, but it does not involve copying the private key from one machine to
-another, so it may also be a little more secure.
-
-1. Run the following command on the Open vSwitch itself::
-
-       $ ovs-pki req sc
-
-   .. note::
-     This command does not require a copy of any of the PKI files generated by
-     "ovs-pki init", and you should not copy them to the switch because some of
-     them have contents that must remain secret for security.
-
-   The "ovs-pki req" command has the following output:
-
-   sc-privkey.pem
-     the switch private key file.  For security, the contents of this file must
-     remain secret.  There is ordinarily no need to copy this file off the Open
-     vSwitch.
-
-   sc-req.pem
-     the switch "certificate request", which is essentially the switch's public
-     key.  Its contents are not a secret.
-
-   a fingerprint
-     this is output on stdout.
-
-2. Write the fingerprint down on a slip of paper and copy `sc-req.pem` to the
-   machine that contains the PKI structure.
-
-3. On the machine that contains the PKI structure, run::
-
-       $ ovs-pki sign sc switch
-
-   This command will output a fingerprint to stdout and request that you verify
-   it.  Check that it is the same as the fingerprint that you wrote down on the
-   slip of paper before you answer "yes".
-
-   ``ovs-pki sign`` creates a file named `sc-cert.pem`, which is the switch
-   certificate.  Its contents are not a secret.
-
-4. Copy the generated `sc-cert.pem`, plus `controllerca/cacert.pem` from the
-   PKI structure, to the Open vSwitch, and verify that they were copied
-   correctly.
-
-   You may delete `sc-cert.pem` from the machine that hosts the PKI
-   structure now, although it is not important that you do so.
-
-   .. warning::
-     Don't delete `controllerca/cacert.pem`!  It is not security-sensitive and
-     you will need it to configure additional switches.
-
-5. Configure Open vSwitch to use the keys and certificates (see "Configuring
-   SSL Support", below).
-
-Configuring SSL Support
------------------------
-
-SSL configuration requires three additional configuration files.  The first two
-of these are unique to each Open vSwitch.  If you used the instructions above
-to build your PKI, then these files will be named `sc-privkey.pem` and
-`sc-cert.pem`, respectively:
-
-- A private key file, which contains the private half of an RSA or DSA key.
-
-  This file can be generated on the Open vSwitch itself, for the greatest
-  security, or it can be generated elsewhere and copied to the Open vSwitch.
-
-  The contents of the private key file are secret and must not be exposed.
-
-- A certificate file, which certifies that the private key is that of a
-  trustworthy Open vSwitch.
-
-  This file has to be generated on a machine that has the private key for the
-  switch certification authority, which should not be an Open vSwitch; ideally,
-  it should be a machine that is not networked at all.
-
-  The certificate file itself is not a secret.
-
-The third configuration file is typically the same across all the switches in a
-given administrative unit.  If you used the instructions above to build your
-PKI, then this file will be named `cacert.pem`:
-
-- The root certificate for the controller certificate authority.  The Open
-  vSwitch verifies it that is authorized to connect to an OpenFlow controller
-  by verifying a signature against this CA certificate.
-
-Once you have these files, configure ovs-vswitchd to use them using the
-``ovs-vsctl set-ssl`` command, e.g.::
-
-    $ ovs-vsctl set-ssl /etc/openvswitch/sc-privkey.pem \
-        /etc/openvswitch/sc-cert.pem /etc/openvswitch/cacert.pem
-
-Substitute the correct file names, of course, if they differ from the ones used
-above.  You should use absolute file names (ones that begin with ``/``),
-because ovs-vswitchd's current directory is unrelated to the one from which you
-run ovs-vsctl.
-
-If you are using self-signed certificates (see "SSL Concepts for OpenFlow") and
-you did not copy controllerca/cacert.pem from the PKI machine to the Open
-vSwitch, then add the ``--bootstrap`` option, e.g.::
-
-    $ ovs-vsctl -- --bootstrap set-ssl /etc/openvswitch/sc-privkey.pem \
-        /etc/openvswitch/sc-cert.pem /etc/openvswitch/cacert.pem
-
-After you have added all of these configuration keys, you may specify ``ssl:``
-connection methods elsewhere in the configuration database.  ``tcp:`` connection
-methods are still allowed even after SSL has been configured, so for security
-you should use only ``ssl:`` connections.
-
-Reporting Bugs
---------------
-
-Report problems to bugs@openvswitch.org.
diff --git a/Documentation/index.rst b/Documentation/index.rst
index 78b7d89b0..192ed7631 100644
--- a/Documentation/index.rst
+++ b/Documentation/index.rst
@@ -59,12 +59,8 @@  vSwitch? Start here.
   :doc:`intro/install/windows` |
   :doc:`intro/install/xenserver`
 
-- **Tutorials:** :doc:`tutorials/faucet` |
-  :doc:`tutorials/ovs-advanced` |
-  :doc:`tutorials/ovn-sandbox` |
+- **Tutorials:** :doc:`tutorials/ovn-sandbox` |
   :doc:`tutorials/ovn-openstack` |
-  :doc:`tutorials/ovs-conntrack` |
-  :doc:`tutorials/ipsec` |
   :doc:`tutorials/ovn-ipsec` |
   :doc:`tutorials/ovn-rbac`
 
diff --git a/Documentation/tutorials/faucet.rst b/Documentation/tutorials/faucet.rst
deleted file mode 100644
index 9696dfd02..000000000
--- a/Documentation/tutorials/faucet.rst
+++ /dev/null
@@ -1,1436 +0,0 @@ 
-..
-      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.
-
-      Convention for heading levels in Open vSwitch documentation:
-
-      =======  Heading 0 (reserved for the title in a document)
-      -------  Heading 1
-      ~~~~~~~  Heading 2
-      +++++++  Heading 3
-      '''''''  Heading 4
-
-      Avoid deeper levels because they do not render well.
-
-===================
-OVS Faucet Tutorial
-===================
-
-This tutorial demonstrates how Open vSwitch works with a general-purpose
-OpenFlow controller, using the Faucet controller as a simple way to get
-started.  It was tested with the "master" branch of Open vSwitch and version
-1.6.15 of Faucet.  It does not use advanced or recently added features in OVS
-or Faucet, so other versions of both pieces of software are likely to work
-equally well.
-
-The goal of the tutorial is to demonstrate Open vSwitch and Faucet in an
-end-to-end way, that is, to show how it works from the Faucet controller
-configuration at the top, through the OpenFlow flow table, to the datapath
-processing.  Along the way, in addition to helping to understand the
-architecture at each level, we discuss performance and troubleshooting issues.
-We hope that this demonstration makes it easier for users and potential users
-to understand how Open vSwitch works and how to debug and troubleshoot it.
-
-We provide enough details in the tutorial that you should be able to fully
-follow along by following the instructions.
-
-Setting Up OVS
---------------
-
-This section explains how to set up Open vSwitch for the purpose of using it
-with Faucet for the tutorial.
-
-You might already have Open vSwitch installed on one or more computers or VMs,
-perhaps set up to control a set of VMs or a physical network.  This is
-admirable, but we will be using Open vSwitch in a different way to set up a
-simulation environment called the OVS "sandbox".  The sandbox does not use
-virtual machines or containers, which makes it more limited, but on the other
-hand it is (in this writer's opinion) easier to set up.
-
-There are two ways to start a sandbox: one that uses the Open vSwitch that is
-already installed on a system, and another that uses a copy of Open vSwitch
-that has been built but not yet installed.  The latter is more often used and
-thus better tested, but both should work.  The instructions below explain both
-approaches:
-
-1. Get a copy of the Open vSwitch source repository using Git, then ``cd`` into
-   the new directory::
-
-     $ git clone https://github.com/openvswitch/ovs.git
-     $ cd ovs
-
-   The default checkout is the master branch.  You can check out a tag
-   (such as v2.8.0) or a branch (such as origin/branch-2.8), if you
-   prefer.
-
-2. If you do not already have an installed copy of Open vSwitch on your system,
-   or if you do not want to use it for the sandbox (the sandbox will not
-   disturb the functionality of any existing switches), then proceed to step 3.
-   If you do have an installed copy and you want to use it for the sandbox, try
-   to start the sandbox by running::
-
-     $ tutorial/ovs-sandbox
-
-   If it is successful, you will find yourself in a subshell environment, which
-   is the sandbox (you can exit with ``exit`` or Control+D).  If so, you're
-   finished and do not need to complete the rest of the steps.  If it fails,
-   you can proceed to step 3 to build Open vSwitch anyway.
-
-3. Before you build, you might want to check that your system meets the build
-   requirements.  Read :doc:`/intro/install/general` to find out.  For this
-   tutorial, there is no need to compile the Linux kernel module, or to use any
-   of the optional libraries such as OpenSSL, DPDK, or libcap-ng.
-
-4. Configure and build Open vSwitch::
-
-     $ ./boot.sh
-     $ ./configure
-     $ make -j4
-
-5. Try out the sandbox by running::
-
-     $ make sandbox
-
-   You can exit the sandbox with ``exit`` or Control+D.
-
-Setting up Faucet
------------------
-
-This section explains how to get a copy of Faucet and set it up
-appropriately for the tutorial.  There are many other ways to install
-Faucet, but this simple approach worked well for me.  It has the
-advantage that it does not require modifying any system-level files or
-directories on your machine.  It does, on the other hand, require
-Docker, so make sure you have it installed and working.
-
-It will be a little easier to go through the rest of the tutorial if
-you run these instructions in a separate terminal from the one that
-you're using for Open vSwitch, because it's often necessary to switch
-between one and the other.
-
-1. Get a copy of the Faucet source repository using Git, then ``cd``
-   into the new directory::
-
-     $ git clone https://github.com/faucetsdn/faucet.git
-     $ cd faucet
-
-   At this point I checked out the latest tag::
-
-     $ latest_tag=$(git describe --tags $(git rev-list --tags --max-count=1))
-     $ git checkout $latest_tag
-
-2. Build a docker container image::
-
-     $ docker build -t faucet/faucet .
-
-   This will take a few minutes.
-
-3. Create an installation directory under the ``faucet`` directory for
-   the docker image to use::
-
-     $ mkdir inst
-
-   The Faucet configuration will go in ``inst/faucet.yaml`` and its
-   main log will appear in ``inst/faucet.log``.  (The official Faucet
-   installation instructions call to put these in ``/etc/ryu/faucet``
-   and ``/var/log/ryu/faucet``, respectively, but we avoid modifying
-   these system directories.)
-
-4. Create a container and start Faucet::
-
-     $ docker run -d --name faucet --restart=always -v $(pwd)/inst/:/etc/faucet/ -v $(pwd)/inst/:/var/log/faucet/ -p 6653:6653 -p 9302:9302 faucet/faucet
-
-5. Look in ``inst/faucet.log`` to verify that Faucet started.  It will
-   probably start with an exception and traceback because we have not
-   yet created ``inst/faucet.yaml``.
-
-6. Later on, to make a new or updated Faucet configuration take
-   effect quickly, you can run::
-
-     $ docker exec faucet pkill -HUP -f faucet.faucet
-
-   Another way is to stop and start the Faucet container::
-
-     $ docker restart faucet
-
-   You can also stop and delete the container; after this, to start it
-   again, you need to rerun the ``docker run`` command::
-
-     $ docker stop faucet
-     $ docker rm faucet
-
-Overview
---------
-
-Now that Open vSwitch and Faucet are ready, here's an overview of what
-we're going to do for the remainder of the tutorial:
-
-1. Switching: Set up an L2 network with Faucet.
-
-2. Routing: Route between multiple L3 networks with Faucet.
-
-3. ACLs: Add and modify access control rules.
-
-At each step, we will take a look at how the features in question work
-from Faucet at the top to the data plane layer at the bottom.  From
-the highest to lowest level, these layers and the software components
-that connect them are:
-
-Faucet.
-  As the top level in the system, this is the authoritative source of the
-  network configuration.
-
-  Faucet connects to a variety of monitoring and performance tools,
-  but we won't use them in this tutorial.  Our main insights into the
-  system will be through ``faucet.yaml`` for configuration and
-  ``faucet.log`` to observe state, such as MAC learning and ARP
-  resolution, and to tell when we've screwed up configuration syntax
-  or semantics.
-
-The OpenFlow subsystem in Open vSwitch.
-  OpenFlow is the protocol, standardized by the Open Networking Foundation,
-  that controllers like Faucet use to control how Open vSwitch and other
-  switches treat packets in the network.
-
-  We will use ``ovs-ofctl``, a utility that comes with Open vSwitch,
-  to observe and occasionally modify Open vSwitch's OpenFlow behavior.
-  We will also use ``ovs-appctl``, a utility for communicating with
-  ``ovs-vswitchd`` and other Open vSwitch daemons, to ask "what-if?"
-  type questions.
-
-  In addition, the OVS sandbox by default raises the Open vSwitch
-  logging level for OpenFlow high enough that we can learn a great
-  deal about OpenFlow behavior simply by reading its log file.
-
-Open vSwitch datapath.
-  This is essentially a cache designed to accelerate packet processing.  Open
-  vSwitch includes a few different datapaths, such as one based on the Linux
-  kernel and a userspace-only datapath (sometimes called the "DPDK" datapath).
-  The OVS sandbox uses the latter, but the principles behind it apply equally
-  well to other datapaths.
-
-At each step, we discuss how the design of each layer influences
-performance.  We demonstrate how Open vSwitch features can be used to
-debug, troubleshoot, and understand the system as a whole.
-
-Switching
----------
-
-Layer-2 (L2) switching is the basis of modern networking.  It's also
-very simple and a good place to start, so let's set up a switch with
-some VLANs in Faucet and see how it works at each layer.  Begin by
-putting the following into ``inst/faucet.yaml``::
-
-  dps:
-      switch-1:
-          dp_id: 0x1
-          timeout: 3600
-          arp_neighbor_timeout: 3600
-          interfaces:
-              1:
-                  native_vlan: 100
-              2:
-                  native_vlan: 100
-              3:
-                  native_vlan: 100
-              4:
-                  native_vlan: 200
-              5:
-                  native_vlan: 200
-  vlans:
-      100:
-      200:
-
-This configuration file defines a single switch ("datapath" or "dp")
-named ``switch-1``.  The switch has five ports, numbered 1 through 5.
-Ports 1, 2, and 3 are in VLAN 100, and ports 4 and 5 are in VLAN 2.
-Faucet can identify the switch from its datapath ID, which is defined
-to be 0x1.
-
-.. note::
-
-  This also sets high MAC learning and ARP timeouts.  The defaults are
-  5 minutes and about 8 minutes, which are fine in production but
-  sometimes too fast for manual experimentation.  (Don't use a timeout
-  bigger than about 65000 seconds because it will crash Faucet.)
-
-Now restart Faucet so that the configuration takes effect, e.g.::
-
-  $ docker restart faucet
-
-Assuming that the configuration update is successful, you should now
-see a new line at the end of ``inst/faucet.log``::
-
-  Jan 06 15:14:35 faucet INFO     Add new datapath DPID 1 (0x1)
-
-Faucet is now waiting for a switch with datapath ID 0x1 to connect to
-it over OpenFlow, so our next step is to create a switch with OVS and
-make it connect to Faucet.  To do that, switch to the terminal where
-you checked out OVS and start a sandbox with ``make sandbox`` or
-``tutorial/ovs-sandbox`` (as explained earlier under `Setting Up
-OVS`_).  You should see something like this toward the end of the
-output::
-
-  ----------------------------------------------------------------------
-  You are running in a dummy Open vSwitch environment.  You can use
-  ovs-vsctl, ovs-ofctl, ovs-appctl, and other tools to work with the
-  dummy switch.
-
-  Log files, pidfiles, and the configuration database are in the
-  "sandbox" subdirectory.
-
-  Exit the shell to kill the running daemons.
-  blp@sigabrt:~/nicira/ovs/tutorial(0)$
-
-Inside the sandbox, create a switch ("bridge") named ``br0``, set its
-datapath ID to 0x1, add simulated ports to it named ``p1`` through
-``p5``, and tell it to connect to the Faucet controller.  To make it
-easier to understand, we request for port ``p1`` to be assigned
-OpenFlow port 1, ``p2`` port 2, and so on.  As a final touch,
-configure the controller to be "out-of-band" (this is mainly to avoid
-some annoying messages in the ``ovs-vswitchd`` logs; for more
-information, run ``man ovs-vswitchd.conf.db`` and search for
-``connection_mode``)::
-
-  $ ovs-vsctl add-br br0 \
-           -- set bridge br0 other-config:datapath-id=0000000000000001 \
-           -- add-port br0 p1 -- set interface p1 ofport_request=1 \
-           -- add-port br0 p2 -- set interface p2 ofport_request=2 \
-           -- add-port br0 p3 -- set interface p3 ofport_request=3 \
-           -- add-port br0 p4 -- set interface p4 ofport_request=4 \
-           -- add-port br0 p5 -- set interface p5 ofport_request=5 \
-           -- set-controller br0 tcp:127.0.0.1:6653 \
-           -- set controller br0 connection-mode=out-of-band
-
-.. note::
-
-  You don't have to run all of these as a single ``ovs-vsctl``
-  invocation.  It is a little more efficient, though, and since it
-  updates the OVS configuration in a single database transaction it
-  means that, for example, there is never a time when the controller
-  is set but it has not yet been configured as out-of-band.
-
-Now, if you look at ``inst/faucet.log`` again, you should see that
-Faucet recognized and configured the new switch and its ports::
-
-  Jan 06 15:17:10 faucet       INFO     DPID 1 (0x1) connected
-  Jan 06 15:17:10 faucet.valve INFO     DPID 1 (0x1) Cold start configuring DP
-  Jan 06 15:17:10 faucet.valve INFO     DPID 1 (0x1) Configuring VLAN 100 vid:100 ports:Port 1,Port 2,Port 3
-  Jan 06 15:17:10 faucet.valve INFO     DPID 1 (0x1) Configuring VLAN 200 vid:200 ports:Port 4,Port 5
-  Jan 06 15:17:10 faucet.valve INFO     DPID 1 (0x1) Port 1 up, configuring
-  Jan 06 15:17:10 faucet.valve INFO     DPID 1 (0x1) Port 2 up, configuring
-  Jan 06 15:17:10 faucet.valve INFO     DPID 1 (0x1) Port 3 up, configuring
-  Jan 06 15:17:10 faucet.valve INFO     DPID 1 (0x1) Port 4 up, configuring
-  Jan 06 15:17:10 faucet.valve INFO     DPID 1 (0x1) Port 5 up, configuring
-
-Over on the Open vSwitch side, you can see a lot of related activity
-if you take a look in ``sandbox/ovs-vswitchd.log``.  For example, here
-is the basic OpenFlow session setup and Faucet's probe of the switch's
-ports and capabilities::
-
-  rconn|INFO|br0<->tcp:127.0.0.1:6653: connecting...
-  vconn|DBG|tcp:127.0.0.1:6653: sent (Success): OFPT_HELLO (OF1.4) (xid=0x1):
-   version bitmap: 0x01, 0x02, 0x03, 0x04, 0x05
-  vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_HELLO (OF1.3) (xid=0x2f24810a):
-   version bitmap: 0x01, 0x02, 0x03, 0x04
-  vconn|DBG|tcp:127.0.0.1:6653: negotiated OpenFlow version 0x04 (we support version 0x05 and earlier, peer supports version 0x04 and earlier)
-  rconn|INFO|br0<->tcp:127.0.0.1:6653: connected
-  vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_ECHO_REQUEST (OF1.3) (xid=0x2f24810b): 0 bytes of payload
-  vconn|DBG|tcp:127.0.0.1:6653: sent (Success): OFPT_ECHO_REPLY (OF1.3) (xid=0x2f24810b): 0 bytes of payload
-  vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_FEATURES_REQUEST (OF1.3) (xid=0x2f24810c):
-  vconn|DBG|tcp:127.0.0.1:6653: sent (Success): OFPT_FEATURES_REPLY (OF1.3) (xid=0x2f24810c): dpid:0000000000000001
-   n_tables:254, n_buffers:0
-   capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS
-  vconn|DBG|tcp:127.0.0.1:6653: received: OFPST_PORT_DESC request (OF1.3) (xid=0x2f24810d): port=ANY
-  vconn|DBG|tcp:127.0.0.1:6653: sent (Success): OFPST_PORT_DESC reply (OF1.3) (xid=0x2f24810d):
-   1(p1): addr:aa:55:aa:55:00:14
-       config:     PORT_DOWN
-       state:      LINK_DOWN
-       speed: 0 Mbps now, 0 Mbps max
-   2(p2): addr:aa:55:aa:55:00:15
-       config:     PORT_DOWN
-       state:      LINK_DOWN
-       speed: 0 Mbps now, 0 Mbps max
-   3(p3): addr:aa:55:aa:55:00:16
-       config:     PORT_DOWN
-       state:      LINK_DOWN
-       speed: 0 Mbps now, 0 Mbps max
-   4(p4): addr:aa:55:aa:55:00:17
-       config:     PORT_DOWN
-       state:      LINK_DOWN
-       speed: 0 Mbps now, 0 Mbps max
-   5(p5): addr:aa:55:aa:55:00:18
-       config:     PORT_DOWN
-       state:      LINK_DOWN
-       speed: 0 Mbps now, 0 Mbps max
-   LOCAL(br0): addr:c6:64:ff:59:48:41
-       config:     PORT_DOWN
-       state:      LINK_DOWN
-       speed: 0 Mbps now, 0 Mbps max
-
-After that, you can see Faucet delete all existing flows and then
-start adding new ones::
-
-  vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_FLOW_MOD (OF1.3) (xid=0x2f24810e): DEL table:255 priority=0 actions=drop
-  vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_BARRIER_REQUEST (OF1.3) (xid=0x2f24810f):
-  vconn|DBG|tcp:127.0.0.1:6653: sent (Success): OFPT_BARRIER_REPLY (OF1.3) (xid=0x2f24810f):
-  vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_FLOW_MOD (OF1.3) (xid=0x2f248110): ADD priority=0 cookie:0x5adc15c0 out_port:0 actions=drop
-  vconn|DBG|tcp:127.0.0.1:6653: received: OFPT_FLOW_MOD (OF1.3) (xid=0x2f248111): ADD table:1 priority=0 cookie:0x5adc15c0 out_port:0 actions=drop
-  ...
-
-OpenFlow Layer
-~~~~~~~~~~~~~~
-
-Let's take a look at the OpenFlow tables that Faucet set up.  Before
-we do that, it's helpful to take a look at ``docs/architecture.rst``
-in the Faucet documentation to learn how Faucet structures its flow
-tables.  In summary, this document says:
-
-Table 0
-  Port-based ACLs
-
-Table 1
-  Ingress VLAN processing
-
-Table 2
-  VLAN-based ACLs
-
-Table 3
-  Ingress L2 processing, MAC learning
-
-Table 4
-  L3 forwarding for IPv4
-
-Table 5
-  L3 forwarding for IPv6
-
-Table 6
-  Virtual IP processing, e.g. for router IP addresses implemented by Faucet
-
-Table 7
-  Egress L2 processing
-
-Table 8
-  Flooding
-
-With that in mind, let's dump the flow tables.  The simplest way is to
-just run plain ``ovs-ofctl dump-flows``::
-
-  $ ovs-ofctl dump-flows br0
-
-If you run that bare command, it produces a lot of extra junk that
-makes the output harder to read, like statistics and "cookie" values
-that are all the same.  In addition, for historical reasons
-``ovs-ofctl`` always defaults to using OpenFlow 1.0 even though Faucet
-and most modern controllers use OpenFlow 1.3, so it's best to force it
-to use OpenFlow 1.3.  We could throw in a lot of options to fix these,
-but we'll want to do this more than once, so let's start by defining a
-shell function for ourselves::
-
-  $ dump-flows () {
-    ovs-ofctl -OOpenFlow13 --names --no-stat dump-flows "$@" \
-      | sed 's/cookie=0x5adc15c0, //'
-  }
-
-Let's also define ``save-flows`` and ``diff-flows`` functions for
-later use::
-
-  $ save-flows () {
-    ovs-ofctl -OOpenFlow13 --no-names --sort dump-flows "$@"
-  }
-  $ diff-flows () {
-    ovs-ofctl -OOpenFlow13 diff-flows "$@" | sed 's/cookie=0x5adc15c0 //'
-  }
-
-Now let's take a look at the flows we've got and what they mean, like
-this::
-
-  $ dump-flows br0
-
-First, table 0 has a flow that just jumps to table 1 for each
-configured port, and drops other unrecognized packets.  Presumably it
-will do more if we configured port-based ACLs::
-
-  priority=9099,in_port=p1 actions=goto_table:1
-  priority=9099,in_port=p2 actions=goto_table:1
-  priority=9099,in_port=p3 actions=goto_table:1
-  priority=9099,in_port=p4 actions=goto_table:1
-  priority=9099,in_port=p5 actions=goto_table:1
-  priority=0 actions=drop
-
-Table 1, for ingress VLAN processing, has a bunch of flows that drop
-inappropriate packets, such as LLDP and STP::
-
-  table=1, priority=9099,dl_dst=01:80:c2:00:00:00 actions=drop
-  table=1, priority=9099,dl_dst=01:00:0c:cc:cc:cd actions=drop
-  table=1, priority=9099,dl_type=0x88cc actions=drop
-
-Table 1 also has some more interesting flows that recognize packets
-without a VLAN header on each of our ports
-(``vlan_tci=0x0000/0x1fff``), push on the VLAN configured for the
-port, and proceed to table 3.  Presumably these skip table 2 because
-we did not configure any VLAN-based ACLs.  There is also a fallback
-flow to drop other packets, which in practice means that if any
-received packet already has a VLAN header then it will be dropped::
-
-  table=1, priority=9000,in_port=p1,vlan_tci=0x0000/0x1fff actions=push_vlan:0x8100,set_field:4196->vlan_vid,goto_table:3
-  table=1, priority=9000,in_port=p2,vlan_tci=0x0000/0x1fff actions=push_vlan:0x8100,set_field:4196->vlan_vid,goto_table:3
-  table=1, priority=9000,in_port=p3,vlan_tci=0x0000/0x1fff actions=push_vlan:0x8100,set_field:4196->vlan_vid,goto_table:3
-  table=1, priority=9000,in_port=p4,vlan_tci=0x0000/0x1fff actions=push_vlan:0x8100,set_field:4296->vlan_vid,goto_table:3
-  table=1, priority=9000,in_port=p5,vlan_tci=0x0000/0x1fff actions=push_vlan:0x8100,set_field:4296->vlan_vid,goto_table:3
-  table=1, priority=0 actions=drop
-
-.. note::
-
-  The syntax ``set_field:4196->vlan_vid`` is curious and somewhat
-  misleading.  OpenFlow 1.3 defines the ``vlan_vid`` field as a 13-bit
-  field where bit 12 is set to 1 if the VLAN header is present.  Thus,
-  since 4196 is 0x1064, this action sets VLAN value 0x64, which in
-  decimal is 100.
-
-Table 2 isn't used because there are no VLAN-based ACLs.  It just has
-a drop flow::
-
-  table=2, priority=0 actions=drop
-
-Table 3 is used for MAC learning but the controller hasn't learned any
-MAC yet. It also drops some inappropriate packets such as those that claim
-to be from a broadcast source address (why not from all multicast source
-addresses, though?). We'll come back here later::
-
-  table=3, priority=9099,dl_src=ff:ff:ff:ff:ff:ff actions=drop
-  table=3, priority=9001,dl_src=0e:00:00:00:00:01 actions=drop
-  table=3, priority=0 actions=drop
-  table=3, priority=9000 actions=CONTROLLER:96,goto_table:7
-
-Tables 4, 5, and 6 aren't used because we haven't configured any
-routing::
-
-  table=4, priority=0 actions=drop
-  table=5, priority=0 actions=drop
-  table=6, priority=0 actions=drop
-
-Table 7 is used to direct packets to learned MACs but Faucet hasn't
-learned any MACs yet, so it just sends all the packets along to table
-8::
-
-  table=7, priority=0 actions=drop
-  table=7, priority=9000 actions=goto_table:8
-
-Table 8 implements flooding, broadcast, and multicast.  The flows for
-broadcast and flood are easy to understand: if the packet came in on a
-given port and needs to be flooded or broadcast, output it to all the
-other ports in the same VLAN::
-
-  table=8, priority=9008,in_port=p1,dl_vlan=100,dl_dst=ff:ff:ff:ff:ff:ff actions=pop_vlan,output:p2,output:p3
-  table=8, priority=9008,in_port=p2,dl_vlan=100,dl_dst=ff:ff:ff:ff:ff:ff actions=pop_vlan,output:p1,output:p3
-  table=8, priority=9008,in_port=p3,dl_vlan=100,dl_dst=ff:ff:ff:ff:ff:ff actions=pop_vlan,output:p1,output:p2
-  table=8, priority=9008,in_port=p4,dl_vlan=200,dl_dst=ff:ff:ff:ff:ff:ff actions=pop_vlan,output:p5
-  table=8, priority=9008,in_port=p5,dl_vlan=200,dl_dst=ff:ff:ff:ff:ff:ff actions=pop_vlan,output:p4
-  table=8, priority=9000,in_port=p1,dl_vlan=100 actions=pop_vlan,output:p2,output:p3
-  table=8, priority=9000,in_port=p2,dl_vlan=100 actions=pop_vlan,output:p1,output:p3
-  table=8, priority=9000,in_port=p3,dl_vlan=100 actions=pop_vlan,output:p1,output:p2
-  table=8, priority=9000,in_port=p4,dl_vlan=200 actions=pop_vlan,output:p5
-  table=8, priority=9000,in_port=p5,dl_vlan=200 actions=pop_vlan,output:p4
-
-.. note::
-
-  These flows could apparently be simpler because OpenFlow says that
-  ``output:<port>`` is ignored if ``<port>`` is the input port.  That
-  means that the first three flows above could apparently be collapsed
-  into just::
-
-    table=8, priority=9008,dl_vlan=100,dl_dst=ff:ff:ff:ff:ff:ff actions=pop_vlan,output:p1,output:p2,output:p3
-
-  There might be some reason why this won't work or isn't practical,
-  but that isn't obvious from looking at the flow table.
-
-There are also some flows for handling some standard forms of
-multicast, and a fallback drop flow::
-
-  table=8, priority=9006,in_port=p1,dl_vlan=100,dl_dst=33:33:00:00:00:00/ff:ff:00:00:00:00 actions=pop_vlan,output:p2,output:p3
-  table=8, priority=9006,in_port=p2,dl_vlan=100,dl_dst=33:33:00:00:00:00/ff:ff:00:00:00:00 actions=pop_vlan,output:p1,output:p3
-  table=8, priority=9006,in_port=p3,dl_vlan=100,dl_dst=33:33:00:00:00:00/ff:ff:00:00:00:00 actions=pop_vlan,output:p1,output:p2
-  table=8, priority=9006,in_port=p4,dl_vlan=200,dl_dst=33:33:00:00:00:00/ff:ff:00:00:00:00 actions=pop_vlan,output:p5
-  table=8, priority=9006,in_port=p5,dl_vlan=200,dl_dst=33:33:00:00:00:00/ff:ff:00:00:00:00 actions=pop_vlan,output:p4
-  table=8, priority=9002,in_port=p1,dl_vlan=100,dl_dst=01:80:c2:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p2,output:p3
-  table=8, priority=9002,in_port=p2,dl_vlan=100,dl_dst=01:80:c2:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p1,output:p3
-  table=8, priority=9002,in_port=p3,dl_vlan=100,dl_dst=01:80:c2:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p1,output:p2
-  table=8, priority=9004,in_port=p1,dl_vlan=100,dl_dst=01:00:5e:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p2,output:p3
-  table=8, priority=9004,in_port=p2,dl_vlan=100,dl_dst=01:00:5e:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p1,output:p3
-  table=8, priority=9004,in_port=p3,dl_vlan=100,dl_dst=01:00:5e:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p1,output:p2
-  table=8, priority=9002,in_port=p4,dl_vlan=200,dl_dst=01:80:c2:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p5
-  table=8, priority=9002,in_port=p5,dl_vlan=200,dl_dst=01:80:c2:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p4
-  table=8, priority=9004,in_port=p4,dl_vlan=200,dl_dst=01:00:5e:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p5
-  table=8, priority=9004,in_port=p5,dl_vlan=200,dl_dst=01:00:5e:00:00:00/ff:ff:ff:00:00:00 actions=pop_vlan,output:p4
-  table=8, priority=0 actions=drop
-
-Tracing
-~~~~~~~
-
-Let's go a level deeper.  So far, everything we've done has been
-fairly general.  We can also look at something more specific: the path
-that a particular packet would take through Open vSwitch.  We can use
-OVN ``ofproto/trace`` command to play "what-if?" games.  This command
-is one that we send directly to ``ovs-vswitchd``, using the
-``ovs-appctl`` utility.
-
-.. note::
-
-  ``ovs-appctl`` is actually a very simple-minded JSON-RPC client, so you could
-  also use some other utility that speaks JSON-RPC, or access it from a program
-  as an API.
-
-The ``ovs-vswitchd``\(8) manpage has a lot of detail on how to use
-``ofproto/trace``, but let's just start by building up from a simple
-example.  You can start with a command that just specifies the
-datapath (e.g. ``br0``), an input port, and nothing else; unspecified
-fields default to all-zeros.  Let's look at the full output for this
-trivial example::
-
-  $ ovs-appctl ofproto/trace br0 in_port=p1
-  Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
-
-  bridge("br0")
-  -------------
-   0. in_port=1, priority 9099, cookie 0x5adc15c0
-      goto_table:1
-   1. in_port=1,vlan_tci=0x0000/0x1fff, priority 9000, cookie 0x5adc15c0
-      push_vlan:0x8100
-      set_field:4196->vlan_vid
-      goto_table:3
-   3. priority 9000, cookie 0x5adc15c0
-      CONTROLLER:96
-      goto_table:7
-   7. priority 9000, cookie 0x5adc15c0
-      goto_table:8
-   8. in_port=1,dl_vlan=100, priority 9000, cookie 0x5adc15c0
-      pop_vlan
-      output:2
-      output:3
-
-  Final flow: unchanged
-  Megaflow: recirc_id=0,eth,in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
-  Datapath actions: push_vlan(vid=100,pcp=0),userspace(pid=0,controller(reason=1,flags=1,recirc_id=1,rule_cookie=0x5adc15c0,controller_id=0,max_len=96)),pop_vlan,2,3
-
-The first line of output, beginning with ``Flow:``, just repeats our
-request in a more verbose form, including the L2 fields that were
-zeroed.
-
-Each of the numbered items under ``bridge("br0")`` shows what would
-happen to our hypothetical packet in the table with the given number.
-For example, we see in table 1 that the packet matches a flow that
-push on a VLAN header, set the VLAN ID to 100, and goes on to further
-processing in table 3.  In table 3, the packet gets sent to the
-controller to allow MAC learning to take place, and then table 8
-floods the packet to the other ports in the same VLAN.
-
-Summary information follows the numbered tables.  The packet hasn't
-been changed (overall, even though a VLAN was pushed and then popped
-back off) since ingress, hence ``Final flow: unchanged``.  We'll look
-at the ``Megaflow`` information later.  The ``Datapath actions``
-summarize what would actually happen to such a packet.
-
-Triggering MAC Learning
-~~~~~~~~~~~~~~~~~~~~~~~
-
-We just saw how a packet gets sent to the controller to trigger MAC
-learning.  Let's actually send the packet and see what happens.  But
-before we do that, let's save a copy of the current flow tables for
-later comparison::
-
-  $ save-flows br0 > flows1
-
-Now use ``ofproto/trace``, as before, with a few new twists: we
-specify the source and destination Ethernet addresses and append the
-``-generate`` option so that side effects like sending a packet to the
-controller actually happen::
-
-  $ ovs-appctl ofproto/trace br0 in_port=p1,dl_src=00:11:11:00:00:00,dl_dst=00:22:22:00:00:00 -generate
-
-The output is almost identical to that before, so it is not repeated
-here.  But, take a look at ``inst/faucet.log`` now.  It should now
-include a line at the end that says that it learned about our MAC
-00:11:11:00:00:00, like this::
-
-  Jan 06 15:56:02 faucet.valve INFO     DPID 1 (0x1) L2 learned 00:11:11:00:00:00 (L2 type 0x0000, L3 src None) on Port 1 on VLAN 100 (1 hosts total
-
-Now compare the flow tables that we saved to the current ones::
-
-  diff-flows flows1 br0
-
-The result should look like this, showing new flows for the learned
-MACs::
-
-  +table=3 priority=9098,in_port=1,dl_vlan=100,dl_src=00:11:11:00:00:00 hard_timeout=3601 actions=goto_table:7
-  +table=7 priority=9099,dl_vlan=100,dl_dst=00:11:11:00:00:00 idle_timeout=3601 actions=pop_vlan,output:1
-
-To demonstrate the usefulness of the learned MAC, try tracing (with
-side effects) a packet arriving on ``p2`` (or ``p3``) and destined to
-the address learned on ``p1``, like this::
-
-  $ ovs-appctl ofproto/trace br0 in_port=p2,dl_src=00:22:22:00:00:00,dl_dst=00:11:11:00:00:00 -generate
-
-The first time you run this command, you will notice that it sends the
-packet to the controller, to learn ``p2``'s 00:22:22:00:00:00 source
-address::
-
-  bridge("br0")
-  -------------
-   0. in_port=2, priority 9099, cookie 0x5adc15c0
-      goto_table:1
-   1. in_port=2,vlan_tci=0x0000/0x1fff, priority 9000, cookie 0x5adc15c0
-      push_vlan:0x8100
-      set_field:4196->vlan_vid
-      goto_table:3
-   3. priority 9000, cookie 0x5adc15c0
-      CONTROLLER:96
-      goto_table:7
-   7. dl_vlan=100,dl_dst=00:11:11:00:00:00, priority 9099, cookie 0x5adc15c0
-      pop_vlan
-      output:1
-
-If you check ``inst/faucet.log``, you can see that ``p2``'s MAC has
-been learned too::
-
-  Jan 06 15:58:09 faucet.valve INFO     DPID 1 (0x1) L2 learned 00:22:22:00:00:00 (L2 type 0x0000, L3 src None) on Port 2 on VLAN 100 (2 hosts total)
-
-Similarly for ``diff-flows``::
-
-  $ diff-flows flows1 br0
-  +table=3 priority=9098,in_port=1,dl_vlan=100,dl_src=00:11:11:00:00:00 hard_timeout=3601 actions=goto_table:7
-  +table=3 priority=9098,in_port=2,dl_vlan=100,dl_src=00:22:22:00:00:00 hard_timeout=3604 actions=goto_table:7
-  +table=7 priority=9099,dl_vlan=100,dl_dst=00:11:11:00:00:00 idle_timeout=3601 actions=pop_vlan,output:1
-  +table=7 priority=9099,dl_vlan=100,dl_dst=00:22:22:00:00:00 idle_timeout=3604 actions=pop_vlan,output:2
-
-Then, if you re-run either of the ``ofproto/trace`` commands (with or
-without ``-generate``), you can see that the packets go back and forth
-without any further MAC learning, e.g.::
-
-  $ ovs-appctl ofproto/trace br0 in_port=p2,dl_src=00:22:22:00:00:00,dl_dst=00:11:11:00:00:00 -generate
-  Flow: in_port=2,vlan_tci=0x0000,dl_src=00:22:22:00:00:00,dl_dst=00:11:11:00:00:00,dl_type=0x0000
-
-  bridge("br0")
-  -------------
-   0. in_port=2, priority 9099, cookie 0x5adc15c0
-      goto_table:1
-   1. in_port=2,vlan_tci=0x0000/0x1fff, priority 9000, cookie 0x5adc15c0
-      push_vlan:0x8100
-      set_field:4196->vlan_vid
-      goto_table:3
-   3. in_port=2,dl_vlan=100,dl_src=00:22:22:00:00:00, priority 9098, cookie 0x5adc15c0
-      goto_table:7
-   7. dl_vlan=100,dl_dst=00:11:11:00:00:00, priority 9099, cookie 0x5adc15c0
-      pop_vlan
-      output:1
-
-  Final flow: unchanged
-  Megaflow: recirc_id=0,eth,in_port=2,vlan_tci=0x0000/0x1fff,dl_src=00:22:22:00:00:00,dl_dst=00:11:11:00:00:00,dl_type=0x0000
-  Datapath actions: 1
-
-Performance
-~~~~~~~~~~~
-
-Open vSwitch has a concept of a "fast path" and a "slow path"; ideally
-all packets stay in the fast path.  This distinction between slow path
-and fast path is the key to making sure that Open vSwitch performs as
-fast as possible.
-
-Some factors can force a flow or a packet to take the slow path.  As one
-example, all CFM, BFD, LACP, STP, and LLDP processing takes place in the
-slow path, in the cases where Open vSwitch processes these protocols
-itself instead of delegating to controller-written flows.  As a second
-example, any flow that modifies ARP fields is processed in the slow
-path.  These are corner cases that are unlikely to cause performance
-problems in practice because these protocols send packets at a
-relatively slow rate, and users and controller authors do not normally
-need to be concerned about them.
-
-To understand what cases users and controller authors should consider,
-we need to talk about how Open vSwitch optimizes for performance.  The
-Open vSwitch code is divided into two major components which, as
-already mentioned, are called the "slow path" and "fast path" (aka
-"datapath").  The slow path is embedded in the ``ovs-vswitchd``
-userspace program.  It is the part of the Open vSwitch packet
-processing logic that understands OpenFlow.  Its job is to take a
-packet and run it through the OpenFlow tables to determine what should
-happen to it.  It outputs a list of actions in a form similar to
-OpenFlow actions but simpler, called "ODP actions" or "datapath
-actions".  It then passes the ODP actions to the datapath, which
-applies them to the packet.
-
-.. note::
-
-  Open vSwitch contains a single slow path and multiple fast paths.
-  The difference between using Open vSwitch with the Linux kernel
-  versus with DPDK is the datapath.
-
-If every packet passed through the slow path and the fast path in this
-way, performance would be terrible.  The key to getting high
-performance from this architecture is caching.  Open vSwitch includes
-a multi-level cache.  It works like this:
-
-1. A packet initially arrives at the datapath.  Some datapaths (such
-   as DPDK and the in-tree version of the OVS kernel module) have a
-   first-level cache called the "microflow cache".  The microflow
-   cache is the key to performance for relatively long-lived, high
-   packet rate flows.  If the datapath has a microflow cache, then it
-   consults it and, if there is a cache hit, the datapath executes the
-   associated actions.  Otherwise, it proceeds to step 2.
-
-2. The datapath consults its second-level cache, called the "megaflow
-   cache".  The megaflow cache is the key to performance for shorter
-   or low packet rate flows.  If there is a megaflow cache hit, the
-   datapath executes the associated actions.  Otherwise, it proceeds
-   to step 3.
-
-3. The datapath passes the packet to the slow path, which runs it
-   through the OpenFlow table to yield ODP actions, a process that is
-   often called "flow translation".  It then passes the packet back to
-   the datapath to execute the actions and to, if possible, install a
-   megaflow cache entry so that subsequent similar packets can be
-   handled directly by the fast path.  (We already described above
-   most of the cases where a cache entry cannot be installed.)
-
-The megaflow cache is the key cache to consider for performance
-tuning.  Open vSwitch provides tools for understanding and optimizing
-its behavior.  The ``ofproto/trace`` command that we have already been
-using is the most common tool for this use.  Let's take another look
-at the most recent ``ofproto/trace`` output::
-
-  $ ovs-appctl ofproto/trace br0 in_port=p2,dl_src=00:22:22:00:00:00,dl_dst=00:11:11:00:00:00 -generate
-  Flow: in_port=2,vlan_tci=0x0000,dl_src=00:22:22:00:00:00,dl_dst=00:11:11:00:00:00,dl_type=0x0000
-
-  bridge("br0")
-  -------------
-   0. in_port=2, priority 9099, cookie 0x5adc15c0
-      goto_table:1
-   1. in_port=2,vlan_tci=0x0000/0x1fff, priority 9000, cookie 0x5adc15c0
-      push_vlan:0x8100
-      set_field:4196->vlan_vid
-      goto_table:3
-   3. in_port=2,dl_vlan=100,dl_src=00:22:22:00:00:00, priority 9098, cookie 0x5adc15c0
-      goto_table:7
-   7. dl_vlan=100,dl_dst=00:11:11:00:00:00, priority 9099, cookie 0x5adc15c0
-      pop_vlan
-      output:1
-
-  Final flow: unchanged
-  Megaflow: recirc_id=0,eth,in_port=2,vlan_tci=0x0000/0x1fff,dl_src=00:22:22:00:00:00,dl_dst=00:11:11:00:00:00,dl_type=0x0000
-  Datapath actions: 1
-
-This time, it's the last line that we're interested in.  This line
-shows the entry that Open vSwitch would insert into the megaflow cache
-given the particular packet with the current flow tables.  The
-megaflow entry includes:
-
-* ``recirc_id``.  This is an implementation detail that users don't
-  normally need to understand.
-
-* ``eth``.  This just indicates that the cache entry matches only
-  Ethernet packets; Open vSwitch also supports other types of packets,
-  such as IP packets not encapsulated in Ethernet.
-
-* All of the fields matched by any of the flows that the packet
-  visited:
-
-  ``in_port``
-    In tables 0, 1, and 3.
-
-  ``vlan_tci``
-    In tables 1, 3, and 7 (``vlan_tci`` includes the VLAN ID and PCP
-    fields and``dl_vlan`` is just the VLAN ID).
-
-  ``dl_src``
-    In table 3
-
-  ``dl_dst``
-    In table 7.
-
-* All of the fields matched by flows that had to be ruled out to
-  ensure that the ones that actually matched were the highest priority
-  matching rules.
-
-The last one is important.  Notice how the megaflow matches on
-``dl_type=0x0000``, even though none of the tables matched on
-``dl_type`` (the Ethernet type).  One reason is because of this flow
-in OpenFlow table 1 (which shows up in ``dump-flows`` output)::
-
-  table=1, priority=9099,dl_type=0x88cc actions=drop
-
-This flow has higher priority than the flow in table 1 that actually
-matched.  This means that, to put it in the megaflow cache,
-``ovs-vswitchd`` has to add a match on ``dl_type`` to ensure that the
-cache entry doesn't match LLDP packets (with Ethertype 0x88cc).
-
-.. note::
-
-  In fact, in some cases ``ovs-vswitchd`` matches on fields that
-  aren't strictly required according to this description.  ``dl_type``
-  is actually one of those, so deleting the LLDP flow probably would
-  not have any effect on the megaflow.  But the principle here is
-  sound.
-
-So why does any of this matter?  It's because, the more specific a
-megaflow is, that is, the more fields or bits within fields that a
-megaflow matches, the less valuable it is from a caching viewpoint.  A
-very specific megaflow might match on L2 and L3 addresses and L4 port
-numbers.  When that happens, only packets in one (half-)connection
-match the megaflow.  If that connection has only a few packets, as
-many connections do, then the high cost of the slow path translation
-is amortized over only a few packets, so the average cost of
-forwarding those packets is high.  On the other hand, if a megaflow
-only matches a relatively small number of L2 and L3 packets, then the
-cache entry can potentially be used by many individual connections,
-and the average cost is low.
-
-For more information on how Open vSwitch constructs megaflows,
-including about ways that it can make megaflow entries less specific
-than one would infer from the discussion here, please refer to the
-2015 NSDI paper, "The Design and Implementation of Open vSwitch",
-which focuses on this algorithm.
-
-Routing
--------
-
-We've looked at how Faucet implements switching in OpenFlow, and how
-Open vSwitch implements OpenFlow through its datapath architecture.
-Now let's start over, adding L3 routing into the picture.
-
-It's remarkably easy to enable routing.  We just change our ``vlans``
-section in ``inst/faucet.yaml`` to specify a router IP address for
-each VLAN and define a router between them. The ``dps`` section is unchanged::
-
-  dps:
-      switch-1:
-          dp_id: 0x1
-          timeout: 3600
-          arp_neighbor_timeout: 3600
-          interfaces:
-              1:
-                  native_vlan: 100
-              2:
-                  native_vlan: 100
-              3:
-                  native_vlan: 100
-              4:
-                  native_vlan: 200
-              5:
-                  native_vlan: 200
-  vlans:
-      100:
-          faucet_vips: ["10.100.0.254/24"]
-      200:
-          faucet_vips: ["10.200.0.254/24"]
-  routers:
-      router-1:
-          vlans: [100, 200]
-
-Then we restart Faucet::
-
-  $ docker restart faucet
-
-.. note::
-
-  One should be able to tell Faucet to re-read its configuration file
-  without restarting it.  I sometimes saw anomalous behavior when I
-  did this, although I didn't characterize it well enough to make a
-  quality bug report.  I found restarting the container to be
-  reliable.
-
-OpenFlow Layer
-~~~~~~~~~~~~~~
-
-Back in the OVS sandbox, let's see how the flow table has changed, with::
-
-  $ diff-flows flows1 br0
-
-First, table 3 has new flows to direct ARP packets to table 6 (the
-virtual IP processing table), presumably to handle ARP for the router
-IPs.  New flows also send IP packets destined to a particular Ethernet
-address to table 4 (the L3 forwarding table); we can make the educated
-guess that the Ethernet address is the one used by the Faucet router::
-
-  +table=3 priority=9131,arp,dl_vlan=100 actions=goto_table:6
-  +table=3 priority=9131,arp,dl_vlan=200 actions=goto_table:6
-  +table=3 priority=9099,ip,dl_vlan=100,dl_dst=0e:00:00:00:00:01 actions=goto_table:4
-  +table=3 priority=9099,ip,dl_vlan=200,dl_dst=0e:00:00:00:00:01 actions=goto_table:4
-
-The new flows in table 4 appear to be verifying that the packets are
-indeed addressed to a network or IP address that Faucet knows how to
-route::
-
-  +table=4 priority=9131,ip,dl_vlan=100,nw_dst=10.100.0.254 actions=goto_table:6
-  +table=4 priority=9131,ip,dl_vlan=200,nw_dst=10.200.0.254 actions=goto_table:6
-  +table=4 priority=9123,ip,dl_vlan=100,nw_dst=10.100.0.0/24 actions=goto_table:6
-  +table=4 priority=9123,ip,dl_vlan=200,nw_dst=10.100.0.0/24 actions=goto_table:6
-  +table=4 priority=9123,ip,dl_vlan=100,nw_dst=10.200.0.0/24 actions=goto_table:6
-  +table=4 priority=9123,ip,dl_vlan=200,nw_dst=10.200.0.0/24 actions=goto_table:6
-
-Table 6 has a few different things going on.  It sends ARP requests
-for the router IPs to the controller; presumably the controller will
-generate replies and send them back to the requester.  It switches
-other ARP packets, either broadcasting them if they have a broadcast
-destination or attempting to unicast them otherwise.  It sends all
-other IP packets to the controller::
-
-  +table=6 priority=9133,arp,arp_tpa=10.100.0.254 actions=CONTROLLER:128
-  +table=6 priority=9133,arp,arp_tpa=10.200.0.254 actions=CONTROLLER:128
-  +table=6 priority=9132,arp,dl_dst=ff:ff:ff:ff:ff:ff actions=goto_table:8
-  +table=6 priority=9131,arp actions=goto_table:7
-  +table=6 priority=9130,ip actions=CONTROLLER:128
-
-Performance is clearly going to be poor if every packet that needs to
-be routed has to go to the controller, but it's unlikely that's the
-full story.  In the next section, we'll take a closer look.
-
-Tracing
-~~~~~~~
-
-As in our switching example, we can play some "what-if?" games to
-figure out how this works.  Let's suppose that a machine with IP
-10.100.0.1, on port ``p1``, wants to send a IP packet to a machine
-with IP 10.200.0.1 on port ``p4``.  Assuming that these hosts have not
-been in communication recently, the steps to accomplish this are
-normally the following:
-
-1. Host 10.100.0.1 sends an ARP request to router 10.100.0.254.
-
-2. The router sends an ARP reply to the host.
-
-3. Host 10.100.0.1 sends an IP packet to 10.200.0.1, via the router's
-   Ethernet address.
-
-4. The router broadcasts an ARP request to ``p4`` and ``p5``, the
-   ports that carry the 10.200.0.<x> network.
-
-5. Host 10.200.0.1 sends an ARP reply to the router.
-
-6. Either the router sends the IP packet (which it buffered) to
-   10.200.0.1, or eventually 10.100.0.1 times out and resends it.
-
-Let's use ``ofproto/trace`` to see whether Faucet and OVS follow this
-procedure.
-
-Before we start, save a new snapshot of the flow tables for later
-comparison::
-
-  $ save-flows br0 > flows2
-
-Step 1: Host ARP for Router
-+++++++++++++++++++++++++++
-
-Let's simulate the ARP from 10.100.0.1 to its gateway router
-10.100.0.254.  This requires more detail than any of the packets we've
-simulated previously::
-
-  $ ovs-appctl ofproto/trace br0 in_port=p1,dl_src=00:01:02:03:04:05,dl_dst=ff:ff:ff:ff:ff:ff,dl_type=0x806,arp_spa=10.100.0.1,arp_tpa=10.100.0.254,arp_sha=00:01:02:03:04:05,arp_tha=ff:ff:ff:ff:ff:ff,arp_op=1 -generate
-
-The important part of the output is where it shows that the packet was
-recognized as an ARP request destined to the router gateway and
-therefore sent to the controller::
-
-   6. arp,arp_tpa=10.100.0.254, priority 9133, cookie 0x5adc15c0
-      CONTROLLER:128
-
-The Faucet log shows that Faucet learned the host's MAC address,
-its MAC-to-IP mapping, and responded to the ARP request::
-
-  Jan 06 16:12:23 faucet.valve INFO     DPID 1 (0x1) Adding new route 10.100.0.1/32 via 10.100.0.1 (00:01:02:03:04:05) on VLAN 100
-  Jan 06 16:12:23 faucet.valve INFO     DPID 1 (0x1) Responded to ARP request for 10.100.0.254 from 10.100.0.1 (00:01:02:03:04:05) on VLAN 100
-  Jan 06 16:12:23 faucet.valve INFO     DPID 1 (0x1) L2 learned 00:01:02:03:04:05 (L2 type 0x0806, L3 src 10.100.0.1) on Port 1 on VLAN 100 (1 hosts total)
-
-We can also look at the changes to the flow tables::
-
-  $ diff-flows flows2 br0
-  +table=3 priority=9098,in_port=1,dl_vlan=100,dl_src=00:01:02:03:04:05 hard_timeout=3600 actions=goto_table:7
-  +table=4 priority=9131,ip,dl_vlan=100,nw_dst=10.100.0.1 actions=set_field:4196->vlan_vid,set_field:0e:00:00:00:00:01->eth_src,set_field:00:01:02:03:04:05->eth_dst,dec_ttl,goto_table:7
-  +table=4 priority=9131,ip,dl_vlan=200,nw_dst=10.100.0.1 actions=set_field:4196->vlan_vid,set_field:0e:00:00:00:00:01->eth_src,set_field:00:01:02:03:04:05->eth_dst,dec_ttl,goto_table:7
-  +table=7 priority=9099,dl_vlan=100,dl_dst=00:01:02:03:04:05 idle_timeout=3600 actions=pop_vlan,output:1
-
-The new flows include one in table 3 and one in table 7 for the
-learned MAC, which have the same forms we saw before.  The new flows
-in table 4 are different.  They matches packets directed to 10.100.0.1
-(in two VLANs) and forward them to the host by updating the Ethernet
-source and destination addresses appropriately, decrementing the TTL,
-and skipping ahead to unicast output in table 7.  This means that
-packets sent **to** 10.100.0.1 should now get to their destination.
-
-Step 2: Router Sends ARP Reply
-++++++++++++++++++++++++++++++
-
-``inst/faucet.log`` said that the router sent an ARP reply.  How can
-we see it?  Simulated packets just get dropped by default.  One way is
-to configure the dummy ports to write the packets they receive to a
-file.  Let's try that.  First configure the port::
-
-  $ ovs-vsctl set interface p1 options:pcap=p1.pcap
-
-Then re-run the "trace" command::
-
-  $ ovs-appctl ofproto/trace br0 in_port=p1,dl_src=00:01:02:03:04:05,dl_dst=ff:ff:ff:ff:ff:ff,dl_type=0x806,arp_spa=10.100.0.1,arp_tpa=10.100.0.254,arp_sha=00:01:02:03:04:05,arp_tha=ff:ff:ff:ff:ff:ff,arp_op=1 -generate
-
-And dump the reply packet::
-
-  $ /usr/sbin/tcpdump -evvvr sandbox/p1.pcap
-  reading from file sandbox/p1.pcap, link-type EN10MB (Ethernet)
-  16:14:47.670727 0e:00:00:00:00:01 (oui Unknown) > 00:01:02:03:04:05 (oui Unknown), ethertype ARP (0x0806), length 60: Ethernet (len 6), IPv4 (len 4), Reply 10.100.0.254 is-at 0e:00:00:00:00:01 (oui Unknown), length 46
-
-We clearly see the ARP reply, which tells us that the Faucet router's
-Ethernet address is 0e:00:00:00:00:01 (as we guessed before from the
-flow table.
-
-Let's configure the rest of our ports to log their packets, too::
-
-  $ for i in 2 3 4 5; do ovs-vsctl set interface p$i options:pcap=p$i.pcap; done
-
-Step 3: Host Sends IP Packet
-++++++++++++++++++++++++++++
-
-Now that host 10.100.0.1 has the MAC address for its router, it can
-send an IP packet to 10.200.0.1 via the router's MAC address, like
-this::
-
-  $ ovs-appctl ofproto/trace br0 in_port=p1,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,udp,nw_src=10.100.0.1,nw_dst=10.200.0.1,nw_ttl=64 -generate
-  Flow: udp,in_port=1,vlan_tci=0x0000,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,nw_src=10.100.0.1,nw_dst=10.200.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=0
-
-  bridge("br0")
-  -------------
-   0. in_port=1, priority 9099, cookie 0x5adc15c0
-      goto_table:1
-   1. in_port=1,vlan_tci=0x0000/0x1fff, priority 9000, cookie 0x5adc15c0
-      push_vlan:0x8100
-      set_field:4196->vlan_vid
-      goto_table:3
-   3. ip,dl_vlan=100,dl_dst=0e:00:00:00:00:01, priority 9099, cookie 0x5adc15c0
-      goto_table:4
-   4. ip,dl_vlan=100,nw_dst=10.200.0.0/24, priority 9123, cookie 0x5adc15c0
-      goto_table:6
-   6. ip, priority 9130, cookie 0x5adc15c0
-      CONTROLLER:128
-
-  Final flow: udp,in_port=1,dl_vlan=100,dl_vlan_pcp=0,vlan_tci1=0x0000,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,nw_src=10.100.0.1,nw_dst=10.200.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=0
-  Megaflow: recirc_id=0,eth,ip,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,nw_dst=10.200.0.0/25,nw_frag=no
-  Datapath actions: push_vlan(vid=100,pcp=0),userspace(pid=0,controller(reason=1,flags=0,recirc_id=6,rule_cookie=0x5adc15c0,controller_id=0,max_len=128))
-
-Observe that the packet gets recognized as destined to the router, in
-table 3, and then as properly destined to the 10.200.0.0/24 network,
-in table 4.  In table 6, however, it gets sent to the controller.
-Presumably, this is because Faucet has not yet resolved an Ethernet
-address for the destination host 10.200.0.1.  It probably sent out an
-ARP request.  Let's take a look in the next step.
-
-Step 4: Router Broadcasts ARP Request
-+++++++++++++++++++++++++++++++++++++
-
-The router needs to know the Ethernet address of 10.200.0.1.  It knows
-that, if this machine exists, it's on port ``p4`` or ``p5``, since we
-configured those ports as VLAN 200.
-
-Let's make sure::
-
-  $ /usr/sbin/tcpdump -evvvr sandbox/p4.pcap
-  reading from file sandbox/p4.pcap, link-type EN10MB (Ethernet)
-  16:17:43.174006 0e:00:00:00:00:01 (oui Unknown) > Broadcast, ethertype ARP (0x0806), length 60: Ethernet (len 6), IPv4 (len 4), Request who-has 10.200.0.1 tell 10.200.0.254, length 46
-
-and::
-
-  $ /usr/sbin/tcpdump -evvvr sandbox/p5.pcap
-  reading from file sandbox/p5.pcap, link-type EN10MB (Ethernet)
-  16:17:43.174268 0e:00:00:00:00:01 (oui Unknown) > Broadcast, ethertype ARP (0x0806), length 60: Ethernet (len 6), IPv4 (len 4), Request who-has 10.200.0.1 tell 10.200.0.254, length 46
-
-For good measure, let's make sure that it wasn't sent to ``p3``::
-
-  $ /usr/sbin/tcpdump -evvvr sandbox/p3.pcap
-  reading from file sandbox/p3.pcap, link-type EN10MB (Ethernet)
-
-Step 5: Host 2 Sends ARP Reply
-++++++++++++++++++++++++++++++
-
-The Faucet controller sent an ARP request, so we can send an ARP
-reply::
-
-  $ ovs-appctl ofproto/trace br0 in_port=p4,dl_src=00:10:20:30:40:50,dl_dst=0e:00:00:00:00:01,dl_type=0x806,arp_spa=10.200.0.1,arp_tpa=10.200.0.254,arp_sha=00:10:20:30:40:50,arp_tha=0e:00:00:00:00:01,arp_op=2 -generate
-  Flow: arp,in_port=4,vlan_tci=0x0000,dl_src=00:10:20:30:40:50,dl_dst=0e:00:00:00:00:01,arp_spa=10.200.0.1,arp_tpa=10.200.0.254,arp_op=2,arp_sha=00:10:20:30:40:50,arp_tha=0e:00:00:00:00:01
-
-  bridge("br0")
-  -------------
-   0. in_port=4, priority 9099, cookie 0x5adc15c0
-      goto_table:1
-   1. in_port=4,vlan_tci=0x0000/0x1fff, priority 9000, cookie 0x5adc15c0
-      push_vlan:0x8100
-      set_field:4296->vlan_vid
-      goto_table:3
-   3. arp,dl_vlan=200, priority 9131, cookie 0x5adc15c0
-      goto_table:6
-   6. arp,arp_tpa=10.200.0.254, priority 9133, cookie 0x5adc15c0
-      CONTROLLER:128
-
-  Final flow: arp,in_port=4,dl_vlan=200,dl_vlan_pcp=0,vlan_tci1=0x0000,dl_src=00:10:20:30:40:50,dl_dst=0e:00:00:00:00:01,arp_spa=10.200.0.1,arp_tpa=10.200.0.254,arp_op=2,arp_sha=00:10:20:30:40:50,arp_tha=0e:00:00:00:00:01
-  Megaflow: recirc_id=0,eth,arp,in_port=4,vlan_tci=0x0000/0x1fff,dl_dst=0e:00:00:00:00:01,arp_tpa=10.200.0.254
-  Datapath actions: push_vlan(vid=200,pcp=0),userspace(pid=0,controller(reason=1,flags=0,recirc_id=7,rule_cookie=0x5adc15c0,controller_id=0,max_len=128))
-
-It shows up in ``inst/faucet.log``::
-
-  Jan 06 03:20:11 faucet.valve INFO     DPID 1 (0x1) Adding new route 10.200.0.1/32 via 10.200.0.1 (00:10:20:30:40:50) on VLAN 200
-  Jan 06 03:20:11 faucet.valve INFO     DPID 1 (0x1) ARP response 10.200.0.1 (00:10:20:30:40:50) on VLAN 200
-  Jan 06 03:20:11 faucet.valve INFO     DPID 1 (0x1) L2 learned 00:10:20:30:40:50 (L2 type 0x0806, L3 src 10.200.0.1) on Port 4 on VLAN 200 (1 hosts total)
-
-and in the OVS flow tables::
-
-  $ diff-flows flows2 br0
-  +table=3 priority=9098,in_port=4,dl_vlan=200,dl_src=00:10:20:30:40:50 hard_timeout=3601 actions=goto_table:7
-  ...
-  +table=4 priority=9131,ip,dl_vlan=200,nw_dst=10.200.0.1 actions=set_field:4296->vlan_vid,set_field:0e:00:00:00:00:01->eth_src,set_field:00:10:20:30:40:50->eth_dst,dec_ttl,goto_table:7
-  +table=4 priority=9131,ip,dl_vlan=100,nw_dst=10.200.0.1 actions=set_field:4296->vlan_vid,set_field:0e:00:00:00:00:01->eth_src,set_field:00:10:20:30:40:50->eth_dst,dec_ttl,goto_table:7
-  ...
-  +table=4 priority=9123,ip,dl_vlan=100,nw_dst=10.200.0.0/24 actions=goto_table:6
-  +table=7 priority=9099,dl_vlan=200,dl_dst=00:10:20:30:40:50 idle_timeout=3601 actions=pop_vlan,output:4
-
-Step 6: IP Packet Delivery
-++++++++++++++++++++++++++
-
-Now both the host and the router have everything they need to deliver
-the packet.  There are two ways it might happen.  If Faucet's router
-is smart enough to buffer the packet that trigger ARP resolution, then
-it might have delivered it already.  If so, then it should show up in
-``p4.pcap``.  Let's take a look::
-
-  $ /usr/sbin/tcpdump -evvvr sandbox/p4.pcap ip
-  reading from file sandbox/p4.pcap, link-type EN10MB (Ethernet)
-
-Nope.  That leaves the other possibility, which is that Faucet waits
-for the original sending host to re-send the packet.  We can do that
-by re-running the trace::
-
-  $ ovs-appctl ofproto/trace br0 in_port=p1,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,udp,nw_src=10.100.0.1,nw_dst=10.200.0.1,nw_ttl=64 -generate
-  Flow: udp,in_port=1,vlan_tci=0x0000,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,nw_src=10.100.0.1,nw_dst=10.200.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=0
-
-  bridge("br0")
-  -------------
-   0. in_port=1, priority 9099, cookie 0x5adc15c0
-      goto_table:1
-   1. in_port=1,vlan_tci=0x0000/0x1fff, priority 9000, cookie 0x5adc15c0
-      push_vlan:0x8100
-      set_field:4196->vlan_vid
-      goto_table:3
-   3. ip,dl_vlan=100,dl_dst=0e:00:00:00:00:01, priority 9099, cookie 0x5adc15c0
-      goto_table:4
-   4. ip,dl_vlan=100,nw_dst=10.200.0.1, priority 9131, cookie 0x5adc15c0
-      set_field:4296->vlan_vid
-      set_field:0e:00:00:00:00:01->eth_src
-      set_field:00:10:20:30:40:50->eth_dst
-      dec_ttl
-      goto_table:7
-   7. dl_vlan=200,dl_dst=00:10:20:30:40:50, priority 9099, cookie 0x5adc15c0
-      pop_vlan
-      output:4
-
-  Final flow: udp,in_port=1,vlan_tci=0x0000,dl_src=0e:00:00:00:00:01,dl_dst=00:10:20:30:40:50,nw_src=10.100.0.1,nw_dst=10.200.0.1,nw_tos=0,nw_ecn=0,nw_ttl=63,tp_src=0,tp_dst=0
-  Megaflow: recirc_id=0,eth,ip,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,nw_dst=10.200.0.1,nw_ttl=64,nw_frag=no
-  Datapath actions: set(eth(src=0e:00:00:00:00:01,dst=00:10:20:30:40:50)),set(ipv4(dst=10.200.0.1,ttl=63)),4
-
-Finally, we have working IP packet forwarding!
-
-Performance
-~~~~~~~~~~~
-
-Take another look at the megaflow line above::
-
-  Megaflow: recirc_id=0,eth,ip,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,nw_dst=10.200.0.1,nw_ttl=64,nw_frag=no
-
-This means that (almost) any packet between these Ethernet source and
-destination hosts, destined to the given IP host, will be handled by
-this single megaflow cache entry.  So regardless of the number of UDP
-packets or TCP connections that these hosts exchange, Open vSwitch
-packet processing won't need to fall back to the slow path.  It is
-quite efficient.
-
-.. note::
-
-  The exceptions are packets with a TTL other than 64, and fragmented
-  packets.  Most hosts use a constant TTL for outgoing packets, and
-  fragments are rare.  If either of those did change, then that would
-  simply result in a new megaflow cache entry.
-
-The datapath actions might also be worth a look::
-
-  Datapath actions: set(eth(src=0e:00:00:00:00:01,dst=00:10:20:30:40:50)),set(ipv4(dst=10.200.0.1,ttl=63)),4
-
-This just means that, to process these packets, the datapath changes
-the Ethernet source and destination addresses and the IP TTL, and then
-transmits the packet to port ``p4`` (also numbered 4).  Notice in
-particular that, despite the OpenFlow actions that pushed, modified,
-and popped back off a VLAN, there is nothing in the datapath actions
-about VLANs.  This is because the OVS flow translation code "optimizes
-out" redundant or unneeded actions, which saves time when the cache
-entry is executed later.
-
-.. note::
-
-  It's not clear why the actions also re-set the IP destination
-  address to its original value.  Perhaps this is a minor performance
-  bug.
-
-ACLs
-----
-
-Let's try out some ACLs, since they do a good job illustrating some of
-the ways that OVS tries to optimize megaflows.  Update
-``inst/faucet.yaml`` to the following::
-
-  dps:
-      switch-1:
-          dp_id: 0x1
-          timeout: 3600
-          arp_neighbor_timeout: 3600
-          interfaces:
-              1:
-                  native_vlan: 100
-                  acl_in: 1
-              2:
-                  native_vlan: 100
-              3:
-                  native_vlan: 100
-              4:
-                  native_vlan: 200
-              5:
-                  native_vlan: 200
-  vlans:
-      100:
-          faucet_vips: ["10.100.0.254/24"]
-      200:
-          faucet_vips: ["10.200.0.254/24"]
-  routers:
-      router-1:
-          vlans: [100, 200]
-  acls:
-      1:
-          - rule:
-              dl_type: 0x800
-              nw_proto: 6
-              tcp_dst: 8080
-              actions:
-                  allow: 0
-          - rule:
-              actions:
-                  allow: 1
-
-Then restart Faucet::
-
-  $ docker restart faucet
-
-On port 1, this new configuration blocks all traffic to TCP port 8080
-and allows all other traffic.  The resulting change in the flow table
-shows this clearly too::
-
-  $ diff-flows flows2 br0
-  -priority=9099,in_port=1 actions=goto_table:1
-  +priority=9098,in_port=1 actions=goto_table:1
-  +priority=9099,tcp,in_port=1,tp_dst=8080 actions=drop
-
-The most interesting question here is performance.  If you recall the
-earlier discussion, when a packet through the flow table encounters a
-match on a given field, the resulting megaflow has to match on that
-field, even if the flow didn't actually match.  This is expensive.
-
-In particular, here you can see that any TCP packet is going to
-encounter the ACL flow, even if it is directed to a port other than
-8080.  If that means that every megaflow for a TCP packet is going to
-have to match on the TCP destination, that's going to be bad for
-caching performance because there will be a need for a separate
-megaflow for every TCP destination port that actually appears in
-traffic, which means a lot more megaflows than otherwise.  (Really, in
-practice, if such a simple ACL blew up performance, OVS wouldn't be a
-very good switch!)
-
-Let's see what happens, by sending a packet to port 80 (instead of
-8080)::
-
-  $ ovs-appctl ofproto/trace br0 in_port=p1,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,tcp,nw_src=10.100.0.1,nw_dst=10.200.0.1,nw_ttl=64,tp_dst=80 -generate
-  Flow: tcp,in_port=1,vlan_tci=0x0000,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,nw_src=10.100.0.1,nw_dst=10.200.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
-
-  bridge("br0")
-  -------------
-   0. in_port=1, priority 9098, cookie 0x5adc15c0
-      goto_table:1
-   1. in_port=1,vlan_tci=0x0000/0x1fff, priority 9000, cookie 0x5adc15c0
-      push_vlan:0x8100
-      set_field:4196->vlan_vid
-      goto_table:3
-   3. ip,dl_vlan=100,dl_dst=0e:00:00:00:00:01, priority 9099, cookie 0x5adc15c0
-      goto_table:4
-   4. ip,dl_vlan=100,nw_dst=10.200.0.0/24, priority 9123, cookie 0x5adc15c0
-      goto_table:6
-   6. ip, priority 9130, cookie 0x5adc15c0
-      CONTROLLER:128
-
-  Final flow: tcp,in_port=1,dl_vlan=100,dl_vlan_pcp=0,vlan_tci1=0x0000,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,nw_src=10.100.0.1,nw_dst=10.200.0.1,nw_tos=0,nw_ecn=0,nw_ttl=64,tp_src=0,tp_dst=80,tcp_flags=0
-  Megaflow: recirc_id=0,eth,tcp,in_port=1,vlan_tci=0x0000/0x1fff,dl_src=00:01:02:03:04:05,dl_dst=0e:00:00:00:00:01,nw_dst=10.200.0.1,nw_frag=no,tp_dst=0x0/0xf000
-  Datapath actions: push_vlan(vid=100,pcp=0)
-
-Take a look at the Megaflow line and in particular the match on
-``tp_dst``, which says ``tp_dst=0x0/0xf000``.  What this means is that
-the megaflow matches on only the top 4 bits of the TCP destination
-port.  That works because::
-
-    80 (base 10) == 0000,0000,0101,0000 (base 2)
-  8080 (base 10) == 0001,1111,1001,0000 (base 2)
-
-and so by matching on only the top 4 bits, rather than all 16, the OVS
-fast path can distinguish port 80 from port 8080.  This allows this
-megaflow to match one-sixteenth of the TCP destination port address
-space, rather than just 1/65536th of it.
-
-.. note::
-
-  The algorithm OVS uses for this purpose isn't perfect.  In this
-  case, a single-bit match would work (e.g. tp_dst=0x0/0x1000), and
-  would be superior since it would only match half the port address
-  space instead of one-sixteenth.
-
-For details of this algorithm, please refer to ``lib/classifier.c`` in
-the Open vSwitch source tree, or our 2015 NSDI paper "The Design and
-Implementation of Open vSwitch".
-
-Finishing Up
-------------
-
-When you're done, you probably want to exit the sandbox session, with
-Control+D or ``exit``, and stop the Faucet controller with ``docker
-stop faucet; docker rm faucet``.
-
-Further Directions
-------------------
-
-We've looked a fair bit at how Faucet interacts with Open vSwitch.  If
-you still have some interest, you might want to explore some of these
-directions:
-
-* Adding more than one switch.  Faucet can control multiple switches
-  but we've only been simulating one of them.  It's easy enough to
-  make a single OVS instance act as multiple switches (just
-  ``ovs-vsctl add-br`` another bridge), or you could use genuinely
-  separate OVS instances.
-
-* Additional features.  Faucet has more features than we've
-  demonstrated, such as IPv6 routing and port mirroring.  These should
-  also interact gracefully with Open vSwitch.
-
-* Real performance testing.  We've looked at how flows and traces
-  **should** demonstrate good performance, but of course there's no
-  proof until it actually works in practice.  We've also only tested
-  with trivial configurations.  Open vSwitch can scale to millions of
-  OpenFlow flows, but the scaling in practice depends on the
-  particular flow tables and traffic patterns, so it's valuable to
-  test with large configurations, either in the way we've done it or
-  with real traffic.
diff --git a/Documentation/tutorials/index.rst b/Documentation/tutorials/index.rst
index 35340ee56..4f3e3103d 100644
--- a/Documentation/tutorials/index.rst
+++ b/Documentation/tutorials/index.rst
@@ -39,11 +39,7 @@  vSwitch.
 .. toctree::
    :maxdepth: 2
 
-   faucet
-   ipsec
-   ovs-advanced
    ovn-sandbox
    ovn-openstack
    ovn-rbac
    ovn-ipsec
-   ovs-conntrack
diff --git a/Documentation/tutorials/ipsec.rst b/Documentation/tutorials/ipsec.rst
deleted file mode 100644
index b4c323513..000000000
--- a/Documentation/tutorials/ipsec.rst
+++ /dev/null
@@ -1,347 +0,0 @@ 
-..
-      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.
-
-      Convention for heading levels in Open vSwitch documentation:
-
-      =======  Heading 0 (reserved for the title in a document)
-      -------  Heading 1
-      ~~~~~~~  Heading 2
-      +++++++  Heading 3
-      '''''''  Heading 4
-
-      Avoid deeper levels because they do not render well.
-
-==================
-OVS IPsec Tutorial
-==================
-
-This document provides a step-by-step guide for running IPsec tunnel in Open
-vSwitch. A more detailed description on OVS IPsec tunnel and its
-configuration modes can be found in :doc:`/howto/ipsec`.
-
-Requirements
-------------
-
-OVS IPsec tunnel requires Linux kernel (>= v3.10.0) and OVS out-of-tree kernel
-module. The compatible IKE daemons are LibreSwan (>= v3.23) and StrongSwan
-(>= v5.3.5).
-
-.. _install-ovs-ipsec:
-
-Installing OVS and IPsec Packages
----------------------------------
-
-OVS IPsec has .deb and .rpm packages. You should use the right package
-based on your Linux distribution. This tutorial uses Ubuntu 16.04 and Fedora 27
-as examples.
-
-Ubuntu
-~~~~~~
-
-1. Follow :doc:`/intro/install/debian` to build debian packages.
-
-   .. note::
-
-     If you have already installed OVS, then you only need to install
-     openvswitch-pki_*.deb and openvswitch-ipsec_*.deb in the following step.
-     If your kernel version is below v4.13.0, update your kernel to v4.13.0 or
-     above.
-
-2. Install the related packages::
-
-       $ apt-get install dkms strongswan
-       $ dpkg -i libopenvswitch_*.deb openvswitch-common_*.deb \
-             openvswitch-switch_*.deb openvswitch-datapath-dkms_*.deb \
-             python-openvswitch_*.deb openvswitch-pki_*.deb \
-             openvswitch-ipsec_*.deb
-
-   If the installation is successful, you should be able to see the
-   ovs-monitor-ipsec daemon is running in your system.
-
-Fedora
-~~~~~~
-
-1. Follow :doc:`/intro/install/fedora` to build RPM packages.
-
-2. Install the related packages::
-
-       $ dnf install python2-openvswitch libreswan \
-                     "kernel-devel-uname-r == $(uname -r)"
-       $ rpm -i openvswitch-*.rpm openvswitch-kmod-*.rpm \
-                openvswitch-openvswitch-ipsec-*.rpm
-
-3. Install firewall rules to allow ESP and IKE traffic::
-
-       $ iptables -A IN_FedoraServer_allow -p esp -j ACCEPT
-       $ iptables -A IN_FedoraServer_allow -p udp --dport 500 -j ACCEPT
-
-4. Run the openvswitch-ipsec service::
-
-       $ systemctl start openvswitch-ipsec.service
-
-   .. note::
-
-     The SELinux policies might prevent openvswitch-ipsec.service to access
-     certain resources. You can configure SELinux to remove such restrictions.
-
-Configuring IPsec tunnel
-------------------------
-
-Suppose you want to build IPsec tunnel between two hosts. Assume `host_1`'s
-external IP is 1.1.1.1, and `host_2`'s external IP is 2.2.2.2. Make sure
-`host_1` and `host_2` can ping each other via these external IPs.
-
-0. Set up some variables to make life easier.  On both hosts, set ``ip_1`` and
-   ``ip_2`` variables, e.g.::
-
-     $ ip_1=1.1.1.1
-     $ ip_2=2.2.2.2
-
-1. Set up OVS bridges in both hosts.
-
-   In `host_1`::
-
-       $ ovs-vsctl add-br br-ipsec
-       $ ip addr add 192.0.0.1/24 dev br-ipsec
-       $ ip link set br-ipsec up
-
-   In `host_2`::
-
-       $ ovs-vsctl add-br br-ipsec
-       $ ip addr add 192.0.0.2/24 dev br-ipsec
-       $ ip link set br-ipsec up
-
-2. Set up IPsec tunnel.
-
-   There are three authentication methods. You can choose one to set up your
-   IPsec tunnel.
-
-   a) Using pre-shared key:
-
-      In `host_1`::
-
-          $ ovs-vsctl add-port br-ipsec tun -- \
-                      set interface tun type=gre \
-                                    options:remote_ip=$ip_2 \
-                                    options:psk=swordfish
-
-      In `host_2`::
-
-          $ ovs-vsctl add-port br-ipsec tun -- \
-                      set interface tun type=gre \
-                                    options:remote_ip=$ip_1 \
-                                    options:psk=swordfish
-
-      .. note::
-
-        Pre-shared key (PSK) based authentication is easy to set up but less
-        secure compared with other authentication methods. You should use it
-        cautiously in production systems.
-
-   b) Using self-signed certificate:
-
-      Generate self-signed certificate in both `host_1` and `host_2`. Then copy
-      the certificate of `host_1` to `host_2` and the certificate of `host_2`
-      to `host_1`.
-
-      In `host_1`::
-
-          $ ovs-pki req -u host_1
-          $ ovs-pki self-sign host_1
-          $ scp host_1-cert.pem $ip_2:/etc/keys/host_1-cert.pem
-
-      In `host_2`::
-
-          $ ovs-pki req -u host_2
-          $ ovs-pki self-sign host_2
-          $ scp host_2-cert.pem $ip_1:/etc/keys/host_2-cert.pem
-
-      .. note::
-
-        If you use StrongSwan as IKE daemon, please move the host certificates
-        to /etc/ipsec.d/certs/ and private key to /etc/ipsec.d/private/ so that
-        StrongSwan has permission to access those files.
-
-      Configure IPsec tunnel to use self-signed certificates.
-
-      In `host_1`::
-
-          $ ovs-vsctl set Open_vSwitch . \
-                     other_config:certificate=/etc/keys/host_1-cert.pem \
-                     other_config:private_key=/etc/keys/host_1-privkey.pem
-          $ ovs-vsctl add-port br-ipsec tun -- \
-                      set interface tun type=gre \
-                             options:remote_ip=$ip_2 \
-                             options:remote_cert=/etc/keys/host_2-cert.pem
-
-      In `host_2`::
-
-          $ ovs-vsctl set Open_vSwitch . \
-                     other_config:certificate=/etc/keys/host_2-cert.pem \
-                     other_config:private_key=/etc/keys/host_2-privkey.pem
-          $ ovs-vsctl add-port br-ipsec tun -- \
-                      set interface tun type=gre \
-                             options:remote_ip=$ip_1 \
-                             options:remote_cert=/etc/keys/host_1-cert.pem
-
-      .. note::
-
-        The confidentiality of the private key is very critical.  Don't copy it
-        to places where it might be compromised.  (The certificate need not be
-        kept confidential.)
-
-   c) Using CA-signed certificate:
-
-      First you need to establish a public key infrastructure (PKI). Suppose
-      you choose `host_1` to host PKI.
-
-      In `host_1`::
-
-          $ ovs-pki init
-
-      Generate certificate requests and copy the certificate request of
-      `host_2` to `host_1`.
-
-      In `host_1`::
-
-          $ ovs-pki req -u host_1
-
-      In `host_2`::
-
-          $ ovs-pki req -u host_2
-          $ scp host_2-req.pem $ip_1:/etc/keys/host_2-req.pem
-
-      Sign the certificate requests with the CA key. Copy `host_2`'s signed
-      certificate and the CA certificate to `host_2`.
-
-      In `host_1`::
-
-          $ ovs-pki sign host_1 switch
-          $ ovs-pki sign host_2 switch
-          $ scp host_2-cert.pem $ip_2:/etc/keys/host_2-cert.pem
-          $ scp /var/lib/openvswitch/pki/switchca/cacert.pem \
-                    $ip_2:/etc/keys/cacert.pem
-
-      .. note::
-
-        If you use StrongSwan as IKE daemon, please move the host certificates
-        to /etc/ipsec.d/certs/, CA certificate to /etc/ipsec.d/cacerts/, and
-        private key to /etc/ipsec.d/private/ so that StrongSwan has permission
-        to access those files.
-
-      Configure IPsec tunnel to use CA-signed certificate.
-
-      In `host_1`::
-
-          $ ovs-vsctl set Open_vSwitch . \
-                  other_config:certificate=/etc/keys/host_1-cert.pem \
-                  other_config:private_key=/etc/keys/host_1-privkey.pem \
-                  other_config:ca_cert=/etc/keys/cacert.pem
-          $ ovs-vsctl add-port br-ipsec tun -- \
-                   set interface tun type=gre \
-                                 options:remote_ip=$ip_2 \
-                                 options:remote_name=host_2
-
-      In `host_2`::
-
-          $ ovs-vsctl set Open_vSwitch . \
-                  other_config:certificate=/etc/keys/host_2-cert.pem \
-                  other_config:private_key=/etc/keys/host_2-privkey.pem \
-                  other_config:ca_cert=/etc/keys/cacert.pem
-          $ ovs-vsctl add-port br-ipsec tun -- \
-                   set interface tun type=gre \
-                                 options:remote_ip=$ip_1 \
-                                 options:remote_name=host_1
-
-      .. note::
-
-        remote_name is the common name (CN) of the signed-certificate.  It must
-        match the name given as the argument to the ``ovs-pki sign command``.
-        It ensures that only certificate with the expected CN can be
-        authenticated; otherwise, any certificate signed by the CA would be
-        accepted.
-
-3. Test IPsec tunnel.
-
-   Now you should have an IPsec GRE tunnel running between two hosts. To verify
-   it, in `host_1`::
-
-       $ ping 192.0.0.2 &
-       $ tcpdump -ni any net $ip_2
-
-   You should be able to see that ESP packets are being sent from `host_1` to
-   `host_2`.
-
-Troubleshooting
----------------
-
-The ``ovs-monitor-ipsec`` daemon manages and monitors the IPsec tunnel state.
-Use the following ``ovs-appctl`` command to view ``ovs-monitor-ipsec`` internal
-representation of tunnel configuration::
-
-    $ ovs-appctl -t ovs-monitor-ipsec tunnels/show
-
-If there is misconfiguration, then ``ovs-appctl`` should indicate why.
-For example::
-
-   Interface name: gre0 v5 (CONFIGURED) <--- Should be set to CONFIGURED.
-                                             Otherwise, error message will
-                                             be provided
-   Tunnel Type:    gre
-   Remote IP:      2.2.2.2
-   SKB mark:       None
-   Local cert:     None
-   Local name:     None
-   Local key:      None
-   Remote cert:    None
-   Remote name:    None
-   CA cert:        None
-   PSK:            swordfish
-   Ofport:         1          <--- Whether ovs-vswitchd has assigned Ofport
-                                   number to this Tunnel Port
-   CFM state:      Up         <--- Whether CFM declared this tunnel healthy
-   Kernel policies installed:
-   ...                          <--- IPsec policies for this OVS tunnel in
-                                     Linux Kernel installed by strongSwan
-   Kernel security associations installed:
-   ...                          <--- IPsec security associations for this OVS
-                                     tunnel in Linux Kernel installed by
-                                     strongswan
-   IPsec connections that are active:
-   ...                          <--- IPsec "connections" for this OVS
-                                     tunnel
-
-If you don't see any active connections, try to run the following command to
-refresh the ``ovs-monitor-ipsec`` daemon::
-
-    $ ovs-appctl -t ovs-monitor-ipsec refresh
-
-You can also check the logs of the ``ovs-monitor-ipsec`` daemon and the IKE
-daemon to locate issues. ``ovs-monitor-ipsec`` outputs log messages to
-/var/log/openvswitch/ovs-monitor-ipsec.log.
-
-Bug Reporting
--------------
-
-If you think you may have found a bug with security implications, like
-
-1. IPsec protected tunnel accepted packets that came unencrypted; OR
-2. IPsec protected tunnel allowed packets to leave unencrypted;
-
-Then report such bugs according to :doc:`/internals/security`.
-
-If bug does not have security implications, then report it according to
-instructions in :doc:`/internals/bugs`.
-
-If you have suggestions to improve this tutorial, please send a email to
-ovs-discuss@openvswitch.org.
diff --git a/Documentation/tutorials/ovn-ipsec.rst b/Documentation/tutorials/ovn-ipsec.rst
index feb695ea3..e0c702a04 100644
--- a/Documentation/tutorials/ovn-ipsec.rst
+++ b/Documentation/tutorials/ovn-ipsec.rst
@@ -34,8 +34,8 @@  manipulated. More details about the OVN IPsec design can be found in
 ``ovn-architecture``\(7) manpage.
 
 This document assumes OVN is installed in your system and runs normally. Also,
-you need to install OVS IPsec packages in each chassis (refer to
-:ref:`install-ovs-ipsec`).
+you need to install OVS IPsec packages in each chassis (refer to Open vSwitch
+documentation on ipsec).
 
 Generating Certificates and Keys
 --------------------------------
diff --git a/Documentation/tutorials/ovn-sandbox.rst b/Documentation/tutorials/ovn-sandbox.rst
index b906b799d..3acc7b210 100644
--- a/Documentation/tutorials/ovn-sandbox.rst
+++ b/Documentation/tutorials/ovn-sandbox.rst
@@ -33,8 +33,8 @@  ovn-architecture_, but this tutorial lets you quickly see it in action.
 Getting Started
 ---------------
 
-For some general information about ``ovs-sandbox``, see the "Getting Started"
-section of :doc:`ovs-advanced`.
+For some general information about ``ovs-sandbox``, see the Open vSwitch
+documentaion on ``ovs-sandbox``.
 
 ``ovs-sandbox`` does not include OVN support by default.  To enable OVN, you
 must pass the ``--ovn`` flag.  For example, if running it straight from the OVS
@@ -64,8 +64,8 @@  Using GDB
 ---------
 
 GDB support is not required to go through the tutorial. See the "Using GDB"
-section of :doc:`ovs-advanced` for more info. Additional flags exist for
-launching the debugger for the OVN programs::
+section of ovs-advanced in Open vSwitch documentation for more info.
+Additional flags exist for launching the debugger for the OVN programs::
 
     --gdb-ovn-northd
     --gdb-ovn-controller
diff --git a/Documentation/tutorials/ovs-advanced.rst b/Documentation/tutorials/ovs-advanced.rst
deleted file mode 100644
index fa9fdc7bf..000000000
--- a/Documentation/tutorials/ovs-advanced.rst
+++ /dev/null
@@ -1,941 +0,0 @@ 
-..
-      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.
-
-      Convention for heading levels in Open vSwitch documentation:
-
-      =======  Heading 0 (reserved for the title in a document)
-      -------  Heading 1
-      ~~~~~~~  Heading 2
-      +++++++  Heading 3
-      '''''''  Heading 4
-
-      Avoid deeper levels because they do not render well.
-
-==============================
-Open vSwitch Advanced Features
-==============================
-
-Many tutorials cover the basics of OpenFlow.  This is not such a tutorial.
-Rather, a knowledge of the basics of OpenFlow is a prerequisite.  If you do not
-already understand how an OpenFlow flow table works, please go read a basic
-tutorial and then continue reading here afterward.
-
-It is also important to understand the basics of Open vSwitch before you begin.
-If you have never used ovs-vsctl or ovs-ofctl before, you should learn a little
-about them before proceeding.
-
-Most of the features covered in this tutorial are Open vSwitch extensions to
-OpenFlow.  Also, most of the features in this tutorial are specific to the
-software Open vSwitch implementation.  If you are using an Open vSwitch port to
-an ASIC-based hardware switch, this tutorial will not help you.
-
-This tutorial does not cover every aspect of the features that it mentions.
-You can find the details elsewhere in the Open vSwitch documentation,
-especially ``ovs-ofctl(8)`` and the comments in the
-``include/openflow/nicira-ext.h`` and ``include/openvswitch/meta-flow.h``
-header files.
-
-Getting Started
----------------
-
-This is a hands-on tutorial.  To get the most out of it, you will need Open
-vSwitch binaries.  You do not, on the other hand, need any physical networking
-hardware or even supervisor privilege on your system.  Instead, we will use a
-script called ``ovs-sandbox``, which accompanies the tutorial, that constructs
-a software simulated network environment based on Open vSwitch.
-
-You can use ``ovs-sandbox`` three ways:
-
-* If you have already installed Open vSwitch on your system, then you should be
-  able to just run ``ovs-sandbox`` from this directory without any options.
-
-* If you have not installed Open vSwitch (and you do not want to install it),
-  then you can build Open vSwitch according to the instructions in
-  :doc:`/intro/install/general`, without installing it.  Then run
-  ``./ovs-sandbox -b DIRECTORY`` from this directory, substituting the Open
-  vSwitch build directory for ``DIRECTORY``.
-
-* As a slight variant on the latter, you can run ``make sandbox`` from an Open
-  vSwitch build directory.
-
-When you run ``ovs-sandbox``, it does the following:
-
-1. **CAUTION:** Deletes any subdirectory of the current directory named
-   "sandbox" and any files in that directory.
-
-2. Creates a new directory "sandbox" in the current directory.
-
-3. Sets up special environment variables that ensure that Open vSwitch programs
-   will look inside the "sandbox" directory instead of in the Open vSwitch
-   installation directory.
-
-4. If you are using a built but not installed Open vSwitch, installs the Open
-   vSwitch manpages in a subdirectory of "sandbox" and adjusts the ``MANPATH``
-   environment variable to point to this directory.  This means that you can
-   use, for example, ``man ovs-vsctl`` to see a manpage for the ``ovs-vsctl``
-   program that you built.
-
-5. Creates an empty Open vSwitch configuration database under "sandbox".
-
-6. Starts ``ovsdb-server`` running under "sandbox".
-
-7. Starts ``ovs-vswitchd`` running under "sandbox", passing special options
-   that enable a special "dummy" mode for testing.
-
-8. Starts a nested interactive shell inside "sandbox".
-
-At this point, you can run all the usual Open vSwitch utilities from the nested
-shell environment.  You can, for example, use ``ovs-vsctl`` to create a bridge::
-
-    $ ovs-vsctl add-br br0
-
-From Open vSwitch's perspective, the bridge that you create this way is as real
-as any other.  You can, for example, connect it to an OpenFlow controller or
-use ``ovs-ofctl`` to examine and modify it and its OpenFlow flow table.  On the
-other hand, the bridge is not visible to the operating system's network stack,
-so ``ip`` cannot see it or affect it, which means that utilities like ``ping``
-and ``tcpdump`` will not work either.  (That has its good side, too: you can't
-screw up your computer's network stack by manipulating a sandboxed OVS.)
-
-When you're done using OVS from the sandbox, exit the nested shell (by entering
-the "exit" shell command or pressing Control+D).  This will kill the daemons
-that ``ovs-sandbox`` started, but it leaves the "sandbox" directory and its
-contents in place.
-
-The sandbox directory contains log files for the Open vSwitch dameons.  You can
-examine them while you're running in the sandboxed environment or after you
-exit.
-
-Using GDB
----------
-
-GDB support is not required to go through the tutorial. It is added in case
-user wants to explore the internals of OVS programs.
-
-GDB can already be used to debug any running process, with the usual
-``gdb <program> <process-id>`` command.
-
-``ovs-sandbox`` also has a ``-g`` option for launching ovs-vswitchd under GDB.
-This option can be handy for setting break points before ovs-vswitchd runs, or
-for catching early segfaults. Similarly, a ``-d`` option can be used to run
-ovsdb-server under GDB. Both options can be specified at the same time.
-
-In addition, a ``-e`` option also launches ovs-vswitchd under GDB. However,
-instead of displaying a ``gdb>`` prompt and waiting for user input,
-ovs-vswitchd will start to execute immediately. ``-r`` option is the
-corresponding option for running ovsdb-server under gdb with immediate
-execution.
-
-To avoid GDB mangling with the sandbox sub shell terminal, ``ovs-sandbox``
-starts a new xterm to run each GDB session.  For systems that do not support X
-windows, GDB support is effectively disabled.
-
-When launching sandbox through the build tree's make file, the ``-g`` option
-can be passed via the ``SANDBOXFLAGS`` environment variable.  ``make sandbox
-SANDBOXFLAGS=-g`` will start the sandbox with ovs-vswitchd running under GDB in
-its own xterm if X is available.
-
-In addition, a set of GDB macros are available in ``utilities/gdb/ovs_gdb.py``.
-Which are able to dump various internal data structures. See the header of the
-file itself for some more details and an example.
-
-Motivation
-----------
-
-The goal of this tutorial is to demonstrate the power of Open vSwitch flow
-tables.  The tutorial works through the implementation of a MAC-learning switch
-with VLAN trunk and access ports.  Outside of the Open vSwitch features that we
-will discuss, OpenFlow provides at least two ways to implement such a switch:
-
-1. An OpenFlow controller to implement MAC learning in a "reactive" fashion.
-   Whenever a new MAC appears on the switch, or a MAC moves from one switch
-   port to another, the controller adjusts the OpenFlow flow table to match.
-
-2. The "normal" action.  OpenFlow defines this action to submit a packet to
-   "the traditional non-OpenFlow pipeline of the switch".  That is, if a flow
-   uses this action, then the packets in the flow go through the switch in the
-   same way that they would if OpenFlow was not configured on the switch.
-
-Each of these approaches has unfortunate pitfalls.  In the first approach,
-using an OpenFlow controller to implement MAC learning, has a significant cost
-in terms of network bandwidth and latency.  It also makes the controller more
-difficult to scale to large numbers of switches, which is especially important
-in environments with thousands of hypervisors (each of which contains a virtual
-OpenFlow switch).  MAC learning at an OpenFlow controller also behaves poorly
-if the OpenFlow controller fails, slows down, or becomes unavailable due to
-network problems.
-
-The second approach, using the "normal" action, has different problems.  First,
-little about the "normal" action is standardized, so it behaves differently on
-switches from different vendors, and the available features and how those
-features are configured (usually not through OpenFlow) varies widely.  Second,
-"normal" does not work well with other OpenFlow actions.  It is
-"all-or-nothing", with little potential to adjust its behavior slightly or to
-compose it with other features.
-
-Scenario
---------
-
-We will construct Open vSwitch flow tables for a VLAN-capable,
-MAC-learning switch that has four ports:
-
-p1
-  a trunk port that carries all VLANs, on OpenFlow port 1.
-
-p2
-  an access port for VLAN 20, on OpenFlow port 2.
-
-p3, p4
-  both access ports for VLAN 30, on OpenFlow ports 3 and 4, respectively.
-
-.. note::
-  The ports' names are not significant.  You could call them eth1 through eth4,
-  or any other names you like.
-
-.. note::
-  An OpenFlow switch always has a "local" port as well.  This scenario won't
-  use the local port.
-
-Our switch design will consist of five main flow tables, each of which
-implements one stage in the switch pipeline:
-
-Table 0
-  Admission control.
-
-Table 1
-  VLAN input processing.
-
-Table 2
-  Learn source MAC and VLAN for ingress port.
-
-Table 3
-  Look up learned port for destination MAC and VLAN.
-
-Table 4
-  Output processing.
-
-The section below describes how to set up the scenario, followed by a section
-for each OpenFlow table.
-
-You can cut and paste the ``ovs-vsctl`` and ``ovs-ofctl`` commands in each of
-the sections below into your ``ovs-sandbox`` shell.  They are also available as
-shell scripts in this directory, named ``t-setup``, ``t-stage0``, ``t-stage1``,
-..., ``t-stage4``.  The ``ovs-appctl`` test commands are intended for cutting
-and pasting and are not supplied separately.
-
-Setup
------
-
-To get started, start ``ovs-sandbox``.  Inside the interactive shell that it
-starts, run this command::
-
-    $ ovs-vsctl add-br br0 -- set Bridge br0 fail-mode=secure
-
-This command creates a new bridge "br0" and puts "br0" into so-called
-"fail-secure" mode.  For our purpose, this just means that the OpenFlow flow
-table starts out empty.
-
-.. note::
-  If we did not do this, then the flow table would start out with a single flow
-  that executes the "normal" action.  We could use that feature to yield a
-  switch that behaves the same as the switch we are currently building, but
-  with the caveats described under "Motivation" above.)
-
-The new bridge has only one port on it so far, the "local port" br0.  We need
-to add ``p1``, ``p2``, ``p3``, and ``p4``.  A shell ``for`` loop is one way to
-do it::
-
-    for i in 1 2 3 4; do
-        ovs-vsctl add-port br0 p$i -- set Interface p$i ofport_request=$i
-        ovs-ofctl mod-port br0 p$i up
-    done
-
-In addition to adding a port, the ``ovs-vsctl`` command above sets its
-``ofport_request`` column to ensure that port ``p1`` is assigned OpenFlow port
-1, ``p2`` is assigned OpenFlow port 2, and so on.
-
-.. note::
-  We could omit setting the ofport_request and let Open vSwitch choose port
-  numbers for us, but it's convenient for the purposes of this tutorial because
-  we can talk about OpenFlow port 1 and know that it corresponds to ``p1``.
-
-The ``ovs-ofctl`` command above brings up the simulated interfaces, which are
-down initially, using an OpenFlow request.  The effect is similar to ``ip link
-up``, but the sandbox's interfaces are not visible to the operating system and
-therefore ``ip`` would not affect them.
-
-We have not configured anything related to VLANs or MAC learning.  That's
-because we're going to implement those features in the flow table.
-
-To see what we've done so far to set up the scenario, you can run a command
-like ``ovs-vsctl show`` or ``ovs-ofctl show br0``.
-
-Implementing Table 0: Admission control
----------------------------------------
-
-Table 0 is where packets enter the switch.  We use this stage to discard
-packets that for one reason or another are invalid.  For example, packets with
-a multicast source address are not valid, so we can add a flow to drop them at
-ingress to the switch with::
-
-    $ ovs-ofctl add-flow br0 \
-        "table=0, dl_src=01:00:00:00:00:00/01:00:00:00:00:00, actions=drop"
-
-A switch should also not forward IEEE 802.1D Spanning Tree Protocol (STP)
-packets, so we can also add a flow to drop those and other packets with
-reserved multicast protocols::
-
-    $ ovs-ofctl add-flow br0 \
-        "table=0, dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0, actions=drop"
-
-We could add flows to drop other protocols, but these demonstrate the pattern.
-
-We need one more flow, with a priority lower than the default, so that flows
-that don't match either of the "drop" flows we added above go on to pipeline
-stage 1 in OpenFlow table 1::
-
-    $ ovs-ofctl add-flow br0 "table=0, priority=0, actions=resubmit(,1)"
-
-.. note::
-  The "resubmit" action is an Open vSwitch extension to OpenFlow.
-
-Testing Table 0
----------------
-
-If we were using Open vSwitch to set up a physical or a virtual switch, then we
-would naturally test it by sending packets through it one way or another,
-perhaps with common network testing tools like ``ping`` and ``tcpdump`` or more
-specialized tools like Scapy.  That's difficult with our simulated switch,
-since it's not visible to the operating system.
-
-But our simulated switch has a few specialized testing tools.  The most
-powerful of these tools is ``ofproto/trace``.  Given a switch and the
-specification of a flow, ``ofproto/trace`` shows, step-by-step, how such a flow
-would be treated as it goes through the switch.
-
-Example 1
-~~~~~~~~~
-
-Try this command::
-
-    $ ovs-appctl ofproto/trace br0 in_port=1,dl_dst=01:80:c2:00:00:05
-
-The output should look something like this::
-
-    Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=01:80:c2:00:00:05,dl_type=0x0000
-
-    bridge("br0")
-    -------------
-     0. dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0, priority 32768
-        drop
-
-    Final flow: unchanged
-    Megaflow: recirc_id=0,in_port=1,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
-    Datapath actions: drop
-
-The first line shows the flow being traced, in slightly greater detail
-than specified on the command line.  It is mostly zeros because
-unspecified fields default to zeros.
-
-The second group of lines shows the packet's trip through bridge br0.
-We see, in table 0, the OpenFlow flow that the fields matched, along
-with its priority, followed by its actions, one per line.  In this
-case, we see that this packet that has a reserved multicast
-destination address matches the flow that drops those packets.
-
-The final block of lines summarizes the results, which are not very
-interesting here.
-
-Example 2
-~~~~~~~~~
-
-Try another command::
-
-    $ ovs-appctl ofproto/trace br0 in_port=1,dl_dst=01:80:c2:00:00:10
-
-The output should be::
-
-    Flow: in_port=1,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=01:80:c2:00:00:10,dl_type=0x0000
-
-    bridge("br0")
-    -------------
-     0. priority 0
-        resubmit(,1)
-     1. No match.
-        drop
-
-    Final flow: unchanged
-    Megaflow: recirc_id=0,in_port=1,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=01:80:c2:00:00:10/ff:ff:ff:ff:ff:f0,dl_type=0x0000
-    Datapath actions: drop
-
-This time the flow we handed to ``ofproto/trace`` doesn't match any of
-our "drop" flows in table 0, so it falls through to the low-priority
-"resubmit" flow.  The "resubmit" causes a second lookup in OpenFlow
-table 1, described by the block of text that starts with "1."  We
-haven't yet added any flows to OpenFlow table 1, so no flow actually
-matches in the second lookup.  Therefore, the packet is still actually
-dropped, which means that the externally observable results would be
-identical to our first example.
-
-Implementing Table 1: VLAN Input Processing
--------------------------------------------
-
-A packet that enters table 1 has already passed basic validation in table 0.
-The purpose of table 1 is validate the packet's VLAN, based on the VLAN
-configuration of the switch port through which the packet entered the switch.
-We will also use it to attach a VLAN header to packets that arrive on an access
-port, which allows later processing stages to rely on the packet's VLAN always
-being part of the VLAN header, reducing special cases.
-
-Let's start by adding a low-priority flow that drops all packets, before we add
-flows that pass through acceptable packets.  You can think of this as a
-"default drop" flow::
-
-    $ ovs-ofctl add-flow br0 "table=1, priority=0, actions=drop"
-
-Our trunk port ``p1``, on OpenFlow port 1, is an easy case.  ``p1`` accepts any
-packet regardless of whether it has a VLAN header or what the VLAN was, so we
-can add a flow that resubmits everything on input port 1 to the next table::
-
-    $ ovs-ofctl add-flow br0 \
-        "table=1, priority=99, in_port=1, actions=resubmit(,2)"
-
-On the access ports, we want to accept any packet that has no VLAN header, tag
-it with the access port's VLAN number, and then pass it along to the next
-stage::
-
-    $ ovs-ofctl add-flows br0 - <<'EOF'
-    table=1, priority=99, in_port=2, vlan_tci=0, actions=mod_vlan_vid:20, resubmit(,2)
-    table=1, priority=99, in_port=3, vlan_tci=0, actions=mod_vlan_vid:30, resubmit(,2)
-    table=1, priority=99, in_port=4, vlan_tci=0, actions=mod_vlan_vid:30, resubmit(,2)
-    EOF
-
-We don't write any flows that match packets with 802.1Q that enter this stage
-on any of the access ports, so the "default drop" flow we added earlier causes
-them to be dropped, which is ordinarily what we want for access ports.
-
-.. note::
-  Another variation of access ports allows ingress of packets tagged with VLAN
-  0 (aka 802.1p priority tagged packets).  To allow such packets, replace
-  ``vlan_tci=0`` by ``vlan_tci=0/0xfff`` above.
-
-Testing Table 1
----------------
-
-``ofproto/trace`` allows us to test the ingress VLAN flows that we added above.
-
-Example 1: Packet on Trunk Port
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here's a test of a packet coming in on the trunk port::
-
-    $ ovs-appctl ofproto/trace br0 in_port=1,vlan_tci=5
-
-The output shows the lookup in table 0, the resubmit to table 1, and the
-resubmit to table 2 (which does nothing because we haven't put anything there
-yet)::
-
-    Flow: in_port=1,vlan_tci=0x0005,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
-
-    bridge("br0")
-    -------------
-     0. priority 0
-        resubmit(,1)
-     1. in_port=1, priority 99
-        resubmit(,2)
-     2. No match.
-        drop
-
-    Final flow: unchanged
-    Megaflow: recirc_id=0,in_port=1,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
-    Datapath actions: drop
-
-Example 2: Valid Packet on Access Port
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Here's a test of a valid packet (a packet without an 802.1Q header) coming in
-on access port ``p2``::
-
-    $ ovs-appctl ofproto/trace br0 in_port=2
-
-The output is similar to that for the previous case, except that it
-additionally tags the packet with ``p2``'s VLAN 20 before it passes it along to
-table 2::
-
-    Flow: in_port=2,vlan_tci=0x0000,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
-
-    bridge("br0")
-    -------------
-     0. priority 0
-        resubmit(,1)
-     1. in_port=2,vlan_tci=0x0000, priority 99
-        mod_vlan_vid:20
-        resubmit(,2)
-     2. No match.
-        drop
-
-    Final flow: in_port=2,dl_vlan=20,dl_vlan_pcp=0,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
-    Megaflow: recirc_id=0,in_port=2,vlan_tci=0x0000,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
-    Datapath actions: drop
-
-Example 3: Invalid Packet on Access Port
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This tests an invalid packet (one that includes an 802.1Q header) coming in on
-access port ``p2``::
-
-    $ ovs-appctl ofproto/trace br0 in_port=2,vlan_tci=5
-
-The output shows the packet matching the default drop flow::
-
-    Flow: in_port=2,vlan_tci=0x0005,dl_src=00:00:00:00:00:00,dl_dst=00:00:00:00:00:00,dl_type=0x0000
-
-    bridge("br0")
-    -------------
-     0. priority 0
-        resubmit(,1)
-     1. priority 0
-        drop
-
-    Final flow: unchanged
-    Megaflow: recirc_id=0,in_port=2,vlan_tci=0x0005,dl_src=00:00:00:00:00:00/01:00:00:00:00:00,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
-    Datapath actions: drop
-
-Implementing Table 2: MAC+VLAN Learning for Ingress Port
---------------------------------------------------------
-
-This table allows the switch we're implementing to learn that the packet's
-source MAC is located on the packet's ingress port in the packet's VLAN.
-
-.. note::
-  This table is a good example why table 1 added a VLAN tag to packets that
-  entered the switch through an access port.  We want to associate a MAC+VLAN
-  with a port regardless of whether the VLAN in question was originally part of
-  the packet or whether it was an assumed VLAN associated with an access port.
-
-It only takes a single flow to do this.  The following command adds it::
-
-    $ ovs-ofctl add-flow br0 \
-        "table=2 actions=learn(table=10, NXM_OF_VLAN_TCI[0..11], \
-                               NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], \
-                               load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15]), \
-                         resubmit(,3)"
-
-The "learn" action (an Open vSwitch extension to OpenFlow) modifies a flow
-table based on the content of the flow currently being processed.  Here's how
-you can interpret each part of the "learn" action above:
-
-``table=10``
-    Modify flow table 10.  This will be the MAC learning table.
-
-``NXM_OF_VLAN_TCI[0..11]``
-    Make the flow that we add to flow table 10 match the same VLAN ID that the
-    packet we're currently processing contains.  This effectively scopes the
-    MAC learning entry to a single VLAN, which is the ordinary behavior for a
-    VLAN-aware switch.
-
-``NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[]``
-    Make the flow that we add to flow table 10 match, as Ethernet destination,
-    the Ethernet source address of the packet we're currently processing.
-
-``load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15]``
-    Whereas the preceding parts specify fields for the new flow to match, this
-    specifies an action for the flow to take when it matches.  The action is
-    for the flow to load the ingress port number of the current packet into
-    register 0 (a special field that is an Open vSwitch extension to OpenFlow).
-
-.. note::
-  A real use of "learn" for MAC learning would probably involve two additional
-  elements.  First, the "learn" action would specify a hard_timeout for the new
-  flow, to enable a learned MAC to eventually expire if no new packets were
-  seen from a given source within a reasonable interval.  Second, one would
-  usually want to limit resource consumption by using the Flow_Table table in
-  the Open vSwitch configuration database to specify a maximum number of flows
-  in table 10.
-
-This definitely calls for examples.
-
-Testing Table 2
----------------
-
-Example 1
-~~~~~~~~~
-
-Try the following test command::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=1,vlan_tci=20,dl_src=50:00:00:00:00:01 -generate
-
-The output shows that "learn" was executed in table 2 and the
-particular flow that was added::
-
-    Flow: in_port=1,vlan_tci=0x0014,dl_src=50:00:00:00:00:01,dl_dst=00:00:00:00:00:00,dl_type=0x0000
-
-    bridge("br0")
-    -------------
-     0. priority 0
-        resubmit(,1)
-     1. in_port=1, priority 99
-        resubmit(,2)
-     2. priority 32768
-        learn(table=10,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15])
-         -> table=10 vlan_tci=0x0014/0x0fff,dl_dst=50:00:00:00:00:01 priority=32768 actions=load:0x1->NXM_NX_REG0[0..15]
-        resubmit(,3)
-     3. No match.
-        drop
-
-    Final flow: unchanged
-    Megaflow: recirc_id=0,in_port=1,vlan_tci=0x0014/0x1fff,dl_src=50:00:00:00:00:01,dl_dst=00:00:00:00:00:00/ff:ff:ff:ff:ff:f0,dl_type=0x0000
-    Datapath actions: drop
-
-The ``-generate`` keyword is new.  Ordinarily, ``ofproto/trace`` has no side
-effects: "output" actions do not actually output packets, "learn" actions do
-not actually modify the flow table, and so on.  With ``-generate``, though,
-``ofproto/trace`` does execute "learn" actions.  That's important now, because
-we want to see the effect of the "learn" action on table 10.  You can see that
-by running::
-
-    $ ovs-ofctl dump-flows br0 table=10
-
-which (omitting the ``duration`` and ``idle_age`` fields, which will vary based
-on how soon you ran this command after the previous one, as well as some other
-uninteresting fields) prints something like::
-
-    NXST_FLOW reply (xid=0x4):
-     table=10, vlan_tci=0x0014/0x0fff,dl_dst=50:00:00:00:00:01 actions=load:0x1->NXM_NX_REG0[0..15]
-
-You can see that the packet coming in on VLAN ``20`` with source MAC
-``50:00:00:00:00:01`` became a flow that matches VLAN ``20`` (written in
-hexadecimal) and destination MAC ``50:00:00:00:00:01``.  The flow loads port
-number ``1``, the input port for the flow we tested, into register 0.
-
-Example 2
-~~~~~~~~~
-
-Here's a second test command::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=2,dl_src=50:00:00:00:00:01 -generate
-
-The flow that this command tests has the same source MAC and VLAN as example 1,
-although the VLAN comes from an access port VLAN rather than an 802.1Q header.
-If we again dump the flows for table 10 with::
-
-    $ ovs-ofctl dump-flows br0 table=10
-
-then we see that the flow we saw previously has changed to indicate that the
-learned port is port 2, as we would expect::
-
-    NXST_FLOW reply (xid=0x4):
-     table=10, vlan_tci=0x0014/0x0fff,dl_dst=50:00:00:00:00:01 actions=load:0x2->NXM_NX_REG0[0..15]
-
-Implementing Table 3: Look Up Destination Port
-----------------------------------------------
-
-This table figures out what port we should send the packet to based on the
-destination MAC and VLAN.  That is, if we've learned the location of the
-destination (from table 2 processing some previous packet with that destination
-as its source), then we want to send the packet there.
-
-We need only one flow to do the lookup::
-
-    $ ovs-ofctl add-flow br0 \
-        "table=3 priority=50 actions=resubmit(,10), resubmit(,4)"
-
-The flow's first action resubmits to table 10, the table that the "learn"
-action modifies.  As you saw previously, the learned flows in this table write
-the learned port into register 0.  If the destination for our packet hasn't
-been learned, then there will be no matching flow, and so the "resubmit" turns
-into a no-op.  Because registers are initialized to 0, we can use a register 0
-value of 0 in our next pipeline stage as a signal to flood the packet.
-
-The second action resubmits to table 4, continuing to the next pipeline stage.
-
-We can add another flow to skip the learning table lookup for multicast and
-broadcast packets, since those should always be flooded::
-
-    $ ovs-ofctl add-flow br0 \
-        "table=3 priority=99 dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 \
-          actions=resubmit(,4)"
-
-.. note::
-  We don't strictly need to add this flow, because multicast addresses will
-  never show up in our learning table.  (In turn, that's because we put a flow
-  into table 0 to drop packets that have a multicast source address.)
-
-Testing Table 3
----------------
-
-Example
-~~~~~~~
-
-Here's a command that should cause OVS to learn that ``f0:00:00:00:00:01`` is
-on ``p1`` in VLAN ``20``::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=1,dl_vlan=20,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01 \
-        -generate
-
-The output shows (from the "no match" looking up the resubmit to
-table 10) that the flow's destination was unknown::
-
-    Flow: in_port=1,dl_vlan=20,dl_vlan_pcp=0,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01,dl_type=0x0000
-
-    bridge("br0")
-    -------------
-     0. priority 0
-        resubmit(,1)
-     1. in_port=1, priority 99
-        resubmit(,2)
-     2. priority 32768
-        learn(table=10,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15])
-         -> table=10 vlan_tci=0x0014/0x0fff,dl_dst=f0:00:00:00:00:01 priority=32768 actions=load:0x1->NXM_NX_REG0[0..15]
-        resubmit(,3)
-     3. priority 50
-        resubmit(,10)
-        10. No match.
-                drop
-        resubmit(,4)
-     4. No match.
-        drop
-
-    Final flow: unchanged
-    Megaflow: recirc_id=0,in_port=1,dl_vlan=20,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01,dl_type=0x0000
-    Datapath actions: drop
-
-There are two ways that you can verify that the packet's source was
-learned.  The most direct way is to dump the learning table with::
-
-    $ ovs-ofctl dump-flows br0 table=10
-
-which ought to show roughly the following, with extraneous details removed::
-
-    table=10, vlan_tci=0x0014/0x0fff,dl_dst=f0:00:00:00:00:01 actions=load:0x1->NXM_NX_REG0[0..15]
-
-.. note::
-    If you tried the examples for the previous step, or if you did some of your
-    own experiments, then you might see additional flows there.  These
-    additional flows are harmless.  If they bother you, then you can remove
-    them with `ovs-ofctl del-flows br0 table=10`.
-
-The other way is to inject a packet to take advantage of the learning entry.
-For example, we can inject a packet on p2 whose destination is the MAC address
-that we just learned on p1::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=2,dl_src=90:00:00:00:00:01,dl_dst=f0:00:00:00:00:01 -generate
-
-Here is this command's output.  Take a look at the lines that trace
-the ``resubmit(,10)``, showing that the packet matched the learned
-flow for the first MAC we used, loading the OpenFlow port number for
-the learned port ``p1`` into register ``0``::
-
-    Flow: in_port=2,vlan_tci=0x0000,dl_src=90:00:00:00:00:01,dl_dst=f0:00:00:00:00:01,dl_type=0x0000
-
-    bridge("br0")
-    -------------
-     0. priority 0
-        resubmit(,1)
-     1. in_port=2,vlan_tci=0x0000, priority 99
-        mod_vlan_vid:20
-        resubmit(,2)
-     2. priority 32768
-        learn(table=10,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15])
-         -> table=10 vlan_tci=0x0014/0x0fff,dl_dst=90:00:00:00:00:01 priority=32768 actions=load:0x2->NXM_NX_REG0[0..15]
-        resubmit(,3)
-     3. priority 50
-        resubmit(,10)
-        10. vlan_tci=0x0014/0x0fff,dl_dst=f0:00:00:00:00:01, priority 32768
-                load:0x1->NXM_NX_REG0[0..15]
-        resubmit(,4)
-     4. No match.
-        drop
-
-    Final flow: reg0=0x1,in_port=2,dl_vlan=20,dl_vlan_pcp=0,dl_src=90:00:00:00:00:01,dl_dst=f0:00:00:00:00:01,dl_type=0x0000
-    Megaflow: recirc_id=0,in_port=2,vlan_tci=0x0000,dl_src=90:00:00:00:00:01,dl_dst=f0:00:00:00:00:01,dl_type=0x0000
-    Datapath actions: drop
-
-If you read the commands above carefully, then you might have noticed that they
-simply have the Ethernet source and destination addresses exchanged.  That
-means that if we now rerun the first ``ovs-appctl`` command above, e.g.::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=1,dl_vlan=20,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01 \
-        -generate
-
-then we see in the output, looking at the indented "load" action
-executed in table 10, that the destination has now been learned::
-
-    Flow: in_port=1,dl_vlan=20,dl_vlan_pcp=0,dl_src=f0:00:00:00:00:01,dl_dst=90:00:00:00:00:01,dl_type=0x0000
-
-    bridge("br0")
-    -------------
-     0. priority 0
-        resubmit(,1)
-     1. in_port=1, priority 99
-        resubmit(,2)
-     2. priority 32768
-        learn(table=10,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG0[0..15])
-         -> table=10 vlan_tci=0x0014/0x0fff,dl_dst=f0:00:00:00:00:01 priority=32768 actions=load:0x1->NXM_NX_REG0[0..15]
-        resubmit(,3)
-     3. priority 50
-        resubmit(,10)
-        10. vlan_tci=0x0014/0x0fff,dl_dst=90:00:00:00:00:01, priority 32768
-                load:0x2->NXM_NX_REG0[0..15]
-        resubmit(,4)
-     4. No match.
-        drop
-
-
-Implementing Table 4: Output Processing
----------------------------------------
-
-At entry to stage 4, we know that register 0 contains either the desired output
-port or is zero if the packet should be flooded.  We also know that the
-packet's VLAN is in its 802.1Q header, even if the VLAN was implicit because
-the packet came in on an access port.
-
-The job of the final pipeline stage is to actually output packets.  The job is
-trivial for output to our trunk port ``p1``::
-
-    $ ovs-ofctl add-flow br0 "table=4 reg0=1 actions=1"
-
-For output to the access ports, we just have to strip the VLAN header before
-outputting the packet::
-
-    $ ovs-ofctl add-flows br0 - <<'EOF'
-    table=4 reg0=2 actions=strip_vlan,2
-    table=4 reg0=3 actions=strip_vlan,3
-    table=4 reg0=4 actions=strip_vlan,4
-    EOF
-
-The only slightly tricky part is flooding multicast and broadcast packets and
-unicast packets with unlearned destinations.  For those, we need to make sure
-that we only output the packets to the ports that carry our packet's VLAN, and
-that we include the 802.1Q header in the copy output to the trunk port but not
-in copies output to access ports::
-
-    $ ovs-ofctl add-flows br0 - <<'EOF'
-    table=4 reg0=0 priority=99 dl_vlan=20 actions=1,strip_vlan,2
-    table=4 reg0=0 priority=99 dl_vlan=30 actions=1,strip_vlan,3,4
-    table=4 reg0=0 priority=50            actions=1
-    EOF
-
-.. note::
-  Our flows rely on the standard OpenFlow behavior that an output action will
-  not forward a packet back out the port it came in on.  That is, if a packet
-  comes in on p1, and we've learned that the packet's destination MAC is also
-  on p1, so that we end up with ``actions=1`` as our actions, the switch will
-  not forward the packet back out its input port.  The
-  multicast/broadcast/unknown destination cases above also rely on this
-  behavior.
-
-Testing Table 4
----------------
-
-Example 1: Broadcast, Multicast, and Unknown Destination
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Try tracing a broadcast packet arriving on ``p1`` in VLAN ``30``::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=1,dl_dst=ff:ff:ff:ff:ff:ff,dl_vlan=30
-
-The interesting part of the output is the final line, which shows that the
-switch would remove the 802.1Q header and then output the packet to ``p3``
-and ``p4``, which are access ports for VLAN ``30``::
-
-    Datapath actions: pop_vlan,3,4
-
-Similarly, if we trace a broadcast packet arriving on ``p3``::
-
-    $ ovs-appctl ofproto/trace br0 in_port=3,dl_dst=ff:ff:ff:ff:ff:ff
-
-then we see that it is output to ``p1`` with an 802.1Q tag and then to ``p4``
-without one::
-
-    Datapath actions: push_vlan(vid=30,pcp=0),1,pop_vlan,4
-
-.. note::
-  Open vSwitch could simplify the datapath actions here to just
-  ``4,push_vlan(vid=30,pcp=0),1`` but it is not smart enough to do so.
-
-The following are also broadcasts, but the result is to drop the packets
-because the VLAN only belongs to the input port::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=1,dl_dst=ff:ff:ff:ff:ff:ff
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=1,dl_dst=ff:ff:ff:ff:ff:ff,dl_vlan=55
-
-Try some other broadcast cases on your own::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=1,dl_dst=ff:ff:ff:ff:ff:ff,dl_vlan=20
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=2,dl_dst=ff:ff:ff:ff:ff:ff
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=4,dl_dst=ff:ff:ff:ff:ff:ff
-
-You can see the same behavior with multicast packets and with unicast
-packets whose destination has not been learned, e.g.::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=4,dl_dst=01:00:00:00:00:00
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=1,dl_dst=90:12:34:56:78:90,dl_vlan=20
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=1,dl_dst=90:12:34:56:78:90,dl_vlan=30
-
-Example 2: MAC Learning
-~~~~~~~~~~~~~~~~~~~~~~~
-
-Let's follow the same pattern as we did for table 3.  First learn a MAC on port
-``p1`` in VLAN ``30``::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=1,dl_vlan=30,dl_src=10:00:00:00:00:01,dl_dst=20:00:00:00:00:01 \
-        -generate
-
-You can see from the last line of output that the packet's destination is
-unknown, so it gets flooded to both ``p3`` and ``p4``, the other ports in VLAN
-``30``::
-
-    Datapath actions: pop_vlan,3,4
-
-Then reverse the MACs and learn the first flow's destination on port ``p4``::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=4,dl_src=20:00:00:00:00:01,dl_dst=10:00:00:00:00:01 -generate
-
-The last line of output shows that the this packet's destination is known to be
-``p1``, as learned from our previous command::
-
-    Datapath actions: push_vlan(vid=30,pcp=0),1
-
-Now, if we rerun our first command::
-
-    $ ovs-appctl ofproto/trace br0 \
-        in_port=1,dl_vlan=30,dl_src=10:00:00:00:00:01,dl_dst=20:00:00:00:00:01 \
-        -generate
-
-...we can see that the result is no longer a flood but to the specified learned
-destination port ``p4``::
-
-    Datapath actions: pop_vlan,4
-
-Contact
-=======
-
-bugs@openvswitch.org
-http://openvswitch.org/
diff --git a/Documentation/tutorials/ovs-conntrack.rst b/Documentation/tutorials/ovs-conntrack.rst
deleted file mode 100644
index 27d6e04c3..000000000
--- a/Documentation/tutorials/ovs-conntrack.rst
+++ /dev/null
@@ -1,572 +0,0 @@ 
-..
-      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.
-
-      Convention for heading levels in Open vSwitch documentation:
-
-      =======  Heading 0 (reserved for the title in a document)
-      -------  Heading 1
-      ~~~~~~~  Heading 2
-      +++++++  Heading 3
-      '''''''  Heading 4
-
-      Avoid deeper levels because they do not render well.
-
-======================
-OVS Conntrack Tutorial
-======================
-
-OVS can be used with the Connection tracking system
-where OpenFlow flow can be used to match on the state of a TCP, UDP, ICMP,
-etc., connections. (Connection tracking system supports tracking of both
-statefull and stateless protocols)
-
-This tutorial demonstrates how OVS can use the connection tracking system
-to match on the TCP segments from connection setup to connection tear down.
-It will use OVS with the Linux kernel module as the datapath for this
-tutorial. (The datapath that utilizes the openvswitch kernel module to do
-the packet processing in the Linux kernel)
-It was tested with the “master” branch of Open vSwitch.
-
-Definitions
------------
-
-**conntrack**: is a connection tracking module for stateful packet
-inspection.
-
-**pipeline**: is the packet processing pipeline which is the path taken by
-the packet when traversing through the tables where the packet matches the
-match fields of a flow in the table and performs the actions present in
-the matched flow.
-
-**network namespace**: is a way to create virtual routing domains within
-a single instance of linux kernel.  Each network namespace has it's own
-instance of network tables (arp, routing) and certain interfaces attached
-to it.
-
-**flow**: used in this tutorial refers to the OpenFlow flow which can be
-programmed using an OpenFlow controller or OVS command line tools like
-ovs-ofctl which is used here.  A flow will have match fields and actions.
-
-Conntrack Related Fields
-------------------------
-
-Match Fields
-~~~~~~~~~~~~
-OVS supports following match fields related to conntrack:
-
-1. **ct_state**:
-The state of a connection matching the packet.
-Possible values:
-
-    - *new*
-    - *est*
-    - *rel*
-    - *rpl*
-    - *inv*
-    - *trk*
-    - *snat*
-    - *dnat*
-
-Each of these flags is preceded by either a "+" for a flag that
-must be set, or a "-" for a flag that must be unset.
-Multiple flags can also be specified e.g. ct_state=+trk+new.
-We will see the usage of some of these flags below. For a detailed
-description, please see the OVS fields documentation at:
-http://openvswitch.org/support/dist-docs/ovs-fields.7.txt
-
-2. **ct_zone**: A zone is an independent connection tracking context which can
-be set by a ct action.
-A 16-bit ct_zone set by the most recent ct action (by an OpenFlow
-flow on a conntrack entry) can be used as a match field in
-another flow entry.
-
-3. **ct_mark**:
-The 32-bit metadata committed, by an action within the exec
-parameter to the ct action, to the connection to which the
-current packet belongs.
-
-4. **ct_label**:
-The 128-bit label committed by an action within the exec parameter to
-the ct action, to the connection to which the current packet
-belongs.
-
-5.  **ct_nw_src** /  **ct_ipv6_src**:
-Matches IPv4/IPv6 conntrack original direction tuple
-source address.
-
-6.  **ct_nw_dst** / **ct_ipv6_dst**:
-Matches IPv4/IPv6 conntrack original direction tuple destination address.
-
-7. **ct_nw_proto**:
-Matches conntrack original direction tuple IP protocol type.
-
-8. **ct_tp_src**:
-Matches on the conntrack original direction tuple
-transport source port.
-
-9. **ct_tp_dst**:
-Matches on the conntrack original direction tuple
-transport destination port.
-
-
-Actions
-~~~~~~~
-OVS supports "ct" action related to conntrack.
-
-*ct([argument][,argument...])*
-
-The **ct** action sends the packet through the connection tracker.
-
-The following arguments are supported:
-
-1. **commit**:
-Commit the connection to the connection tracking module which
-will be stored beyond the lifetime of packet in the pipeline.
-
-2. **force**:
-The force flag may be used in addition to commit flag to effectively
-terminate the existing connection and start a new one in the
-current direction.
-
-3. **table=number**:
-Fork pipeline processing in two. The original instance of the packet
-will continue processing the current actions list as an untracked packet.
-An additional instance of the packet will be sent to the connection
-tracker, which will be re-injected into the OpenFlow pipeline to resume
-processing in table number, with the ct_state and other ct match fields set.
-
-4. **zone=value OR
-zone=src[start..end]**:
-A 16-bit context id that can be used to isolate connections into separate
-domains, allowing over‐lapping network addresses in different zones. If a
-zone is not provided, then the default is to use zone zero.
-
-5. **exec([action][,action...])**:
-Perform restricted set of actions within the context of connection tracking.
-Only actions which modify the *ct_mark* or *ct_label* fields are accepted
-within the exec action.
-
-6. **alg=<ftp/tftp>**:
-Specify alg (application layer gateway) to track specific connection
-types.
-
-7. **nat**:
-Specifies the address and port translation for the connection being tracked.
-
-
-
-Sample Topology
----------------
-This tutorial uses the following topology to carry out the tests.
-
-::
-
-         +                                                       +
-         |                                                       |
-         |                       +-----+                         |
-         |                       |     |                         |
-         |                       |     |                         |
-         |     +----------+      | OVS |     +----------+        |
-         |     |   left   |      |     |     |  right   |        |
-         |     | namespace|      |     |     |namespace |        |
-         +-----+        A +------+     +-----+ B        +--------+
-         |     |          |    A'|     | B'  |          |        |
-         |     |          |      |     |     |          |        |
-         |     +----------+      |     |     +----------+        |
-         |                       |     |                         |
-         |                       |     |                         |
-         |                       |     |                         |
-         |                       +-----+                         |
-         |                                                       |
-         |                                                       |
-         +                                                       +
-     192.168.0.X n/w                                          10.0.0.X n/w
-
-     A  = veth_l1
-     A' = veth_l0
-     B  = veth_r1
-     B' = veth_r0
-
-     Diagram: Sample Topology for conntrack testing
-
-
-The steps for creation of the setup are mentioned below.
-
-Create "left" network namespace::
-
-  $ ip netns add left
-
-Create "right" network namespace::
-
-  $ ip netns add right
-
-Create first pair of veth interfaces::
-
-  $ ip link add veth_l0 type veth peer name veth_l1
-
-Add veth_l1 to "left" network namespace::
-
-  $ ip link set veth_l1 netns left
-
-Create second pair of veth interfaces::
-
-  $ ip link add veth_r0 type veth peer name veth_r1
-
-Add veth_r1 to "right" network namespace::
-
-  $ ip link set veth_r1 netns right
-
-Create a bridge br0::
-
-  $ ovs-vsctl add-br br0
-
-Add veth_l0 and veth_r0 to br0::
-
-  $ ovs-vsctl add-port br0 veth_l0
-  $ ovs-vsctl add-port br0 veth_r0
-
-
-Packets generated with src/dst IP set to 192.168.0.X / 10.0.0.X
-in the "left" and the inverse in the "right" namespaces
-will appear to OVS as hosts in two networks (192.168.0.X and 10.0.0.X)
-communicating with each other.
-This is basically a simulation of two networks / subnets with hosts
-communicating with each other with OVS in middle.
-
-Tool used to generate TCP segments
-----------------------------------
-You can use scapy to generate the TCP segments. We used scapy on Ubuntu 16.04
-for the steps carried out in this testing.
-(Installation of scapy is not discussed and is out of scope of this document.)
-
-You can keep two scapy sessions active on each of the namespaces::
-
-     $ sudo ip netns exec left sudo `which scapy`
-
-     $ sudo ip netns exec right sudo `which scapy`
-
-Note: In case you encounter this error::
-
-    ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x",LOOPBACK_NAME))
-
-    IOError: [Errno 99] Cannot assign requested address
-
-run the command::
-
-    $ sudo ip netns exec <namespace> sudo ip link set lo up
-
-
-Matching TCP packets
---------------------
-
-TCP Connection setup
-~~~~~~~~~~~~~~~~~~~~
-Two simple flows can be added in OVS which will forward
-packets from "left" to "right" and from "right" to "left"::
-
-     $ ovs-ofctl add-flow br0 \
-              "table=0, priority=10, in_port=veth_l0, actions=veth_r0"
-
-     $ ovs-ofctl add-flow br0 \
-              "table=0, priority=10, in_port=veth_r0, actions=veth_l0"
-
-Instead of adding these two flows, we will add flows to match on the
-states of the TCP segments.
-
-We will send the TCP connection setup segments namely:
-syn, syn-ack and ack between hosts 192.168.0.2 in the "left" namespace and
-10.0.0.2 in the "right" namespace.
-
-First, let's add a flow to start "tracking" a packet received at OVS.
-
-*How do we start tracking a packet?*
-
-To start tracking a packet, it first needs to match a flow, which has action
-as "ct".  This action sends the packet through the connection tracker.  To
-identify that a packet is an "untracked" packet, the ct_state in the flow
-match field must be set to "-trk", which means it is not a tracked packet.
-Once the packet is sent to the connection tracker, then only we will know about
-its conntrack state.  (i.e. whether this packet represents start of a new
-connection or the packet belongs to an existing connection or it is
-a malformed packet and so on.)
-
-Let's add that flow::
-
-     (flow #1)
-     $ ovs-ofctl add-flow br0 \
-        "table=0, priority=50, ct_state=-trk, tcp, in_port=veth_l0, actions=ct(table=0)"
-
-A TCP syn packet sent from "left" namespace will match flow #1
-because the packet is coming to OVS from veth_l0 port and it is not being
-tracked.  (as the packet just entered OVS. All packets entering OVS for the
-first time are "untracked")
-The flow will send the packet to the connection tracker due to the action "ct".
-Also "table=0" in the "ct" action forks the pipeline processing in two.  The
-original instance of packet will continue processing the current action list
-as untracked packet. (Since there are no actions after this, the original
-packet gets dropped.)
-The forked instance of the packet will be sent to the  connection  tracker,
-which will be re-injected into the OpenFlow pipeline to resume processing
-in table number, with the ct_state and other ct match fields set.
-In this case, the packet with the ct_state and other ct match fields comes back
-to table 0.
-
-Next, we add a flow to match on the packet coming back from conntrack::
-
-    (flow #2)
-    $ ovs-ofctl add-flow br0 \
-        "table=0, priority=50, ct_state=+trk+new, tcp, in_port=veth_l0, actions=ct(commit),veth_r0"
-
-Now that the packet is coming back from conntrack, the ct_state would have
-the "trk" set.
-Also, if this is the first packet of the TCP connection, the ct_state "new"
-would be set. (Which is the condition here as there does not exist any TCP
-connection between hosts 192.168.0.2 and 10.0.0.2)
-The ct argument "commit" will commit the connection to the connection tracking
-module.  The significance of this action is that the information about the
-connection will now be stored beyond the lifetime of the packet in the
-pipeline.
-
-Let's send the TCP syn segment using scapy (at the "left" scapy session)
-(flags=0x02 is syn)::
-
-    $ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x02, seq=100), iface="veth_l1")
-
-This packet will match flow #1 and flow #2.
-
-The conntrack module will now have an entry for this connection::
-
-    $ ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
-    tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=SYN_SENT)
-
-
-Note: At this stage, if the TCP syn packet is re-transmitted, it will again
-match flow #1 (since a new packet is untracked) and it will match flow #2.
-The reason it will match flow #2 is that although conntrack has information
-about the connection, but it is not in "ESTABLISHED" state, therefore it
-matches the "new" state again.
-
-Next for the TCP syn-ack from the opposite/server direction, we need
-following flows at OVS::
-
-    (flow #3)
-    $ ovs-ofctl add-flow br0 \
-        "table=0, priority=50, ct_state=-trk, tcp, in_port=veth_r0, actions=ct(table=0)"
-    (flow #4)
-    $ ovs-ofctl add-flow br0 \
-        "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_r0, actions=veth_l0"
-
-
-flow #3 matches untracked packets coming back from server (10.0.0.2) and sends
-this to conntrack. (Alternatively, we could have also combined
-flow #1 and flow #3 into one flow by not having the "in_port" match)
-
-The syn-ack packet which has now gone through the conntrack has the ct_state of
-"est".
-
-Note: Conntrack puts the ct_state of the connection to "est" state when
-it sees bidirectional traffic, but till it does not get the third ack from
-client, it puts a short cleanup timer on the conntrack entry.
-
-Sending TCP syn-ack segment using scapy (at the "right" scapy session)
-(flags=0x12 is ack and syn)::
-
-    $ >>> sendp(Ether()/IP(src="10.0.0.2", dst="192.168.0.2")/TCP(sport=2048, dport=1024, flags=0x12, seq=200, ack=101), iface="veth_r1")
-
-This packet will match flow #3 and flow #4.
-
-conntrack entry::
-
-     $ ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
-
-     tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=ESTABLISHED)
-
-The conntrack state is "ESTABLISHED" on receiving just syn and syn-ack packets,
-but at this point if it does not receive the third ack (from client), the
-connection gets cleared up from conntrack quickly.
-
-Next, for a TCP ack from client direction, we can add following flows to
-match on the packet::
-
-    (flow #5)
-    $ ovs-ofctl add-flow br0 \
-        "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_l0, actions=veth_r0"
-
-Send the third TCP ack segment using scapy (at the "left" scapy session)
-(flags=0x10 is ack)::
-
-    $ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x10, seq=101, ack=201), iface="veth_l1")
-
-This packet will match on flow #1 and flow #5.
-
-
-conntrack entry::
-
-    $ ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
-
-     tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048), \
-         reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024), \
-                                         protoinfo=(state=ESTABLISHED)
-
-The conntrack state stays in "ESTABLISHED" state, but now since it has received
-the ack from client, it will stay in this state for a longer time even without
-receiving any data on this connection.
-
-TCP Data
-~~~~~~~~
-When a data segment, carrying one byte of TCP payload, is sent from
-192.168.0.2 to 10.0.0.2, the packet carrying the segment would hit flow #1
-and then flow #5.
-
-Send a TCP segment with one byte data using scapy
-(at the "left" scapy session)
-(flags=0x10 is ack)::
-
-    $ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x10, seq=101, ack=201)/"X", iface="veth_l1")
-
-
-Send the TCP ack for the above segment using scapy (at the
-"right" scapy session)
-(flags=0x10 is ack)::
-
-    $ >>> sendp(Ether()/IP(src="10.0.0.2", dst="192.168.0.2")/TCP(sport=2048, dport=1024, flags=0X10, seq=201, ack=102), iface="veth_r1")
-
-The acknowledgement for the data would hit flow #3 and flow #4.
-
-TCP Connection Teardown
-~~~~~~~~~~~~~~~~~~~~~~~
-There are different ways to tear down TCP connection. We will tear down the
-connection by sending "fin" from client, "fin-ack" from server followed
-by the last "ack" by client.
-
-All the packets from client to server would hit flow #1 and flow #5.
-All the packets from server to client would hit flow #3 and flow #4.
-Interesting point to note is that even when the TCP connection is going
-down, all the packets (which are actually tearing down the connection) still
-hits "+est" state.  A packet, for which the conntrack
-entry *is* or *was* in "ESTABLISHED" state, would continue to match
-"+est" ct_state in OVS.
-
-Note: In fact, when the conntrack connection state is in "TIME_WAIT" state
-(after all the TCP fins and their acks are exchanged),
-a re-transmitted data packet (from 192.168.0.2 -> 10.0.0.2), still hits
-flows #1 and #5.
-
-Sending TCP fin segment using scapy (at the "left" scapy session)
-(flags=0x11 is ack and fin)::
-
-    $ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x11, seq=102, ack=201), iface="veth_l1")
-
-This packet hits flow #1 and flow #5.
-
-conntrack entry::
-
-    $ sudo ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
-
-      tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=FIN_WAIT_1)
-
-
-Sending TCP fin-ack segment using scapy (at the "right" scapy session)
-(flags=0x11 is ack and fin)::
-
-    $ >>> sendp(Ether()/IP(src="10.0.0.2", dst="192.168.0.2")/TCP(sport=2048, dport=1024, flags=0X11, seq=201, ack=103), iface="veth_r1")
-
-This packet hits flow #3 and flow #4.
-
-conntrack entry::
-
-    $ sudo ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
-
-      tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=LAST_ACK)
-
-
-Sending TCP ack segment using scapy (at the "left" scapy session)
-(flags=0x10 is ack)::
-
-    $ >>> sendp(Ether()/IP(src="192.168.0.2", dst="10.0.0.2")/TCP(sport=1024, dport=2048, flags=0x10, seq=103, ack=202), iface="veth_l1")
-
-This packet hits flow #1 and flow #5.
-
-conntrack entry::
-
-    $ sudo ovs-appctl dpctl/dump-conntrack | grep "192.168.0.2"
-
-      tcp,orig=(src=192.168.0.2,dst=10.0.0.2,sport=1024,dport=2048),reply=(src=10.0.0.2,dst=192.168.0.2,sport=2048,dport=1024),protoinfo=(state=TIME_WAIT)
-
-
-Summary
--------
-
-Following table summarizes the TCP segments exchanged against the flow
-match fields
-
-  +-------------------------------------------------------+-------------------+
-  |                     TCP Segment                       |ct_state(flow#)    |
-  +=======================================================+===================+
-  |                     **Connection Setup**              |                   |
-  +-------------------------------------------------------+-------------------+
-  |192.168.0.2 → 10.0.0.2 [SYN] Seq=0                     | -trk(#1) then     |
-  |                                                       | +trk+new(#2)      |
-  +-------------------------------------------------------+-------------------+
-  |10.0.0.2 → 192.168.0.2 [SYN, ACK] Seq=0 Ack=1          | -trk(#3) then     |
-  |                                                       | +trk+est(#4)      |
-  +-------------------------------------------------------+-------------------+
-  |192.168.0.2 → 10.0.0.2 [ACK] Seq=1 Ack=1               | -trk(#1) then     |
-  |                                                       | +trk+est(#5)      |
-  +-------------------------------------------------------+-------------------+
-  |                     **Data Transfer**                 |                   |
-  +-------------------------------------------------------+-------------------+
-  |192.168.0.2 → 10.0.0.2 [ACK] Seq=1 Ack=1               | -trk(#1) then     |
-  |                                                       | +trk+est(#5)      |
-  +-------------------------------------------------------+-------------------+
-  |10.0.0.2 → 192.168.0.2 [ACK] Seq=1 Ack=2               | -trk(#3) then     |
-  |                                                       | +trk+est(#4)      |
-  +-------------------------------------------------------+-------------------+
-  |                     **Connection Teardown**           |                   |
-  +-------------------------------------------------------+-------------------+
-  |192.168.0.2 → 10.0.0.2 [FIN, ACK] Seq=2 Ack=1          | -trk(#1) then     |
-  |                                                       | +trk+est(#5)      |
-  +-------------------------------------------------------+-------------------+
-  |10.0.0.2 → 192.168.0.2 [FIN, ACK] Seq=1 Ack=3          | -trk(#3) then     |
-  |                                                       | +trk+est(#4)      |
-  +-------------------------------------------------------+-------------------+
-  |192.168.0.2 → 10.0.0.2 [ACK] Seq=3 Ack=2               | -trk(#1) then     |
-  |                                                       | +trk+est(#5)      |
-  +-------------------------------------------------------+-------------------+
-
-Note: Relative sequence number and acknowledgement numbers are shown as
-captured from tshark.
-
-Flows
-~~~~~
-::
-
-     (flow #1)
-     $ ovs-ofctl add-flow br0 \
-        "table=0, priority=50, ct_state=-trk, tcp, in_port=veth_l0, actions=ct(table=0)"
-
-    (flow #2)
-    $ ovs-ofctl add-flow br0 \
-        "table=0, priority=50, ct_state=+trk+new, tcp, in_port=veth_l0, actions=ct(commit),veth_r0"
-
-    (flow #3)
-    $ ovs-ofctl add-flow br0 \
-        "table=0, priority=50, ct_state=-trk, tcp, in_port=veth_r0, actions=ct(table=0)"
-
-    (flow #4)
-    $ ovs-ofctl add-flow br0 \
-        "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_r0, actions=veth_l0"
-
-    (flow #5)
-    $ ovs-ofctl add-flow br0 \
-        "table=0, priority=50, ct_state=+trk+est, tcp, in_port=veth_l0, actions=veth_r0"