[ovs-dev] [PATCH v2 ovn] Add support for DHCP options - Domain Search List (119) and TFTP server (66).

Numan Siddique numans at ovn.org
Thu May 28 12:51:58 UTC 2020


On Thu, May 7, 2020 at 11:27 PM Ankur Sharma <svc.mail.git at nutanix.com>
wrote:

> From: Dhathri Purohith <dhathri.purohith at nutanix.com>
>
> 1. Add support for DHCP domain search option (119)
>    Domain search list is encoded according to the specifications in RFC
> 1035,
>    section 4.1.4.
>
> 2. Fix the data type for DHCP option tftp_server (66)
>    Currently, DHCP option is of type ipv4. But, according to RFC 2132,
>    option 66 can be a hostname i.e, we should also accept string type.
>    In order to be backward compatible, a new type called "host_id" is
>    introduced, which accepts both ipv4 address and string. Type for DHCP
>    option 66 is changed to "host_id" instead of ipv4.
>    OVN northd code that updates the OVN southbound database is enhanced to
>    consider the change in the type and code for DHCP option, so that the
>    change in datatype is reflected.
>
> Signed-off-by: Dhathri Purohith <dhathri.purohith at nutanix.com>
>

Hi Ankur and Dhathri,

Thanks for the patch. Overall the patch looks good to me.

The compilation is failing with the below error when configured with
"--enable-Werror --enable-sparse"

****
t -Wbool-compare -Wshift-negative-value -Wduplicated-cond -Wshadow
-Wmultistatement-macros -Wcast-align=strict -Werror -Werror  -g -O2 -MT
lib/actions.lo -MD -MP -MF $depbase.Tpo -c -o lib/actions.lo
../lib/actions.c &&\
mv -f $depbase.Tpo $depbase.Plo
../ovn-sb.ovsschema:4: The checksum "712869723 21916" was calculated from
the schema file and does not match cksum field in the schema file - you
should probably update the version number and the checksum in the schema
file with the value listed here.
make[1]: *** [Makefile:3168: ovn-sb.ovsschema.stamp] Error 1
make[1]: *** Waiting for unfinished jobs....
libtool: compile:  env REAL_CC=gcc "CHECK=sparse -Wsparse-error -I
/home/nusiddiq/workspace_cpp/openvswitch/ovn_split/ovs/include/sparse -m64
-I /usr/local/include  " cgcc -target=x86_64 -DHAVE_CONFIG_H -I. -I.. -I
../include -I ../include -I ../ovn -I ./include -I
/home/nusiddiq/workspace_cpp/openvswitch/ovn_split/ovs/include -I
/home/nusiddiq/workspace_cpp/openvswitch/ovn_split/ovs/_gcc/include -I
/home/nusiddiq/workspace_cpp/openvswitch/ovn_split/ovs/lib -I
/home/nusiddiq/workspace_cpp/openvswitch/ovn_split/ovs/_gcc/lib -I
/home/nusiddiq/workspace_cpp/openvswitch/ovn_split/ovs -I
/home/nusiddiq/workspace_cpp/openvswitch/ovn_split/ovs/_gcc -I ../lib -I
./lib -Wstrict-prototypes -Wall -Wextra -Wno-sign-compare -Wpointer-arith
-Wformat -Wformat-security -Wswitch-enum -Wunused-parameter
-Wbad-function-cast -Wcast-align -Wstrict-prototypes -Wold-style-definition
-Wmissing-prototypes -Wmissing-field-initializers -fno-strict-aliasing
-Wswitch-bool -Wlogical-not-parentheses -Wsizeof-array-argument
-Wbool-compare -Wshift-negative-value -Wduplicated-cond -Wshadow
-Wmultistatement-macros -Wcast-align=strict -Werror -Werror -g -O2 -MT
lib/actions.lo -MD -MP -MF lib/.deps/actions.Tpo -c ../lib/actions.c -o
lib/actions.o
../lib/actions.c:2373:54: error: restricted ovs_be16 degrades to integer
make[1]: *** [Makefile:2016: lib/actions.lo] Error 1
*****

Looks like the patch needs rebase as there is schema checksum error.

This patch does 2 things. Can you please split into 2 patch series.

Thanks
Numan




