> Add an "ia_pd" DHCPv6 option that lets the CMS supply a delegated prefix in a
> logical port's DHCP_Options for OVN's native DHCPv6 server to hand out, with 
> no
> pool or lease state kept in the dataplane.  This lets OVN delegate a prefix
> (for example to a VM that in turn sub-delegates to its own workloads) while
> remaining the stateless responder it already is for IA_NA.
> 
> The server is request-aware per RFC 8415: it parses the client's IA_PD,
> captures its IAID, and emits an IA_PD -> IA_PREFIX carrying the configured
> prefix only when the client actually solicited one, echoing the client's IAID.
> Prefixes are advertised with infinite lifetimes, matching the existing IA_NA
> emit.  Only Solicit and Request elicit a delegated prefix; an IA_PD in 
> Confirm,
> Decline or Information-request is ignored, and only the first IA_PD from a
> client is honored (a single prefix is delegated).
> 
> A port must also receive a managed IPv6 address (ia_addr), which is what makes
> northd intercept its DHCPv6 traffic; PD-only ports are not yet supported.
> 
>   - lib/ovn-l7.h, northd/ovn-northd.c: register DHCPV6_OPT_IA_PD_PREFIX
>     ("ia_pd", code 25, type "ia_pd") and add it to supported_dhcpv6_opts[].
>   - lib/actions.c: encode the "ia_pd" type into the action buffer as
>     [plen][prefix], deriving plen from the value's mask.  parse_gen_opt
>     rejects a value that is not a single masked IPv6 prefix, since the mask
>     supplies the on-wire prefix length (a bare address would silently encode
>     a /0, and a set would drop all but the first).
>   - controller/pinctrl.c: parse the client IA_PD and emit the delegated
>     prefix, copying it with memcpy to avoid an unaligned struct in6_addr
>     access on strict-alignment architectures.
>   - ovn-sb.ovsschema: allow "ia_pd" in the DHCPv6_Options "type" column enum
>     and bump the schema version.  northd writes the supported option into the
>     Southbound DHCPv6_Options table, so without this every northd SB commit
>     failed with a constraint violation.
>   - ovn-nb.xml, ovn-sb.xml: document the new option and the SB type.
>   - tests: register ia_pd in the test harness, add put_dhcpv6_opts parse and
>     encode cases, and extend the dhcpv6 system test to exercise the
>     request-aware path (a sibling IA_NA-only port must not receive an IA_PD).
> 
> Signed-off-by: Dax Kelson <[email protected]>

Hi Dax,

just a nit inline.

Regards,
Lorenzo

