This patch adds DHCPv6 stateless option support, to allow ovn native dhcpv6 work in stateless mode.
User can add new option dhcpv6_stateless with string value true in DHCP_Options.options column, to let ovn dhcpv6 only reply other configurations for DHCPv6 request messages come from VM/VIF ports, and let VM/VIF ports get their IPv6 addresses configured via stateless way. Signed-off-by: Zongkai LI <zealo...@gmail.com> --- ovn/northd/ovn-northd.c | 24 ++++++++++++++++++++--- ovn/ovn-nb.xml | 11 +++++++++++ tests/ovn.at | 51 +++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 1731332..d5d9fcd 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -1899,10 +1899,26 @@ build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip, ipv6_string_mapped(ia_addr, offer_ip); ds_put_format(options_action, - REGBIT_DHCP_OPTS_RESULT" = put_dhcpv6_opts(ia_addr = %s, ", - ia_addr); + REGBIT_DHCP_OPTS_RESULT" = put_dhcpv6_opts("); + + struct smap dhcpv6_options = SMAP_INITIALIZER(&dhcpv6_options); + smap_clone(&dhcpv6_options, &op->nbsp->dhcpv6_options->options); + + /* Check whether the dhcpv6 options should be configured as stateful. + * Only reply with ia_addr option for dhcpv6 stateful address mode. */ + const char *dhcpv6_stateless = smap_get( + &dhcpv6_options, "dhcpv6_stateless"); + if (!dhcpv6_stateless || strcmp(dhcpv6_stateless, "true")) { + char ia_addr[INET6_ADDRSTRLEN + 1]; + ipv6_string_mapped(ia_addr, offer_ip); + + ds_put_format(options_action, "ia_addr = %s, ", ia_addr); + } + /* dhcpv6_stateless is not DHCPv6 option, delete it from the smap. */ + smap_remove(&dhcpv6_options, "dhcpv6_stateless"); + struct smap_node *node; - SMAP_FOR_EACH (node, &op->nbsp->dhcpv6_options->options) { + SMAP_FOR_EACH (node, &dhcpv6_options) { ds_put_format(options_action, "%s = %s, ", node->key, node->value); } ds_chomp(options_action, ' '); @@ -1914,6 +1930,8 @@ build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip, "udp.dst = 546; outport = inport; flags.loopback = 1; " "output;", server_mac, server_ip); + + smap_destroy(&dhcpv6_options); return true; } diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml index 5719e74..9b8c0f0 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -1315,6 +1315,17 @@ Example: <code>"ovn.org"</code>. </p> </column> + + <column name="options" key="dhcpv6_stateless"> + <p> + This option specifies the OVN native DHCPv6 will work in stateless + mode, which means OVN native DHCPv6 will not offer IPv6 addresses + for VM/VIF ports, but only reply other configurations, such as + DNS and domain search list. When setting this option with string + value "true", VM/VIF will configure IPv6 addresses by stateless + way. Default value for this option is false. + </p> + </column> </group> </group> diff --git a/tests/ovn.at b/tests/ovn.at index a23b422..1de67b6 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -921,6 +921,9 @@ reg1[0] = put_dhcpv6_opts(); reg1[0] = put_dhcpv6_opts(dns_server={ae70::1,ae70::2}); formats as reg1[0] = put_dhcpv6_opts(dns_server = {ae70::1, ae70::2}); encodes as controller(userdata=00.00.00.05.00.00.00.00.00.01.de.10.00.00.00.40.17.00.20.00.ae.70.00.00.00.00.00.00.00.00.00.00.00.00.00.01.ae.70.00.00.00.00.00.00.00.00.00.00.00.00.00.02,pause) +reg1[0] = put_dhcpv6_opts(server_id=12:34:56:78:9a:bc, dns_server={ae70::1,ae89::2}); + formats as reg1[0] = put_dhcpv6_opts(server_id = 12:34:56:78:9a:bc, dns_server = {ae70::1, ae89::2}); + encodes as controller(userdata=00.00.00.05.00.00.00.00.00.01.de.10.00.00.00.40.02.00.06.00.12.34.56.78.9a.bc.17.00.20.00.ae.70.00.00.00.00.00.00.00.00.00.00.00.00.00.01.ae.89.00.00.00.00.00.00.00.00.00.00.00.00.00.02,pause) reg1[0] = put_dhcpv6_opts(domain_search = "ovn.org"); encodes as controller(userdata=00.00.00.05.00.00.00.00.00.01.de.10.00.00.00.40.18.00.07.00.6f.76.6e.2e.6f.72.67,pause) reg1[0] = put_dhcpv6_opts(x = 1.2.3.4); @@ -3744,7 +3747,7 @@ OVS_APP_EXIT_AND_WAIT([ovsdb-server]) AT_CLEANUP -AT_SETUP([ovn -- dhcpv6 : 1 HV, 2 LS, 2 LSPs/LS]) +AT_SETUP([ovn -- dhcpv6 : 1 HV, 2 LS, 5 LSPs]) AT_KEYWORDS([dhcpv6]) AT_SKIP_IF([test $HAVE_PYTHON = no]) ovn_start @@ -3760,11 +3763,20 @@ ovn-nbctl lsp-add ls1 ls1-lp2 \ ovn-nbctl lsp-set-port-security ls1-lp2 "f0:00:00:00:00:02 ae70::5" +ovn-nbctl lsp-add ls1 ls1-lp3 \ +-- lsp-set-addresses ls1-lp3 "f0:00:00:00:00:22 ae70::22" + +ovn-nbctl lsp-set-port-security ls1-lp3 "f0:00:00:00:00:22 ae70::22" + ovn-nbctl -- --id=@d1 create DHCP_Options cidr="ae70\:\:/64" \ options="\"server_id\"=\"00:00:00:10:00:01\"" \ -- add Logical_Switch_Port ls1-lp1 dhcpv6_options @d1 \ -- add Logical_Switch_Port ls1-lp2 dhcpv6_options @d1 +ovn-nbctl -- --id=@d2 create DHCP_Options cidr="ae70\:\:/64" \ +options="\"dhcpv6_stateless\"=\"true\" \"server_id\"=\"00:00:00:10:00:01\"" \ +-- add Logical_Switch_Port ls1-lp3 dhcpv6_options @d2 + ovn-nbctl ls-add ls2 ovn-nbctl lsp-add ls2 ls2-lp1 \ -- lsp-set-addresses ls2-lp1 "f0:00:00:00:00:03 be70::3" @@ -3803,6 +3815,12 @@ ovs-vsctl -- add-port br-int hv1-vif4 -- \ options:rxq_pcap=hv1/vif4-rx.pcap \ ofport-request=4 +ovs-vsctl -- add-port br-int hv1-vif5 -- \ + set interface hv1-vif5 external-ids:iface-id=ls1-lp3 \ + options:tx_pcap=hv1/vif5-tx.pcap \ + options:rxq_pcap=hv1/vif5-rx.pcap \ + ofport-request=5 + ovn_populate_arp sleep 2 @@ -3812,8 +3830,8 @@ trim_zeros() { } # This shell function sends a DHCPv6 request packet -# test_dhcp INPORT SRC_MAC DHCPv6_MSG_TYPE OUTPORT... -# The OUTPORTs (zero or more) list the VIFs on which the original DHCP +# test_dhcpv6 INPORT SRC_MAC SRC_LLA DHCPv6_MSG_TYPE OFFER_IP OUTPORT... +# The OUTPORTs (zero or more) list the VIFs on which the original DHCPv6 # packet should be received twice (one from ovn-controller and the other # from the "ovs-ofctl monitor br-int resume" test_dhcpv6() { @@ -3835,13 +3853,19 @@ test_dhcpv6() { if test $msg_code = 01; then reply_code=02 fi - local reply=${src_mac}${server_mac}86dd0000000000541101${server_lla}${src_lla} + local msg_len=54 + if test $offer_ip = 1; then + msg_len=28 + fi + local reply=${src_mac}${server_mac}86dd0000000000${msg_len}1101${server_lla}${src_lla} # udp header and dhcpv6 header - reply+=022302220054ffff${reply_code}010203 + reply+=0223022200${msg_len}ffff${reply_code}010203 # Client identifier reply+=0001000a00030001${src_mac} # IA-NA - reply+=0003002801020304ffffffffffffffff00050018${offer_ip}ffffffffffffffff + if test $offer_ip != 1; then + reply+=0003002801020304ffffffffffffffff00050018${offer_ip}ffffffffffffffff + fi # Server identifier reply+=0002000a00030001${server_mac} echo $reply | trim_zeros >> $inport.expected @@ -3950,6 +3974,21 @@ $PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif4-tx.pcap | trim_zeros > 4.pa cat 4.expected > expout AT_CHECK([cat 4.packets], [0], [expout]) +# Send DHCPv6 packet on ls1-lp3. native DHCPv6 works as stateless mode for this port. +# The DHCPv6 reply should doesn't contian offer_ip. +src_mac=f00000000022 +src_lla=fe80000000000000f20000fffe000022 +reset_pcap_file hv1-vif5 hv1/vif5 +test_dhcpv6 5 $src_mac $src_lla 01 1 5 + +# NXT_RESUMEs should be 3. +OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif5-tx.pcap | trim_zeros > 5.packets +# Skipping the UDP checksum +cat 5.expected | cut -c 1-120,125- > expout +AT_CHECK([cat 5.packets | cut -c 1-120,125- ], [0], [expout]) + as hv1 OVS_APP_EXIT_AND_WAIT([ovn-controller]) OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) -- 2.7.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev