summaryrefslogtreecommitdiff
path: root/tutorial
diff options
context:
space:
mode:
authorStephen Finucane <stephen@that.guru>2016-12-08 12:55:27 +0000
committerBen Pfaff <blp@ovn.org>2016-12-12 08:57:07 -0800
commite12569bb305f86d59c5b3a594903a96c869aeed3 (patch)
tree9542f7468d86738a404036890b08a469239a28d5 /tutorial
parent7c9afefd0ac4a6923c6b0c9480429b68dfb75c1a (diff)
downloadopenvswitch-e12569bb305f86d59c5b3a594903a96c869aeed3.tar.gz
doc: Populate 'tutorials' section
Rename 'tutorial' to 'ovs-advanced' and 'ovn-tutorial' to 'ovn-basics'. Signed-off-by: Stephen Finucane <stephen@that.guru> Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'tutorial')
-rw-r--r--tutorial/automake.mk3
-rw-r--r--tutorial/ovn-tutorial.rst976
-rwxr-xr-xtutorial/ovn/env1/setup.sh2
-rwxr-xr-xtutorial/ovn/env6/setup.sh2
-rw-r--r--tutorial/tutorial.rst872
5 files changed, 2 insertions, 1853 deletions
diff --git a/tutorial/automake.mk b/tutorial/automake.mk
index 79f9b6835..5509062ea 100644
--- a/tutorial/automake.mk
+++ b/tutorial/automake.mk
@@ -1,6 +1,3 @@
-docs += \
- tutorial/tutorial.rst \
- tutorial/ovn-tutorial.rst
EXTRA_DIST += \
tutorial/ovs-sandbox \
tutorial/t-setup \
diff --git a/tutorial/ovn-tutorial.rst b/tutorial/ovn-tutorial.rst
deleted file mode 100644
index bb5f6201f..000000000
--- a/tutorial/ovn-tutorial.rst
+++ /dev/null
@@ -1,976 +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.
-
-============
-OVN Tutorial
-============
-
-This tutorial is intended to give you a tour of the basic OVN features using
-``ovs-sandbox`` as a simulated test environment. It's assumed that you have an
-understanding of OVS before going through this tutorial. Detail about OVN is
-covered in 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 the tutorial_.
-
-``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
-git tree you would run::
-
- $ make sandbox SANDBOXFLAGS="--ovn"
-
-Running the sandbox with OVN enabled does the following additional steps to the
-environment:
-
-1. Creates the ``OVN_Northbound`` and ``OVN_Southbound`` databases as described in
- `ovn-nb(5)`_ and `ovn-sb(5)`_.
-
-2. Creates a backup server for ``OVN_Southbond`` database. Sandbox launch
- screen provides the instructions on accessing the backup database. However
- access to the backup server is not required to go through the tutorial.
-
-3. Creates the ``hardware_vtep`` database as described in `vtep(5)`_.
-
-4. Runs the `ovn-northd(8)`_, `ovn-controller(8)`_, and
- `ovn-controller-vtep(8)`_ daemons.
-
-5. Makes OVN and VTEP utilities available for use in the environment, including
- `vtep-ctl(8)`_, `ovn-nbctl(8)`_, and `ovn-sbctl(8)`_.
-
-Note that each of these demos assumes you start with a fresh sandbox
-environment. **Re-run `ovs-sandbox` before starting each section.**
-
-Using GDB
----------
-
-GDB support is not required to go through the tutorial. See the "Using GDB"
-section of the `tutorial`_ for more info. Additional flags exist for launching
-the debugger for the OVN programs::
-
- --gdb-ovn-northd
- --gdb-ovn-controller
- --gdb-ovn-controller-vtep
-
-Simple Two Port Setup
----------------------
-
-This first environment is the simplest OVN example. It demonstrates using OVN
-with a single logical switch that has two logical ports, both residing on the
-same hypervisor.
-
-Start by running the setup script for this environment::
-
- $ ovn/env1/setup.sh
-
-You can use the ``ovn-nbctl`` utility to see an overview of the logical
-topology::
-
- $ ovn-nbctl show
- switch 78687d53-e037-4555-bcd3-f4f8eaf3f2aa (sw0)
- port sw0-port1
- addresses: ["00:00:00:00:00:01"]
- port sw0-port2
- addresses: ["00:00:00:00:00:02"]
-
-The ``ovn-sbctl`` utility can be used to see into the state stored in the
-``OVN_Southbound`` database. The ``show`` command shows that there is a single
-chassis with two logical ports bound to it. In a more realistic
-multi-hypervisor environment, this would list all hypervisors and where all
-logical ports are located::
-
- $ ovn-sbctl show
- Chassis "56b18105-5706-46ef-80c4-ff20979ab068"
- Encap geneve
- ip: "127.0.0.1"
- Port_Binding "sw0-port1"
- Port_Binding "sw0-port2"
-
-OVN creates logical flows to describe how the network should behave in logical
-space. Each chassis then creates OpenFlow flows based on those logical flows
-that reflect its own local view of the network. The ``ovn-sbctl`` command can
-show the logical flows::
-
- $ ovn-sbctl lflow-list
- Datapath: 2503dd42-14b1-414a-abbf-33e554e09ddc Pipeline: ingress
- table=0 (ls_in_port_sec_l2 ), priority=100 , match=(eth.src[40]), action=(drop;)
- table=0 (ls_in_port_sec_l2 ), priority=100 , match=(vlan.present), action=(drop;)
- table=0 (ls_in_port_sec_l2 ), priority=50 , match=(inport == "sw0-port1" && eth.src == {00:00:00:00:00:01}), action=(next;)
- table=0 (ls_in_port_sec_l2 ), priority=50 , match=(inport == "sw0-port2" && eth.src == {00:00:00:00:00:02}), action=(next;)
- table=1 (ls_in_port_sec_ip ), priority=0 , match=(1), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && arp.sha == 00:00:00:00:00:01), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:01) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:01)))), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw0-port2" && eth.src == 00:00:00:00:00:02 && arp.sha == 00:00:00:00:00:02), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw0-port2" && eth.src == 00:00:00:00:00:02 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:02) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:02)))), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=80 , match=(inport == "sw0-port1" && (arp || nd)), action=(drop;)
- table=2 (ls_in_port_sec_nd ), priority=80 , match=(inport == "sw0-port2" && (arp || nd)), action=(drop;)
- table=2 (ls_in_port_sec_nd ), priority=0 , match=(1), action=(next;)
- table=3 (ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=4 (ls_in_pre_lb ), priority=0 , match=(1), action=(next;)
- table=5 (ls_in_pre_stateful ), priority=100 , match=(reg0[0] == 1), action=(ct_next;)
- table=5 (ls_in_pre_stateful ), priority=0 , match=(1), action=(next;)
- table=6 (ls_in_acl ), priority=0 , match=(1), action=(next;)
- table=7 (ls_in_lb ), priority=0 , match=(1), action=(next;)
- table=8 (ls_in_stateful ), priority=100 , match=(reg0[1] == 1), action=(ct_commit; next;)
- table=8 (ls_in_stateful ), priority=100 , match=(reg0[2] == 1), action=(ct_lb;)
- table=8 (ls_in_stateful ), priority=0 , match=(1), action=(next;)
- table=9 (ls_in_arp_rsp ), priority=0 , match=(1), action=(next;)
- table=10(ls_in_l2_lkup ), priority=100 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
- table=10(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0-port1"; output;)
- table=10(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:02), action=(outport = "sw0-port2"; output;)
- Datapath: 2503dd42-14b1-414a-abbf-33e554e09ddc Pipeline: egress
- table=0 (ls_out_pre_lb ), priority=0 , match=(1), action=(next;)
- table=1 (ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=2 (ls_out_pre_stateful), priority=100 , match=(reg0[0] == 1), action=(ct_next;)
- table=2 (ls_out_pre_stateful), priority=0 , match=(1), action=(next;)
- table=3 (ls_out_lb ), priority=0 , match=(1), action=(next;)
- table=4 (ls_out_acl ), priority=0 , match=(1), action=(next;)
- table=5 (ls_out_stateful ), priority=100 , match=(reg0[1] == 1), action=(ct_commit; next;)
- table=5 (ls_out_stateful ), priority=100 , match=(reg0[2] == 1), action=(ct_lb;)
- table=5 (ls_out_stateful ), priority=0 , match=(1), action=(next;)
- table=6 (ls_out_port_sec_ip ), priority=0 , match=(1), action=(next;)
- table=7 (ls_out_port_sec_l2 ), priority=100 , match=(eth.mcast), action=(output;)
- table=7 (ls_out_port_sec_l2 ), priority=50 , match=(outport == "sw0-port1" && eth.dst == {00:00:00:00:00:01}), action=(output;)
- table=7 (ls_out_port_sec_l2 ), priority=50 , match=(outport == "sw0-port2" && eth.dst == {00:00:00:00:00:02}), action=(output;)
-
-Now we can start taking a closer look at how ``ovn-controller`` has programmed
-the local switch. Before looking at the flows, we can use ``ovs-ofctl`` to
-verify the OpenFlow port numbers for each of the logical ports on the switch.
-The output shows that ``lport1``, which corresponds with our logical port
-``sw0-port1``, has an OpenFlow port number of ``1``. Similarly, ``lport2`` has
-an OpenFlow port number of ``2``::
-
- $ ovs-ofctl show br-int
- OFPT_FEATURES_REPLY (xid=0x2): dpid:00003e1ba878364d
- n_tables:254, n_buffers:0
- capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
- actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
- 1(lport1): addr:aa:55:aa:55:00:07
- config: PORT_DOWN
- state: LINK_DOWN
- speed: 0 Mbps now, 0 Mbps max
- 2(lport2): addr:aa:55:aa:55:00:08
- config: PORT_DOWN
- state: LINK_DOWN
- speed: 0 Mbps now, 0 Mbps max
- LOCAL(br-int): addr:3e:1b:a8:78:36:4d
- config: PORT_DOWN
- state: LINK_DOWN
- speed: 0 Mbps now, 0 Mbps max
- OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0
-
-Finally, use ``ovs-ofctl`` to see the OpenFlow flows for ``br-int``. Note that
-some fields have been omitted for brevity::
-
- $ ovs-ofctl -O OpenFlow13 dump-flows br-int
- OFPST_FLOW reply (OF1.3) (xid=0x2):
- table=0, priority=100,in_port=1 actions=set_field:0x1->metadata,set_field:0x1->reg6,resubmit(,16)
- table=0, priority=100,in_port=2 actions=set_field:0x1->metadata,set_field:0x2->reg6,resubmit(,16)
- table=16, priority=100,metadata=0x1,vlan_tci=0x1000/0x1000 actions=drop
- table=16, priority=100,metadata=0x1,dl_src=01:00:00:00:00:00/01:00:00:00:00:00 actions=drop
- table=16, priority=50,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01 actions=resubmit(,17)
- table=16, priority=50,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02 actions=resubmit(,17)
- table=17, priority=0,metadata=0x1 actions=resubmit(,18)
- table=18, priority=90,icmp6,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:00 actions=resubmit(,19)
- table=18, priority=90,icmp6,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:02 actions=resubmit(,19)
- table=18, priority=90,icmp6,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:00 actions=resubmit(,19)
- table=18, priority=90,icmp6,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01,icmp_type=136,icmp_code=0,nd_tll=00:00:00:00:00:01 actions=resubmit(,19)
- table=18, priority=90,icmp6,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:01 actions=resubmit(,19)
- table=18, priority=90,icmp6,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:00 actions=resubmit(,19)
- table=18, priority=90,icmp6,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:00 actions=resubmit(,19)
- table=18, priority=90,icmp6,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02,icmp_type=135,icmp_code=0,nd_sll=00:00:00:00:00:02 actions=resubmit(,19)
- table=18, priority=90,arp,reg6=0x1,metadata=0x1,dl_src=00:00:00:00:00:01,arp_sha=00:00:00:00:00:01 actions=resubmit(,19)
- table=18, priority=90,arp,reg6=0x2,metadata=0x1,dl_src=00:00:00:00:00:02,arp_sha=00:00:00:00:00:02 actions=resubmit(,19)
- table=18, priority=80,icmp6,reg6=0x2,metadata=0x1,icmp_type=136,icmp_code=0 actions=drop
- table=18, priority=80,icmp6,reg6=0x1,metadata=0x1,icmp_type=136,icmp_code=0 actions=drop
- table=18, priority=80,icmp6,reg6=0x1,metadata=0x1,icmp_type=135,icmp_code=0 actions=drop
- table=18, priority=80,icmp6,reg6=0x2,metadata=0x1,icmp_type=135,icmp_code=0 actions=drop
- table=18, priority=80,arp,reg6=0x2,metadata=0x1 actions=drop
- table=18, priority=80,arp,reg6=0x1,metadata=0x1 actions=drop
- table=18, priority=0,metadata=0x1 actions=resubmit(,19)
- table=19, priority=0,metadata=0x1 actions=resubmit(,20)
- table=20, priority=0,metadata=0x1 actions=resubmit(,21)
- table=21, priority=0,metadata=0x1 actions=resubmit(,22)
- table=22, priority=0,metadata=0x1 actions=resubmit(,23)
- table=23, priority=0,metadata=0x1 actions=resubmit(,24)
- table=24, priority=0,metadata=0x1 actions=resubmit(,25)
- table=25, priority=0,metadata=0x1 actions=resubmit(,26)
- table=26, priority=100,metadata=0x1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=set_field:0xffff->reg7,resubmit(,32)
- table=26, priority=50,metadata=0x1,dl_dst=00:00:00:00:00:01 actions=set_field:0x1->reg7,resubmit(,32)
- table=26, priority=50,metadata=0x1,dl_dst=00:00:00:00:00:02 actions=set_field:0x2->reg7,resubmit(,32)
- table=32, priority=0 actions=resubmit(,33)
- table=33, priority=100,reg7=0x1,metadata=0x1 actions=resubmit(,34)
- table=33, priority=100,reg7=0xffff,metadata=0x1 actions=set_field:0x2->reg7,resubmit(,34),set_field:0x1->reg7,resubmit(,34),set_field:0xffff->reg7
- table=33, priority=100,reg7=0x2,metadata=0x1 actions=resubmit(,34)
- table=34, priority=100,reg6=0x1,reg7=0x1,metadata=0x1 actions=drop
- table=34, priority=100,reg6=0x2,reg7=0x2,metadata=0x1 actions=drop
- table=34, priority=0 actions=set_field:0->reg0,set_field:0->reg1,set_field:0->reg2,resubmit(,48)
- table=48, priority=0,metadata=0x1 actions=resubmit(,49)
- table=49, priority=0,metadata=0x1 actions=resubmit(,50)
- table=50, priority=0,metadata=0x1 actions=resubmit(,51)
- table=51, priority=0,metadata=0x1 actions=resubmit(,52)
- table=52, priority=0,metadata=0x1 actions=resubmit(,53)
- table=53, priority=0,metadata=0x1 actions=resubmit(,54)
- table=54, priority=0,metadata=0x1 actions=resubmit(,55)
- table=55, priority=100,metadata=0x1,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=resubmit(,64)
- table=55, priority=50,reg7=0x2,metadata=0x1,dl_dst=00:00:00:00:00:02 actions=resubmit(,64)
- table=55, priority=50,reg7=0x1,metadata=0x1,dl_dst=00:00:00:00:00:01 actions=resubmit(,64)
- table=64, priority=100,reg7=0x1,metadata=0x1 actions=output:1
-
-The ``ovs-appctl`` command can be used to generate an OpenFlow trace of how a
-packet would be processed in this configuration. This first trace shows a
-packet from ``sw0-port1`` to ``sw0-port2``. The packet arrives from port ``1``
-and should be output to port ``2``::
-
- $ ovn/env1/packet1.sh
-
-Trace a broadcast packet from ``sw0-port1``. The packet arrives from port
-``1`` and should be output to port ``2``::
-
- $ ovn/env1/packet2.sh
-
-You can extend this setup by adding additional ports. For example, to add a
-third port, run this command::
-
- $ ovn/env1/add-third-port.sh
-
-Now if you do another trace of a broadcast packet from ``sw0-port1``, you will
-see that it is output to both ports ``2`` and ``3``::
-
- $ ovn/env1/packet2.sh
-
-The logical port may have an unknown set of Ethernet addresses. When an OVN logical
-switch processes a unicast Ethernet frame whose destination MAC address is not in any
-logical port's addresses column, it delivers it to the port (or ports) whose addresses
-columns include unknown::
-
- $ ovn/env1/add-unknown-ports.sh
-
-This trace shows a packet from ``sw0-port1`` to ``sw0-port4``, ``sw0-port5``
-whose addresses columns include unknown. You will see that it is output to
-both ports ``4`` and ``5``::
-
- $ ovn/env1/packet3.sh
-
-The logical port would restrict the host to sending packets from and receiving
-packets to the ethernet addresses defined in the logical port's
-``port_security`` column. In addition to the restrictions described for
-Ethernet addresses above, such an element of port_security restricts the IPv4
-or IPv6 addresses from which the host may send and to which it may receive
-packets to the specified addresses::
-
- $ ovn/env1/add-security-ip-ports.sh
-
-This trace shows a packet from ``sw0-port6`` to ``sw0-port7``::
-
- $ ovn/env1/packet4.sh
-
-Two Switches, Four Ports
-------------------------
-
-This environment is an extension of the last example. The previous example
-showed two ports on a single logical switch. In this environment we add a
-second logical switch that also has two ports. This lets you start to see how
-``ovn-controller`` creates flows for isolated networks to co-exist on the same
-switch::
-
- $ ovn/env2/setup.sh
-
-View the logical topology with ``ovn-nbctl``::
-
- $ ovn-nbctl show
- switch e3190dc2-89d1-44ed-9308-e7077de782b3 (sw0)
- port sw0-port1
- addresses: 00:00:00:00:00:01
- port sw0-port2
- addresses: 00:00:00:00:00:02
- switch c8ed4c5f-9733-43f6-93da-795b1aabacb1 (sw1)
- port sw1-port1
- addresses: 00:00:00:00:00:03
- port sw1-port2
- addresses: 00:00:00:00:00:04
-
-Physically, all ports reside on the same chassis::
-
- $ ovn-sbctl show
- Chassis "56b18105-5706-46ef-80c4-ff20979ab068"
- Encap geneve
- ip: "127.0.0.1"
- Port_Binding "sw1-port2"
- Port_Binding "sw0-port2"
- Port_Binding "sw0-port1"
- Port_Binding "sw1-port1"
-
-OVN creates separate logical flows for each logical switch::
-
- $ ovn-sbctl lflow-list
- Datapath: 7ee908c1-b0d3-4d03-acc9-42cd7ef7f27d Pipeline: ingress
- table=0 (ls_in_port_sec_l2 ), priority=100 , match=(eth.src[40]), action=(drop;)
- table=0 (ls_in_port_sec_l2 ), priority=100 , match=(vlan.present), action=(drop;)
- table=0 (ls_in_port_sec_l2 ), priority=50 , match=(inport == "sw1-port1" && eth.src == {00:00:00:00:00:03}), action=(next;)
- table=0 (ls_in_port_sec_l2 ), priority=50 , match=(inport == "sw1-port2" && eth.src == {00:00:00:00:00:04}), action=(next;)
- table=1 (ls_in_port_sec_ip ), priority=0 , match=(1), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw1-port1" && eth.src == 00:00:00:00:00:03 && arp.sha == 00:00:00:00:00:03), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw1-port1" && eth.src == 00:00:00:00:00:03 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:03) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:03)))), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw1-port2" && eth.src == 00:00:00:00:00:04 && arp.sha == 00:00:00:00:00:04), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw1-port2" && eth.src == 00:00:00:00:00:04 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:04) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:04)))), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=80 , match=(inport == "sw1-port1" && (arp || nd)), action=(drop;)
- table=2 (ls_in_port_sec_nd ), priority=80 , match=(inport == "sw1-port2" && (arp || nd)), action=(drop;)
- table=2 (ls_in_port_sec_nd ), priority=0 , match=(1), action=(next;)
- table=3 (ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=4 (ls_in_pre_lb ), priority=0 , match=(1), action=(next;)
- table=5 (ls_in_pre_stateful ), priority=100 , match=(reg0[0] == 1), action=(ct_next;)
- table=5 (ls_in_pre_stateful ), priority=0 , match=(1), action=(next;)
- table=6 (ls_in_acl ), priority=0 , match=(1), action=(next;)
- table=7 (ls_in_lb ), priority=0 , match=(1), action=(next;)
- table=8 (ls_in_stateful ), priority=100 , match=(reg0[1] == 1), action=(ct_commit; next;)
- table=8 (ls_in_stateful ), priority=100 , match=(reg0[2] == 1), action=(ct_lb;)
- table=8 (ls_in_stateful ), priority=0 , match=(1), action=(next;)
- table=9 (ls_in_arp_rsp ), priority=0 , match=(1), action=(next;)
- table=10(ls_in_l2_lkup ), priority=100 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
- table=10(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:03), action=(outport = "sw1-port1"; output;)
- table=10(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:04), action=(outport = "sw1-port2"; output;)
- Datapath: 7ee908c1-b0d3-4d03-acc9-42cd7ef7f27d Pipeline: egress
- table=0 (ls_out_pre_lb ), priority=0 , match=(1), action=(next;)
- table=1 (ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=2 (ls_out_pre_stateful), priority=100 , match=(reg0[0] == 1), action=(ct_next;)
- table=2 (ls_out_pre_stateful), priority=0 , match=(1), action=(next;)
- table=3 (ls_out_lb ), priority=0 , match=(1), action=(next;)
- table=4 (ls_out_acl ), priority=0 , match=(1), action=(next;)
- table=5 (ls_out_stateful ), priority=100 , match=(reg0[1] == 1), action=(ct_commit; next;)
- table=5 (ls_out_stateful ), priority=100 , match=(reg0[2] == 1), action=(ct_lb;)
- table=5 (ls_out_stateful ), priority=0 , match=(1), action=(next;)
- table=6 (ls_out_port_sec_ip ), priority=0 , match=(1), action=(next;)
- table=7 (ls_out_port_sec_l2 ), priority=100 , match=(eth.mcast), action=(output;)
- table=7 (ls_out_port_sec_l2 ), priority=50 , match=(outport == "sw1-port1" && eth.dst == {00:00:00:00:00:03}), action=(output;)
- table=7 (ls_out_port_sec_l2 ), priority=50 , match=(outport == "sw1-port2" && eth.dst == {00:00:00:00:00:04}), action=(output;)
- Datapath: 9ea0c8f9-4f82-4be3-a6c7-6e6f9c2de583 Pipeline: ingress
- table=0 (ls_in_port_sec_l2 ), priority=100 , match=(eth.src[40]), action=(drop;)
- table=0 (ls_in_port_sec_l2 ), priority=100 , match=(vlan.present), action=(drop;)
- table=0 (ls_in_port_sec_l2 ), priority=50 , match=(inport == "sw0-port1" && eth.src == {00:00:00:00:00:01}), action=(next;)
- table=0 (ls_in_port_sec_l2 ), priority=50 , match=(inport == "sw0-port2" && eth.src == {00:00:00:00:00:02}), action=(next;)
- table=1 (ls_in_port_sec_ip ), priority=0 , match=(1), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && arp.sha == 00:00:00:00:00:01), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw0-port1" && eth.src == 00:00:00:00:00:01 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:01) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:01)))), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw0-port2" && eth.src == 00:00:00:00:00:02 && arp.sha == 00:00:00:00:00:02), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=90 , match=(inport == "sw0-port2" && eth.src == 00:00:00:00:00:02 && ip6 && nd && ((nd.sll == 00:00:00:00:00:00 || nd.sll == 00:00:00:00:00:02) || ((nd.tll == 00:00:00:00:00:00 || nd.tll == 00:00:00:00:00:02)))), action=(next;)
- table=2 (ls_in_port_sec_nd ), priority=80 , match=(inport == "sw0-port1" && (arp || nd)), action=(drop;)
- table=2 (ls_in_port_sec_nd ), priority=80 , match=(inport == "sw0-port2" && (arp || nd)), action=(drop;)
- table=2 (ls_in_port_sec_nd ), priority=0 , match=(1), action=(next;)
- table=3 (ls_in_pre_acl ), priority=0 , match=(1), action=(next;)
- table=4 (ls_in_pre_lb ), priority=0 , match=(1), action=(next;)
- table=5 (ls_in_pre_stateful ), priority=100 , match=(reg0[0] == 1), action=(ct_next;)
- table=5 (ls_in_pre_stateful ), priority=0 , match=(1), action=(next;)
- table=6 (ls_in_acl ), priority=0 , match=(1), action=(next;)
- table=7 (ls_in_lb ), priority=0 , match=(1), action=(next;)
- table=8 (ls_in_stateful ), priority=100 , match=(reg0[1] == 1), action=(ct_commit; next;)
- table=8 (ls_in_stateful ), priority=100 , match=(reg0[2] == 1), action=(ct_lb;)
- table=8 (ls_in_stateful ), priority=0 , match=(1), action=(next;)
- table=9 (ls_in_arp_rsp ), priority=0 , match=(1), action=(next;)
- table=10(ls_in_l2_lkup ), priority=100 , match=(eth.mcast), action=(outport = "_MC_flood"; output;)
- table=10(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:01), action=(outport = "sw0-port1"; output;)
- table=10(ls_in_l2_lkup ), priority=50 , match=(eth.dst == 00:00:00:00:00:02), action=(outport = "sw0-port2"; output;)
- Datapath: 9ea0c8f9-4f82-4be3-a6c7-6e6f9c2de583 Pipeline: egress
- table=0 (ls_out_pre_lb ), priority=0 , match=(1), action=(next;)
- table=1 (ls_out_pre_acl ), priority=0 , match=(1), action=(next;)
- table=2 (ls_out_pre_stateful), priority=100 , match=(reg0[0] == 1), action=(ct_next;)
- table=2 (ls_out_pre_stateful), priority=0 , match=(1), action=(next;)
- table=3 (ls_out_lb ), priority=0 , match=(1), action=(next;)
- table=4 (ls_out_acl ), priority=0 , match=(1), action=(next;)
- table=5 (ls_out_stateful ), priority=100 , match=(reg0[1] == 1), action=(ct_commit; next;)
- table=5 (ls_out_stateful ), priority=100 , match=(reg0[2] == 1), action=(ct_lb;)
- table=5 (ls_out_stateful ), priority=0 , match=(1), action=(next;)
- table=6 (ls_out_port_sec_ip ), priority=0 , match=(1), action=(next;)
- table=7 (ls_out_port_sec_l2 ), priority=100 , match=(eth.mcast), action=(output;)
- table=7 (ls_out_port_sec_l2 ), priority=50 , match=(outport == "sw0-port1" && eth.dst == {00:00:00:00:00:01}), action=(output;)
- table=7 (ls_out_port_sec_l2 ), priority=50 , match=(outport == "sw0-port2" && eth.dst == {00:00:00:00:00:02}), action=(output;)
-
-In this setup, ``sw0-port1`` and ``sw0-port2`` can send packets to each other,
-but not to either of the ports on ``sw1``. This first trace shows a packet
-from ``sw0-port1`` to ``sw0-port2``. You should see th packet arrive on
-OpenFlow port ``1`` and output to OpenFlow port ``2``::
-
- $ ovn/env2/packet1.sh
-
-This next example shows a packet from ``sw0-port1`` with a destination MAC
-address of ``00:00:00:00:00:03``, which is the MAC address for ``sw1-port1``.
-Since these ports are not on the same logical switch, the packet should just be
-dropped::
-
- $ ovn/env2/packet2.sh
-
-
-Two Hypervisors
----------------
-
-The first two examples started by showing OVN on a single hypervisor. A more
-realistic deployment of OVN would span multiple hypervisors. This example
-creates a single logical switch with 4 logical ports. It then simulates having
-two hypervisors with two of the logical ports bound to each hypervisor::
-
- $ ovn/env3/setup.sh
-
-You can start by viewing the logical topology with ``ovn-nbctl``::
-
- $ ovn-nbctl show
- switch b977dc03-79a5-41ba-9665-341a80e1abfd (sw0)
- port sw0-port1
- addresses: 00:00:00:00:00:01
- port sw0-port2
- addresses: 00:00:00:00:00:02
- port sw0-port4
- addresses: 00:00:00:00:00:04
- port sw0-port3
- addresses: 00:00:00:00:00:03
-
-Using ``ovn-sbctl`` to view the state of the system, we can see that there are
-two chassis: one local that we can interact with, and a fake remote chassis.
-Two logical ports are bound to each. Both chassis have an IP address of
-localhost, but in a realistic deployment that would be the IP address used for
-tunnels to that chassis::
-
- $ ovn-sbctl show
- Chassis "56b18105-5706-46ef-80c4-ff20979ab068"
- Encap geneve
- ip: "127.0.0.1"
- Port_Binding "sw0-port2"
- Port_Binding "sw0-port1"
- Chassis fakechassis
- Encap geneve
- ip: "127.0.0.1"
- Port_Binding "sw0-port4"
- Port_Binding "sw0-port3"
-
-Packets between ``sw0-port1`` and ``sw0-port2`` behave just like the previous
-examples. Packets to ports on a remote chassis are the interesting part of
-this example. You may have noticed before that OVN's logical flows are broken
-up into ingress and egress tables. Given a packet from ``sw0-port1`` on the
-local chassis to ``sw0-port3`` on the remote chassis, the ingress pipeline is
-executed on the local switch. OVN then determines that it must forward the
-packet over a geneve tunnel. When it arrives at the remote chassis, the egress
-pipeline will be executed there.
-
-This first packet trace shows the first part of this example. It's a packet
-from ``sw0-port1`` to ``sw0-port3`` from the perspective of the local chassis.
-``sw0-port1`` is OpenFlow port ``1``. The tunnel to the fake remote chassis is
-OpenFlow port ``3``. You should see the ingress pipeline being executed and
-then the packet output to port ``3``, the geneve tunnel::
-
- $ ovn/env3/packet1.sh
-
-To simulate what would happen when that packet arrives at the remote chassis we
-can flip this example around. Consider a packet from ``sw0-port3`` to
-``sw0-port1``. This trace shows what would happen when that packet arrives at
-the local chassis. The packet arrives on OpenFlow port ``3`` (the tunnel).
-You should then see the egress pipeline get executed and the packet output to
-OpenFlow port ``1``::
-
- $ ovn/env3/packet2.sh
-
-Locally Attached Networks
--------------------------
-
-While OVN is generally focused on the implementation of logical networks using
-overlays, it's also possible to use OVN as a control plane to manage logically
-direct connectivity to networks that are locally accessible to each chassis.
-
-This example includes two hypervisors. Both hypervisors have two ports on
-them. We want to use OVN to manage the connectivity of these ports to a
-network attached to each hypervisor that we will call "physnet1".
-
-This scenario requires some additional configuration of ``ovn-controller``. We
-must configure a mapping between ``physnet1`` and a local OVS bridge that
-provides connectivity to that network. We call these "bridge mappings". For
-our example, the following script creates a bridge called ``br-eth1`` and then
-configures ``ovn-controller`` with a bridge mapping from ``physnet1`` to
-``br-eth1``.
-
-We want to create a fake second chassis and then create the topology that tells
-OVN we want both ports on both hypervisors connected to ``physnet1``. The way
-this is modeled in OVN is by creating a logical switch for each port. The
-logical switch has the regular VIF port and a ``localnet`` port::
-
- $ ovn/env4/setup.sh
-
-At this point we should be able to see that ``ovn-controller`` has
-automatically created patch ports between ``br-int`` and ``br-eth1``::
-
- $ ovs-vsctl show
- c0a06d85-d70a-4e11-9518-76a92588b34e
- Bridge "br-eth1"
- Port "patch-provnet1-1-physnet1-to-br-int"
- Interface "patch-provnet1-1-physnet1-to-br-int"
- type: patch
- options: {peer="patch-br-int-to-provnet1-1-physnet1"}
- Port "br-eth1"
- Interface "br-eth1"
- type: internal
- Port "patch-provnet1-2-physnet1-to-br-int"
- Interface "patch-provnet1-2-physnet1-to-br-int"
- type: patch
- options: {peer="patch-br-int-to-provnet1-2-physnet1"}
- Bridge br-int
- fail_mode: secure
- Port "ovn-fakech-0"
- Interface "ovn-fakech-0"
- type: geneve
- options: {key=flow, remote_ip="127.0.0.1"}
- Port "patch-br-int-to-provnet1-2-physnet1"
- Interface "patch-br-int-to-provnet1-2-physnet1"
- type: patch
- options: {peer="patch-provnet1-2-physnet1-to-br-int"}
- Port br-int
- Interface br-int
- type: internal
- Port "patch-br-int-to-provnet1-1-physnet1"
- Interface "patch-br-int-to-provnet1-1-physnet1"
- type: patch
- options: {peer="patch-provnet1-1-physnet1-to-br-int"}
- Port "lport2"
- Interface "lport2"
- Port "lport1"
- Interface "lport1
-
-
-The logical topology from ``ovn-nbctl`` should look like this::
-
- $ ovn-nbctl show
- switch 9db81140-5504-4f60-be3d-2bee45b57e27 (provnet1-2)
- port provnet1-2-port1
- addresses: ["00:00:00:00:00:02"]
- port provnet1-2-physnet1
- addresses: ["unknown"]
- switch cf175cb9-35c5-41cf-8bc7-2d322cdbead0 (provnet1-3)
- port provnet1-3-physnet1
- addresses: ["unknown"]
- port provnet1-3-port1
- addresses: ["00:00:00:00:00:03"]
- switch b85f7af6-8055-4db2-ba93-efc7887cf38f (provnet1-1)
- port provnet1-1-port1
- addresses: ["00:00:00:00:00:01"]
- port provnet1-1-physnet1
- addresses: ["unknown"]
- switch 63a5e276-8807-417d-bbec-a7e907e106b1 (provnet1-4)
- port provnet1-4-port1
- addresses: ["00:00:00:00:00:04"]
- port provnet1-4-physnet1
- addresses: ["unknown"]
-
-``port1`` on each logical switch represents a regular logical port for a VIF on
-a hypervisor. ``physnet1`` on each logical switch is the special ``localnet``
-port. You can use ``ovn-nbctl`` to see that this port has a ``type`` and
-``options`` set::
-
- $ ovn-nbctl lsp-get-type provnet1-1-physnet1
- localnet
-
- $ ovn-nbctl lsp-get-options provnet1-1-physnet1
- network_name=physnet1
-
-The physical topology should reflect that there are two regular ports on each
-chassis::
-
- $ ovn-sbctl show
- Chassis "56b18105-5706-46ef-80c4-ff20979ab068"
- hostname: sandbox
- Encap geneve
- ip: "127.0.0.1"
- Port_Binding "provnet1-1-port1"
- Port_Binding "provnet1-2-port1"
- Chassis fakechassis
- Encap geneve
- ip: "127.0.0.1"
- Port_Binding "provnet1-3-port1"
- Port_Binding "provnet1-4-port1"
-
-All four of our ports should be able to communicate with each other, but they
-do so through ``physnet1``. A packet from any of these ports to any
-destination should be output to the OpenFlow port number that corresponds to
-the patch port to ``br-eth1``.
-
-This example assumes following OpenFlow port number mappings:
-
-* ``1`` = tunnel to the fake second chassis
-* ``2`` = ``lport1``, which is the logical port named ``provnet1-1-port1``
-* ``3`` = ``patch-br-int-to-provnet1-1-physnet1``, patch port to ``br-eth1``
-* ``4`` = ``lport2``, which is the logical port named ``provnet1-2-port1``
-* ``5`` = ``patch-br-int-to-provnet1-2-physnet1``, patch port to ``br-eth1``
-
-We get those port numbers using ``ovs-ofctl``::
-
- $ ovs-ofctl show br-int
- OFPT_FEATURES_REPLY (xid=0x2): dpid:00002a84824b0d40
- n_tables:254, n_buffers:0
- capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
- actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst
- 1(ovn-fakech-0): addr:aa:55:aa:55:00:0e
- config: PORT_DOWN
- state: LINK_DOWN
- speed: 0 Mbps now, 0 Mbps max
- 2(lport1): addr:aa:55:aa:55:00:0f
- config: PORT_DOWN
- state: LINK_DOWN
- speed: 0 Mbps now, 0 Mbps max
- 3(patch-br-int-to): addr:7a:6f:8a:d5:69:2a
- config: 0
- state: 0
- speed: 0 Mbps now, 0 Mbps max
- 4(lport2): addr:aa:55:aa:55:00:10
- config: PORT_DOWN
- state: LINK_DOWN
- speed: 0 Mbps now, 0 Mbps max
- 5(patch-br-int-to): addr:4a:fd:c1:11:fc:a5
- config: 0
- state: 0
- speed: 0 Mbps now, 0 Mbps max
- LOCAL(br-int): addr:2a:84:82:4b:0d:40
- config: PORT_DOWN
- state: LINK_DOWN
- speed: 0 Mbps now, 0 Mbps max
- OFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0
-
-This first trace shows a packet from ``provnet1-1-port1`` with a destination
-MAC address of ``provnet1-2-port1``. We expect the packets from ``lport1``
-(OpenFlow port 2) to be sent out to ``lport2`` (OpenFlow port 4). For example,
-the following topology illustrates how the packets travel from ``lport1`` to
-``lport2``::
-
- `lport1` --> `patch-br-int-to-provnet1-1-physnet1`(OpenFlow port 3)
- --> `br-eth1` --> `patch-br-int-to-provnet1-2-physnet1` --> `lport2`(OpenFlow port 4)
-
-Similarly, We expect the packets from ``provnet1-2-port1`` to be sent out to
-``provnet1-1-port1``. We then expect the network to handle getting the packet
-to its destination. In practice, this will be optimized at ``br-eth1`` and the
-packet won't actually go out and back on the network::
-
- $ ovn/env4/packet1.sh
-
-This next trace shows an example of a packet being sent to a destination on
-another hypervisor. The source is ``provnet1-1-port1``, but the destination is
-``provnet1-3-port1``, which is on the other fake chassis. As usual, we expect
-the output to be to ``br-eth1`` (``patch-br-int-to-provnet1-1-physnet1``,
-OpenFlow port 3)::
-
- $ ovn/env4/packet2.sh
-
-This next test shows a broadcast packet. The destination should still only be
-OpenFlow port 3 and 4::
-
- $ ovn/env4/packet3.sh
-
-Finally, this last trace shows what happens when a broadcast packet arrives
-from the network. In this case, it simulates a broadcast that originated from a
-port on the remote fake chassis and arrived at the local chassis via ``br-eth1``.
-We should see it output to both local ports that are attached to this network
-(OpenFlow ports 2 and 4)::
-
- $ ovn/env4/packet4.sh
-
-Locally Attached Networks with VLANs
-------------------------------------
-
-This example is an extension of the previous one. We take the same setup and
-add two more ports to each hypervisor. Instead of having the new ports
-directly connected to ``physnet1`` as before, we indicate that we want them on
-VLAN 101 of ``physnet1``. This shows how ``localnet`` ports can be used to
-provide connectivity to either a flat network or a VLAN on that network::
-
- $ ovn/env5/setup.sh
-
-The logical topology shown by ``ovn-nbctl`` is similar to ``env4``, except we
-now have 8 regular VIF ports connected to ``physnet1`` instead of 4. The
-additional 4 ports we have added are all on VLAN 101 of ``physnet1``. Note
-that the ``localnet`` ports representing connectivity to VLAN 101 of
-``physnet1`` have the ``tag`` field set to ``101``::
-
- $ ovn-nbctl show
- switch 3e60b940-00bf-44c6-9db6-04abf28d7e5f (provnet1-1)
- port provnet1-1-physnet1
- addresses: ["unknown"]
- port provnet1-1-port1
- addresses: ["00:00:00:00:00:01"]
- switch 87f6bea0-f74d-4f39-aa65-ca1f94670429 (provnet1-2)
- port provnet1-2-port1
- addresses: ["00:00:00:00:00:02"]
- port provnet1-2-physnet1
- addresses: ["unknown"]
- switch e6c9cb69-a056-428d-aa40-e903ce416dcd (provnet1-6-101)
- port provnet1-6-101-port1
- addresses: ["00:00:00:00:00:06"]
- port provnet1-6-physnet1-101
- parent:
- tag: 101
- addresses: ["unknown"]
- switch 5f8f72ca-6030-4f66-baea-fe6174eb54df (provnet1-4)
- port provnet1-4-port1
- addresses: ["00:00:00:00:00:04"]
- port provnet1-4-physnet1
- addresses: ["unknown"]
- switch 15d585eb-d2c1-45ea-a946-b08de0eb2f55 (provnet1-7-101)
- port provnet1-7-physnet1-101
- parent:
- tag: 101
- addresses: ["unknown"]
- port provnet1-7-101-port1
- addresses: ["00:00:00:00:00:07"]
- switch 7be4aabe-1bb0-4e16-a755-a1f6d81c1c2f (provnet1-5-101)
- port provnet1-5-101-port1
- addresses: ["00:00:00:00:00:05"]
- port provnet1-5-physnet1-101
- parent:
- tag: 101
- addresses: ["unknown"]
- switch 9bbdbf0e-50f3-4286-ba5a-29bf347531bb (provnet1-8-101)
- port provnet1-8-101-port1
- addresses: ["00:00:00:00:00:08"]
- port provnet1-8-physnet1-101
- parent:
- tag: 101
- addresses: ["unknown"]
- switch 70d053f7-2bca-4dff-96ae-bd728d3ba1d2 (provnet1-3)
- port provnet1-3-physnet1
- addresses: ["unknown"]
- port provnet1-3-port1
- addresses: ["00:00:00:00:00:03"]
-
-The physical topology shows that we have 4 regular VIF ports on each simulated
-hypervisor::
-
- $ ovn-sbctl show
- Chassis fakechassis
- Encap geneve
- ip: "127.0.0.1"
- Port_Binding "provnet1-3-port1"
- Port_Binding "provnet1-8-101-port1"
- Port_Binding "provnet1-7-101-port1"
- Port_Binding "provnet1-4-port1"
- Chassis "56b18105-5706-46ef-80c4-ff20979ab068"
- hostname: sandbox
- Encap geneve
- ip: "127.0.0.1"
- Port_Binding "provnet1-2-port1"
- Port_Binding "provnet1-5-101-port1"
- Port_Binding "provnet1-1-port1"
- Port_Binding "provnet1-6-101-port1"
-
-All of the traces from the previous example, ``env4``, should work in this
-environment and provide the same result. Now we can show what happens for the
-ports connected to VLAN 101. This first example shows a packet originating
-from ``provnet1-5-101-port1``, which is OpenFlow port 6. We should see VLAN
-tag 101 pushed on the packet and then output to OpenFlow port 7, the patch port
-to ``br-eth1`` (the bridge providing connectivity to ``physnet1``), and finally
-arrives on OpenFlow port 8.
-
- $ ovn/env5/packet1.sh
-
-If we look at a broadcast packet arriving on VLAN 101 of ``physnet1``, we
-should see it output to OpenFlow ports 6 and 8 only::
-
- $ ovn/env5/packet2.sh
-
-Stateful ACLs
--------------
-
-ACLs provide a way to do distributed packet filtering for OVN networks. One
-example use of ACLs is that OpenStack Neutron uses them to implement security
-groups. ACLs are implemented using conntrack integration with OVS.
-
-Start with a simple logical switch with 2 logical ports::
-
- $ ovn/env6/setup.sh
-
-A common use case would be the following policy applied for ``sw0-port1``:
-
-* Allow outbound IP traffic and associated return traffic.
-* Allow incoming ICMP requests and associated return traffic.
-* Allow incoming SSH connections and associated return traffic.
-* Drop other incoming IP traffic.
-
-The following script applies this policy to our environment::
-
- $ ovn/env6/add-acls.sh
-
-We can view the configured ACLs on this network using the ``ovn-nbctl``
-command::
-
- $ ovn-nbctl acl-list sw0
- from-lport 1002 (inport == "sw0-port1" && ip) allow-related
- to-lport 1002 (outport == "sw0-port1" && ip && icmp) allow-related
- to-lport 1002 (outport == "sw0-port1" && ip && tcp && tcp.dst == 22) allow-related
- to-lport 1001 (outport == "sw0-port1" && ip) drop
-
-Now that we have ACLs configured, there are new entries in the logical flow
-table in the stages ``switch_in_pre_acl``, ``switch_in_acl``,
-``switch_out_pre_acl``, and ``switch_out_acl``.
-
- $ ovn-sbctl lflow-list
-
-Let's look more closely at ``switch_out_pre_acl`` and ``switch_out_acl``.
-
-In ``switch_out_pre_acl``, we match IP traffic and put it through the
-connection tracker. This populates the connection state fields so that we can
-apply policy as appropriate::
-
- table=0(switch_out_pre_acl), priority= 100, match=(ip), action=(ct_next;)
- table=1(switch_out_pre_acl), priority= 0, match=(1), action=(next;)
-
-In ``switch_out_acl``, we allow packets associated with existing connections.
-We drop packets that are deemed to be invalid (such as non-SYN TCP packet not
-associated with an existing connection)::
-
- table=1(switch_out_acl), priority=65535, match=(!ct.est && ct.rel && !ct.new && !ct.inv), action=(next;)
- table=1(switch_out_acl), priority=65535, match=(ct.est && !ct.rel && !ct.new && !ct.inv), action=(next;)
- table=1(switch_out_acl), priority=65535, match=(ct.inv), action=(drop;)
-
-For new connections, we apply our configured ACL policy to decide whether to
-allow the connection or not. In this case, we'll allow ICMP or SSH.
-Otherwise, we'll drop the packet::
-
- table=1(switch_out_acl), priority= 2002, match=(ct.new && (outport == "sw0-port1" && ip && icmp)), action=(ct_commit; next;)
- table=1(switch_out_acl), priority= 2002, match=(ct.new && (outport == "sw0-port1" && ip && tcp && tcp.dst == 22)), action=(ct_commit; next;)
- table=1(switch_out_acl), priority= 2001, match=(outport == "sw0-port1" && ip), action=(drop;)
-
-When using ACLs, the default policy is to allow and track IP connections.
-Based on our above policy, IP traffic directed at ``sw0-port1`` will never hit
-this flow at priority 1::
-
- table=1(switch_out_acl), priority= 1, match=(ip), action=(ct_commit; next;)
- table=1(switch_out_acl), priority= 0, match=(1), action=(next;)
-
-Note that conntrack integration is not yet supported in ovs-sandbox, so the
-OpenFlow flows will not represent what you'd see in a real environment. The
-logical flows described above give a very good idea of what the flows look
-like, though.
-
-`This blog post
-<http://blog.russellbryant.net/2015/10/22/openstack-security-groups-using-ovn-acls/>`__
-discusses OVN ACLs from an OpenStack perspective and also provides an example
-of what the resulting OpenFlow flows look like.
-
-Container Ports
----------------
-
-.. TODO(stephenfin): Update Docker link when this is moved.
-
-OVN supports containers running directly on the hypervisors and running
-containers inside VMs. This example shows how OVN supports network
-virtualization to containers when run inside VMs. Details about how to use
-docker containers in OVS can be found in the `Docker installlation guide`.
-
-To support container traffic created inside a VM and to distinguish network
-traffic coming from different container vifs, for each container a logical port
-needs to be created with parent name set to the VM's logical port and the tag
-set to the vlan tag of the container vif.
-
-Start with a simple logical switch with three logical ports::
-
- $ ovn/env7/setup.sh
-
-Lets create a container vif attached to the logical port ``sw0-port1`` and
-another container vif attached to the logical port ``sw0-port2``::
-
- $ ovn/env7/add-container-ports.sh
-
-Run the ``ovn-nbctl`` command to see the logical ports::
-
- $ovn-nbctl show
-
-As you can see a logical port ``csw0-cport1`` is created on a logical switch
-'csw0' whose parent is ``sw0-port1`` and it has tag set to ``42``. In
-addition, a logical port ``csw0-cport2`` is created on the logical switch
-``csw0`` whose parent is ``sw0-port2`` and it has tag set to ``43``.
-
-Bridge ``br-vmport1`` represents the ovs bridge running inside the VM connected
-to the logical port ``sw0-port1``. In this tutorial the ovs port to
-``sw0-port1`` is created as a patch port with its peer connected to the ovs
-bridge ``br-vmport1``. An ovs port ``cport1`` is added to ``br-vmport1`` which
-represents the container interface connected to the ovs bridge and vlan tag set
-to ``42``. Similarly ``br-vmport2`` represents the ovs bridge for the logical
-port ``sw0-port2`` and ``cport2`` connected to ``br-vmport2`` with vlan tag set
-to ``43``.
-
-This first trace shows a packet from ``csw0-port1`` with a destination mac
-address of ``csw0-port2``. You can see ovs bridge of the vm ``br-vmport1`` tags
-the traffic with vlan id ``42`` and the traffic reaches to the br-int because
-of the patch port. As you can see below ``ovn-controller`` has added a flow to
-strip the vlan tag and set the reg6 and metadata appropriately::
-
- $ ovs-ofctl -O OpenFlow13 dump-flows br-int
- OFPST_FLOW reply (OF1.3) (xid=0x2):
- cookie=0x0, duration=2767.032s, table=0, n_packets=0, n_bytes=0, priority=150,in_port=3,dl_vlan=42 actions=pop_vlan,set_field:0x3->reg5,set_field:0x2->metadata,set_field:0x1->reg6,resubmit(,16)
- cookie=0x0, duration=2767.002s, table=0, n_packets=0, n_bytes=0, priority=150,in_port=4,dl_vlan=43 actions=pop_vlan,set_field:0x4->reg5,set_field:0x2->metadata,set_field:0x2->reg6,resubmit(,16)
- cookie=0x0, duration=2767.032s, table=0, n_packets=0, n_bytes=0, priority=100,in_port=3 actions=set_field:0x1->reg5,set_field:0x1->metadata,set_field:0x1->reg6,resubmit(,16)
- cookie=0x0, duration=2767.001s, table=0, n_packets=0, n_bytes=0, priority=100,in_port=4 actions=set_field:0x2->reg5,set_field:0x1->metadata,set_field:0x2->reg6,resubmit(,16)
-
-::
-
- $ ovn/env7/packet1.sh
-
-The second trace shows a packet from ``csw0-port2`` to ``csw0-port1``::
-
- $ ovn/env7/packet2.sh
-
-You can extend this setup by adding additional container ports with two
-hypervisors. Refer to tutorial three above.
-
-L2Gateway Ports
----------------
-
-L2Gateway provides a way to connect logical switch ports of type ``l2gateway``
-to a physical network. The difference between ``l2gateway`` ports and
-``localnet`` ports is that an ``l2gateway`` port is bound to a specific
-chassis. A single chassis serves as the L2 gateway to the physical network and
-all traffic between chassis continues to go over geneve tunnels.
-
-Start with a simple logical switch with three logical ports::
-
- $ ovn/env8/setup.sh
-
-This first example shows a packet originating from ``lport1``, which is
-OpenFlow port 1. We expect all packets from ``lport1`` to be sent out to
-``br-eth1`` (``patch-br-int-to-sw0-port3``, OpenFlow port 3). The patch port
-to ``br-eth1`` provides connectivity to the physical network.
-
- $ ovn/env8/packet1.sh
-
-The last trace shows what happens when a broadcast packet arrives from the
-network. In this case, it simulates a broadcast that originated from a port on
-the physical network and arrived at the local chassis via ``br-eth1``. We
-should see it output to the local ports ``lport1`` and ``lport2``::
-
- $ ovn/env8/packet2.sh
-
-.. _ovn-architecture: http://openvswitch.org/support/dist-docs/ovn-architecture.7.html
-.. _Tutorial: https://github.com/openvswitch/ovs/blob/master/tutorial/tutorial.rst
-.. _ovn-nb(5): http://openvswitch.org/support/dist-docs/ovn-nb.5.html
-.. _ovn-sb(5): http://openvswitch.org/support/dist-docs/ovn-sb.5.html
-.. _vtep(5): http://openvswitch.org/support/dist-docs/vtep.5.html
-.. _ovn-northd(8): http://openvswitch.org/support/dist-docs/ovn-northd.8.html
-.. _ovn-controller(8): http://openvswitch.org/support/dist-docs/ovn-controller.8.html
-.. _ovn-controller-vtep(8): http://openvswitch.org/support/dist-docs/ovn-controller-vtep.8.html
-.. _vtep-ctl(8): http://openvswitch.org/support/dist-docs/vtep-ctl.8.html
-.. _ovn-nbctl(8): http://openvswitch.org/support/dist-docs/ovn-nbctl.8.html
-.. _ovn-sbctl(8): http://openvswitch.org/support/dist-docs/ovn-sbctl.8.html
diff --git a/tutorial/ovn/env1/setup.sh b/tutorial/ovn/env1/setup.sh
index 80a5d0d79..a9c6f39a7 100755
--- a/tutorial/ovn/env1/setup.sh
+++ b/tutorial/ovn/env1/setup.sh
@@ -14,7 +14,7 @@
#
#
-# See "Simple two-port setup" in tutorial/ovn-tutorial.rst.
+# See "Simple two-port setup" in Documentation/tutorial/ovn-basics.rst.
#
set -o xtrace
diff --git a/tutorial/ovn/env6/setup.sh b/tutorial/ovn/env6/setup.sh
index 80a5d0d79..a9c6f39a7 100755
--- a/tutorial/ovn/env6/setup.sh
+++ b/tutorial/ovn/env6/setup.sh
@@ -14,7 +14,7 @@
#
#
-# See "Simple two-port setup" in tutorial/ovn-tutorial.rst.
+# See "Simple two-port setup" in Documentation/tutorial/ovn-basics.rst.
#
set -o xtrace
diff --git a/tutorial/tutorial.rst b/tutorial/tutorial.rst
deleted file mode 100644
index 422bc0d61..000000000
--- a/tutorial/tutorial.rst
+++ /dev/null
@@ -1,872 +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 Tutorial
-=======================================
-
-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.
-
-.. TODO(stephenfin): Update installation guide link when this is moved.
-
-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 the
- `installation guide`, 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 ``ifconfig`` or ``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.
-
-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 ``ifconfig
-up``, but the sandbox's interfaces are not visible to the operating system and
-therefore ``ifconfig`` 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: metadata=0,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
- Rule: table=0 cookie=0 dl_dst=01:80:c2:00:00:00/ff:ff:ff:ff:ff:f0
- OpenFlow actions=drop
-
- Final flow: unchanged
- Datapath actions: drop
-
-The first block of lines describes an OpenFlow table lookup. The first line
-shows the fields used for the table lookup (which is mostly zeros because
-that's the default if we don't specify everything). The second line gives the
-OpenFlow flow that the fields matched (called a "rule" because that is the name
-used inside Open vSwitch for an OpenFlow flow). In this case, we see that this
-packet that has a reserved multicast destination address matches the rule that
-drops those packets. The third line gives the rule's OpenFlow actions.
-
-The second 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: metadata=0,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
- Rule: table=0 cookie=0 priority=0
- OpenFlow actions=resubmit(,1)
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- No match
-
- Final flow: unchanged
- Datapath actions: drop
-
-This time the flow we handed to ``ofproto/trace`` doesn't match any of our
-"drop" rules, so it falls through to the low-priority "resubmit" rule, which we
-see in the rule and the actions selected in the first block. The "resubmit"
-causes a second lookup in OpenFlow table 1, described by the additional block
-of indented text in the output. 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" rule::
-
- $ 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 rules that match packets with 802.1Q that enter this stage
-on any of the access ports, so the "default drop" rule 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 rules 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: metadata=0,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
- Rule: table=0 cookie=0 priority=0
- OpenFlow actions=resubmit(,1)
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=1 cookie=0 priority=99,in_port=1
- OpenFlow actions=resubmit(,2)
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- No match
-
- Final flow: unchanged
- 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: metadata=0,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
- Rule: table=0 cookie=0 priority=0
- OpenFlow actions=resubmit(,1)
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=1 cookie=0 priority=99,in_port=2,vlan_tci=0x0000
- OpenFlow actions=mod_vlan_vid:20,resubmit(,2)
-
- Resubmitted flow: metadata=0,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
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- No match
-
- Final flow: unchanged
- 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 rule::
-
- Flow: metadata=0,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
- Rule: table=0 cookie=0 priority=0
- OpenFlow actions=resubmit(,1)
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=1 cookie=0 priority=0
- OpenFlow actions=drop
-
- Final flow: unchanged
- 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, but it isn't otherwise informative,
-so we won't include it here.
-
-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
-
-Here's an excerpt from the output that shows (from the "no match" looking up
-the resubmit to table 10) that the flow's destination was unknown::
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=3 cookie=0 priority=50
- OpenFlow actions=resubmit(,10),resubmit(,4)
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- No match
-
-You can verify that the packet's source was learned two ways. 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's an interesting excerpt from that command's output. This group of lines
-traces 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``::
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=10 cookie=0 vlan_tci=0x0014/0x0fff,dl_dst=f0:00:00:00:00:01
- OpenFlow actions=load:0x1->NXM_NX_REG0[0..15]
-
-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 that the destination has now been learned::
-
- Resubmitted flow: unchanged
- Resubmitted regs: reg0=0x0 reg1=0x0 reg2=0x0 reg3=0x0 reg4=0x0 reg5=0x0 reg6=0x0 reg7=0x0
- Resubmitted odp: drop
- Rule: table=10 cookie=0 vlan_tci=0x0014/0x0fff,dl_dst=90:00:00:00:00:01
- OpenFlow actions=load:0x2->NXM_NX_REG0[0..15]
-
-
-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 rules 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/