> ---
>  controller/pinctrl.c | 84 +++++++++++++++++++++++++++++++++++++++++---
>  lib/actions.c        | 20 +++++++++++
>  lib/ovn-l7.h         |  3 ++
>  northd/ovn-northd.c  |  1 +
>  ovn-nb.xml           | 33 +++++++++++++++++
>  ovn-sb.ovsschema     |  7 ++--
>  ovn-sb.xml           | 18 ++++++++++
>  tests/ovn.at         | 68 ++++++++++++++++++++++++++++++++++-
>  tests/test-ovn.c     |  1 +
>  9 files changed, 227 insertions(+), 8 deletions(-)
> 
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index fce1c4be0..ff5004746 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -2962,7 +2962,8 @@ encode_dhcpv6_server_id_opt(struct ofpbuf *opts, void 
> *user_data)
>  static bool
>  compose_out_dhcpv6_opts(struct ofpbuf *userdata,
>                          struct ofpbuf *out_dhcpv6_opts,
> -                        ovs_be32 iaid, bool ipxe_req, uint8_t fqdn_flags)
> +                        ovs_be32 iaid, bool ipxe_req, uint8_t fqdn_flags,
> +                        ovs_be32 pd_iaid, bool pd_requested)
>  {
>      while (userdata->size) {
>          struct dhcpv6_opt_header *userdata_opt = ofpbuf_try_pull(
> @@ -3025,6 +3026,54 @@ compose_out_dhcpv6_opts(struct ofpbuf *userdata,
>              break;
>          }
>  
> +        case DHCPV6_OPT_IA_PD:
> +        {
> +            if (size != sizeof(uint8_t) + sizeof(struct in6_addr)) {
> +                return false;
> +            }
> +
> +            if (!pd_requested) {
> +                /* The client did not ask for a delegated prefix, so don't
> +                 * put an IA_PD option in the response. */
> +                break;
> +            }
> +
> +            /* The IA Prefix option carries a delegated prefix and must be
> +             * encapsulated in the Options field of an IA_PD option.  Please
> +             * see RFC 8415 sections 21.21 and 21.22. */
> +            uint8_t plen = *(uint8_t *) userdata_opt_data;
> +
> +            struct dhcpv6_opt_ia_na *opt_ia_pd = ofpbuf_put_zeros(
> +                out_dhcpv6_opts, sizeof *opt_ia_pd);
> +            opt_ia_pd->opt.code = htons(DHCPV6_OPT_IA_PD);
> +            /* IA_PD length (in bytes)-
> +             *  IAID - 4
> +             *  T1   - 4
> +             *  T2   - 4
> +             *  IA Prefix - sizeof(struct dhcpv6_opt_ia_prefix)
> +             */
> +            opt_ia_pd->opt.len =
> +                htons(12 + sizeof(struct dhcpv6_opt_ia_prefix));
> +            opt_ia_pd->iaid = pd_iaid;
> +            /* Set the lifetime of the prefix to infinity. */
> +            opt_ia_pd->t1 = OVS_BE32_MAX;
> +            opt_ia_pd->t2 = OVS_BE32_MAX;
> +
> +            struct dhcpv6_opt_ia_prefix *opt_ia_prefix = ofpbuf_put_zeros(
> +                out_dhcpv6_opts, sizeof *opt_ia_prefix);
> +            opt_ia_prefix->opt.code = htons(DHCPV6_OPT_IA_PREFIX);
> +            opt_ia_prefix->opt.len =
> +                htons(sizeof(struct dhcpv6_opt_ia_prefix) -
> +                      DHCP6_OPT_HEADER_LEN);
> +            opt_ia_prefix->plife_time = OVS_BE32_MAX;
> +            opt_ia_prefix->vlife_time = OVS_BE32_MAX;
> +            opt_ia_prefix->plen = plen;
> +            memcpy(&opt_ia_prefix->ipv6,
> +                   (uint8_t *) userdata_opt_data + sizeof plen,
> +                   sizeof opt_ia_prefix->ipv6);
> +            break;
> +        }
> +
>          case DHCPV6_OPT_DNS_SERVER_CODE:
>          {
>              struct dhcpv6_opt_header *opt_dns = ofpbuf_put_zeros(
> @@ -3209,6 +3258,8 @@ pinctrl_handle_put_dhcpv6_opts(
>       * option. So we don't need to copy that in the Server's response.
>       * */
>      ovs_be32 iaid = 0;
> +    ovs_be32 pd_iaid = 0;
> +    bool pd_requested = false;
>      struct dhcpv6_opt_header const *in_opt_client_id = NULL;
>      bool ipxe_req = false;
>      uint8_t fqdn_flags = DHCPV6_FQDN_FLAGS_UNDEFINED;
> @@ -3234,6 +3285,23 @@ pinctrl_handle_put_dhcpv6_opts(
>              break;
>          }
>  
> +        case DHCPV6_OPT_IA_PD:
> +        {
> +            if (opt_len < sizeof(struct dhcpv6_opt_ia_na)) {
> +                break;
> +            }
> +
> +            /* IA_PD shares the IAID/T1/T2 header layout with IA_NA.  OVN
> +             * delegates a single prefix, so honor only the first IA_PD. */
> +            if (!pd_requested) {
> +                struct dhcpv6_opt_ia_na *opt_ia_pd =
> +                    (struct dhcpv6_opt_ia_na *) in_opt;
> +                pd_iaid = opt_ia_pd->iaid;
> +                pd_requested = true;
> +            }
> +            break;
> +        }
> +
>          case DHCPV6_OPT_CLIENT_ID_CODE:
>              in_opt_client_id = in_opt;
>              break;
> @@ -3271,8 +3339,15 @@ pinctrl_handle_put_dhcpv6_opts(
>          goto exit;
>      }
>  
> -    if (!iaid && hdr->msg_type != DHCPV6_MSG_TYPE_INFO_REQ) {
> -        VLOG_WARN_RL(&rl, "DHCPv6 option - IA NA not present in the "
> +    /* A delegated prefix is only offered in reply to a Solicit or Request. 
> */
> +    if (hdr->msg_type != DHCPV6_MSG_TYPE_SOLICIT &&
> +        hdr->msg_type != DHCPV6_MSG_TYPE_REQUEST) {
> +        pd_requested = false;
> +    }
> +
> +    if (!iaid && !pd_requested &&
> +        hdr->msg_type != DHCPV6_MSG_TYPE_INFO_REQ) {
> +        VLOG_WARN_RL(&rl, "DHCPv6 option - no IA_NA or IA_PD present in the "
>                       "DHCPv6 packet");
>          goto exit;
>      }
> @@ -3286,7 +3361,8 @@ pinctrl_handle_put_dhcpv6_opts(
>          compose = compose_dhcpv6_status(userdata, &out_dhcpv6_opts);
>      } else {
>          compose = compose_out_dhcpv6_opts(userdata, &out_dhcpv6_opts, iaid,
> -                                          ipxe_req, fqdn_flags);
> +                                          ipxe_req, fqdn_flags, pd_iaid,
> +                                          pd_requested);
>      }
>  
>      if (!compose) {
> diff --git a/lib/actions.c b/lib/actions.c
> index 0367b330c..725674b0c 100644
> --- a/lib/actions.c
> +++ b/lib/actions.c
> @@ -2694,6 +2694,20 @@ parse_gen_opt(struct action_context *ctx, struct 
> ovnact_gen_option *o,
>              return;
>          }
>      }
> +
> +    /* The ia_pd value is a single IPv6 prefix: its mask supplies the
> +     * delegated prefix length on the wire, so reject a bare address (which
> +     * would encode a meaningless /0) or a set of addresses. */
> +    if (!strcmp(o->option->type, "ia_pd")) {
> +        const struct expr_constant *c = vector_get_ptr(&o->value.values, 0);
> +        if (vector_len(&o->value.values) != 1 ||
> +            c->format != LEX_F_IPV6 || !c->masked) {
> +            lexer_error(ctx->lexer, "%s option %s requires a single IPv6 "
> +                        "prefix value, e.g. aef0:1::/64.",
> +                        opts_type, o->option->name);
> +            return;
> +        }
> +    }
>  }
>  
>  static const struct ovnact_gen_option *
> @@ -3221,6 +3235,12 @@ encode_put_dhcpv6_option(const struct 
> ovnact_gen_option *o,
>          ofpbuf_put(ofpacts, encoded, size);
>  
>          free(encoded);
> +    } else if (!strcmp(o->option->type, "ia_pd")) {
> +        uint8_t plen = ipv6_count_cidr_bits(&c->mask.ipv6);
> +        size = sizeof plen + sizeof c->value.ipv6;
> +        opt->len = htons(size);
> +        ofpbuf_put(ofpacts, &plen, sizeof plen);
> +        ofpbuf_put(ofpacts, &c->value.ipv6, sizeof c->value.ipv6);

should we use a proper mask here? something like:

struct in6_addr masked;
ipv6_addr_bitand(&c->value.ipv6, &c->mask.ipv6, &masked);
ofpbuf_put(ofpacts, &masked, sizeof masked);

>      }
>  }
>  
> diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
> index 5f52e1791..b23e3ca29 100644
> --- a/lib/ovn-l7.h
> +++ b/lib/ovn-l7.h
> @@ -286,6 +286,9 @@ BUILD_ASSERT_DECL(DHCP_OPT_HEADER_LEN == sizeof(struct 
> dhcp_opt_header));
>  #define DHCPV6_OPT_IA_ADDR  \
>      DHCP_OPTION("ia_addr", DHCPV6_OPT_IA_ADDR_CODE, "ipv6")
>  
> +#define DHCPV6_OPT_IA_PD_PREFIX  \
> +    DHCP_OPTION("ia_pd", DHCPV6_OPT_IA_PD, "ia_pd")
> +
>  #define DHCPV6_OPT_DNS_SERVER  \
>      DHCP_OPTION("dns_server", DHCPV6_OPT_DNS_SERVER_CODE, "ipv6")
>  
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index c4c71ca81..e5ea2fdf7 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -284,6 +284,7 @@ static struct gen_opts_map supported_dhcp_opts[] = {
>  
>  static struct gen_opts_map supported_dhcpv6_opts[] = {
>      DHCPV6_OPT_IA_ADDR,
> +    DHCPV6_OPT_IA_PD_PREFIX,
>      DHCPV6_OPT_SERVER_ID,
>      DHCPV6_OPT_DOMAIN_SEARCH,
>      DHCPV6_OPT_DNS_SERVER,
> diff --git a/ovn-nb.xml b/ovn-nb.xml
> index 15fb1d7e8..8622267e1 100644
> --- a/ovn-nb.xml
> +++ b/ovn-nb.xml
> @@ -5918,6 +5918,39 @@ or
>            </p>
>          </column>
>        </group>
> +
> +      <group title="Prefix Delegation DHCPv6 options">
> +        <p>
> +          The option below makes OVN delegate an IPv6 prefix to a client that
> +          requests one.  OVN does not manage a prefix pool or any lease 
> state;
> +          the CMS supplies the prefix to delegate, and OVN emits it only when
> +          the client solicits a prefix.
> +        </p>
> +
> +        <column name="options" key="ia_pd">
> +          <p>
> +            The DHCPv6 option code for this option is 25, ``Identity
> +            Association for Prefix Delegation'' (IA_PD), which carries an IA
> +            Prefix (option 26).  The value is the delegated prefix in CIDR
> +            notation, e.g. <code>aef0:1::/64</code>.  When the client 
> requests
> +            an IA_PD, OVN replies with this prefix and echoes the client's
> +            IA_PD IAID.  Please refer to RFC 8415 for more details.
> +          </p>
> +
> +          <p>
> +            A single prefix is delegated: only the first IA_PD a client
> +            requests is answered.  If this option is not set, no IA_PD is
> +            returned even when the client requests one, the same way a 
> missing
> +            <code>ia_addr</code> is handled.
> +          </p>
> +
> +          <p>
> +            The logical port must also receive a DHCPv6-managed IPv6 address
> +            (see <code>ia_addr</code>), which is what makes OVN intercept the
> +            port's DHCPv6 traffic.
> +          </p>
> +        </column>
> +      </group>
>      </group>
>  
>      <group title="Common Columns">
> diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema
> index 3d79a64b4..40bdf9b32 100644
> --- a/ovn-sb.ovsschema
> +++ b/ovn-sb.ovsschema
> @@ -1,7 +1,7 @@
>  {
>      "name": "OVN_Southbound",
> -    "version": "21.10.0",
> -    "cksum": "2298996353 36780",
> +    "version": "21.11.0",
> +    "cksum": "2650041963 36830",
>      "tables": {
>          "SB_Global": {
>              "columns": {
> @@ -324,7 +324,8 @@
>                  "type": {
>                      "type": {"key": {
>                          "type": "string",
> -                        "enum": ["set", ["ipv6", "str", "mac", 
> "domain"]]}}}},
> +                        "enum": ["set", ["ipv6", "str", "mac", "domain",
> +                                         "ia_pd"]]}}}},
>              "isRoot": true},
>          "Connection": {
>              "columns": {
> diff --git a/ovn-sb.xml b/ovn-sb.xml
> index 0d3ec6c2c..4069acfc0 100644
> --- a/ovn-sb.xml
> +++ b/ovn-sb.xml
> @@ -4440,6 +4440,24 @@ tcp.flags = RST;
>              put_dhcpv6_opts(..., server_id = 01:02:03:04L05:06,...)
>            </p>
>          </dd>
> +
> +        <dt><code>value: ia_pd</code></dt>
> +        <dd>
> +          <p>
> +            This indicates that the value of the DHCPv6 option is a single 
> IPv6
> +            prefix to be delegated to the client via Prefix Delegation
> +            (IA_PD/IA_PREFIX).  The value must be a masked IPv6 address; the
> +            mask supplies the delegated prefix length.
> +          </p>
> +
> +          <p>
> +            Example. "name=ia_pd", "code=25", "type=ia_pd".
> +          </p>
> +
> +          <p>
> +            put_dhcpv6_opts(..., ia_pd = aef0:1::/64,...)
> +          </p>
> +        </dd>
>        </dl>
>      </column>
>    </table>
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 5dda50044..9ae023577 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -1625,6 +1625,10 @@ put_nd(inport, nd.target, nd.sll);
>  # put_dhcpv6_opts
>  reg1[[0]] = put_dhcpv6_opts(ia_addr = ae70::4, server_id = 
> 00:00:00:00:10:02);
>      encodes as 
> controller(userdata=00.00.00.05.00.00.00.00.00.01.de.10.00.00.00.40.00.05.00.10.ae.70.00.00.00.00.00.00.00.00.00.00.00.00.00.04.00.02.00.06.00.00.00.00.10.02,pause)
> +reg1[[0]] = put_dhcpv6_opts(ia_pd = aef0:1::/64);
> +    encodes as 
> controller(userdata=00.00.00.05.00.00.00.00.00.01.de.10.00.00.00.40.00.19.00.11.40.ae.f0.00.01.00.00.00.00.00.00.00.00.00.00.00.00,pause)
> +reg1[[0]] = put_dhcpv6_opts(ia_addr = ae70::4, ia_pd = aef0:1::/64, 
> server_id = 00:00:00:00:10:02);
> +    encodes as 
> controller(userdata=00.00.00.05.00.00.00.00.00.01.de.10.00.00.00.40.00.05.00.10.ae.70.00.00.00.00.00.00.00.00.00.00.00.00.00.04.00.19.00.11.40.ae.f0.00.01.00.00.00.00.00.00.00.00.00.00.00.00.00.02.00.06.00.00.00.00.10.02,pause)
>  reg1[[0]] = put_dhcpv6_opts();
>      encodes as 
> controller(userdata=00.00.00.05.00.00.00.00.00.01.de.10.00.00.00.40,pause)
>  reg1[[0]] = put_dhcpv6_opts(dns_server={ae70::1,ae70::2});
> @@ -1645,6 +1649,14 @@ reg1[[0]] = put_dhcpv6_opts(ia_addr="ae70::4");
>      DHCPv6 option ia_addr requires numeric value.
>  reg1[[0]] = put_dhcpv6_opts(ia_addr=ae70::4, domain_search=ae70::1);
>      DHCPv6 option domain_search requires string value.
> +reg1[[0]] = put_dhcpv6_opts(ia_pd = "aef0:1::/64");
> +    DHCPv6 option ia_pd requires numeric value.
> +reg1[[0]] = put_dhcpv6_opts(ia_pd = aef0:1::);
> +    DHCPv6 option ia_pd requires a single IPv6 prefix value, e.g. 
> aef0:1::/64.
> +reg1[[0]] = put_dhcpv6_opts(ia_pd = {aef0:1::/64, aef0:2::/64});
> +    DHCPv6 option ia_pd requires a single IPv6 prefix value, e.g. 
> aef0:1::/64.
> +reg1[[0]] = put_dhcpv6_opts(ia_pd = 1.2.3.4/24);
> +    DHCPv6 option ia_pd requires a single IPv6 prefix value, e.g. 
> aef0:1::/64.
>  reg1[[0]] = put_dhcpv6_opts(bootfile_name="https://127.0.0.1/boot.ipxe";);
>      formats as reg1[[0]] = put_dhcpv6_opts(bootfile_name = 
> "https://127.0.0.1/boot.ipxe";);
>      encodes as 
> controller(userdata=00.00.00.05.00.00.00.00.00.01.de.10.00.00.00.40.00.3b.00.1b.68.74.74.70.73.3a.2f.2f.31.32.37.2e.30.2e.30.2e.31.2f.62.6f.6f.74.2e.69.70.78.65,pause)
> @@ -7623,7 +7635,7 @@ check ovn-nbctl lsp-add ls1 ls1-lp3 \
>  check ovn-nbctl lsp-set-port-security ls1-lp3 "f0:00:00:00:00:22 ae70::22"
>  
>  d1="$(ovn-nbctl create DHCP_Options cidr="ae70\:\:/64" \
> -options="\"server_id\"=\"00:00:00:10:00:01\"")"
> +options="\"server_id\"=\"00:00:00:10:00:01\" \"ia_pd\"=\"aef0:1::/64\"")"
>  
>  check ovn-nbctl lsp-set-dhcpv6-options ls1-lp1 ${d1}
>  check ovn-nbctl lsp-set-dhcpv6-options ls1-lp2 ${d1}
> @@ -7783,6 +7795,51 @@ test_dhcpv6_release() {
>      n_resume=$((n_resume + 1))
>  }
>  
> +# This shell function sends a DHCPv6 request that carries an IA_PD option and
> +# checks that the reply delegates a prefix in an IA_PD -> IA_PREFIX.  The
> +# request's IA_PD uses a distinct IAID so the reply must echo the IA_PD IAID,
> +# not the IA_NA one.
> +# test_dhcpv6_pd INPORT SRC_MAC SRC_LLA DHCPv6_MSG_TYPE OFFER_IP PD_PREFIX 
> PD_PLEN
> +test_dhcpv6_pd() {
> +    local inport=$1 src_mac=$2 src_lla=$3 msg_code=$4 offer_ip=$5
> +    local pd_prefix=$6 pd_plen=$7
> +
> +    local req_scapy="Ether(dst='33:33:00:01:00:02', src='${src_mac}')/ \
> +                     IPv6(dst='ff02::1:2', src='${src_lla}')/ \
> +                     UDP(sport=546, dport=547)/ \
> +                     DHCP6(msgtype=${msg_code}, trid=0x010203)/ \
> +                     DHCP6OptClientId(duid=DUID_LL(lladdr='${src_mac}'))/ \
> +                     DHCP6OptIA_NA(iaid=0x01020304, T1=3600, T2=5400)/ \
> +                     DHCP6OptIA_PD(iaid=0x0a0b0c0d, T1=3600, T2=5400)"
> +    request=$(fmt_pkt "${req_scapy}")
> +
> +    local reply_code=7
> +    if test $msg_code = 1; then
> +        reply_code=2
> +    fi
> +
> +    local ip_scapy="DHCP6OptIAAddress(addr='${offer_ip}', \
> +                    preflft=0xffffffff, validlft=0xffffffff)"
> +    local pd_scapy="DHCP6OptIAPrefix(prefix='${pd_prefix}', plen=${pd_plen}, 
> \
> +                    preflft=0xffffffff, validlft=0xffffffff)"
> +    local rep_scapy="Ether(dst='${src_mac}', src='00:00:00:10:00:01')/ \
> +                     IPv6(dst='${src_lla}', 
> src='fe80::0200:00ff:fe10:0001')/ \
> +                     UDP(sport=547, dport=546)/ \
> +                     DHCP6(msgtype=${reply_code}, trid=0x010203)/ \
> +                     DHCP6OptClientId(duid=DUID_LL(lladdr='${src_mac}'))/ \
> +                     DHCP6OptIA_NA(iaid=0x01020304, T1=0xffffffff, \
> +                     T2=0xffffffff, ianaopts=[[${ip_scapy}]])/ \
> +                     DHCP6OptIA_PD(iaid=0x0a0b0c0d, T1=0xffffffff, \
> +                     T2=0xffffffff, iapdopt=[[${pd_scapy}]])/ \
> +                     
> DHCP6OptServerId(duid=DUID_LL(lladdr='00:00:00:10:00:01'))"
> +    reply=$(fmt_pkt "${rep_scapy}")
> +    echo $reply | trim_zeros >> $inport.expected
> +
> +    as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request
> +    OVS_WAIT_UNTIL([test $n_resume = `cat ofctl_monitor*.log | grep -c 
> NXT_RESUME`])
> +    n_resume=$((n_resume + 1))
> +}
> +
>  check_packets() {
>      local port=$1
>  
> @@ -7845,6 +7902,15 @@ reset_pcap_file hv1-vif1 hv1/vif1
>  test_dhcpv6_release 1 $src_mac $src_lla $offer_ip
>  check_packets 1
>  
> +# Request a delegated prefix on ls1-lp2.  d1 carries an ia_pd option, so the
> +# reply must include an IA_PD -> IA_PREFIX with the delegated prefix and the
> +# client's IA_PD IAID.  The IA_NA-only request on ls1-lp1 above must NOT get 
> an
> +# IA_PD, which exercises the request-aware path.
> +reset_pcap_file hv1-vif2 hv1/vif2
> +test_dhcpv6_pd 2 f0:00:00:00:00:02 fe80::f200:00ff:fe00:0002 1 ae70::5 
> aef0:1:: 64
> +check_packets 2
> +reset_pcap_file hv1-vif2 hv1/vif2
> +
>  # 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
> diff --git a/tests/test-ovn.c b/tests/test-ovn.c
> index 51471750b..460035b7f 100644
> --- a/tests/test-ovn.c
> +++ b/tests/test-ovn.c
> @@ -203,6 +203,7 @@ create_gen_opts(struct hmap *dhcp_opts, struct hmap 
> *dhcpv6_opts,
>      hmap_init(dhcpv6_opts);
>      dhcp_opt_add(dhcpv6_opts, "server_id",  2, "mac");
>      dhcp_opt_add(dhcpv6_opts, "ia_addr",  5, "ipv6");
> +    dhcp_opt_add(dhcpv6_opts, "ia_pd",  25, "ia_pd");
>      dhcp_opt_add(dhcpv6_opts, "dns_server",  23, "ipv6");
>      dhcp_opt_add(dhcpv6_opts, "domain_search",  24, "str");
>      dhcp_opt_add(dhcpv6_opts, "bootfile_name", 59, "str");
> -- 
> 2.50.1 (Apple Git-155)
> 
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> 
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to