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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev