[ovs-dev] [PATCH v5 0/6] OVN support for Neutron provider networks

Russell Bryant rbryant at redhat.com
Fri Jul 31 17:14:39 UTC 2015


v4->v5:
 - Fix some bugs where code assume br_int existed and that there was an active
   ovs_idl transaction that could be used.
 - Add patch for automatically creating br-int if it does not already exist.
   I added it to this series because it would conflict if I split it out.
v3->v4:
 - Drop patches that either merged or are no longer necessary.
 - Rework patches so that there are no longer any blocking transactions.
   Everything is now done in the transactions committed in the main loop.


Russell Bryant (6):
  lib: Add smap_equal().
  ovn: Add bridge mappings to ovn-controller.
  ovn: Add type and options to logical port.
  ovn: Get/set lport type and options in ovn-nbctl.
  ovn: Add "localnet" logical port type.
  ovn: Automatically create br-int in ovn-controller.

 lib/smap.c                      |  20 +++
 lib/smap.h                      |   2 +
 ovn/controller/ovn-controller.c | 306 ++++++++++++++++++++++++++++++++++++++--
 ovn/controller/ovn-controller.h |   2 +
 ovn/controller/physical.c       | 145 +++++++++++++++----
 ovn/controller/physical.h       |   4 +-
 ovn/northd/ovn-northd.c         |  11 ++
 ovn/ovn-nb.ovsschema            |   6 +
 ovn/ovn-nb.xml                  |  27 ++++
 ovn/ovn-nbctl.8.xml             |  24 +++-
 ovn/ovn-nbctl.c                 | 111 +++++++++++++++
 ovn/ovn-sb.ovsschema            |   6 +
 ovn/ovn-sb.xml                  |  41 ++++++
 tutorial/ovs-sandbox            |   2 -
 14 files changed, 657 insertions(+), 50 deletions(-)

OpenStack Neutron as an API extension called "provider networks" which
allows an administrator to specify that it would like ports directly
attached to some pre-existing network in their environment.  There was a
previous thread where we got into the details of this here:

  http://openvswitch.org/pipermail/dev/2015-June/056765.html

The case where this would be used is an environment that isn't actually
interested in virtual networks and just wants all of their compute
resources connected up to externally managed networks.  Even in this
environment, OVN still has a lot of value to add.  OVN implements port
security and ACLs for all ports connected to these networks.  OVN also
provides the configuration interface and control plane to manage this
across many hypervisors.

Let's start from how this would be used from Neutron and go down through
OVN to show how it works in OVN.  

Imagine an environment where every hypervisor has a NIC attached to the
same physical network that you would like all of your VMs connected to.
We'll refer to this physical network as "physnet1".  Let's also assume
that the interface to "physne1" is eth1 on every hypervisor.  You would
need to first create an OVS bridge and add eth1 to it by doing something
like:

  $ ovs-vsctl add-br br-eth1
  $ ovs-vsctl add-port br-eth1 eth1

Now you must also configure ovn-controller to tell it that it can get
traffic to "physnet1" by sending it to the bridge "br-eth1".

  $ ovs-vsctl set open . external-ids:ovn-bridge-mappings=physnet1:br-eth1

When ovn-controller starts up, it parses the bridge mappings and
automatically creates patch ports between the OVN integration bridge and
the bridges specified in bridge mappings.

Now that ovn-controller on every hypervisor understands what "physnet1"
is, you can create this network in Neutron.  The following command
defines a network in Neutron called "provnet1" which is implemented as
connecting to a physical network called "physnet1".  The type is set to
"flat" meaning that the traffic is not tagged.

  $ neutron net-create provnet1 --shared \
  > --provider:physical_network physnet1 \
  > --provider:network_type flat

(Note that the Neutron API supports specifying a VLAN tag here, but that
is not yet supported in this patch series but will be added later as an
addition.)

At this point an OpenStack user can start creating Neutron ports for VMs
to be attached to this network.

  $ neutron port-create provnet1

When the Neutron network is defined, nothing is actually created in
OVN_Northbound.  Instead, every time a Neutron port is created on this
Neutron provider network, this connection is modeled as a 2-port OVN
logical switch.

