OVN implements native DHCPv6. DHCPv6 options are stored in the 'DHCP_Options' NB table and logical ports refer to this table to configure the DHCPv6 options.
For each logical port configured with DHCPv6 Options following flows are added - A logical flow which copies the DHCPv6 options to the DHCPv6 request packets using the 'put_dhcpv6_opts' action and advances the packet to the next stage. - A logical flow which implements the DHCPv6 reponder by sending the DHCPv6 reply back to the inport once the 'put_dhcpv6_opts' action is applied. Signed-off-by: Numan Siddique <nusid...@redhat.com> --- lib/packets.h | 1 + ovn/northd/ovn-northd.8.xml | 66 ++++++++++++- ovn/northd/ovn-northd.c | 171 ++++++++++++++++++++++++++++++++- ovn/ovn-nb.ovsschema | 9 +- ovn/ovn-nb.xml | 75 ++++++++++++++- tests/ovn.at | 226 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 538 insertions(+), 10 deletions(-) diff --git a/lib/packets.h b/lib/packets.h index 9b98b29..dcfcd04 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -920,6 +920,7 @@ static inline bool ipv6_addr_equals(const struct in6_addr *a, #endif } +/* Checks the IPv6 address in 'mask' for all zeroes. */ static inline bool ipv6_mask_is_any(const struct in6_addr *mask) { return ipv6_addr_equals(mask, &in6addr_any); } diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml index 7797417..a26c4aa 100644 --- a/ovn/northd/ovn-northd.8.xml +++ b/ovn/northd/ovn-northd.8.xml @@ -487,8 +487,9 @@ nd_na { <h3>Ingress Table 10: DHCP option processing</h3> <p> - This table adds the DHCPv4 options to a DHCPv4 packet from the - logical ports configured with IPv4 address(es) and DHCPv4 options. + This table adds the DHCPv4 options to a DHCPv4 packet and DHCPv6 options + to a DHCPv6 packet from the logical ports configured with IPv4 address(es) + and DHCPv4 options and IPv6 address(es) and DHCPv6 options. </p> <ul> @@ -516,6 +517,29 @@ next; </li> <li> + <p> + A priority-100 logical flow is added for these logical ports + which matches the IPv6 packet with <code>udp.src</code> = 546 and + <code>udp.dst</code> = 547 and applies the action + <code>put_dhcpv6_opts</code> and advances the packet to the next + table. + </p> + + <pre> +reg0[3] = put_dhcpv6_opts(ia_addr = <var>0</var>, <i>options</i>...); +next; + </pre> + + <p> + For DHCPv6 Solicit/Request/Confirm packets, this transforms the + packet into a DHCPv6 Advertise/Reply, adds the DHCPv6 offer IP + <var>O</var> and options to the packet, and stores 1 into reg0[3]. + For other kinds of packets, it just stores 0 into reg0[3]. Either + way, it continues to the next table. + </p> + </li> + + <li> A priority-0 flow that matches all packets to advances to table 11. </li> </ul> @@ -563,6 +587,41 @@ output; </li> <li> + <p> + A priority 100 logical flow is added for the logical ports configured + with DHCPv6 options which matches IPv6 packets with <code>udp.src == 546 + && udp.dst == 547 && reg0[3] == 1</code> and + responds back to the <code>inport</code> after applying these + actions. If <code>reg0[3]</code> is set to 1, it means that the + action <code>put_dhcpv6_opts</code> was successful. + </p> + + <pre> +eth.dst = eth.src; +eth.src = <var>E</var>; +ip6.dst = <var>O</var>; +ip6.src = <var>S</var>; +udp.src = 547; +udp.dst = 546; +outport = <var>P</var>; +inport = ""; /* Allow sending out inport. */ +output; + </pre> + + <p> + where <var>E</var> is the server MAC address and <var>S</var> is the + server IPv6 LLA address generated from the <code>server_id</code> + defined in the DHCPv6 options and <var>O</var> is + the IPv6 address defined in the logical port's addresses column. + </p> + + <p> + (This terminates packet processing; the packet does not go on the + next ingress table.) + </p> + </li> + + <li> A priority-0 flow that matches all packets to advances to table 12. </li> </ul> @@ -643,7 +702,8 @@ output; <p> Also a priority 34000 logical flow is added for each logical port which - has DHCPv4 options defined to allow the DHCPv4 reply packet from the + has DHCPv4 options defined to allow the DHCPv4 reply packet and which has + DHCPv6 options defined to allow the DHCPv6 reply packet from the <code>Ingress Table 11: DHCP responses</code>. </p> diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index d6c14cf..79683c1 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -1811,6 +1811,72 @@ build_dhcpv4_action(struct ovn_port *op, ovs_be32 offer_ip, } static bool +build_dhcpv6_action(struct ovn_port *op, struct in6_addr *offer_ip, + struct ds *options_action, struct ds *response_action) +{ + if (!op->nbsp->dhcpv6_options) { + /* CMS has disabled native DHCPv6 for this lport. */ + return false; + } + + struct in6_addr host_ip, mask; + + char *error = ipv6_parse_masked(op->nbsp->dhcpv6_options->cidr, &host_ip, + &mask); + if (error) { + free(error); + return false; + } + struct in6_addr ip6_mask = ipv6_addr_bitxor(offer_ip, &host_ip); + ip6_mask = ipv6_addr_bitand(&ip6_mask, &mask); + if (!ipv6_mask_is_any(&ip6_mask)) { + /* offer_ip doesn't belongs to the cidr defined in lport's DHCPv6 + * options.*/ + return false; + } + + /* "server_id" should be the MAC address. */ + const char *server_mac = smap_get(&op->nbsp->dhcpv6_options->options, + "server_id"); + struct eth_addr ea; + if (!server_mac || !eth_addr_from_string(server_mac, &ea)) { + /* "server_id" should be present in the dhcpv6_options. */ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + VLOG_WARN_RL(&rl, "server_id not present in the DHCPv6 options" + " for lport %s", op->json_key); + return false; + } + + /* Get the link local ip of the DHCPv6 server from the server mac. */ + struct in6_addr lla; + in6_generate_lla(ea, &lla); + + char server_ip[INET6_ADDRSTRLEN + 1]; + ipv6_string_mapped(server_ip, &lla); + + char ia_addr[INET6_ADDRSTRLEN + 1]; + ipv6_string_mapped(ia_addr, offer_ip); + + ds_put_format(options_action, + REGBIT_DHCP_OPTS_RESULT" = put_dhcpv6_opts(ia_addr = %s, ", + ia_addr); + struct smap_node *node; + SMAP_FOR_EACH(node, &op->nbsp->dhcpv6_options->options) { + ds_put_format(options_action, "%s = %s, ", node->key, node->value); + } + ds_chomp(options_action, ' '); + ds_chomp(options_action, ','); + ds_put_cstr(options_action, "); next;"); + + ds_put_format(response_action, "eth.dst = eth.src; eth.src = %s; " + "ip6.dst = ip6.src; ip6.src = %s; udp.src = 547; " + "udp.dst = 546; outport = inport; flags.loopback = 1; " + "output;", + server_mac, server_ip); + return true; +} + +static bool has_stateful_acl(struct ovn_datapath *od) { for (size_t i = 0; i < od->nbs->n_acls; i++) { @@ -2241,6 +2307,32 @@ build_acls(struct ovn_datapath *od, struct hmap *lflows) actions); } } + + if (od->nbs->ports[i]->dhcpv6_options) { + const char *server_mac = smap_get( + &od->nbs->ports[i]->dhcpv6_options->options, "server_id"); + struct eth_addr ea; + if (server_mac && eth_addr_from_string(server_mac, &ea)) { + /* Get the link local ip of the DHCPv6 server from the + * server mac. */ + struct in6_addr lla; + in6_generate_lla(ea, &lla); + + char server_ip[IPV6_SCAN_LEN + 1]; + ipv6_string_mapped(server_ip, &lla); + + struct ds match = DS_EMPTY_INITIALIZER; + const char *actions = has_stateful ? "ct_commit; next;" : + "next;"; + ds_put_format(&match, "outport == \"%s\" && eth.src == %s " + "&& ip6.src == %s && udp && udp.src == 547 " + "&& udp.dst == 546", od->nbs->ports[i]->name, + server_mac, server_ip); + ovn_lflow_add( + lflows, od, S_SWITCH_OUT_ACL, 34000, ds_cstr(&match), + actions); + } + } } } } @@ -2533,8 +2625,9 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, continue; } - if (!op->nbsp->dhcpv4_options) { - /* CMS has disabled native DHCPv4 for this lport. */ + if (!op->nbsp->dhcpv4_options && !op->nbsp->dhcpv6_options) { + /* CMS has disabled both native DHCPv4 and DHCPv6 for this lport. + */ continue; } @@ -2567,6 +2660,34 @@ build_lswitch_flows(struct hmap *datapaths, struct hmap *ports, break; } } + + for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs; j++) { + struct ds options_action = DS_EMPTY_INITIALIZER; + struct ds response_action = DS_EMPTY_INITIALIZER; + if (build_dhcpv6_action( + op, &op->lsp_addrs[i].ipv6_addrs[j].addr, + &options_action, &response_action)) { + struct ds match = DS_EMPTY_INITIALIZER; + ds_put_format( + &match, "inport == %s && eth.src == %s" + " && ip6.dst == ff02::1:2 && udp.src == 546 &&" + " udp.dst == 547", op->json_key, + op->lsp_addrs[i].ea_s); + + ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_OPTIONS, 100, + ds_cstr(&match), ds_cstr(&options_action)); + + /* If REGBIT_DHCP_OPTS_RESULT is set to 1, it means the + * put_dhcpv6_opts action is successful */ + ds_put_cstr(&match, " && "REGBIT_DHCP_OPTS_RESULT); + ovn_lflow_add(lflows, op->od, S_SWITCH_IN_DHCP_RESPONSE, 100, + ds_cstr(&match), ds_cstr(&response_action)); + ds_destroy(&match); + ds_destroy(&options_action); + ds_destroy(&response_action); + break; + } + } } } @@ -3940,6 +4061,13 @@ static struct dhcp_opts_map supported_dhcp_opts[] = { DHCP_OPT_T2 }; +static struct dhcp_opts_map supported_dhcpv6_opts[] = { + DHCPV6_OPT_IA_ADDR, + DHCPV6_OPT_SERVER_ID, + DHCPV6_OPT_DOMAIN_SEARCH, + DHCPV6_OPT_DNS_SERVER +}; + static void check_and_add_supported_dhcp_opts_to_sb_db(struct northd_context *ctx) { @@ -3973,6 +4101,39 @@ check_and_add_supported_dhcp_opts_to_sb_db(struct northd_context *ctx) hmap_destroy(&dhcp_opts_to_add); } +static void +check_and_add_supported_dhcpv6_opts_to_sb_db(struct northd_context *ctx) +{ + struct hmap dhcpv6_opts_to_add = HMAP_INITIALIZER(&dhcpv6_opts_to_add); + for (size_t i = 0; (i < sizeof(supported_dhcpv6_opts) / + sizeof(supported_dhcpv6_opts[0])); i++) { + hmap_insert(&dhcpv6_opts_to_add, &supported_dhcpv6_opts[i].hmap_node, + dhcp_opt_hash(supported_dhcpv6_opts[i].name)); + } + + const struct sbrec_dhcpv6_options *opt_row, *opt_row_next; + SBREC_DHCPV6_OPTIONS_FOR_EACH_SAFE(opt_row, opt_row_next, ctx->ovnsb_idl) { + struct dhcp_opts_map *dhcp_opt = + dhcp_opts_find(&dhcpv6_opts_to_add, opt_row->name); + if (dhcp_opt) { + hmap_remove(&dhcpv6_opts_to_add, &dhcp_opt->hmap_node); + } else { + sbrec_dhcpv6_options_delete(opt_row); + } + } + + struct dhcp_opts_map *opt; + HMAP_FOR_EACH(opt, hmap_node, &dhcpv6_opts_to_add) { + struct sbrec_dhcpv6_options *sbrec_dhcpv6_option = + sbrec_dhcpv6_options_insert(ctx->ovnsb_txn); + sbrec_dhcpv6_options_set_name(sbrec_dhcpv6_option, opt->name); + sbrec_dhcpv6_options_set_code(sbrec_dhcpv6_option, opt->code); + sbrec_dhcpv6_options_set_type(sbrec_dhcpv6_option, opt->type); + } + + hmap_destroy(&dhcpv6_opts_to_add); +} + /* Updates the sb_cfg and hv_cfg columns in the northbound NB_Global table. */ static void update_northbound_cfg(struct northd_context *ctx, @@ -4193,7 +4354,10 @@ main(int argc, char *argv[]) add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_code); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_type); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcp_options_col_name); - + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dhcpv6_options); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_code); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_type); + add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dhcpv6_options_col_name); ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_address_set); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_name); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_address_set_col_addresses); @@ -4215,6 +4379,7 @@ main(int argc, char *argv[]) ovnsb_db_run(&ctx, &ovnsb_idl_loop); if (ctx.ovnsb_txn) { check_and_add_supported_dhcp_opts_to_sb_db(&ctx); + check_and_add_supported_dhcpv6_opts_to_sb_db(&ctx); } unixctl_server_run(unixctl); diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema index 660db76..6e33135 100644 --- a/ovn/ovn-nb.ovsschema +++ b/ovn/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.3.0", - "cksum": "1305504870 9051", + "version": "5.3.1", + "cksum": "3864094809 9343", "tables": { "NB_Global": { "columns": { @@ -69,6 +69,11 @@ "refType": "weak"}, "min": 0, "max": 1}}, + "dhcpv6_options": {"type": {"key": {"type": "uuid", + "refTable": "DHCP_Options", + "refType": "weak"}, + "min": 0, + "max": 1}}, "external_ids": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml index 4ce295a..e5f06fb 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -593,6 +593,12 @@ Please see the <ref table="DHCP_Options"/> table. </column> + <column name="dhcpv6_options"> + This column defines the DHCPv6 Options to be included by the + <code>ovn-controller</code> when it replies to the DHCPv6 requests. + Please see the <ref table="DHCP_Options"/> table. + </column> + <column name="external_ids"> See <em>External IDs</em> at the beginning of this document. </column> @@ -1025,11 +1031,15 @@ DHCPv4 options to be configured and applied at each compute host running ovn-controller. </p> + <p> + OVN also implements a native DHCPv6 support which provides stateless + replies to DHCPv6 requests. + </p> <column name="cidr"> <p> - The DHCPv4 options will be included if the logical port has the IPv4 - address in this <ref column="cidr"/>. + The DHCPv4/DHCPv6 options will be included if the logical port has the + IP address in this <ref column="cidr"/>. </p> </column> @@ -1236,6 +1246,67 @@ </group> </group> + <group title="DHCPv6 options"> + <p> + OVN also implements native DHCPv6 support. CMS should define + the set of DHCPv6 options as key/value pairs. The define DHCPv6 + options will be included in the DHCPv6 response to the DHCPv6 + Solicit/Request/Confirm packet from the logical ports having the + IPv6 addresses in the <ref column="cidr"/>. + </p> + + <group title="Mandatory DHCPv4 options"> + <p> + The following options must be defined. + </p> + + <column name="options" key="server_id"> + <p> + The Ethernet address for the DHCP server to use. This is also + included in the DHCPv6 reply as option 2, ``Server Identifier'' + to carry a DUID identifying a server between a client and a server. + <code>ovn-controller</code> defines DUID Based on + Link-layer Address [DUID-LL] + </p> + </column> + </group> + + <group title="IPv6 DHCPv6 options"> + <p> + Below are the supported DHCPv6 options whose values are an IPv6 + address, e.g. <code>aef0::4</code>. Some options accept multiple + IPv6 addresses enclosed within curly braces, e.g. <code>{aef0::4, + aef0::5}</code>. Please refer the RFC 3315 for more details on + DHCPv6 options and their codes. + </p> + + <column name="options" key="dns_server"> + <p> + The DHCPv6 option code for this option is 23. This option is used + to specify the DNS servers. + </p> + </column> + </group> + + <group title="String DHCPv6 options"> + <p> + These options accept string values. + </p> + + <column name="options" key="domain_search"> + <p> + The DHCPv6 option code for this option is 24. This option is used + to specify the domain search list the client can use when resolving + hostnames with DNS. + </p> + + <p> + Example: <code>"ovn.org"</code>. + </p> + </column> + </group> + </group> + <group title="Common Columns"> <column name="external_ids"> See <em>External IDs</em> at the beginning of this document. diff --git a/tests/ovn.at b/tests/ovn.at index 7f6758a..602d873 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -3296,6 +3296,232 @@ OVS_APP_EXIT_AND_WAIT([ovsdb-server]) AT_CLEANUP +AT_SETUP([ovn -- dhcpv6 : 1 HV, 2 LS, 2 LSPs/LS]) +AT_KEYWORDS([dhcpv6]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +ovn_start + +ovn-nbctl ls-add ls1 +ovn-nbctl lsp-add ls1 ls1-lp1 \ +-- lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01 10.0.0.4 ae70::4" + +ovn-nbctl lsp-set-port-security ls1-lp1 "f0:00:00:00:00:01 10.0.0.4 ae70::4" + +ovn-nbctl lsp-add ls1 ls1-lp2 \ +-- lsp-set-addresses ls1-lp2 "f0:00:00:00:00:02 ae70::5" + +ovn-nbctl lsp-set-port-security ls1-lp2 "f0:00:00:00:00:02 ae70::5" + +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 ls-add ls2 +ovn-nbctl lsp-add ls2 ls2-lp1 \ +-- lsp-set-addresses ls2-lp1 "f0:00:00:00:00:03 be70::3" +ovn-nbctl lsp-set-port-security ls2-lp1 "f0:00:00:00:00:03 be70::3" +ovn-nbctl lsp-add ls2 ls2-lp2 \ +-- lsp-set-addresses ls2-lp2 "f0:00:00:00:00:04 be70::4" +ovn-nbctl lsp-set-port-security ls2-lp2 "f0:00:00:00:00:04 be70::4" + +net_add n1 +sim_add hv1 + +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +ovs-vsctl -- add-port br-int hv1-vif2 -- \ + set interface hv1-vif2 external-ids:iface-id=ls1-lp2 \ + options:tx_pcap=hv1/vif2-tx.pcap \ + options:rxq_pcap=hv1/vif2-rx.pcap \ + ofport-request=2 + +ovs-vsctl -- add-port br-int hv1-vif3 -- \ + set interface hv1-vif3 external-ids:iface-id=ls2-lp1 \ + options:tx_pcap=hv1/vif3-tx.pcap \ + options:rxq_pcap=hv1/vif3-rx.pcap \ + ofport-request=3 + +ovs-vsctl -- add-port br-int hv1-vif4 -- \ + set interface hv1-vif4 external-ids:iface-id=ls2-lp2 \ + options:tx_pcap=hv1/vif4-tx.pcap \ + options:rxq_pcap=hv1/vif4-rx.pcap \ + ofport-request=4 + +ovn_populate_arp + +sleep 2 + +trim_zeros() { + sed 's/\(00\)\{1,\}$//' +} + +# 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 +# packet should be received twice (one from ovn-controller and the other +# from the "ovs-ofctl monitor br-int resume" +test_dhcpv6() { + local inport=$1 src_mac=$2 src_lla=$3 msg_code=$4 offer_ip=$5 + local request=ffffffffffff${src_mac}86dd00000000002a1101${src_lla} + # dst ip ff02::1:2 + request+=ff020000000000000000000000010002 + # udp header and dhcpv6 header + request+=02220223002affff${msg_code}010203 + # Client identifier + request+=0001000a00030001${src_mac} + # IA-NA (Identity Association for Non Temporary Address) + request+=0003000c0102030400000e1000001518 + shift; shift; shift; shift; shift; + if test $offer_ip != 0; then + local server_mac=000000100001 + local server_lla=fe80000000000000020000fffe100001 + local reply_code=07 + if test $msg_code = 01; then + reply_code=02 + fi + local reply=${src_mac}${server_mac}86dd0000000000541101${server_lla}${src_lla} + # udp header and dhcpv6 header + reply+=022302220054ffff${reply_code}010203 + # Client identifier + reply+=0001000a00030001${src_mac} + # IA-NA + reply+=0003002801020304ffffffffffffffff00050018${offer_ip}ffffffffffffffff + # Server identifier + reply+=0002000a00030001${server_mac} + echo $reply | trim_zeros >> $inport.expected + else + for outport; do + echo $request | trim_zeros >> $outport.expected + done + fi + + as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request +} + +reset_pcap_file() { + local iface=$1 + local pcap_file=$2 + ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \ +options:rxq_pcap=dummy-rx.pcap + rm -f ${pcap_file}*.pcap + ovs-vsctl -- set Interface $iface options:tx_pcap=${pcap_file}-tx.pcap \ +options:rxq_pcap=${pcap_file}-rx.pcap +} + +AT_CAPTURE_FILE([ofctl_monitor0.log]) +as hv1 ovs-ofctl monitor br-int resume --detach --no-chdir \ +--pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log + +echo "---------NB dump-----" +ovn-nbctl show +echo "---------------------" +echo "---------SB dump-----" +ovn-sbctl list datapath_binding +echo "---------------------" +ovn-sbctl list logical_flow +echo "---------------------" + +echo "---------------------" +ovn-sbctl dump-flows +echo "---------------------" + +echo "------ hv1 dump ----------" +as hv1 ovs-ofctl dump-flows br-int + +src_mac=f00000000001 +src_lla=fe80000000000000f20000fffe000001 +offer_ip=ae700000000000000000000000000004 +test_dhcpv6 1 $src_mac $src_lla 01 $offer_ip + +# NXT_RESUMEs should be 1. +OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap | trim_zeros > 1.packets +# cat 1.expected | trim_zeros > expout +cat 1.expected | cut -c -120 > expout +AT_CHECK([cat 1.packets | cut -c -120], [0], [expout]) +# Skipping the UDP checksum +cat 1.expected | cut -c 125- > expout +AT_CHECK([cat 1.packets | cut -c 125-], [0], [expout]) + +rm 1.expected + +# Send invalid packet on ls1-lp2. ovn-controller should resume the packet +# without any modifications and the packet should be received by ls1-lp1. +# ls1-lp1 will receive the packet twice, one from the ovn-controller after the +# resume and the other from ovs-ofctl monitor resume. + +reset_pcap_file hv1-vif1 hv1/vif1 +reset_pcap_file hv1-vif2 hv1/vif2 + +src_mac=f00000000002 +src_lla=fe80000000000000f20000fffe000002 +offer_ip=ae700000000000000000000000000005 +# Set invalid msg_type + +test_dhcpv6 2 $src_mac $src_lla 10 0 1 1 + +# NXT_RESUMEs should be 2. +OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + +# vif2-tx.pcap should not have received the DHCPv6 reply packet +rm 2.packets +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap | trim_zeros > 2.packets +AT_CHECK([cat 2.packets], [0], []) + +# vif1-tx.pcap should have received the DHCPv6 (invalid) request packet +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap | trim_zeros > 1.packets +cat 1.expected > expout +AT_CHECK([cat 1.packets], [0], [expout]) + +# Send DHCPv6 packet on ls2-lp1. native DHCPv6 is disabled on this port. +# There should be no DHCPv6 reply from ovn-controller and the request packet +# should be received by ls2-lp2. + +src_mac=f00000000003 +src_lla=fe80000000000000f20000fffe000003 +test_dhcpv6 3 $src_mac $src_lla 01 0 4 + +# NXT_RESUMEs should be 2 only. +OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) + +# vif3-tx.pcap should not have received the DHCPv6 reply packet +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif3-tx.pcap | trim_zeros > 3.packets +AT_CHECK([cat 3.packets], [0], []) + +# vif4-tx.pcap should have received the DHCPv6 request packet +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif4-tx.pcap | trim_zeros > 4.packets +cat 4.expected > expout +AT_CHECK([cat 4.packets], [0], [expout]) + +as hv1 +OVS_APP_EXIT_AND_WAIT([ovn-controller]) +OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as main +OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +AT_CLEANUP + AT_SETUP([ovn -- 2 HVs, 2 LRs connected via LS, gateway router]) AT_KEYWORDS([ovngatewayrouter]) AT_SKIP_IF([test $HAVE_PYTHON = no]) -- 2.7.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev