Recently native DHCP support has been added to OVN. In this post we will see how native DHCP is supported in OVN and how it is used by OpenStack Neutron OVN ML2 driver. The code which supports native DHCP can be found here and here.
Please see this to understand the architecture of OVN and the services of the OVN. To brief, OVN has a service called ovn-northd which generates the logical flows based on the OVN northbound database state. OVN northbound database is populated by the OVN ML2 neutron driver. OVN has another service called ovn-controller which is run on each compute host. ovn-controller translates the logical flows generated by ovn-northd into OpenFlow flows and adds these flows into the integration bridge (br-int) managed by the local ovs-vswitchd instance.
OpenStack Neutron supports DHCP and provides the IP addresses to the VMs using the Neutron dhcp agent. The dhcp agent can be configured to run on multiple nodes. When a VM boots up it sends DHCP discover broadcast packets which is received by the “dnsmasq” (spawned and configured by dhcp agent) which looks its configuration and send the DHCP reply packet with the appropriate IP address. In the OpenStack world, the IPv4 addresses are assigned when the neutron port is created. So it becomes easier to send the DHCP reply packet with the appropriate IPv4 address.
Until the native DHCP support was added into OVN, we were relying on the dhcp agent to support DHCP in the OpenStack environment.
Advantages of having native DHCP support are
- We don’t need to rely on dhcp agent. So no namespace and ‘dnsmasq’ instance for each virtual network is needed.
- With the dhcp agent approach, it is not completely distributed. In cases where the dhcp agent is down, the VMs might not get the DHCP replies.
- It is completely distributed. ovn-controller running in each compute node handles the DHCP requests from the VMs hosted locally which makes the DHCP support in OVN distributed.
A little about Continuations feature of OVS
Native DHCP is supported using an OVS feature called “Continuations”. This feature which will be available in OVS 2.6. release. Please see here for detailed information.
“Continuations” provides an OpenFlow action called “NXT_PACKET_IN2” which has a flag called “pause” and a field called “userdata”. With the “pause” flag set, the controller when receives a packet as packet-in, can inspect the packet and modify it if required and can send the packet back to the switch which will resume the pipeline from the point where it was interrupted.
Native DHCP details
Lets see some details on how native DHCP is supported in OVN.
When ovn-controller receives a DHCP request packet, in order to send a DHCP reply
- It needs to know the IPv4 address to be offered
- The DHCP options to be added in the DHCP reply packet.
OVN Northbound database has a new table called “DHCP_Options” which is used to define the set of DHCP options. In the Logical_Switch_Port table a new column called “dhcpv4_options” is added which refers to the DHCP_Options rows. In order to make use of native DHCPv4 feature, the CMS (Cloud management system) is expected to define DHCP options for each of the logical ports.
ovn-northd then adds logical flows to send the DHCP replies for each logical port which has an IPv4 address and DHCP options defined. ovn-northd adds two new stages in the ingress logical pipeline – “ls_in_dhcp_options” followed by “ls_in_dhcp_response” where these logical flows are added.
Let’s say we have a logical port with name “port1” configured with IPv4 address – “10.0.0.4” and the following DHCP options defined – lease_time=”43200″, mtu=”1442″, router=”10.0.0.1″, server_id=”10.0.0.1″ and server_mac=”fa:16:3e:96:22:da”.
ovn-northd will add the below logical flows
table=10(ls_in_dhcp_options ), priority=100 , match=(inport == “port1” && eth.src == fa:16:3e:50:47:62 && ip4.src == 0.0.0.0 && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67), action=(reg0 = put_dhcp_opts(offerip = 10.0.0.4, netmask = 255.255.255.0, router = 10.0.0.1, mtu = 1442, server_id = 10.0.0.1, lease_time = 43200); next;)
table=11(ls_in_dhcp_response), priority=100 , match=(inport == “port1” && eth.src == fa:16:3e:50:47:62 && ip4.src == 0.0.0.0 && ip4.dst == 255.255.255.255 && udp.src == 68 && udp.dst == 67 && reg0), action=(eth.dst = eth.src; eth.src = fa:16:3e:96:22:da; ip4.dst = 10.0.0.4; ip4.src = 10.0.0.1; udp.src = 67; udp.dst = 68; outport = inport; flags.loopback = 1; output;)
The OVN action “put_dhcp_opts” transforms the DHCP request packet into a reply packet, adds the DHCP options defined and stores 1 in the ovs register reg0 bit 3. If the packet is invalid, it leaves the packet unchanged and stores 0 in the ovs register reg0 bit 3.
In order to understand how this action transforms the DHCP request packet into the reply packet, lets see the corresponding OF flow.
table=26,priority=100,udp,reg14=0x3,metadata=0x4,dl_src=fa:16:3e:b9:ce:e0, nw_src=0.0.0.0,nw_dst=255.255.255.255,tp_src=68,tp_dst=67 actions=controller(userdata=00.00.00.02.00.00.00.00.00.01.00.04.00.00.00.03.01.00.00.03.01.04.ff.ff.ff.00.03.04.01.00.00.01.1a.02.05.a2.36.04.01.00.00.01.42.04.07.07.07.07.33.04.00.00.a8.c0,pause),resubmit(,27)
As you see above, the action “put_dhcp_opts” translates into controller action with “pause” flag set and the DHCP options stored in the “userdata” field.
When a DHCP request packet is received, ovs-vswitchd sends the packet to “ovn-controller”. “ovn-controller” receives this packet, extracts the offer ip and the DHCP options from the “userdata”, frames a DHCP reply packet and adds these DHCP options, stores 1 in the ovs register field bit and sends the packet back to the switch. How would ovn-controller know which register to use ? It is also stored in the “userdata” field.
On receiving the packet back, the ovs-vswitchd resumes the packet and executes the next pipeline “ls_in_dhcp_response”.
table=27,priority=100,udp,reg0=0x8/0x8,reg14=0x1,metadata=0x4,dl_src=fa:16:3e:50:47:62, nw_src=0.0.0.0,nw_dst=255.255.255.255,tp_src=68,tp_dst=67 actions=move:NXM_OF_ETH_SRC->NXM_OF_ETH_DST,mod_dl_src:fa:16:3e:96:22:da,mod_nw_dst:10.0.0.4,mod_nw_src:10.0.0.1,mod_tp_src:67,mod_tp_dst:68,move:NXM_NX_REG14->NXM_NX_REG15,load:0x1->NXM_NX_REG10,resubmit(,32)
The OVN actions “outport = inport; flags.loopback = 1; output;” in the “ls_in_dhcp_response” pipeline causes the reply DHCP packet to be delivered to the VM port(which sent the DHCP request packet).
Below diagram depicts the sequence of actions when the VM sends a DHCP request packet.
OpenStack Neutron OVN ML2 driver
The neutron OVN ML2 driver makes use of this feature. In order to use native DHCP, the configuration option “ovn_native_dhcp” should be set to True in the ML2 plugin configuration file.
OVN ML2 driver creates the DHCP_Options row for every subnet and defines the DHCP options. All the ports of the subnet will refer to the DHCP_Options row. It also supports the extra DHCP options if defined for any port. Please see here to get an overview of how native DHCPv4 is used in neutron.
Native DHCPv6 support in OVN
Patches to support DHCPv6 are submitted for review in the OVS dev mailing list. Once they are reviewed and accepted, OVN will have native DHCPv6 support. This feature will be really useful once OVN supports IPv6 Router Advertisements. OVN already supports IPv6 routing. Patches are up for review to support IPv6 RAs.
Limitation of using native DHCP support
- OVN still doesn’t have native DNS support for internal DNS queries. If support for internal DNS is a requirement in the OpenStack deployments, then the dhcp agent needs to be used.
- To have metadata support, dhcp agent would be still required. There is a patch in networking-ovn which supports VM metadata access using native DHCP which can be found here.