[ovs-dev] [PATCH v2 ovn] dhcp: add iPXE support to OVN

Lorenzo Bianconi lorenzo.bianconi at redhat.com
Thu Oct 22 12:34:00 UTC 2020


> On Tue, Oct 13, 2020 at 4:45 PM Lorenzo Bianconi
> <lorenzo.bianconi at redhat.com> wrote:
> >
> > Introduce the possibility to specify more than 255 options in
> > put_dhcp_opts userdata buffer. This is useful to support conditional
> > options for the DHCP reply. (e.g option 67 used in iPXE protocol).
> > Express the option code using 2 bytes instead of just one in userdata
> > buffer. Moreover, parse userdata buffer in pinctrl_handle_put_dhcp_opts
> > in order to distinguish between 'optional' and 'fixed' options.
> >
> > Add iPXE support to OVN introducing "bootfile_name_alt" dhcp option.
> > When both "bootfile_name" and "bootfile_name_alt" are provided
> > by the CMS, "bootfile_name" will be used for option 67 if the
> > dhcp request contains etherboot option (175), otherwise
> > "bootfile_name_alt" will be used.
> >
> > Tested-by: Lucas Alvares Gomes Martins <lmartins at redhat.com>
> > Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi at redhat.com>
> 
> Hi Lorenzo,

Hi Numan,

thx for the review.

> 
> Thanks for the patch. If I understand correctly, you are encoding all
> the dhcp codes as 2 bytes in the controller userdata
> buffer right ? So that you can encode the  bootfile_alt option as 300 ?

correct

> 
> The drawback of this approach is that it increases the userdata buffer
> a bit and pinctrl thread needs to reencode the dhcp options
> to the standard format - i.e 1 byte code, 1 byte length.
> 
> I have another approach.
> * We can assign a private unused dhcp option code for bootfile_alt -
> may be a code between 224 and 254 -
> https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml
>    Since the chosen option code will not be part of the actual dhcp
> reply, I think it should be fine.
> 
> * We can encode the bootfile_name (67) and bootfile_name_alt (let's
> say we chose 224) soon after the offer_ip in the userdata buffer (in
> actions.c) and then encode the rest of the options.
> 
> * When pinctrl thread has to send the dhcp reply, it will check if 67
> and 224 are present in the userdata buffer. It can easily check since
> those will be encoded after offer_ip.
> 
> * If the dhcp request has etherboot option, it can put the
> bootfile_name in option 67, else it can put bootfile_name_alt in
> option 67.
> 
> * It can then just blindly copy the rest of the userdata buffer in the
> reply like we do now.
> 
> What do you think ?

I think it will work, we will just encode the bootfile_name_alt as option 224
in the userdata buffer. The only problem I can see is if option 224 will be
used in the future, but I am fine with your approach. What do you think?

Regards,
Lorenzo