> ---
>  lib/actions.c       | 112
> +++++++++++++++++++++++++++++++++++++++++++++++++++-
>  lib/ovn-l7.h        |   5 ++-
>  northd/ovn-northd.c |   8 +++-
>  ovn-sb.ovsschema    |   3 +-
>  ovn-sb.xml          |  24 +++++++++++
>  tests/ovn.at        |   9 +++++
>  tests/test-ovn.c    |   3 +-
>  7 files changed, 159 insertions(+), 5 deletions(-)
>
> diff --git a/lib/actions.c b/lib/actions.c
> index 021a376..02068b1 100644
> --- a/lib/actions.c
> +++ b/lib/actions.c
> @@ -1943,7 +1943,12 @@ parse_gen_opt(struct action_context *ctx, struct
> ovnact_gen_option *o,
>          return;
>      }
>
> -    if (!strcmp(o->option->type, "str")) {
> +    if (!strcmp(o->option->type, "host_id")) {
> +        return;
> +    }
> +
> +    if (!strcmp(o->option->type, "str") ||
> +        !strcmp(o->option->type, "domains")) {
>          if (o->value.type != EXPR_C_STRING) {
>              lexer_error(ctx->lexer, "%s option %s requires string value.",
>                          opts_type, o->option->name);
> @@ -2270,6 +2275,111 @@ encode_put_dhcpv4_option(const struct
> ovnact_gen_option *o,
>      } else if (!strcmp(o->option->type, "str")) {
>          opt_header[1] = strlen(c->string);
>          ofpbuf_put(ofpacts, c->string, opt_header[1]);
> +    } 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]);
> +        } else {
> +           opt_header[1] = sizeof(ovs_be32);
> +           ofpbuf_put(ofpacts, &c->value.ipv4, sizeof(ovs_be32));
> +        }
> +    } else if (!strcmp(o->option->type, "domains")) {
> +        /* Please refer to RFC 1035, section 4.1.4 for the format of
> encoding
> +         * domain names. Below is an example for encoding a search list
> +         * consisting of the "abc.com" and "xyz.abc.com".
> +         *
> +         *
> +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
> +         * |119|14 | 3 |'a'|'b'|'c'| 3 |'c'|'o'|'m'| 0
> |'x'|'y'|'z'|xC0|x00|
> +         *
> +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
> +         *
> +         * The encoding of "abc.com" ends with 0 to mark the end of the
> +         * domain name as required by RFC 1035.
> +         *
> +         * The encoding of "xyz" (for "xyz.abc.com") ends with the
> two-octet
> +         * compression pointer C000 (hex), which points to offset 0 where
> +         * another validly encoded domain name can be found to complete
> +         * the name ("abc.com").
> +         */
> +        typedef struct namemap_node {
> +            struct hmap_node node;
> +            uint16_t offset;
> +            char *name;
> +        } namemap_node;
> +        struct hmap namemap;
> +        hmap_init(&namemap);
> +        namemap_node *ref;
> +        /* Encoding adds 2 bytes (one for length and one for delimiter)
> for
> +         * every domain name that is unique. If all the domain names are
> unique
> +         * (which probably never happens in real world), then encoded
> string
> +         * could be longer than the original string. Just to be on the
> safer
> +         * side, allocate the (approx.) worst case length here.
> +         */
> +        uint8_t *dns_encoded = xzalloc(2 * strlen(c->string));
> +        uint8_t encode_offset = 0;
> +        char *domain_list = xstrdup(c->string), *dom_ptr = NULL;
> +        for (char *domain = strtok_r(domain_list, ",", &dom_ptr);
> +             domain != NULL;
> +             domain = strtok_r(NULL, ",", &dom_ptr)) {
> +            if (strlen(domain) > DOMAIN_NAME_MAX_LEN) {
> +                VLOG_WARN("Domain names longer than 255 characters are
> not"
> +                          "supported");
> +                goto out;
> +            }
> +            char *label_ptr = NULL, *label;
> +            for (label = strtok_r(domain, ".", &label_ptr);
> +                 label != NULL;
> +                 label = strtok_r(NULL, ".", &label_ptr)) {
> +                ref = NULL;
> +                /* Check if we have already encoded this label and
> +                 * fill in the reference, if yes. */
> +                uint32_t label_hash = hash_string(label, 0);
> +                HMAP_FOR_EACH_IN_BUCKET (ref, node, label_hash, &namemap)
> {
> +                    if (!strcmp(label, ref->name)) {
> +                        uint16_t temp = (0xc0 | htons(ref->offset));
> +                        memcpy(dns_encoded + encode_offset, &temp,
> +                               sizeof(temp));
> +                        encode_offset += sizeof(temp);
> +                        break;
> +                    }
> +                }
> +                /* Break, since we have already filled the offset for this
> +                 * domain. */
> +                if (ref != NULL) {
> +                    break;
> +                } else {
> +                    /* The label was not encoded before, encode it now
> and add
> +                     * the offset to the namemap map. */
> +                    ref = xzalloc(sizeof *ref);
> +                    ref->name = xstrdup(label);
> +                    ref->offset = encode_offset;
> +                    hmap_insert(&namemap, &ref->node, label_hash);
> +
> +                    uint8_t len = strlen(label);
> +                    memcpy(dns_encoded + encode_offset, &len,
> sizeof(uint8_t));
> +                    encode_offset += sizeof(uint8_t);
> +                    memcpy(dns_encoded + encode_offset, label, len);
> +                    encode_offset += len;
> +                }
> +            }
> +            /* Add the end marker (0 byte) to determine the end of the
> +             * domain. */
> +            if (label == NULL) {
> +                uint8_t end = 0;
> +                memcpy(dns_encoded + encode_offset, &end,
> sizeof(uint8_t));
> +                encode_offset += sizeof(uint8_t);
> +            }
> +        }
> +        opt_header[1] = encode_offset;
> +        ofpbuf_put(ofpacts, dns_encoded, encode_offset);
> +
> +        out:
> +            HMAP_FOR_EACH_POP (ref, node, &namemap) {
> +                free(ref->name);
> +                free(ref);
> +            }
> +            hmap_destroy(&namemap);
> +            free(domain_list);
> +            free(dns_encoded);
>      }
>  }
>
> diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
> index cc63d82..f34bc0d 100644
> --- a/lib/ovn-l7.h
> +++ b/lib/ovn-l7.h
> @@ -34,6 +34,7 @@ struct gen_opts_map {
>      size_t code;
>  };
>
> +#define DOMAIN_NAME_MAX_LEN 255
>  #define DHCP_BROADCAST_FLAG 0x8000
>
>  #define DHCP_OPTION(NAME, CODE, TYPE) \
> @@ -57,7 +58,7 @@ struct gen_opts_map {
>  #define DHCP_OPT_NIS_SERVER  DHCP_OPTION("nis_server", 41, "ipv4")
>  #define DHCP_OPT_NTP_SERVER  DHCP_OPTION("ntp_server", 42, "ipv4")
>  #define DHCP_OPT_SERVER_ID   DHCP_OPTION("server_id", 54, "ipv4")
> -#define DHCP_OPT_TFTP_SERVER DHCP_OPTION("tftp_server", 66, "ipv4")
> +#define DHCP_OPT_TFTP_SERVER DHCP_OPTION("tftp_server", 66, "host_id")
>
>  #define DHCP_OPT_CLASSLESS_STATIC_ROUTE \
>      DHCP_OPTION("classless_static_route", 121, "static_routes")
> @@ -81,6 +82,8 @@ struct gen_opts_map {
>  #define DHCP_OPT_PATH_PREFIX DHCP_OPTION("path_prefix", 210, "str")
>  #define DHCP_OPT_TFTP_SERVER_ADDRESS \
>      DHCP_OPTION("tftp_server_address", 150, "ipv4")
> +#define DHCP_OPT_DOMAIN_SEARCH_LIST \
> +    DHCP_OPTION("domain_search_list", 119, "domains")
>
>  #define DHCP_OPT_ARP_CACHE_TIMEOUT \
>      DHCP_OPTION("arp_cache_timeout", 35, "uint32")
> diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
> index 3324d20..cc8a7e6 100644
> --- a/northd/ovn-northd.c
> +++ b/northd/ovn-northd.c
> @@ -11356,6 +11356,7 @@ static struct gen_opts_map supported_dhcp_opts[] =
> {
>      DHCP_OPT_DOMAIN_NAME,
>      DHCP_OPT_ARP_CACHE_TIMEOUT,
>      DHCP_OPT_TCP_KEEPALIVE_INTERVAL,
> +    DHCP_OPT_DOMAIN_SEARCH_LIST,
>  };
>
>  static struct gen_opts_map supported_dhcpv6_opts[] = {
> @@ -11380,7 +11381,12 @@ check_and_add_supported_dhcp_opts_to_sb_db(struct
> northd_context *ctx)
>          struct gen_opts_map *dhcp_opt =
>              dhcp_opts_find(&dhcp_opts_to_add, opt_row->name);
>          if (dhcp_opt) {
> -            hmap_remove(&dhcp_opts_to_add, &dhcp_opt->hmap_node);
> +            if (!strcmp(dhcp_opt->type, opt_row->type) &&
> +                 dhcp_opt->code == opt_row->code) {
> +                hmap_remove(&dhcp_opts_to_add, &dhcp_opt->hmap_node);
> +            } else {
> +                sbrec_dhcp_options_delete(opt_row);
> +            }
>          } else {
>              sbrec_dhcp_options_delete(opt_row);
>          }
> diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema
> index d89f8db..d1c1e51 100644
> --- a/ovn-sb.ovsschema
> +++ b/ovn-sb.ovsschema
> @@ -214,7 +214,8 @@
>                      "type": {"key": {
>                          "type": "string",
>                          "enum": ["set", ["bool", "uint8", "uint16",
> "uint32",
> -                                         "ipv4", "static_routes",
> "str"]]}}}},
> +                                         "ipv4", "static_routes", "str",
> +                                         "host_id", "domains"]]}}}},
>              "isRoot": true},
>          "DHCPv6_Options": {
>              "columns": {
> diff --git a/ovn-sb.xml b/ovn-sb.xml
> index 3aa7cd4..ddd8bff 100644
> --- a/ovn-sb.xml
> +++ b/ovn-sb.xml
> @@ -3208,6 +3208,30 @@ tcp.flags = RST;
>              Example. "name=host_name", "code=12", "type=str".
>            </p>
>          </dd>
> +
> +        <dt><code>value: host_id</code></dt>
> +        <dd>
> +          <p>
> +            This indicates that the value of the DHCP option is a host_id.
> +            It can either be a host_name or an IP address.
> +          </p>
> +
> +          <p>
> +            Example. "name=tftp_server", "code=66", "type=host_id".
> +          </p>
> +        </dd>
> +
> +        <dt><code>value: domains</code></dt>
> +        <dd>
> +          <p>
> +            This indicates that the value of the DHCP option is a domain
> name
> +            or a comma separated list of domain names.
> +          </p>
> +
> +          <p>
> +            Example. "name=domain_search_list", "code=119",
> "type=domains".
> +          </p>
> +        </dd>
>        </dl>
>      </column>
>    </table>
> diff --git a/tests/ovn.at b/tests/ovn.at
> index f168b14..7e2cd75 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -1195,6 +1195,15 @@ reg2[5] =
> put_dhcp_opts(offerip=10.0.0.4,router=10.0.0.1,netmask=255.255.254.0,m
>  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)
> +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)
> +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)
> +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)
>
>  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.
> diff --git a/tests/test-ovn.c b/tests/test-ovn.c
> index a77d2f1..b43f67f 100644
> --- a/tests/test-ovn.c
> +++ b/tests/test-ovn.c
> @@ -174,7 +174,7 @@ create_gen_opts(struct hmap *dhcp_opts, struct hmap
> *dhcpv6_opts,
>      dhcp_opt_add(dhcp_opts, "nis_server", 41, "ipv4");
>      dhcp_opt_add(dhcp_opts, "ntp_server", 42, "ipv4");
>      dhcp_opt_add(dhcp_opts, "server_id",  54, "ipv4");
> -    dhcp_opt_add(dhcp_opts, "tftp_server", 66, "ipv4");
> +    dhcp_opt_add(dhcp_opts, "tftp_server", 66, "host_id");
>      dhcp_opt_add(dhcp_opts, "classless_static_route", 121,
> "static_routes");
>      dhcp_opt_add(dhcp_opts, "ip_forward_enable",  19, "bool");
>      dhcp_opt_add(dhcp_opts, "router_discovery", 31, "bool");
> @@ -189,6 +189,7 @@ create_gen_opts(struct hmap *dhcp_opts, struct hmap
> *dhcpv6_opts,
>      dhcp_opt_add(dhcp_opts, "tftp_server_address", 150, "ipv4");
>      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");
>
>      /* DHCPv6 options. */
>      hmap_init(dhcpv6_opts);
> --
> 1.8.3.1
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>


More information about the dev mailing list