diff mbox series

[ovs-dev,v3,ovn,2/2] northd: add logical flows for dhcpv6 pfd parsing

Message ID df85460db21e9e6d4977801b965b35623edb5377.1575542805.git.lorenzo.bianconi@redhat.com
State Superseded
Headers show
Series Add IPv6 Prefix delegation (RFC3633) | expand

Commit Message

Lorenzo Bianconi Dec. 5, 2019, 10:50 a.m. UTC
Introduce logical flows in ovn router pipeline in order to parse dhcpv6
advertise/reply from IPv6 prefix delegation router.
Do not overwrite ipv6_ra_pd_list info in options column of SB port_binding
table written by ovn-controller

Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
---
 northd/ovn-northd.c |  69 +++++++++++++++++++++++++++-
 ovn-nb.xml          |  17 +++++++
 tests/atlocal.in    |   5 +-
 tests/system-ovn.at | 109 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 198 insertions(+), 2 deletions(-)

Comments

Numan Siddique Dec. 16, 2019, 10:43 p.m. UTC | #1
On Thu, Dec 5, 2019 at 5:51 AM Lorenzo Bianconi
<lorenzo.bianconi@redhat.com> wrote:
>
> Introduce logical flows in ovn router pipeline in order to parse dhcpv6
> advertise/reply from IPv6 prefix delegation router.
> Do not overwrite ipv6_ra_pd_list info in options column of SB port_binding
> table written by ovn-controller
>
> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@redhat.com>
> ---
>  northd/ovn-northd.c |  69 +++++++++++++++++++++++++++-
>  ovn-nb.xml          |  17 +++++++
>  tests/atlocal.in    |   5 +-
>  tests/system-ovn.at | 109 ++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 198 insertions(+), 2 deletions(-)
>
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index f0847d81e..8c50218ee 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -2644,6 +2644,8 @@ ovn_port_update_sbrec(struct northd_context *ctx,
>                        struct sset *active_ha_chassis_grps)
>  {
>      sbrec_port_binding_set_datapath(op->sb, op->od->sb);
> +    const char *ipv6_pd_list = NULL;
> +
>      if (op->nbrp) {
>          /* If the router is for l3 gateway, it resides on a chassis
>           * and its port type is "l3gateway". */
> @@ -2766,6 +2768,12 @@ ovn_port_update_sbrec(struct northd_context *ctx,
>                  smap_add(&new, "l3gateway-chassis", chassis_name);
>              }
>          }
> +
> +        ipv6_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list");
> +        if (ipv6_pd_list) {
> +            smap_add(&new, "ipv6_ra_pd_list", ipv6_pd_list);
> +        }
> +
>          sbrec_port_binding_set_options(op->sb, &new);
>          smap_destroy(&new);
>
> @@ -2815,6 +2823,12 @@ ovn_port_update_sbrec(struct northd_context *ctx,
>                  smap_add_format(&options,
>                                  "qdisc_queue_id", "%d", queue_id);
>              }
> +
> +            ipv6_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list");
> +            if (ipv6_pd_list) {
> +                smap_add(&options, "ipv6_ra_pd_list", ipv6_pd_list);
> +            }
> +
>              sbrec_port_binding_set_options(op->sb, &options);
>              smap_destroy(&options);
>              if (ovn_is_known_nb_lsp_type(op->nbsp->type)) {
> @@ -2864,6 +2878,12 @@ ovn_port_update_sbrec(struct northd_context *ctx,
>                  if (chassis) {
>                      smap_add(&new, "l3gateway-chassis", chassis);
>                  }
> +
> +                ipv6_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list");
> +                if (ipv6_pd_list) {
> +                    smap_add(&new, "ipv6_ra_pd_list", ipv6_pd_list);
> +                }
> +
>                  sbrec_port_binding_set_options(op->sb, &new);
>                  smap_destroy(&new);
>              } else {
> @@ -7833,7 +7853,36 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
>          free(snat_ips);
>      }
>
> -    /* Logical router ingress table 3: IP Input for IPv6. */
> +    /* DHCPv6 reply handling */
> +    HMAP_FOR_EACH (op, key_node, ports) {
> +        if (!op->nbrp) {
> +            continue;
> +        }
> +
> +        if (op->derived) {
> +            continue;
> +        }
> +
> +        struct lport_addresses lrp_networks;
> +        if (!extract_lrp_networks(op->nbrp, &lrp_networks)) {
> +            continue;
> +        }
> +
> +        for (size_t i = 0; i < lrp_networks.n_ipv6_addrs; i++) {
> +            ds_clear(&actions);
> +            ds_clear(&match);
> +            ds_put_format(&match, "ip6.dst == %s && udp.src == 547 &&"
> +                          " udp.dst == 546",
> +                          lrp_networks.ipv6_addrs[i].addr_s);
> +            ds_put_format(&actions, "reg0 = 0; handle_dhcpv6_reply { "
> +                          "eth.dst <-> eth.src; ip6.dst <-> ip6.src; "
> +                          "outport <-> inport; output; };");
> +            ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
> +                          ds_cstr(&match), ds_cstr(&actions));
> +        }
> +    }
> +
> +    /* Logical router ingress table 1: IP Input for IPv6. */
>      HMAP_FOR_EACH (op, key_node, ports) {
>          if (!op->nbrp) {
>              continue;
> @@ -8634,6 +8683,24 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
>              continue;
>          }
>
> +        struct smap options;
> +        /* enable IPv6 prefix delegation */
> +        bool prefix_delegation = smap_get_bool(&op->nbrp->options,
> +                                               "prefix_delegation", false);
> +        if (prefix_delegation) {
> +            smap_clone(&options, &op->sb->options);
> +            smap_add(&options, "ipv6_prefix_delegation", "true");
> +            sbrec_port_binding_set_options(op->sb, &options);
> +            smap_destroy(&options);
> +        }
> +
> +        if (smap_get_bool(&op->nbrp->options, "prefix", false)) {
> +            smap_clone(&options, &op->sb->options);
> +            smap_add(&options, "ipv6_prefix", "true");
> +            sbrec_port_binding_set_options(op->sb, &options);
> +            smap_destroy(&options);
> +        }
> +
>          const char *address_mode = smap_get(
>              &op->nbrp->ipv6_ra_configs, "address_mode");
>
> diff --git a/ovn-nb.xml b/ovn-nb.xml
> index 5ae52bbde..d7fddcae2 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -2142,6 +2142,23 @@
>            to <code>true</code>.
>          </p>
>        </column>
> +
> +      <column name="options" key="prefix_delegation"
> +              type='{"type": "boolean"}'>
> +        <p>
> +          If set to <code>true</code>, enable IPv6 prefix delegation state
> +          machine on this logical router port (RFC3633). IPv6 prefix
> +          delegation is available just on a gateway router or on a gateway
> +          router port.
> +        </p>
> +      </column>
> +
> +      <column name="options" key="prefix" type='{"type": "boolean"}'>
> +        <p>
> +          If set to <code>true</code>, this interface will receive an IPv6
> +          prefix according to RFC3663
> +        </p>
> +      </column>
>      </group>
>
>      <group title="Attachment">
> diff --git a/tests/atlocal.in b/tests/atlocal.in
> index 5f14c3da0..8f3ff03b9 100644
> --- a/tests/atlocal.in
> +++ b/tests/atlocal.in
> @@ -157,7 +157,7 @@ find_command()
>  {
>      which $1 > /dev/null 2>&1
>      status=$?
> -    var=HAVE_`echo "$1" | tr '[a-z]' '[A-Z]'`
> +    var=HAVE_`echo "$1" | tr '-' '_' | tr '[a-z]' '[A-Z]'`
>      if test "$status" = "0"; then
>          eval ${var}="yes"
>      else
> @@ -192,6 +192,9 @@ else
>      DIFF_SUPPORTS_NORMAL_FORMAT=no
>  fi
>
> +# Set HAVE_DIBBLER-SERVER
> +find_command dibbler-server
> +
>  # Turn off proxies.
>  unset http_proxy
>  unset https_proxy
> diff --git a/tests/system-ovn.at b/tests/system-ovn.at
> index 1a5b0bb7e..dbff58f24 100644
> --- a/tests/system-ovn.at
> +++ b/tests/system-ovn.at
> @@ -3425,3 +3425,112 @@ OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
>  /connection dropped.*/d"])
>
>  AT_CLEANUP
> +
> +AT_SETUP([ovn -- IPv6 prefix delegation])
> +AT_SKIP_IF([test $HAVE_DIBBLER_SERVER = no])
> +AT_KEYWORDS([ovn-ipv6-prefix_d])
> +
> +ovn_start
> +OVS_TRAFFIC_VSWITCHD_START()
> +ADD_BR([br-int])
> +
> +# Set external-ids in br-int needed for ovn-controller
> +ovs-vsctl \
> +        -- set Open_vSwitch . external-ids:system-id=hv1 \
> +        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
> +        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
> +        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
> +        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
> +
> +# Start ovn-controller
> +start_daemon ovn-controller
> +
> +# Logical network:
> +# One LR R1 with switches foo (192.168.1.0/24), bar (192.168.2.0/24),
> +# and alice (172.16.1.0/24) connected to it.  The port between R1 and
> +# alice is the router gateway port where the R1 NAT rules are applied.
> +#
> +#    R1 -- join -- dibbler-server
> +#     |
> +#    bar
> +
> +ovn-nbctl lr-add R1
> +
> +ovn-nbctl ls-add bar
> +ovn-nbctl ls-add join
> +
> +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:03 192.168.1.1/24
> +ovn-nbctl lrp-add R1 join 00:00:02:01:02:03 172.16.1.1/24 2001:db8:3333::1/64 \
> +    -- set Logical_Router_Port join options:redirect-chassis=hv1
> +
> +# Connect bar to R1
> +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
> +    type=router options:router-port=bar \
> +    -- lsp-set-addresses rp-bar router
> +
> +# Connect join to R1
> +ovn-nbctl lsp-add join rp-join -- set Logical_Switch_Port rp-join \
> +    type=router options:router-port=join \
> +    -- lsp-set-addresses rp-join router
> +
> +# Logical port 'bar1' in switch 'bar'.
> +ADD_NAMESPACES(bar1)
> +ADD_VETH(bar1, bar1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
> +         "192.168.1.1")
> +ovn-nbctl lsp-add bar bar1 \
> +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2"
> +
> +# Logical port 'join1' in switch 'join'.
> +ADD_NAMESPACES(join1)
> +ADD_VETH(join1, join1, br-int, "2001:db8:3333::2/64", "f0:00:00:01:02:05", \
> +         "2001:db8:3333::1")
> +OVS_WAIT_UNTIL([test "$(ip netns exec join1 ip a | grep 2001:db8:3333::2 | grep tentative)" = ""])
> +ovn-nbctl lsp-add join join1 \
> +-- lsp-set-addresses join1 "f0:00:00:01:02:05 2001:db8:3333::2"
> +
> +ovn-nbctl set logical_router_port join options:prefix_delegation=true
> +ovn-nbctl set logical_router_port join options:prefix=true
> +
> +# reset dibbler state
> +sed s/eth0/join1/g -i /etc/dibbler/server.conf
> +cat > /var/lib/dibbler/server-AddrMgr.xml <<EOF
> +<AddrMgr>
> +  <timestamp>1575481348</timestamp>
> +  <replayDetection>0</replayDetection>
> +</AddrMgr>
> +EOF
> +cat > /var/lib/dibbler/server-CfgMgr.xml <<EOF
> +<SrvCfgMgr>
> +  <workDir>/var/lib/dibbler</workDir>
> +  <LogName>Server</LogName>
> +  <LogLevel>8</LogLevel>
> +  <InactiveMode>0</InactiveMode>
> +  <GuessMode>0</GuessMode>
> +</SrvCfgMgr>
> +EOF
> +
> +NS_CHECK_EXEC([join1], [dibbler-server run &])

I think it's better to start dibbler-server in a port attached to the
provider bridge
instead of br-int.

Also can you please add another logical router port and make sure that
prefix delegation
address is learnt in both the router ports.

Something like

LR1
   -  Public  (with localnet port)
    - SW0 -> address learnt for this router port
     - SW1  -> address learnt for this router port.


Thanks
Numan

> +ovn-nbctl --wait=hv sync
> +
> +OVS_WAIT_UNTIL([ovn-sbctl list port_binding join | grep ipv6_ra_pd_list])
> +AT_CHECK([ovn-sbctl get port_binding join options:ipv6_ra_pd_list], [0], [dnl
> +"\"2001:db8:3333::6a2f:0:0\"/96"
> +])
> +kill $(pidof dibbler-server)
> +
> +sleep 2
> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
> +
> +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
> +OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
> +/connection dropped.*/d"])
> +AT_CLEANUP
> --
> 2.21.0
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
diff mbox series

Patch

diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
index f0847d81e..8c50218ee 100644
--- a/northd/ovn-northd.c
+++ b/northd/ovn-northd.c
@@ -2644,6 +2644,8 @@  ovn_port_update_sbrec(struct northd_context *ctx,
                       struct sset *active_ha_chassis_grps)
 {
     sbrec_port_binding_set_datapath(op->sb, op->od->sb);
+    const char *ipv6_pd_list = NULL;
+
     if (op->nbrp) {
         /* If the router is for l3 gateway, it resides on a chassis
          * and its port type is "l3gateway". */
@@ -2766,6 +2768,12 @@  ovn_port_update_sbrec(struct northd_context *ctx,
                 smap_add(&new, "l3gateway-chassis", chassis_name);
             }
         }
+
+        ipv6_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list");
+        if (ipv6_pd_list) {
+            smap_add(&new, "ipv6_ra_pd_list", ipv6_pd_list);
+        }
+
         sbrec_port_binding_set_options(op->sb, &new);
         smap_destroy(&new);
 
@@ -2815,6 +2823,12 @@  ovn_port_update_sbrec(struct northd_context *ctx,
                 smap_add_format(&options,
                                 "qdisc_queue_id", "%d", queue_id);
             }
+
+            ipv6_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list");
+            if (ipv6_pd_list) {
+                smap_add(&options, "ipv6_ra_pd_list", ipv6_pd_list);
+            }
+
             sbrec_port_binding_set_options(op->sb, &options);
             smap_destroy(&options);
             if (ovn_is_known_nb_lsp_type(op->nbsp->type)) {
@@ -2864,6 +2878,12 @@  ovn_port_update_sbrec(struct northd_context *ctx,
                 if (chassis) {
                     smap_add(&new, "l3gateway-chassis", chassis);
                 }
+
+                ipv6_pd_list = smap_get(&op->sb->options, "ipv6_ra_pd_list");
+                if (ipv6_pd_list) {
+                    smap_add(&new, "ipv6_ra_pd_list", ipv6_pd_list);
+                }
+
                 sbrec_port_binding_set_options(op->sb, &new);
                 smap_destroy(&new);
             } else {
@@ -7833,7 +7853,36 @@  build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
         free(snat_ips);
     }
 
-    /* Logical router ingress table 3: IP Input for IPv6. */
+    /* DHCPv6 reply handling */
+    HMAP_FOR_EACH (op, key_node, ports) {
+        if (!op->nbrp) {
+            continue;
+        }
+
+        if (op->derived) {
+            continue;
+        }
+
+        struct lport_addresses lrp_networks;
+        if (!extract_lrp_networks(op->nbrp, &lrp_networks)) {
+            continue;
+        }
+
+        for (size_t i = 0; i < lrp_networks.n_ipv6_addrs; i++) {
+            ds_clear(&actions);
+            ds_clear(&match);
+            ds_put_format(&match, "ip6.dst == %s && udp.src == 547 &&"
+                          " udp.dst == 546",
+                          lrp_networks.ipv6_addrs[i].addr_s);
+            ds_put_format(&actions, "reg0 = 0; handle_dhcpv6_reply { "
+                          "eth.dst <-> eth.src; ip6.dst <-> ip6.src; "
+                          "outport <-> inport; output; };");
+            ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_INPUT, 100,
+                          ds_cstr(&match), ds_cstr(&actions));
+        }
+    }
+
+    /* Logical router ingress table 1: IP Input for IPv6. */
     HMAP_FOR_EACH (op, key_node, ports) {
         if (!op->nbrp) {
             continue;
@@ -8634,6 +8683,24 @@  build_lrouter_flows(struct hmap *datapaths, struct hmap *ports,
             continue;
         }
 
+        struct smap options;
+        /* enable IPv6 prefix delegation */
+        bool prefix_delegation = smap_get_bool(&op->nbrp->options,
+                                               "prefix_delegation", false);
+        if (prefix_delegation) {
+            smap_clone(&options, &op->sb->options);
+            smap_add(&options, "ipv6_prefix_delegation", "true");
+            sbrec_port_binding_set_options(op->sb, &options);
+            smap_destroy(&options);
+        }
+
+        if (smap_get_bool(&op->nbrp->options, "prefix", false)) {
+            smap_clone(&options, &op->sb->options);
+            smap_add(&options, "ipv6_prefix", "true");
+            sbrec_port_binding_set_options(op->sb, &options);
+            smap_destroy(&options);
+        }
+
         const char *address_mode = smap_get(
             &op->nbrp->ipv6_ra_configs, "address_mode");
 
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 5ae52bbde..d7fddcae2 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -2142,6 +2142,23 @@ 
           to <code>true</code>.
         </p>
       </column>
+
+      <column name="options" key="prefix_delegation"
+              type='{"type": "boolean"}'>
+        <p>
+          If set to <code>true</code>, enable IPv6 prefix delegation state
+          machine on this logical router port (RFC3633). IPv6 prefix
+          delegation is available just on a gateway router or on a gateway
+          router port.
+        </p>
+      </column>
+
+      <column name="options" key="prefix" type='{"type": "boolean"}'>
+        <p>
+          If set to <code>true</code>, this interface will receive an IPv6
+          prefix according to RFC3663
+        </p>
+      </column>
     </group>
 
     <group title="Attachment">
diff --git a/tests/atlocal.in b/tests/atlocal.in
index 5f14c3da0..8f3ff03b9 100644
--- a/tests/atlocal.in
+++ b/tests/atlocal.in
@@ -157,7 +157,7 @@  find_command()
 {
     which $1 > /dev/null 2>&1
     status=$?
-    var=HAVE_`echo "$1" | tr '[a-z]' '[A-Z]'`
+    var=HAVE_`echo "$1" | tr '-' '_' | tr '[a-z]' '[A-Z]'`
     if test "$status" = "0"; then
         eval ${var}="yes"
     else
@@ -192,6 +192,9 @@  else
     DIFF_SUPPORTS_NORMAL_FORMAT=no
 fi
 
+# Set HAVE_DIBBLER-SERVER
+find_command dibbler-server
+
 # Turn off proxies.
 unset http_proxy
 unset https_proxy
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index 1a5b0bb7e..dbff58f24 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -3425,3 +3425,112 @@  OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
 /connection dropped.*/d"])
 
 AT_CLEANUP
+
+AT_SETUP([ovn -- IPv6 prefix delegation])
+AT_SKIP_IF([test $HAVE_DIBBLER_SERVER = no])
+AT_KEYWORDS([ovn-ipv6-prefix_d])
+
+ovn_start
+OVS_TRAFFIC_VSWITCHD_START()
+ADD_BR([br-int])
+
+# Set external-ids in br-int needed for ovn-controller
+ovs-vsctl \
+        -- set Open_vSwitch . external-ids:system-id=hv1 \
+        -- set Open_vSwitch . external-ids:ovn-remote=unix:$ovs_base/ovn-sb/ovn-sb.sock \
+        -- set Open_vSwitch . external-ids:ovn-encap-type=geneve \
+        -- set Open_vSwitch . external-ids:ovn-encap-ip=169.0.0.1 \
+        -- set bridge br-int fail-mode=secure other-config:disable-in-band=true
+
+# Start ovn-controller
+start_daemon ovn-controller
+
+# Logical network:
+# One LR R1 with switches foo (192.168.1.0/24), bar (192.168.2.0/24),
+# and alice (172.16.1.0/24) connected to it.  The port between R1 and
+# alice is the router gateway port where the R1 NAT rules are applied.
+#
+#    R1 -- join -- dibbler-server
+#     |
+#    bar
+
+ovn-nbctl lr-add R1
+
+ovn-nbctl ls-add bar
+ovn-nbctl ls-add join
+
+ovn-nbctl lrp-add R1 bar 00:00:01:01:02:03 192.168.1.1/24
+ovn-nbctl lrp-add R1 join 00:00:02:01:02:03 172.16.1.1/24 2001:db8:3333::1/64 \
+    -- set Logical_Router_Port join options:redirect-chassis=hv1
+
+# Connect bar to R1
+ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar \
+    type=router options:router-port=bar \
+    -- lsp-set-addresses rp-bar router
+
+# Connect join to R1
+ovn-nbctl lsp-add join rp-join -- set Logical_Switch_Port rp-join \
+    type=router options:router-port=join \
+    -- lsp-set-addresses rp-join router
+
+# Logical port 'bar1' in switch 'bar'.
+ADD_NAMESPACES(bar1)
+ADD_VETH(bar1, bar1, br-int, "192.168.1.2/24", "f0:00:00:01:02:03", \
+         "192.168.1.1")
+ovn-nbctl lsp-add bar bar1 \
+-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2"
+
+# Logical port 'join1' in switch 'join'.
+ADD_NAMESPACES(join1)
+ADD_VETH(join1, join1, br-int, "2001:db8:3333::2/64", "f0:00:00:01:02:05", \
+         "2001:db8:3333::1")
+OVS_WAIT_UNTIL([test "$(ip netns exec join1 ip a | grep 2001:db8:3333::2 | grep tentative)" = ""])
+ovn-nbctl lsp-add join join1 \
+-- lsp-set-addresses join1 "f0:00:00:01:02:05 2001:db8:3333::2"
+
+ovn-nbctl set logical_router_port join options:prefix_delegation=true
+ovn-nbctl set logical_router_port join options:prefix=true
+
+# reset dibbler state
+sed s/eth0/join1/g -i /etc/dibbler/server.conf
+cat > /var/lib/dibbler/server-AddrMgr.xml <<EOF
+<AddrMgr>
+  <timestamp>1575481348</timestamp>
+  <replayDetection>0</replayDetection>
+</AddrMgr>
+EOF
+cat > /var/lib/dibbler/server-CfgMgr.xml <<EOF
+<SrvCfgMgr>
+  <workDir>/var/lib/dibbler</workDir>
+  <LogName>Server</LogName>
+  <LogLevel>8</LogLevel>
+  <InactiveMode>0</InactiveMode>
+  <GuessMode>0</GuessMode>
+</SrvCfgMgr>
+EOF
+
+NS_CHECK_EXEC([join1], [dibbler-server run &])
+ovn-nbctl --wait=hv sync
+
+OVS_WAIT_UNTIL([ovn-sbctl list port_binding join | grep ipv6_ra_pd_list])
+AT_CHECK([ovn-sbctl get port_binding join options:ipv6_ra_pd_list], [0], [dnl
+"\"2001:db8:3333::6a2f:0:0\"/96"
+])
+kill $(pidof dibbler-server)
+
+sleep 2
+OVS_APP_EXIT_AND_WAIT([ovn-controller])
+
+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
+OVS_TRAFFIC_VSWITCHD_STOP(["/failed to query port patch-.*/d
+/connection dropped.*/d"])
+AT_CLEANUP