> 
> Thanks
> Numan
> 
> 
> > ---
> >  controller/pinctrl.c |  56 +++++++++++++++++---
> >  lib/actions.c        |  28 +++++-----
> >  lib/ovn-l7.h         |  11 ++++
> >  northd/ovn-northd.c  |   1 +
> >  ovn-nb.xml           |  10 ++++
> >  ovn-sb.ovsschema     |   6 +--
> >  tests/ovn.at         | 118 ++++++++++++++++++++++++++++++-------------
> >  tests/test-ovn.c     |   1 +
> >  8 files changed, 171 insertions(+), 60 deletions(-)
> >
> > diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> > index 0a7020533..260184566 100644
> > --- a/controller/pinctrl.c
> > +++ b/controller/pinctrl.c
> > @@ -1766,6 +1766,7 @@ pinctrl_handle_put_dhcp_opts(
> >      }
> >      in_dhcp_ptr += sizeof magic_cookie;
> >
> > +    bool ipxe_req = false;
> >      const uint8_t *in_dhcp_msg_type = NULL;
> >      ovs_be32 request_ip = in_dhcp_data->ciaddr;
> >      while (in_dhcp_ptr < end) {
> > @@ -1798,6 +1799,9 @@ pinctrl_handle_put_dhcp_opts(
> >                  request_ip = get_unaligned_be32(DHCP_OPT_PAYLOAD(in_dhcp_opt));
> >              }
> >              break;
> > +        case DHCP_OPT_ETHERBOOT:
> > +            ipxe_req = true;
> > +            break;
> >          default:
> >              break;
> >          }
> > @@ -1855,8 +1859,8 @@ pinctrl_handle_put_dhcp_opts(
> >
> >          reply_dhcp_opts_ptr = dhcp_inform_reply_buf;
> >          while (in_dhcp_ptr < end) {
> > -            const struct dhcp_opt_header *in_dhcp_opt =
> > -                (const struct dhcp_opt_header *)in_dhcp_ptr;
> > +            const struct dhcp_opt_userdata_hdr *in_dhcp_opt =
> > +                (const struct dhcp_opt_userdata_hdr *)in_dhcp_ptr;
> >
> >              switch (in_dhcp_opt->code) {
> >              case OVN_DHCP_OPT_CODE_NETMASK:
> > @@ -1916,9 +1920,47 @@ pinctrl_handle_put_dhcp_opts(
> >       *| 4 Bytes padding | 1 Byte (option end 0xFF ) | 4 Bytes padding|
> >       * --------------------------------------------------------------
> >       */
> > +    /* compute opt len */
> > +    unsigned char *boot_filename_alt = NULL, *boot_filname_opt_ptr = NULL;
> > +    unsigned char *ptr = (unsigned char *)reply_dhcp_opts_ptr->data;
> > +    uint16_t boot_filename_len = 0, boot_filename_alt_len = 0;
> > +    unsigned char *ptr_end = ptr + reply_dhcp_opts_ptr->size;
> > +    unsigned char *buf = xmalloc(reply_dhcp_opts_ptr->size);
> > +    uint16_t opt_len = 0;
> > +
> > +    while (ptr < ptr_end) {
> > +        const struct dhcp_opt_userdata_hdr *in_dhcp_opt =
> > +            (const struct dhcp_opt_userdata_hdr *)ptr;
> > +
> > +        switch (in_dhcp_opt->code) {
> > +        case 300: /* DHCP_OPT_BOOTFILE_ALT */
> > +          boot_filename_alt = ptr + sizeof *in_dhcp_opt;
> > +          boot_filename_alt_len = in_dhcp_opt->len;
> > +          break;
> > +        case 67: /* DHCP_OPT_BOOTFILENAME */
> > +          boot_filname_opt_ptr = &buf[opt_len];
> > +          boot_filename_len = in_dhcp_opt->len;
> > +          /* fall through */
> > +        default:
> > +          /* code < 255 */
> > +          buf[opt_len] = in_dhcp_opt->code;
> > +          memcpy(buf + 1 + opt_len, ptr + 2, in_dhcp_opt->len + 1);
> > +          opt_len += 2 + in_dhcp_opt->len;
> > +          break;
> > +        }
> > +        ptr += sizeof *in_dhcp_opt + in_dhcp_opt->len;
> > +    }
> > +
> > +    if (!ipxe_req && boot_filename_alt_len > 0 && boot_filename_len > 0) {
> > +        memcpy(&boot_filname_opt_ptr[2], boot_filename_alt,
> > +               boot_filename_alt_len);
> > +        boot_filname_opt_ptr[1] = boot_filename_alt_len;
> > +        opt_len += boot_filename_alt_len - boot_filename_len;
> > +    }
> > +
> >      uint16_t new_l4_size = UDP_HEADER_LEN + DHCP_HEADER_LEN + 16;
> >      if (msg_type != DHCP_MSG_NAK) {
> > -        new_l4_size += reply_dhcp_opts_ptr->size;
> > +        new_l4_size += opt_len;
> >      }
> >      size_t new_packet_size = pkt_in->l4_ofs + new_l4_size;
> >
> > @@ -1954,7 +1996,7 @@ pinctrl_handle_put_dhcp_opts(
> >
> >      uint16_t out_dhcp_opts_size = 12;
> >      if (msg_type != DHCP_MSG_NAK) {
> > -      out_dhcp_opts_size += reply_dhcp_opts_ptr->size;
> > +      out_dhcp_opts_size += opt_len;
> >      }
> >      uint8_t *out_dhcp_opts = dp_packet_put_zeros(&pkt_out,
> >                                                   out_dhcp_opts_size);
> > @@ -1965,9 +2007,8 @@ pinctrl_handle_put_dhcp_opts(
> >      out_dhcp_opts += 3;
> >
> >      if (msg_type != DHCP_MSG_NAK) {
> > -        memcpy(out_dhcp_opts, reply_dhcp_opts_ptr->data,
> > -               reply_dhcp_opts_ptr->size);
> > -        out_dhcp_opts += reply_dhcp_opts_ptr->size;
> > +      memcpy(out_dhcp_opts, buf, opt_len);
> > +      out_dhcp_opts += opt_len;
> >      }
> >
> >      /* Padding */
> > @@ -2005,6 +2046,7 @@ pinctrl_handle_put_dhcp_opts(
> >                   ETH_ADDR_ARGS(l2->eth_src), IP_ARGS(*offer_ip));
> >
> >      success = 1;
> > +    free(buf);
> >  exit:
> >      if (!ofperr) {
> >          union mf_subvalue sv;
> > diff --git a/lib/actions.c b/lib/actions.c
> > index 5fe0a3897..48726b7f5 100644
> > --- a/lib/actions.c
> > +++ b/lib/actions.c
> > @@ -2308,23 +2308,23 @@ static void
> >  encode_put_dhcpv4_option(const struct ovnact_gen_option *o,
> >                           struct ofpbuf *ofpacts)
> >  {
> > -    uint8_t *opt_header = ofpbuf_put_zeros(ofpacts, 2);
> > -    opt_header[0] = o->option->code;
> > +    uint8_t *opt_header = ofpbuf_put_zeros(ofpacts, 3);
> >
> > +    memcpy(opt_header, &o->option->code, 2);
> >      const union expr_constant *c = o->value.values;
> >      size_t n_values = o->value.n_values;
> >      if (!strcmp(o->option->type, "bool") ||
> >          !strcmp(o->option->type, "uint8")) {
> > -        opt_header[1] = 1;
> > +        opt_header[2] = 1;
> >          ofpbuf_put(ofpacts, &c->value.u8_val, 1);
> >      } else if (!strcmp(o->option->type, "uint16")) {
> > -        opt_header[1] = 2;
> > +        opt_header[2] = 2;
> >          ofpbuf_put(ofpacts, &c->value.be16_int, 2);
> >      } else if (!strcmp(o->option->type, "uint32")) {
> > -        opt_header[1] = 4;
> > +        opt_header[2] = 4;
> >          ofpbuf_put(ofpacts, &c->value.be32_int, 4);
> >      } else if (!strcmp(o->option->type, "ipv4")) {
> > -        opt_header[1] = n_values * sizeof(ovs_be32);
> > +        opt_header[2] = n_values * sizeof(ovs_be32);
> >          for (size_t i = 0; i < n_values; i++) {
> >              ofpbuf_put(ofpacts, &c[i].value.ipv4, sizeof(ovs_be32));
> >          }
> > @@ -2333,7 +2333,7 @@ encode_put_dhcpv4_option(const struct ovnact_gen_option *o,
> >          if (no_of_routes % 2) {
> >              no_of_routes -= 1;
> >          }
> > -        opt_header[1] = 0;
> > +        opt_header[2] = 0;
> >
> >          /* Calculating the length of this option first because when
> >           * we call ofpbuf_put, it might reallocate the buffer if the
> > @@ -2345,7 +2345,7 @@ encode_put_dhcpv4_option(const struct ovnact_gen_option *o,
> >              if (c[i].masked) {
> >                  plen = (uint8_t) ip_count_cidr_bits(c[i].mask.ipv4);
> >              }
> > -            opt_header[1] += (1 + DIV_ROUND_UP(plen, 8) + sizeof(ovs_be32));
> > +            opt_header[2] += (1 + DIV_ROUND_UP(plen, 8) + sizeof(ovs_be32));
> >          }
> >
> >          /* Copied from RFC 3442. Please refer to this RFC for the format of
> > @@ -2375,14 +2375,14 @@ encode_put_dhcpv4_option(const struct ovnact_gen_option *o,
> >                         sizeof(ovs_be32));
> >          }
> >      } else if (!strcmp(o->option->type, "str")) {
> > -        opt_header[1] = strlen(c->string);
> > -        ofpbuf_put(ofpacts, c->string, opt_header[1]);
> > +        opt_header[2] = strlen(c->string);
> > +        ofpbuf_put(ofpacts, c->string, opt_header[2]);
> >      } else if (!strcmp(o->option->type, "host_id")) {
> >          if (o->value.type == EXPR_C_STRING) {
> > -            opt_header[1] = strlen(c->string);
> > -            ofpbuf_put(ofpacts, c->string, opt_header[1]);
> > +            opt_header[2] = strlen(c->string);
> > +            ofpbuf_put(ofpacts, c->string, opt_header[2]);
> >          } else {
> > -           opt_header[1] = sizeof(ovs_be32);
> > +           opt_header[2] = sizeof(ovs_be32);
> >             ofpbuf_put(ofpacts, &c->value.ipv4, sizeof(ovs_be32));
> >          }
> >      } else if (!strcmp(o->option->type, "domains")) {
> > @@ -2461,7 +2461,7 @@ encode_put_dhcpv4_option(const struct ovnact_gen_option *o,
> >                  encode_offset += sizeof(uint8_t);
> >              }
> >          }
> > -        opt_header[1] = encode_offset;
> > +        opt_header[2] = encode_offset;
> >          ofpbuf_put(ofpacts, dns_encoded, encode_offset);
> >
> >          out:
> > diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
> > index 18c59896d..79c037ba3 100644
> > --- a/lib/ovn-l7.h
> > +++ b/lib/ovn-l7.h
> > @@ -93,6 +93,11 @@ struct gen_opts_map {
> >  #define DHCP_OPT_DOMAIN_SEARCH_LIST \
> >      DHCP_OPTION("domain_search_list", 119, "domains")
> >
> > +/* fixed DHCP header */
> > +#define DHCP_OPT_BOOTFILE_ALT DHCP_OPTION("bootfile_name_alt", 300, "str")
> > +
> > +#define DHCP_OPT_ETHERBOOT     175
> > +
> >  #define DHCP_OPT_ARP_CACHE_TIMEOUT \
> >      DHCP_OPTION("arp_cache_timeout", 35, "uint32")
> >  #define DHCP_OPT_TCP_KEEPALIVE_INTERVAL \
> > @@ -179,6 +184,12 @@ struct dhcp_opt6_header {
> >      ovs_be16 size;
> >  };
> >
> > +OVS_PACKED(
> > +struct dhcp_opt_userdata_hdr {
> > +    uint16_t code;
> > +    uint8_t len;
> > +});
> > +
> >  /* These are not defined in ovs/lib/dhcp.h, hence defining here. */
> >  #define OVN_DHCP_MSG_DECLINE        4
> >  #define OVN_DHCP_MSG_RELEASE        7
> > diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> > index 366fdd95f..a9941bb9a 100644
> > --- a/northd/ovn-northd.c
> > +++ b/northd/ovn-northd.c
> > @@ -12514,6 +12514,7 @@ static struct gen_opts_map supported_dhcp_opts[] = {
> >      DHCP_OPT_ARP_CACHE_TIMEOUT,
> >      DHCP_OPT_TCP_KEEPALIVE_INTERVAL,
> >      DHCP_OPT_DOMAIN_SEARCH_LIST,
> > +    DHCP_OPT_BOOTFILE_ALT,
> >  };
> >
> >  static struct gen_opts_map supported_dhcpv6_opts[] = {
> > diff --git a/ovn-nb.xml b/ovn-nb.xml
> > index 86195af34..43694535e 100644
> > --- a/ovn-nb.xml
> > +++ b/ovn-nb.xml
> > @@ -3096,6 +3096,16 @@
> >              resolving hostnames via the Domain Name System.
> >            </p>
> >          </column>
> > +
> > +        <column name="options" key="bootfile_name_alt">
> > +          <p>
> > +          </p>
> > +            "bootfile_name_alt" option is used to support iPXE.
> > +            When both "bootfile_name" and "bootfile_name_alt" are provided
> > +            by the CMS, "bootfile_name" will be used for option 67 if the
> > +            dhcp request contains etherboot option (175), otherwise
> > +            "bootfile_name_alt" will be used.
> > +        </column>
> >        </group>
> >
> >        <group title="DHCP Options of type host_id">
> > diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema
> > index d1c506a22..9a684d8c0 100644
> > --- a/ovn-sb.ovsschema
> > +++ b/ovn-sb.ovsschema
> > @@ -1,7 +1,7 @@
> >  {
> >      "name": "OVN_Southbound",
> > -    "version": "2.10.0",
> > -    "cksum": "2548342632 22615",
> > +    "version": "2.11.0",
> > +    "cksum": "1750191326 22616",
> >      "tables": {
> >          "SB_Global": {
> >              "columns": {
> > @@ -226,7 +226,7 @@
> >                  "name": {"type": "string"},
> >                  "code": {
> >                      "type": {"key": {"type": "integer",
> > -                                     "minInteger": 0, "maxInteger": 254}}},
> > +                                     "minInteger": 0, "maxInteger": 1000}}},
> >                  "type": {
> >                      "type": {"key": {
> >                          "type": "string",
> > diff --git a/tests/ovn.at b/tests/ovn.at
> > index 488fd119b..9206336ac 100644
> > --- a/tests/ovn.at
> > +++ b/tests/ovn.at
> > @@ -1277,25 +1277,25 @@ reg0[0] = lookup_arp_ip(inport, eth.dst);
> >
> >  # put_dhcp_opts
> >  reg1[0] = put_dhcp_opts(offerip = 1.2.3.4, router = 10.0.0.1);
> > -    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.40.01.02.03.04.03.04.0a.00.00.01,pause)
> > +    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.40.01.02.03.04.03.00.04.0a.00.00.01,pause)
> >  reg2[5] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,mtu=1400,domain_name="ovn.org",wpad="https://example.org",bootfile_name="https://127.0.0.1/boot.ipxe",path_prefix="/tftpboot");
> >      formats as reg2[5] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.254.0, mtu = 1400, domain_name = "ovn.org", wpad = "https://example.org", bootfile_name = "https://127.0.0.1/boot.ipxe", path_prefix = "/tftpboot");
> > -    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.43.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.d2.09.2f.74.66.74.70.62.6f.6f.74,pause)
> > +    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.00.04.0a.00.00.01.01.00.04.ff.ff.fe.00.1a.00.02.05.78.0f.00.07.6f.76.6e.2e.6f.72.67.fc.00.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.43.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.d2.00.09.2f.74.66.74.70.62.6f.6f.74,pause)
> >  reg0[15] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.255.0,mtu=1400,ip_forward_enable=1,default_ttl=121,dns_server={8.8.8.8,7.7.7.7},classless_static_route={30.0.0.0/24,10.0.0.4,40.0.0.0/16,10.0.0.6,0.0.0.0/0,10.0.0.1},ethernet_encap=1,router_discovery=0,tftp_server_address={10.0.0.4,10.0.0.5},arp_cache_timeout=10,tcp_keepalive_interval=10);
> >      formats as reg0[15] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.255.0, mtu = 1400, ip_forward_enable = 1, default_ttl = 121, dns_server = {8.8.8.8, 7.7.7.7}, classless_static_route = {30.0.0.0/24, 10.0.0.4, 40.0.0.0/16, 10.0.0.6, 0.0.0.0/0, 10.0.0.1}, ethernet_encap = 1, router_discovery = 0, tftp_server_address = {10.0.0.4, 10.0.0.5}, arp_cache_timeout = 10, tcp_keepalive_interval = 10);
> > -    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.ff.00.1a.02.05.78.13.01.01.17.01.79.06.08.08.08.08.08.07.07.07.07.79.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.01.01.1f.01.00.96.08.0a.00.00.04.0a.00.00.05.23.04.00.00.00.0a.26.04.00.00.00.0a,pause)
> > +    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.00.04.0a.00.00.01.01.00.04.ff.ff.ff.00.1a.00.02.05.78.13.00.01.01.17.00.01.79.06.00.08.08.08.08.08.07.07.07.07.79.00.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.00.01.01.1f.00.01.00.96.00.08.0a.00.00.04.0a.00.00.05.23.00.04.00.00.00.0a.26.00.04.00.00.00.0a,pause)
> >  reg0[15] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.255.0,mtu=1400,ip_forward_enable=1,default_ttl=121,dns_server={8.8.8.8,7.7.7.7},classless_static_route={30.0.0.0/24,10.0.0.4,40.0.0.0/16,10.0.0.6,0.0.0.0/0,10.0.0.1},ethernet_encap=1,router_discovery=0,tftp_server=10.0.0.10);
> >      formats as reg0[15] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.255.0, mtu = 1400, ip_forward_enable = 1, default_ttl = 121, dns_server = {8.8.8.8, 7.7.7.7}, classless_static_route = {30.0.0.0/24, 10.0.0.4, 40.0.0.0/16, 10.0.0.6, 0.0.0.0/0, 10.0.0.1}, ethernet_encap = 1, router_discovery = 0, tftp_server = 10.0.0.10);
> > -    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.ff.00.1a.02.05.78.13.01.01.17.01.79.06.08.08.08.08.08.07.07.07.07.79.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.01.01.1f.01.00.42.04.0a.00.00.0a,pause)
> > +    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.00.04.0a.00.00.01.01.00.04.ff.ff.ff.00.1a.00.02.05.78.13.00.01.01.17.00.01.79.06.00.08.08.08.08.08.07.07.07.07.79.00.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.00.01.01.1f.00.01.00.42.00.04.0a.00.00.0a,pause)
> >  reg0[15] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.255.0,mtu=1400,ip_forward_enable=1,default_ttl=121,dns_server={8.8.8.8,7.7.7.7},classless_static_route={30.0.0.0/24,10.0.0.4,40.0.0.0/16,10.0.0.6,0.0.0.0/0,10.0.0.1},ethernet_encap=1,router_discovery=0,tftp_server="tftp_server_test");
> >      formats as reg0[15] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.255.0, mtu = 1400, ip_forward_enable = 1, default_ttl = 121, dns_server = {8.8.8.8, 7.7.7.7}, classless_static_route = {30.0.0.0/24, 10.0.0.4, 40.0.0.0/16, 10.0.0.6, 0.0.0.0/0, 10.0.0.1}, ethernet_encap = 1, router_discovery = 0, tftp_server = "tftp_server_test");
> > -    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.ff.00.1a.02.05.78.13.01.01.17.01.79.06.08.08.08.08.08.07.07.07.07.79.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.01.01.1f.01.00.42.10.74.66.74.70.5f.73.65.72.76.65.72.5f.74.65.73.74,pause)
> > +    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.6f.0a.00.00.04.03.00.04.0a.00.00.01.01.00.04.ff.ff.ff.00.1a.00.02.05.78.13.00.01.01.17.00.01.79.06.00.08.08.08.08.08.07.07.07.07.79.00.14.18.1e.00.00.0a.00.00.04.10.28.00.0a.00.00.06.00.0a.00.00.01.24.00.01.01.1f.00.01.00.42.00.10.74.66.74.70.5f.73.65.72.76.65.72.5f.74.65.73.74,pause)
> >  reg2[5] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,mtu=1400,domain_name="ovn.org",wpad="https://example.org",bootfile_name="https://127.0.0.1/boot.ipxe",path_prefix="/tftpboot",domain_search_list="ovn.org,abc.ovn.org");
> >      formats as reg2[5] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.254.0, mtu = 1400, domain_name = "ovn.org", wpad = "https://example.org", bootfile_name = "https://127.0.0.1/boot.ipxe", path_prefix = "/tftpboot", domain_search_list = "ovn.org,abc.ovn.org");
> > -    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.43.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.d2.09.2f.74.66.74.70.62.6f.6f.74.77.0f.03.6f.76.6e.03.6f.72.67.00.03.61.62.63.c0.00,pause)
> > +    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.00.04.0a.00.00.01.01.00.04.ff.ff.fe.00.1a.00.02.05.78.0f.00.07.6f.76.6e.2e.6f.72.67.fc.00.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.43.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.d2.00.09.2f.74.66.74.70.62.6f.6f.74.77.00.0f.03.6f.76.6e.03.6f.72.67.00.03.61.62.63.c0.00,pause)
> >  reg2[5] = put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,mtu=1400,domain_name="ovn.org",wpad="https://example.org",bootfile_name="https://127.0.0.1/boot.ipxe",path_prefix="/tftpboot",domain_search_list="ovn.org,abc.ovn.org,def.ovn.org,ovn.test,def.ovn.test,test.org,abc.com");
> >      formats as reg2[5] = put_dhcp_opts(offerip = 10.0.0.4, router = 10.0.0.1, netmask = 255.255.254.0, mtu = 1400, domain_name = "ovn.org", wpad = "https://example.org", bootfile_name = "https://127.0.0.1/boot.ipxe", path_prefix = "/tftpboot", domain_search_list = "ovn.org,abc.ovn.org,def.ovn.org,ovn.test,def.ovn.test,test.org,abc.com");
> > -    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.04.0a.00.00.01.01.04.ff.ff.fe.00.1a.02.05.78.0f.07.6f.76.6e.2e.6f.72.67.fc.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.43.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.d2.09.2f.74.66.74.70.62.6f.6f.74.77.35.03.6f.76.6e.03.6f.72.67.00.03.61.62.63.c0.00.03.64.65.66.c0.00.03.6f.76.6e.04.74.65.73.74.00.03.64.65.66.c0.15.04.74.65.73.74.c0.04.03.61.62.63.03.63.6f.6d.00,pause)
> > +    encodes as controller(userdata=00.00.00.02.00.00.00.00.00.01.de.10.00.00.00.25.0a.00.00.04.03.00.04.0a.00.00.01.01.00.04.ff.ff.fe.00.1a.00.02.05.78.0f.00.07.6f.76.6e.2e.6f.72.67.fc.00.13.68.74.74.70.73.3a.2f.2f.65.78.61.6d.70.6c.65.2e.6f.72.67.43.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.d2.00.09.2f.74.66.74.70.62.6f.6f.74.77.00.35.03.6f.76.6e.03.6f.72.67.00.03.61.62.63.c0.00.03.64.65.66.c0.00.03.6f.76.6e.04.74.65.73.74.00.03.64.65.66.c0.15.04.74.65.73.74.c0.04.03.61.62.63.03.63.6f.6d.00,pause)
> >
> >  reg1[0..1] = put_dhcp_opts(offerip = 1.2.3.4, router = 10.0.0.1);
> >      Cannot use 2-bit field reg1[0..1] where 1-bit field is required.
> > @@ -5302,10 +5302,10 @@ sleep 2
> >  as hv1 ovs-vsctl show
> >
> >  # This shell function sends a DHCP request packet
> > -# test_dhcp INPORT SRC_MAC DHCP_TYPE BROADCAST CIADDR OFFER_IP REQUEST_IP USE_IP ...
> > +# test_dhcp INPORT SRC_MAC DHCP_TYPE BROADCAST CIADDR OFFER_IP REQUEST_IP ETH_BOOT USE_IP ...
> >  test_dhcp() {
> > -    local inport=$1 src_mac=$2 dhcp_type=$3 broadcast=$4 ciaddr=$5 offer_ip=$6 request_ip=$7 use_ip=$8
> > -    shift; shift; shift; shift; shift; shift; shift; shift;
> > +    local inport=$1 src_mac=$2 dhcp_type=$3 broadcast=$4 ciaddr=$5 offer_ip=$6 request_ip=$7 eth_boot=$8 use_ip=$9
> > +    shift; shift; shift; shift; shift; shift; shift; shift; shift;
> >
> >      if test $use_ip != 0; then
> >          src_ip=$1
> > @@ -5317,11 +5317,21 @@ test_dhcp() {
> >      fi
> >
> >      if test $request_ip != 0; then
> > -        ip_len=0120
> > -        udp_len=010b
> > +        if test $eth_boot != 0; then
> > +            ip_len=0124
> > +            udp_len=010f
> > +        else
> > +            ip_len=0120
> > +            udp_len=010b
> > +        fi
> >      else
> > -        ip_len=011a
> > -        udp_len=0106
> > +        if test $eth_boot != 0; then
> > +            ip_len=011e
> > +            udp_len=010a
> > +        else
> > +            ip_len=011a
> > +            udp_len=0106
> > +        fi
> >      fi
> >
> >      if test $broadcast != 0; then
> > @@ -5362,6 +5372,9 @@ test_dhcp() {
> >          # dhcp requested ip
> >          request=${request}3204${request_ip}
> >      fi
> > +    if test $eth_boot != 0; then
> > +        request=${request}af020000
> > +    fi
> >      # dhcp end option
> >      request=${request}ff
> >
> > @@ -5457,7 +5470,7 @@ server_ip=`ip_to_hex 10 0 0 1`
> >  ciaddr=`ip_to_hex 0 0 0 0`
> >  request_ip=0
> >  expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
> > -test_dhcp 1 f00000000001 01 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
> > +test_dhcp 1 f00000000001 01 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 1.
> >  OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5483,7 +5496,7 @@ server_ip=`ip_to_hex 10 0 0 1`
> >  ciaddr=`ip_to_hex 0 0 0 0`
> >  request_ip=$offer_ip
> >  expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
> > -test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 2.
> >  OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5507,7 +5520,7 @@ server_ip=`ip_to_hex 10 0 0 1`
> >  ciaddr=`ip_to_hex 0 0 0 0`
> >  request_ip=`ip_to_hex 10 0 0 7`
> >  expected_dhcp_opts=""
> > -test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 06 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001 $server_ip 06 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 3.
> >  OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5531,7 +5544,7 @@ rm -f 2.expected
> >  ciaddr=`ip_to_hex 0 0 0 0`
> >  offer_ip=0
> >  request_ip=0
> > -test_dhcp 2 f00000000002 09 0 $ciaddr $offer_ip $request_ip 0 1 1
> > +test_dhcp 2 f00000000002 09 0 $ciaddr $offer_ip $request_ip 0 0 1 1
> >
> >  # NXT_RESUMEs should be 4.
> >  OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5548,18 +5561,18 @@ rm -f 2.expected
> >  # ls2-lp2 (vif4-tx.pcap) should receive the DHCPv4 request packet once.
> >
> >  ciaddr=`ip_to_hex 0 0 0 0`
> > -test_dhcp 3 f00000000003 01 0 $ciaddr 0 0 4 0
> > +test_dhcp 3 f00000000003 01 0 $ciaddr 0 0 0 4 0
> >
> >  # Send DHCPv4 packet on ls2-lp2. "router" DHCPv4 option is not defined for
> >  # this lport.
> >  ciaddr=`ip_to_hex 0 0 0 0`
> > -test_dhcp 4 f00000000004 01 0 $ciaddr 0 0 3 0
> > +test_dhcp 4 f00000000004 01 0 $ciaddr 0 0 0 3 0
> >
> >  # NXT_RESUMEs should be 4.
> >  OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> >
> > -#OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [3.expected])
> > -#OVN_CHECK_PACKETS([hv1/vif4-tx.pcap], [4.expected])
> > +OVN_CHECK_PACKETS([hv1/vif3-tx.pcap], [3.expected])
> > +OVN_CHECK_PACKETS([hv1/vif4-tx.pcap], [4.expected])
> >
> >  # Send DHCPREQUEST in the RENEWING/REBINDING state with ip4.src set to 10.0.0.6
> >  # and ip4.dst set to 10.0.0.1.
> > @@ -5570,7 +5583,7 @@ request_ip=0
> >  src_ip=$offer_ip
> >  dst_ip=$server_ip
> >  expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
> > -test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 5.
> >  OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5596,7 +5609,7 @@ request_ip=0
> >  src_ip=$offer_ip
> >  dst_ip=`ip_to_hex 255 255 255 255`
> >  expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
> > -test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 6.
> >  OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5622,7 +5635,7 @@ request_ip=0
> >  src_ip=$offer_ip
> >  dst_ip=`ip_to_hex 255 255 255 255`
> >  expected_dhcp_opts=""
> > -test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 7.
> >  OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5648,7 +5661,7 @@ request_ip=0
> >  src_ip=$offer_ip
> >  dst_ip=`ip_to_hex 255 255 255 255`
> >  expected_dhcp_opts=""
> > -test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 1 $src_ip $dst_ip ff1000000001 $server_ip 06 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 8.
> >  OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5670,7 +5683,7 @@ rm -f 2.expected
> >  ciaddr=`ip_to_hex 0 0 0 0`
> >  src_ip=`ip_to_hex 10 0 0 6`
> >  dst_ip=`ip_to_hex 10 0 0 4`
> > -test_dhcp 2 f00000000002 03 0 $ciaddr 0 0 1 $src_ip $dst_ip 1
> > +test_dhcp 2 f00000000002 03 0 $ciaddr 0 0 0 1 $src_ip $dst_ip 1
> >
> >  # NXT_RESUMEs should be 8.
> >  OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5689,7 +5702,7 @@ server_ip=`ip_to_hex 10 0 0 1`
> >  ciaddr=`ip_to_hex 0 0 0 0`
> >  request_ip=0
> >  expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a000001
> > -test_dhcp 1 f00000000001 01 1 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
> > +test_dhcp 1 f00000000001 01 1 $ciaddr $offer_ip $request_ip 0 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 9.
> >  OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5712,7 +5725,7 @@ server_ip=`ip_to_hex 10 0 0 1`
> >  ciaddr=`ip_to_hex 10 0 0 6`
> >  request_ip=0
> >  expected_dhcp_opts=0
> > -test_dhcp 2 f00000000002 07 0 $ciaddr $offer_ip $request_ip 0 ff1000000001
> > +test_dhcp 2 f00000000002 07 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001
> >
> >  # NXT_RESUMEs should be 10.
> >  OVS_WAIT_UNTIL([test 10 = $(cat ofctl_monitor*.log | grep -c NXT_RESUME)])
> > @@ -5739,7 +5752,7 @@ dst_ip=$server_ip
> >  # In the expected_dhcp_opts we should not see 330400000e10 which is
> >  # dhcp lease time option and 0104ffffff00 which is subnet mask option.
> >  expected_dhcp_opts=03040a00000136040a000001
> > -test_dhcp 2 f00000000002 08 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 08 0 $ciaddr $offer_ip $request_ip 0 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 11.
> >  OVS_WAIT_UNTIL([test 11 = $(cat ofctl_monitor*.log | grep -c NXT_RESUME)])
> > @@ -5769,7 +5782,7 @@ dst_ip=$server_ip
> >  # In the expected_dhcp_opts we should not see 330400000e10 which is
> >  # dhcp lease time option.
> >  expected_dhcp_opts=3a0400000fa0330400000e100104ffffff0003040a00000136040a000001
> > -test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 12.
> >  OVS_WAIT_UNTIL([test 12 = $(cat ofctl_monitor*.log | grep -c NXT_RESUME)])
> > @@ -5796,7 +5809,7 @@ dst_ip=$server_ip
> >  # In the expected_dhcp_opts we should not see 330400000e10 which is
> >  # dhcp lease time option and 0104ffffff00 which is subnet mask option.
> >  expected_dhcp_opts=03040a00000136040a000001
> > -test_dhcp 2 f00000000002 08 0 $ciaddr $offer_ip $request_ip 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 08 0 $ciaddr $offer_ip $request_ip 0 1 $src_ip $dst_ip ff1000000001 $server_ip 05 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 13.
> >  OVS_WAIT_UNTIL([test 13 = $(cat ofctl_monitor*.log | grep -c NXT_RESUME)])
> > @@ -5827,7 +5840,7 @@ server_ip=`ip_to_hex 10 0 0 1`
> >  ciaddr=`ip_to_hex 0 0 0 0`
> >  request_ip=$offer_ip
> >  expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a00000142040a0a0a0a
> > -test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 14.
> >  OVS_WAIT_UNTIL([test 14 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5858,7 +5871,7 @@ server_ip=`ip_to_hex 10 0 0 1`
> >  ciaddr=`ip_to_hex 0 0 0 0`
> >  request_ip=$offer_ip
> >  expected_dhcp_opts=330400000e100104ffffff0003040a00000136040a0000014210746573745f746674705f736572766572
> > -test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 15.
> >  OVS_WAIT_UNTIL([test 15 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5889,7 +5902,7 @@ server_ip=`ip_to_hex 10 0 0 1`
> >  ciaddr=`ip_to_hex 0 0 0 0`
> >  request_ip=$offer_ip
> >  expected_dhcp_opts=771305746573743103636f6d00057465737432c006330400000e100104ffffff0003040a00000136040a000001
> > -test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
> > +test_dhcp 2 f00000000002 03 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001 $server_ip 05 $expected_dhcp_opts
> >
> >  # NXT_RESUMEs should be 16.
> >  OVS_WAIT_UNTIL([test 16 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
> > @@ -5907,9 +5920,42 @@ server_ip=`ip_to_hex 10 0 0 1`
> >  ciaddr=`ip_to_hex 0 0 0 0`
> >  request_ip=0
> >  expected_dhcp_opts=""
> > -test_dhcp 1 f00000000001 04 0 $ciaddr $offer_ip $request_ip 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
> > +test_dhcp 1 f00000000001 04 0 $ciaddr $offer_ip $request_ip 0 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
> >  AT_CHECK([fgrep -iq 'DHCPDECLINE from f0:00:00:00:00:01, 10.0.0.4 duplicated' hv1/ovn-controller.log], [0], [])
> >
> > +# Send Etherboot.
> > +
> > +reset_pcap_file hv1-vif1 hv1/vif1
> > +reset_pcap_file hv1-vif2 hv1/vif2
> > +rm -f 1.expected
> > +rm -f 2.expected
> > +
> > +ovn-nbctl --all destroy dhcp-option
> > +
> > +ovn-nbctl dhcp-options-create 10.0.0.0/24
> > +d3=$(ovn-nbctl --bare --columns=_uuid find dhcp_options cidr="10.0.0.0/24")
> > +ovn-nbctl dhcp-options-set-options $d3 \
> > +   server_id=10.0.0.1 server_mac=ff:10:00:00:00:01 \
> > +   lease_time=3600 router=10.0.0.1 bootfile_name_alt=\"filename\" \
> > +   bootfile_name=\"bootfile\"
> > +
> > +ovn-nbctl lsp-set-dhcpv4-options ls1-lp1 $d3
> > +
> > +offer_ip=`ip_to_hex 10 0 0 4`
> > +server_ip=`ip_to_hex 10 0 0 1`
> > +ciaddr=`ip_to_hex 0 0 0 0`
> > +request_ip=0
> > +boofile=4308626f6f7466696c65
> > +expected_dhcp_opts=${boofile}330400000e100104ffffff0003040a00000136040a000001
> > +test_dhcp 1 f00000000001 01 0 $ciaddr $offer_ip $request_ip 1 0 ff1000000001 $server_ip 02 $expected_dhcp_opts
> > +
> > +$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
> > +cat 1.expected | cut -c -48 > expout
> > +AT_CHECK([cat 1.packets | cut -c -48], [0], [expout])
> > +# Skipping the IPv4 checksum.
> > +cat 1.expected | cut -c 53- > expout
> > +AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout])
> > +
> >  OVN_CLEANUP([hv1])
> >
> >  AT_CLEANUP
> > diff --git a/tests/test-ovn.c b/tests/test-ovn.c
> > index d94ab025d..96763be60 100644
> > --- a/tests/test-ovn.c
> > +++ b/tests/test-ovn.c
> > @@ -191,6 +191,7 @@ create_gen_opts(struct hmap *dhcp_opts, struct hmap *dhcpv6_opts,
> >      dhcp_opt_add(dhcp_opts, "arp_cache_timeout", 35, "uint32");
> >      dhcp_opt_add(dhcp_opts, "tcp_keepalive_interval", 38, "uint32");
> >      dhcp_opt_add(dhcp_opts, "domain_search_list", 119, "domains");
> > +    dhcp_opt_add(dhcp_opts, "bootfile_name_alt", 300, "str");
> >
> >      /* DHCPv6 options. */
> >      hmap_init(dhcpv6_opts);
> > --
> > 2.26.2
> >
> > _______________________________________________
> > dev mailing list
> > dev at openvswitch.org
> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev
> >
> 


More information about the dev mailing list