At this point, we can model what would happen by using ovn-nbctl.
Consider the following script, which sets up what Neutron would create
for 2 Neutron ports connected to the same Neutron provider network.
Further, it simulates an environment with 2 hypervisors, with one
logical port bound to each hypervisor.


  ovs-vsctl add-br br-eth1
  ovs-vsctl set open .  external-ids:ovn-bridge-mappings=physnet1:br-eth1

  for n in 1 2 ; do 
      ovn-nbctl lswitch-add provnet1-$n

      ovn-nbctl lport-add provnet1-$n provnet1-$n-port1
      ovn-nbctl lport-add provnet1-$n provnet1-$n-port1
      ovn-nbctl lport-set-macs provnet1-$n-port1 00:00:00:00:00:0$n
      ovn-nbctl lport-set-port-security provnet1-$n-port1 00:00:00:00:00:0$n

      ovn-nbctl lport-add provnet1-$n provnet1-$n-physnet1
      ovn-nbctl lport-set-macs provnet1-$n-physnet1 unknown
      ovn-nbctl lport-set-type provnet1-$n-physnet1 localnet
      ovn-nbctl lport-set-options provnet1-$n-physnet1 network_name=physnet1
  done

  # Bind the first logical port to the local chassis.
  ovs-vsctl add-port br-int lport1 -- set Interface lport1 external_ids:iface-id=provnet1-1-port1

  # Create a fake chassis and bind the second logical port there.
  encaps_uuid=$(ovsdb-client dump OVN_Southbound | grep -A 3 Encap | tail -n 1 | awk '{print $1}')
  chassis=$(ovsdb-client transact '["OVN_Southbound",{"op":"insert","table":"Chassis","row":{"name":"fakechassis","encaps":["uuid","'$encaps_uuid'"]}}]')
  chassis_uuid=$(echo $chassis | sed -e 's/^.*\"uuid\",\"\(.*\)\".*/\1/')
  uuid=$(ovsdb-client dump OVN_Southbound | grep -A 6 Binding | grep provnet1-2-port1 | awk '{print $1}')
  ovsdb-client transact '["OVN_Southbound",{"op":"update","table":"Binding","where":[["_uuid","==",["uuid","'$uuid'"]]],"row":{"chassis":["uuid","'$chassis_uuid'"]}}]'


When ovn-northd processes this, the logical Pipeline is no different
than it would be for 2 "normal" logical ports on a logical switch.  As a
result, the OpenFlow flows that implement the logical pipeline also
remain unchanged.

ovn-northd copies the "type" and "options" columsn from the logical port
in OVN_Northbound to the Binding table in OVN_Southbound.  With that
information, ovn-controller can wire things up appropriately.
Specifically, the changes are in ovn-controller's code that does the
logical to physical mappings and creates the associated OpenFlow flows.

Here is the final state of the system using ovs-sandbox using this
example.  First, here's the config in OVN_Northbound:

  $ ovn-nbctl show
    lswitch 9b10ed20-5f68-440f-8d44-7cc4c2ea142d (provnet1-2)
        lport provnet1-2-port1
            macs: 00:00:00:00:00:02
        lport provnet1-2-physnet1
            macs: unknown
    lswitch 55b12691-1d08-4c81-a706-5fa409164c15 (provnet1-1)
        lport provnet1-1-port1
            macs: 00:00:00:00:00:01
        lport provnet1-1-physnet1
            macs: unknown

As we look at ovs, we can see the reuslting config from the perspective of the
first hypervisor.  Only one port is bound locally.

  $ ovs-vsctl show
  66222c5f-b786-40d2-86cd-eee0b5e81437
    Bridge br-int
        fail_mode: secure
        Port br-int
            Interface br-int
                type: internal
        Port "patch-br-int-to-br-eth1"
            Interface "patch-br-int-to-br-eth1"
                type: patch
                options: {peer="br-eth1"}
        Port "ovn-fakech-0"
            Interface "ovn-fakech-0"
                type: geneve
                options: {key=flow, remote_ip="127.0.0.1"}
        Port "lport1"
            Interface "lport1"
    Bridge "br-eth1"
        Port "patch-br-eth1-to-br-int"
            Interface "patch-br-eth1-to-br-int"
                type: patch
                options: {peer=br-int}
        Port "br-eth1"
            Interface "br-eth1"
                type: internal

For reference, the mapping between ports on br-int and OpenFlow port numbers is:

  patch-br-int-to-br-eth1 -- 1 (patch port to provnet1)
  lport1 -- 2 (locally bound port)
  ovn-fakech-0 -- 3  (tunnel to fake chassis)

Finally, here are the flows related to physical-to-logical and
logical-to-physical translation.  When a packet comes in on a localnet port, a
bit is set in reg5 to remember that it came in on a localnet port.  When doing
logical-to-physical translation for output, a packet is only sent out on a
tunnel if it did *not* arrive on a localnet port.  This is to avoid possible
loops and ports receiving duplicate copies of packets.

 table=0, priority=100,in_port=1 actions=set_field:0x1->reg5,set_field:0x2->metadata,set_field:0x4->reg6,resubmit(,16),set_field:0x1->metadata,set_field:0x2->reg6,resubmit(,16)
 table=0, priority=100,in_port=2 actions=set_field:0x1->metadata,set_field:0x1->reg6,resubmit(,16)
 table=0, priority=50,tun_id=0x1 actions=output:2
 ...
 table=64, priority=100,reg6=0x2,reg7=0x2 actions=drop
 table=64, priority=100,reg6=0x4,reg7=0x4 actions=drop
 table=64, priority=100,reg6=0x1,reg7=0x1 actions=drop
 table=64, priority=100,reg6=0x3,reg7=0x3 actions=drop
 table=64, priority=50,reg7=0x2 actions=output:1
 table=64, priority=50,reg7=0x4 actions=output:1
 table=64, priority=50,reg7=0x1 actions=output:2
 table=64, priority=50,reg5=0/0x1,reg7=0x3 actions=set_field:0x3->tun_id,output:3

Thanks!

-- 
2.4.3




More information about the dev mailing list