On Thu, Mar 23, 2017 at 8:52 PM, Guru Shetty <g...@ovn.org> wrote:

>
>
> On 22 March 2017 at 21:25, Numan Siddique <nusid...@redhat.com> wrote:
>
>>
>>
>> On Wed, Mar 22, 2017 at 10:43 PM, Guru Shetty <g...@ovn.org> wrote:
>>
>>>
>>>
>>> On 22 March 2017 at 09:51, Guru Shetty <g...@ovn.org> wrote:
>>>
>>>>
>>>>
>>>> On 13 March 2017 at 00:32, <nusid...@redhat.com> wrote:
>>>>
>>>>> From: Numan Siddique <nusid...@redhat.com>
>>>>>
>>>>> OVN implements native DNS resolution which can be used to resolve the
>>>>> internal DNS names belonging to a logical datapath.
>>>>>
>>>>> To support this, the logical ports should be configured with the
>>>>> hostname in the 'Logical_Switch_Port.options:hostname' and an optional
>>>>> fqdn in 'Logical_Switch_Port.options:fqdn'.
>>>>>
>>>>> For each logical datapath with atleast one of its logical port
>>>>> configured with hostname in the options field, following flows are
>>>>> added
>>>>>  - A logical flow in DNS_LKUP stage which uses the action 'dns_lookup'
>>>>>    which transforms the DNS query to DNS reply packet and advances
>>>>>    to the next stage - DNS_RESPONSE.
>>>>>
>>>>>  - A logical flow in DNS_RESPONSE stage which implements the DNS
>>>>> responder
>>>>>    by sending the DNS reply from previous stage back to the inport.
>>>>>
>>>>> Signed-off-by: Numan Siddique <nusid...@redhat.com>
>>>>>
>>>>
>>>> Would this work if there is a logical router connecting 2 switches and
>>>> the logical ports try to communicate across the router?
>>>>
>>>> I had a use case, where in I wanted to give a DNS name to a VIP of a
>>>> OVN load-balancer. And that would not work with this model.
>>>>
>>>> What if we have a DNS table in NB and then link it to the logical
>>>> switches? Each record in the table is a map of hostname:IP. And then we can
>>>> have a column in logical switch for DNS that links to the DNS table?
>>>> Something similar to the way we add load-balancers to logical switches.
>>>>
>>>> Corrections:
>>> What if we have a DNS table in NB and then link it to the logical
>>> switches? Each record in the table is a map of multiple hostname:IP.
>>> records. And then we can have a column in logical switch for DNS that
>>> links to the DNS table? Something similar to the way we add
>>> load-balancers to logical switches.  This way, someone can create one DNS
>>> table entry per logical topology and link it to all the logical switches of
>>> the topology.
>>>
>>>
>>
>> Thanks Guru for the comments. I thought about this use case.
>>
>> The proposed DNS table in the SB DB  (in this patch) has a column
>> "datapath".  I thought of supporting this use case by making the "datapath"
>> column in the SB DB as a list.
>>
>> For example, If there are two logical switches (sw0, sw1) connected to
>> logical router lr0 and the logical port sw0-port0 is configured with a
>> hostname (say "VM1")  in its options, then ovn-northd would create a DNS
>> row in the SB DB with datapath set as ["sw0-datapath-id",
>> "sw1-datapath-id"].
>> When ovn-controller receives the DNS packet it would match the hostname
>> and the datapath id of the incoming packet from this "datapath" column. If
>> any port belonging to either of the switches, sends a DNS lookup for "VM1",
>> it would be resolved to the IP address of sw0-port0.
>>
>> Is this approach reasonable ? From CMS perspective, I think it would be a
>> lot easier if we don't have DNS table in NB DB.
>> I dropped the idea earlier, as the code in ovn-northd to set the
>> "datapath" was getting a bit complicated.
>>
>
> How would we be able to provide DNS names to VIPs of load-balancers in
> this case?
>
>
I am not too familiar with load balancer support. After seeing the schema
again and your proposal, I agree with your proposal i.e to have a DNS table
in NB DB.

I will work on it, unless you, Ben or anyone else has any comments.

Thanks
Numan




>
>>
>> If this is fine, I can revise the patch.
>>
>> Thanks
>> Numan
>>
>>
>>
>>
>>>>
>>>>
>>>>
>>>>> ---
>>>>>  ovn/northd/ovn-northd.8.xml |  88 +++++++++++-
>>>>>  ovn/northd/ovn-northd.c     | 181 ++++++++++++++++++++++-
>>>>>  ovn/ovn-nb.xml              |  18 ++-
>>>>>  tests/ovn.at                | 340 ++++++++++++++++++++++++++++++
>>>>> ++++++++++++++
>>>>>  4 files changed, 618 insertions(+), 9 deletions(-)
>>>>>
>>>>> diff --git a/ovn/northd/ovn-northd.8.xml b/ovn/northd/ovn-northd.8.xml
>>>>> index ab8fd88..a3fe2a8 100644
>>>>> --- a/ovn/northd/ovn-northd.8.xml
>>>>> +++ b/ovn/northd/ovn-northd.8.xml
>>>>> @@ -724,7 +724,73 @@ output;
>>>>>        </li>
>>>>>      </ul>
>>>>>
>>>>> -    <h3>Ingress Table 13 Destination Lookup</h3>
>>>>> +    <h3>Ingress Table 13 DNS Lookup</h3>
>>>>> +
>>>>> +    <p>
>>>>> +      This table looks up and resolves the DNS names of the logical
>>>>> ports
>>>>> +      if configured with the host names.
>>>>> +    </p>
>>>>> +
>>>>> +    <ul>
>>>>> +      <li>
>>>>> +        <p>
>>>>> +          A priority-100 logical flow for each logical switch data
>>>>> path
>>>>> +          if at least one of its logical port is configured with
>>>>> +          <code>hostname</code>  which matches the IPv4 and IPv6
>>>>> packets with
>>>>> +          <code>udp.src</code> = 53 and applies the action
>>>>> +          <code>dns_lkup</code> and advances the packet to the next
>>>>> table.
>>>>> +        </p>
>>>>> +
>>>>> +        <pre>
>>>>> +reg0[4] = dns_lkup(); next;
>>>>> +        </pre>
>>>>> +
>>>>> +        <p>
>>>>> +          For valid DNS packets, this transforms the packet into a DNS
>>>>> +          reply if the DNS name can be resolved, and stores 1 into
>>>>> reg0[4].
>>>>> +          For failed DNS resolution or other kinds of packets, it
>>>>> just stores
>>>>> +          0 into reg0[4]. Either way, it continues to the next table.
>>>>> +        </p>
>>>>> +      </li>
>>>>> +    </ul>
>>>>> +
>>>>> +    <h3>Ingress Table 14 DNS Responses</h3>
>>>>> +
>>>>> +    <p>
>>>>> +      This table implements DNS responder for the DNS replies
>>>>> generated by
>>>>> +      the previous table.
>>>>> +    </p>
>>>>> +
>>>>> +    <ul>
>>>>> +      <li>
>>>>> +        <p>
>>>>> +          A priority-100 logical flow for each logical switch data
>>>>> path
>>>>> +          if at least one of its logical port is configured with
>>>>> +          <code>hostname</code> which matches IPv4 and IPv6 packets
>>>>> with
>>>>> +          <code>udp.src == 53 &amp;&amp; reg0[4] == 1</code> and
>>>>> responds
>>>>> +          back to the <code>inport</code> after applying these
>>>>> +          actions.  If <code>reg0[4]</code> is set to 1, it means
>>>>> that the
>>>>> +          action <code>dns_lkup</code> was successful.
>>>>> +        </p>
>>>>> +
>>>>> +        <pre>
>>>>> +eth.dst &lt;&#45;&gt; eth.src;
>>>>> +ip4.src &lt;&#45;&gt; ip4.dst;
>>>>> +udp.dst = udp.src;
>>>>> +udp.src = 53;
>>>>> +outport = <var>P</var>;
>>>>> +flags.loopback = 1;
>>>>> +output;
>>>>> +        </pre>
>>>>> +
>>>>> +        <p>
>>>>> +          (This terminates ingress packet processing; the packet does
>>>>> not go
>>>>> +           to the next ingress table.)
>>>>> +        </p>
>>>>> +      </li>
>>>>> +    </ul>
>>>>> +
>>>>> +    <h3>Ingress Table 15 Destination Lookup</h3>
>>>>>
>>>>>      <p>
>>>>>        This table implements switching behavior.  It contains these
>>>>> logical
>>>>> @@ -834,11 +900,23 @@ output;
>>>>>      </p>
>>>>>
>>>>>      <p>
>>>>> -      Also a priority 34000 logical flow is added for each logical
>>>>> port which
>>>>> -      has DHCPv4 options defined to allow the DHCPv4 reply packet and
>>>>> which has
>>>>> -      DHCPv6 options defined to allow the DHCPv6 reply packet from the
>>>>> -      <code>Ingress Table 12: DHCP responses</code>.
>>>>> +      Also the following flows are added.
>>>>>      </p>
>>>>> +    <ul>
>>>>> +      <li>
>>>>> +        A Priority 34000 logical flow is added for each logical port
>>>>> which
>>>>> +        has DHCPv4 options defined to allow the DHCPv4 reply packet
>>>>> and which has
>>>>> +        DHCPv6 options defined to allow the DHCPv6 reply packet from
>>>>> the
>>>>> +        <code>Ingress Table 12: DHCP responses</code>.
>>>>> +      </li>
>>>>> +
>>>>> +      <li>
>>>>> +        A Priority 34000 logical flow for each logical switch data
>>>>> path if at
>>>>> +        least one of its logical port is configured with hostname
>>>>> +        which allows the DNS reply packet from the
>>>>> +        <code>Ingress Table 14:DNS responses</code>.
>>>>> +      </li>
>>>>> +    </ul>
>>>>>
>>>>>      <h3>Egress Table 7: Egress Port Security - IP</h3>
>>>>>
>>>>> diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
>>>>> index cc9b934..8fa42fc 100644
>>>>> --- a/ovn/northd/ovn-northd.c
>>>>> +++ b/ovn/northd/ovn-northd.c
>>>>> @@ -112,7 +112,9 @@ enum ovn_stage {
>>>>>      PIPELINE_STAGE(SWITCH, IN,  ARP_ND_RSP,    10, "ls_in_arp_rsp")
>>>>>      \
>>>>>      PIPELINE_STAGE(SWITCH, IN,  DHCP_OPTIONS,  11,
>>>>> "ls_in_dhcp_options")  \
>>>>>      PIPELINE_STAGE(SWITCH, IN,  DHCP_RESPONSE, 12,
>>>>> "ls_in_dhcp_response") \
>>>>> -    PIPELINE_STAGE(SWITCH, IN,  L2_LKUP,       13, "ls_in_l2_lkup")
>>>>>      \
>>>>> +    PIPELINE_STAGE(SWITCH, IN,  DNS_LOOKUP,      13,
>>>>> "ls_in_dns_lookup") \
>>>>> +    PIPELINE_STAGE(SWITCH, IN,  DNS_RESPONSE,  14,
>>>>> "ls_in_dns_response") \
>>>>> +    PIPELINE_STAGE(SWITCH, IN,  L2_LKUP,       15, "ls_in_l2_lkup")
>>>>>      \
>>>>>
>>>>>  \
>>>>>      /* Logical switch egress stages. */
>>>>>  \
>>>>>      PIPELINE_STAGE(SWITCH, OUT, PRE_LB,       0, "ls_out_pre_lb")
>>>>>  \
>>>>> @@ -160,6 +162,7 @@ enum ovn_stage {
>>>>>  #define REGBIT_CONNTRACK_COMMIT "reg0[1]"
>>>>>  #define REGBIT_CONNTRACK_NAT    "reg0[2]"
>>>>>  #define REGBIT_DHCP_OPTS_RESULT "reg0[3]"
>>>>> +#define REGBIT_DNS_LOOKUP_RESULT "reg0[4]"
>>>>>
>>>>>  /* Register definitions for switches and routers. */
>>>>>  #define REGBIT_NAT_REDIRECT     "reg9[0]"
>>>>> @@ -2817,7 +2820,13 @@ build_acls(struct ovn_datapath *od, struct hmap
>>>>> *lflows)
>>>>>      }
>>>>>
>>>>>      /* Add 34000 priority flow to allow DHCP reply from
>>>>> ovn-controller to all
>>>>> -     * logical ports of the datapath if the CMS has configured DHCPv4
>>>>> options*/
>>>>> +     * logical ports of the datapath if the CMS has configured DHCPv4
>>>>> options.
>>>>> +     *
>>>>> +     * Add one 34000 priority flow to allow DNS reply from
>>>>> ovn-controller to all
>>>>> +     * logical ports of the datapath if the CMS has configured DNS
>>>>> parameters
>>>>> +     * for atleast one logical port.
>>>>> +     * */
>>>>> +    bool dns_flow_added = false;
>>>>>      for (size_t i = 0; i < od->nbs->n_ports; i++) {
>>>>>          if (od->nbs->ports[i]->dhcpv4_options) {
>>>>>              const char *server_id = smap_get(
>>>>> @@ -2869,6 +2878,16 @@ build_acls(struct ovn_datapath *od, struct hmap
>>>>> *lflows)
>>>>>                  ds_destroy(&match);
>>>>>              }
>>>>>          }
>>>>> +
>>>>> +        if (!dns_flow_added && smap_get(&od->nbs->ports[i]->options,
>>>>> +                                        "hostname")) {
>>>>> +            const char *actions = has_stateful ? "ct_commit; next;" :
>>>>> +                "next;";
>>>>> +            ovn_lflow_add(
>>>>> +                lflows, od, S_SWITCH_OUT_ACL, 34000, "udp && udp.src
>>>>> == 53",
>>>>> +                actions);
>>>>> +            dns_flow_added = true;
>>>>> +        }
>>>>>      }
>>>>>  }
>>>>>
>>>>> @@ -3307,8 +3326,51 @@ build_lswitch_flows(struct hmap *datapaths,
>>>>> struct hmap *ports,
>>>>>          }
>>>>>      }
>>>>>
>>>>> +    HMAP_FOR_EACH (od, key_node, datapaths) {
>>>>> +        if (!od->nbs) {
>>>>> +           continue;
>>>>> +        }
>>>>> +
>>>>> +        for (size_t i = 0; i < od->nbs->n_ports; i++) {
>>>>> +            const struct nbrec_logical_switch_port *nbsp =
>>>>> +                od->nbs->ports[i];
>>>>> +
>>>>> +            if (!nbsp || !od->sb || !smap_get(&nbsp->options,
>>>>> "hostname")) {
>>>>> +                continue;
>>>>> +            }
>>>>> +
>>>>> +            struct ds match;
>>>>> +            struct ds action;
>>>>> +            ds_init(&match);
>>>>> +            ds_init(&action);
>>>>> +            ds_put_cstr(&match, "ip && udp.dst == 53");
>>>>> +            ds_put_format(&action,
>>>>> +                          REGBIT_DNS_LOOKUP_RESULT" = dns_lookup();
>>>>> next;");
>>>>> +            ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 100,
>>>>> +                          ds_cstr(&match), ds_cstr(&action));
>>>>> +            ds_clear(&action);
>>>>> +            ds_put_cstr(&match, " && "REGBIT_DNS_LOOKUP_RESULT);
>>>>> +            ds_put_format(&action, "eth.dst <-> eth.src; ip4.src <->
>>>>> ip4.dst; "
>>>>> +                          "udp.dst = udp.src; udp.src = 53; outport =
>>>>> inport; "
>>>>> +                          "flags.loopback = 1; output;");
>>>>> +            ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 100,
>>>>> +                          ds_cstr(&match), ds_cstr(&action));
>>>>> +            ds_clear(&action);
>>>>> +            ds_put_format(&action, "eth.dst <-> eth.src; ip6.src <->
>>>>> ip6.dst; "
>>>>> +                          "udp.dst = udp.src; udp.src = 53; outport =
>>>>> inport; "
>>>>> +                          "flags.loopback = 1; output;");
>>>>> +            ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 100,
>>>>> +                          ds_cstr(&match), ds_cstr(&action));
>>>>> +            ds_destroy(&match);
>>>>> +            ds_destroy(&action);
>>>>> +            break;
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>>      /* Ingress table 11 and 12: DHCP options and response, by default
>>>>> goto next.
>>>>> -     * (priority 0). */
>>>>> +     * (priority 0).
>>>>> +     * Ingress table 13 and 14: DNS lookup and response, by default
>>>>> goto next.
>>>>> +     * (priority 0).*/
>>>>>
>>>>>      HMAP_FOR_EACH (od, key_node, datapaths) {
>>>>>          if (!od->nbs) {
>>>>> @@ -3317,6 +3379,8 @@ build_lswitch_flows(struct hmap *datapaths,
>>>>> struct hmap *ports,
>>>>>
>>>>>          ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_OPTIONS, 0, "1",
>>>>> "next;");
>>>>>          ovn_lflow_add(lflows, od, S_SWITCH_IN_DHCP_RESPONSE, 0, "1",
>>>>> "next;");
>>>>> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_LOOKUP, 0, "1",
>>>>> "next;");
>>>>> +        ovn_lflow_add(lflows, od, S_SWITCH_IN_DNS_RESPONSE, 0, "1",
>>>>> "next;");
>>>>>      }
>>>>>
>>>>>      /* Ingress table 13: Destination lookup, broadcast and multicast
>>>>> handling
>>>>> @@ -5246,6 +5310,112 @@ sync_address_sets(struct northd_context *ctx)
>>>>>      }
>>>>>      shash_destroy(&sb_address_sets);
>>>>>  }
>>>>> +
>>>>> +static void
>>>>> +sync_dns_entries(struct northd_context *ctx, struct hmap *ports)
>>>>> +{
>>>>> +    struct dns_info {
>>>>> +        struct hmap_node hmap_node;
>>>>> +        const struct sbrec_datapath_binding *sb;
>>>>> +        const char *hostname;
>>>>> +        char **ip_addresses;
>>>>> +        size_t n_ip_addresses;
>>>>> +    };
>>>>> +
>>>>> +    struct hmap dns_map = HMAP_INITIALIZER(&dns_map);
>>>>> +    struct ovn_port *op;
>>>>> +
>>>>> +    HMAP_FOR_EACH (op, key_node, ports) {
>>>>> +        if (!op->nbsp || !op->sb || !lsp_is_enabled(op->nbsp) ||
>>>>> op->nbrp) {
>>>>> +            continue;
>>>>> +        }
>>>>> +
>>>>> +        const char *hostname = smap_get(&op->nbsp->options,
>>>>> "hostname");
>>>>> +        if (!hostname) {
>>>>> +            continue;
>>>>> +        }
>>>>> +
>>>>> +        struct dns_info *dns_info = xzalloc(sizeof *dns_info);
>>>>> +        dns_info->sb = op->sb->datapath;
>>>>> +        dns_info->hostname = hostname;
>>>>> +        for (unsigned int i = 0; i < op->n_lsp_addrs; i++) {
>>>>> +             for (size_t j = 0; j < op->lsp_addrs[i].n_ipv4_addrs;
>>>>> j++) {
>>>>> +                 dns_info->ip_addresses = xrealloc(
>>>>> +                     dns_info->ip_addresses,
>>>>> +                     sizeof *dns_info->ip_addresses * (
>>>>> +                         dns_info->n_ip_addresses + 1));
>>>>> +                 dns_info->ip_addresses[dns_info->n_ip_addresses++] =
>>>>> +                     op->lsp_addrs[i].ipv4_addrs[j].addr_s;
>>>>> +             }
>>>>> +
>>>>> +             for (size_t j = 0; j < op->lsp_addrs[i].n_ipv6_addrs;
>>>>> j++) {
>>>>> +                  dns_info->ip_addresses = xrealloc(
>>>>> +                      dns_info->ip_addresses,
>>>>> +                      sizeof *dns_info->ip_addresses * (
>>>>> +                          dns_info->n_ip_addresses + 1));
>>>>> +                  dns_info->ip_addresses[dns_info->n_ip_addresses++]
>>>>> =
>>>>> +                      op->lsp_addrs[i].ipv6_addrs[j].addr_s;
>>>>> +             }
>>>>> +        }
>>>>> +        size_t hash = uuid_hash(&dns_info->sb->header_.uuid);
>>>>> +        hash = hash_string(dns_info->hostname, hash);
>>>>> +        hmap_insert(&dns_map, &dns_info->hmap_node, hash);
>>>>> +    }
>>>>> +
>>>>> +    const struct sbrec_dns *sbrec_dns, *next;
>>>>> +    SBREC_DNS_FOR_EACH_SAFE(sbrec_dns, next, ctx->ovnsb_idl) {
>>>>> +        size_t hash = uuid_hash(&sbrec_dns->datapath->header_.uuid);
>>>>> +        hash = hash_string(sbrec_dns->hostname, hash);
>>>>> +        bool delete_dns_record = true;
>>>>> +        struct dns_info *dns_info;
>>>>> +        HMAP_FOR_EACH_WITH_HASH(dns_info, hmap_node, hash, &dns_map)
>>>>> {
>>>>> +            if (!strcmp(dns_info->hostname, sbrec_dns->hostname)) {
>>>>> +                /* Verify that the IP addresses are same before
>>>>> removing from
>>>>> +                 * the hmap. */
>>>>> +                if (dns_info->n_ip_addresses !=
>>>>> sbrec_dns->n_ip_addresses) {
>>>>> +                    continue;
>>>>> +                }
>>>>> +
>>>>> +                delete_dns_record = false;
>>>>> +                for (size_t i = 0; i < sbrec_dns->n_ip_addresses;
>>>>> i++) {
>>>>> +                    if (strcmp(dns_info->ip_addresses[i],
>>>>> +                               sbrec_dns->ip_addresses[i])) {
>>>>> +                        delete_dns_record = true;
>>>>> +                        break;
>>>>> +                    }
>>>>> +                }
>>>>> +
>>>>> +                if (delete_dns_record) {
>>>>> +                    continue;
>>>>> +                }
>>>>> +
>>>>> +                hmap_remove(&dns_map, &dns_info->hmap_node);
>>>>> +                free(dns_info->ip_addresses);
>>>>> +                free(dns_info);
>>>>> +                delete_dns_record = false;
>>>>> +                break;
>>>>> +            }
>>>>> +        }
>>>>> +
>>>>> +        if (delete_dns_record) {
>>>>> +            sbrec_dns_delete(sbrec_dns);
>>>>> +        }
>>>>> +    }
>>>>> +
>>>>> +    struct dns_info *dns_info;
>>>>> +    HMAP_FOR_EACH_POP(dns_info, hmap_node, &dns_map) {
>>>>> +        struct sbrec_dns *sbrec_dns = sbrec_dns_insert(ctx->ovnsb_tx
>>>>> n);
>>>>> +        sbrec_dns_set_datapath(sbrec_dns, dns_info->sb);
>>>>> +        sbrec_dns_set_hostname(sbrec_dns, dns_info->hostname);
>>>>> +        sbrec_dns_set_ip_addresses(
>>>>> +            sbrec_dns, (const char **) dns_info->ip_addresses,
>>>>> +            dns_info->n_ip_addresses);
>>>>> +        free(dns_info->ip_addresses);
>>>>> +        free(dns_info);
>>>>> +    }
>>>>> +    hmap_destroy(&dns_map);
>>>>> +}
>>>>> +
>>>>>
>>>>>  static void
>>>>>  ovnnb_db_run(struct northd_context *ctx, struct ovsdb_idl_loop
>>>>> *sb_loop)
>>>>> @@ -5260,6 +5430,7 @@ ovnnb_db_run(struct northd_context *ctx, struct
>>>>> ovsdb_idl_loop *sb_loop)
>>>>>      build_lflows(ctx, &datapaths, &ports);
>>>>>
>>>>>      sync_address_sets(ctx);
>>>>> +    sync_dns_entries(ctx, &ports);
>>>>>
>>>>>      struct ovn_datapath *dp, *next_dp;
>>>>>      HMAP_FOR_EACH_SAFE (dp, next_dp, key_node, &datapaths) {
>>>>> @@ -5657,6 +5828,10 @@ main(int argc, char *argv[])
>>>>>      add_column_noalert(ovnsb_idl_loop.idl,
>>>>> &sbrec_address_set_col_name);
>>>>>      add_column_noalert(ovnsb_idl_loop.idl,
>>>>> &sbrec_address_set_col_addresses);
>>>>>
>>>>> +    ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_dns);
>>>>> +    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_datapath);
>>>>> +    add_column_noalert(ovnsb_idl_loop.idl, &sbrec_dns_col_hostname);
>>>>> +
>>>>>      ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis);
>>>>>      ovsdb_idl_add_column(ovnsb_idl_loop.idl,
>>>>> &sbrec_chassis_col_nb_cfg);
>>>>>
>>>>> diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
>>>>> index 88a6082..ccc978d 100644
>>>>> --- a/ovn/ovn-nb.xml
>>>>> +++ b/ovn/ovn-nb.xml
>>>>> @@ -344,6 +344,23 @@
>>>>>            If set, indicates the maximum burst size for data sent from
>>>>> this
>>>>>            interface, in bits.
>>>>>          </column>
>>>>> +
>>>>> +        <column name="options" key="hostname">
>>>>> +          If set, indicates the hostname associated with the logical
>>>>> port.
>>>>> +          <code>OVN</code> supports a simple native internal DNS
>>>>> +          resolution. Any DNS query for this host name from the VIFs
>>>>> belonging
>>>>> +          to the same logical network would be resolved by
>>>>> +          <code>OVN</code> to the IP addresses defined in the
>>>>> +          <ref column="addresses"/> field. If no match is found, the
>>>>> DNS query
>>>>> +          request is expected to be handled by an external DNS
>>>>> resolver.
>>>>> +        </column>
>>>>> +
>>>>> +        <column name="options" key="fqdn">
>>>>> +          If set, indicates the fqdn associated with the logical port.
>>>>> +          Any DNS query for this fqdn would be resolved by
>>>>> +          <code>ovn-controller</code> to the IP addresses defined in
>>>>> the
>>>>> +          <ref column="addresses"/> field.
>>>>> +        </column>
>>>>>        </group>
>>>>>      </group>
>>>>>
>>>>> @@ -1926,5 +1943,4 @@
>>>>>        <column name="external_ids"/>
>>>>>      </group>
>>>>>    </table>
>>>>> -
>>>>>  </database>
>>>>> diff --git a/tests/ovn.at b/tests/ovn.at
>>>>> index 4b4beb0..f5f6885 100644
>>>>> --- a/tests/ovn.at
>>>>> +++ b/tests/ovn.at
>>>>> @@ -6334,6 +6334,346 @@ OVS_APP_EXIT_AND_WAIT([ovsdb-server])
>>>>>
>>>>>  AT_CLEANUP
>>>>>
>>>>> +AT_SETUP([ovn -- dns lookup : 1 HV, 2 LS, 2 LSPs/LS])
>>>>> +AT_SKIP_IF([test $HAVE_PYTHON = no])
>>>>> +ovn_start
>>>>> +
>>>>> +ovn-nbctl ls-add ls1
>>>>> +
>>>>> +ovn-nbctl lsp-add ls1 ls1-lp1 \
>>>>> +-- lsp-set-addresses ls1-lp1 "f0:00:00:00:00:01 10.0.0.4 aef0::4"
>>>>> +
>>>>> +ovn-nbctl lsp-set-port-security ls1-lp1 "f0:00:00:00:00:01 10.0.0.4
>>>>> aef0::4"
>>>>> +
>>>>> +ovn-nbctl lsp-add ls1 ls1-lp2 \
>>>>> +-- lsp-set-addresses ls1-lp2 "f0:00:00:00:00:02 10.0.0.6 20.0.0.4"
>>>>> +
>>>>> +ovn-nbctl lsp-set-port-security ls1-lp2 "f0:00:00:00:00:02 10.0.0.6
>>>>> 20.0.0.4"
>>>>> +
>>>>> +ovn-nbctl lsp-set-options ls1-lp1 hostname=vm1.ovn.org
>>>>> +ovn-nbctl lsp-set-options ls1-lp2 hostname=vm2.ovn.org
>>>>> +
>>>>> +net_add n1
>>>>> +sim_add hv1
>>>>> +
>>>>> +as hv1
>>>>> +ovs-vsctl add-br br-phys
>>>>> +ovn_attach n1 br-phys 192.168.0.1
>>>>> +ovs-vsctl -- add-port br-int hv1-vif1 -- \
>>>>> +    set interface hv1-vif1 external-ids:iface-id=ls1-lp1 \
>>>>> +    options:tx_pcap=hv1/vif1-tx.pcap \
>>>>> +    options:rxq_pcap=hv1/vif1-rx.pcap \
>>>>> +    ofport-request=1
>>>>> +
>>>>> +ovs-vsctl -- add-port br-int hv1-vif2 -- \
>>>>> +    set interface hv1-vif2 external-ids:iface-id=ls1-lp2 \
>>>>> +    options:tx_pcap=hv1/vif2-tx.pcap \
>>>>> +    options:rxq_pcap=hv1/vif2-rx.pcap \
>>>>> +    ofport-request=2
>>>>> +
>>>>> +ovn_populate_arp
>>>>> +sleep 2
>>>>> +as hv1 ovs-vsctl show
>>>>> +
>>>>> +echo "*************************"
>>>>> +ovn-sbctl list DNS
>>>>> +echo "*************************"
>>>>> +
>>>>> +ip_to_hex() {
>>>>> +    printf "%02x%02x%02x%02x" "$@"
>>>>> +}
>>>>> +
>>>>> +reset_pcap_file() {
>>>>> +    local iface=$1
>>>>> +    local pcap_file=$2
>>>>> +    ovs-vsctl -- set Interface $iface options:tx_pcap=dummy-tx.pcap \
>>>>> +options:rxq_pcap=dummy-rx.pcap
>>>>> +    rm -f ${pcap_file}*.pcap
>>>>> +    ovs-vsctl -- set Interface $iface 
>>>>> options:tx_pcap=${pcap_file}-tx.pcap
>>>>> \
>>>>> +options:rxq_pcap=${pcap_file}-rx.pcap
>>>>> +}
>>>>> +
>>>>> +# set_lsp_dns_params lsp_name
>>>>> +# Sets the dns_req_data and dns_resp_data
>>>>> +set_lsp_dns_params() {
>>>>> +    local lsp_name=$1
>>>>> +    local ttl=00000e10
>>>>> +    an_count=0001
>>>>> +    type=0001
>>>>> +    case $lsp_name in
>>>>> +    ls1-lp1)
>>>>> +        # vm1.ovn.org
>>>>> +        hostname=03766d31036f766e036f726700
>>>>> +        # IPv4 address - 10.0.0.4
>>>>> +        expected_dns_answer=${hostname}00010001${ttl}00040a000004
>>>>> +        ;;
>>>>> +    ls1-lp2)
>>>>> +        # vm2.ovn.org
>>>>> +        hostname=03766d32036f766e036f726700
>>>>> +        # IPv4 address - 10.0.0.6
>>>>> +        expected_dns_answer=${hostname}00010001${ttl}00040a000006
>>>>> +        # IPv4 address - 20.0.0.4
>>>>> +        expected_dns_answer=${expected_dns_answer}${hostname}0001000
>>>>> 1${ttl}000414000004
>>>>> +        an_count=0002
>>>>> +        ;;
>>>>> +    ls1-lp1_ipv6_only)
>>>>> +        # vm1.ovn.org
>>>>> +        hostname=03766d31036f766e036f726700
>>>>> +        # IPv6 address - aef0::4
>>>>> +        type=001c
>>>>> +        expected_dns_answer=${hostname}${type}0001${ttl}0010aef00000
>>>>> 000000000000000000000004
>>>>> +        ;;
>>>>> +    ls1-lp1_ipv4_v6)
>>>>> +        # vm1.ovn.org
>>>>> +        hostname=03766d31036f766e036f726700
>>>>> +        type=00ff
>>>>> +        an_count=0002
>>>>> +        # IPv4 address - 10.0.0.4
>>>>> +        # IPv6 address - aef0::4
>>>>> +        expected_dns_answer=${hostname}00010001${ttl}00040a000004
>>>>> +        expected_dns_answer=${expected_dns_answer}${hostname}001c000
>>>>> 1${ttl}0010
>>>>> +        expected_dns_answer=${expected_dns_answer}aef000000000000000
>>>>> 00000000000004
>>>>> +        ;;
>>>>> +    ls1-lp1_invalid_type)
>>>>> +        # vm1.ovn.org
>>>>> +        hostname=03766d31036f766e036f726700
>>>>> +        # IPv6 address - aef0::4
>>>>> +        type=0002
>>>>> +        ;;
>>>>> +    ls1-lp1_incomplete)
>>>>> +        # set type to none
>>>>> +        type=''
>>>>> +    esac
>>>>> +    # TTL - 3600
>>>>> +    local dns_req_header=010201200001000000000000
>>>>> +    local dns_resp_header=010281200001${an_count}00000000
>>>>> +    dns_req_data=${dns_req_header}${hostname}${type}0001
>>>>> +    dns_resp_data=${dns_resp_header}${hostname}${type}0001${expe
>>>>> cted_dns_answer}
>>>>> +}
>>>>> +
>>>>> +# This shell function sends a DNS request packet
>>>>> +# test_dns INPORT SRC_MAC DST_MAC SRC_IP DST_IP DNS_QUERY EXPEC
>>>>> +test_dns() {
>>>>> +    local inport=$1 src_mac=$2 dst_mac=$3 src_ip=$4 dst_ip=$5
>>>>> dns_reply=$6
>>>>> +    local dns_query_data=$7
>>>>> +    shift; shift; shift; shift; shift; shift; shift;
>>>>> +    # Packet size => IPv4 header (20) + UDP header (8) +
>>>>> +    #                DNS data (header + query)
>>>>> +    ip_len=`expr 28 + ${#dns_query_data} / 2`
>>>>> +    udp_len=`expr $ip_len - 20`
>>>>> +    ip_len=$(printf "%x" $ip_len)
>>>>> +    udp_len=$(printf "%x" $udp_len)
>>>>> +    local request=${dst_mac}${src_mac}08
>>>>> 00450000${ip_len}0000000080110000
>>>>> +    request=${request}${src_ip}${dst_ip}9234003500${udp_len}0000
>>>>> +    # dns data
>>>>> +    request=${request}${dns_query_data}
>>>>> +
>>>>> +    if test $dns_reply != 0; then
>>>>> +        local dns_reply=$1
>>>>> +        ip_len=`expr 28 + ${#dns_reply} / 2`
>>>>> +        udp_len=`expr $ip_len - 20`
>>>>> +        ip_len=$(printf "%x" $ip_len)
>>>>> +        udp_len=$(printf "%x" $udp_len)
>>>>> +        local reply=${src_mac}${dst_mac}0800
>>>>> 450000${ip_len}0000000080110000
>>>>> +        reply=${reply}${dst_ip}${src_ip}0035923400${udp_len}0000${dn
>>>>> s_reply}
>>>>> +        echo $reply >> $inport.expected
>>>>> +    else
>>>>> +        for outport; do
>>>>> +            echo $request >> $outport.expected
>>>>> +        done
>>>>> +    fi
>>>>> +    as hv1 ovs-appctl netdev-dummy/receive hv1-vif$inport $request
>>>>> +}
>>>>> +
>>>>> +AT_CAPTURE_FILE([ofctl_monitor0.log])
>>>>> +as hv1 ovs-ofctl monitor br-int resume --detach --no-chdir \
>>>>> +--pidfile=ovs-ofctl0.pid 2> ofctl_monitor0.log
>>>>> +
>>>>> +set_lsp_dns_params ls1-lp2
>>>>> +src_ip=`ip_to_hex 10 0 0 4`
>>>>> +dst_ip=`ip_to_hex 10 0 0 1`
>>>>> +dns_reply=1
>>>>> +test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply
>>>>> $dns_req_data $dns_resp_data
>>>>> +
>>>>> +# NXT_RESUMEs should be 1.
>>>>> +OVS_WAIT_UNTIL([test 1 = `cat ofctl_monitor*.log | grep -c
>>>>> NXT_RESUME`])
>>>>> +
>>>>> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap >
>>>>> 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])
>>>>> +
>>>>> +reset_pcap_file hv1-vif1 hv1/vif1
>>>>> +reset_pcap_file hv1-vif2 hv1/vif2
>>>>> +rm -f 1.expected
>>>>> +rm -f 2.expected
>>>>> +
>>>>> +set_lsp_dns_params ls1-lp1
>>>>> +src_ip=`ip_to_hex 10 0 0 6`
>>>>> +dst_ip=`ip_to_hex 10 0 0 1`
>>>>> +dns_reply=1
>>>>> +test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply
>>>>> $dns_req_data $dns_resp_data
>>>>> +
>>>>> +# NXT_RESUMEs should be 2.
>>>>> +OVS_WAIT_UNTIL([test 2 = `cat ofctl_monitor*.log | grep -c
>>>>> NXT_RESUME`])
>>>>> +
>>>>> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap >
>>>>> 2.packets
>>>>> +cat 2.expected | cut -c -48 > expout
>>>>> +AT_CHECK([cat 2.packets | cut -c -48], [0], [expout])
>>>>> +# Skipping the IPv4 checksum.
>>>>> +cat 2.expected | cut -c 53- > expout
>>>>> +AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout])
>>>>> +
>>>>> +reset_pcap_file hv1-vif1 hv1/vif1
>>>>> +reset_pcap_file hv1-vif2 hv1/vif2
>>>>> +rm -f 1.expected
>>>>> +rm -f 2.expected
>>>>> +
>>>>> +# Clear the hostname options for ls1-lp2
>>>>> +ovn-nbctl lsp-set-options ls1-lp2
>>>>> +
>>>>> +set_lsp_dns_params ls1-lp2
>>>>> +src_ip=`ip_to_hex 10 0 0 4`
>>>>> +dst_ip=`ip_to_hex 10 0 0 1`
>>>>> +dns_reply=0
>>>>> +test_dns 1 f00000000001 f00000000002 $src_ip $dst_ip $dns_reply
>>>>> $dns_req_data
>>>>> +
>>>>> +# NXT_RESUMEs should be 3.
>>>>> +OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c
>>>>> NXT_RESUME`])
>>>>> +
>>>>> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap >
>>>>> 1.packets
>>>>> +AT_CHECK([cat 1.packets], [0], [])
>>>>> +
>>>>> +reset_pcap_file hv1-vif1 hv1/vif1
>>>>> +reset_pcap_file hv1-vif2 hv1/vif2
>>>>> +rm -f 1.expected
>>>>> +rm -f 2.expected
>>>>> +
>>>>> +# Clear the hostname for ls1-lp1
>>>>> +# Since no ports of ls1 has hostname configued,
>>>>> +# ovn-northd should not add the DNS flows.
>>>>> +ovn-nbctl lsp-set-options ls1-lp1
>>>>> +set_lsp_dns_params ls1-lp1
>>>>> +src_ip=`ip_to_hex 10 0 0 6`
>>>>> +dst_ip=`ip_to_hex 10 0 0 1`
>>>>> +dns_reply=0
>>>>> +test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply
>>>>> $dns_req_data
>>>>> +
>>>>> +# NXT_RESUMEs should be 3 only.
>>>>> +OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c
>>>>> NXT_RESUME`])
>>>>> +
>>>>> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap >
>>>>> 2.packets
>>>>> +AT_CHECK([cat 2.packets], [0], [])
>>>>> +
>>>>> +reset_pcap_file hv1-vif1 hv1/vif1
>>>>> +reset_pcap_file hv1-vif2 hv1/vif2
>>>>> +rm -f 1.expected
>>>>> +rm -f 2.expected
>>>>> +
>>>>> +# Test IPv6 (AAAA records) using IPv4 packet.
>>>>> +# Add back the DNS options for ls1-lp1.
>>>>> +ovn-nbctl lsp-set-options ls1-lp1 hostname=vm1.ovn.org
>>>>> +
>>>>> +set_lsp_dns_params ls1-lp1_ipv6_only
>>>>> +src_ip=`ip_to_hex 10 0 0 6`
>>>>> +dst_ip=`ip_to_hex 10 0 0 1`
>>>>> +dns_reply=1
>>>>> +test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply
>>>>> $dns_req_data $dns_resp_data
>>>>> +
>>>>> +# NXT_RESUMEs should be 4.
>>>>> +OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c
>>>>> NXT_RESUME`])
>>>>> +
>>>>> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap >
>>>>> 2.packets
>>>>> +cat 2.expected | cut -c -48 > expout
>>>>> +AT_CHECK([cat 2.packets | cut -c -48], [0], [expout])
>>>>> +# Skipping the IPv4 checksum.
>>>>> +cat 2.expected | cut -c 53- > expout
>>>>> +AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout])
>>>>> +
>>>>> +reset_pcap_file hv1-vif1 hv1/vif1
>>>>> +reset_pcap_file hv1-vif2 hv1/vif2
>>>>> +rm -f 1.expected
>>>>> +rm -f 2.expected
>>>>> +
>>>>> +# Test both IPv4 (A) and IPv6 (AAAA records) using IPv4 packet.
>>>>> +set_lsp_dns_params ls1-lp1_ipv4_v6
>>>>> +src_ip=`ip_to_hex 10 0 0 6`
>>>>> +dst_ip=`ip_to_hex 10 0 0 1`
>>>>> +dns_reply=1
>>>>> +test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply
>>>>> $dns_req_data $dns_resp_data
>>>>> +
>>>>> +# NXT_RESUMEs should be 5.
>>>>> +OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c
>>>>> NXT_RESUME`])
>>>>> +
>>>>> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap >
>>>>> 2.packets
>>>>> +cat 2.expected | cut -c -48 > expout
>>>>> +AT_CHECK([cat 2.packets | cut -c -48], [0], [expout])
>>>>> +# Skipping the IPv4 checksum.
>>>>> +cat 2.expected | cut -c 53- > expout
>>>>> +AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout])
>>>>> +
>>>>> +reset_pcap_file hv1-vif1 hv1/vif1
>>>>> +reset_pcap_file hv1-vif2 hv1/vif2
>>>>> +rm -f 1.expected
>>>>> +rm -f 2.expected
>>>>> +
>>>>> +# Invalid type.
>>>>> +set_lsp_dns_params ls1-lp1_invalid_type
>>>>> +src_ip=`ip_to_hex 10 0 0 6`
>>>>> +dst_ip=`ip_to_hex 10 0 0 1`
>>>>> +dns_reply=0
>>>>> +test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply
>>>>> $dns_req_data
>>>>> +
>>>>> +# NXT_RESUMEs should be 6.
>>>>> +OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c
>>>>> NXT_RESUME`])
>>>>> +
>>>>> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap >
>>>>> 2.packets
>>>>> +AT_CHECK([cat 2.packets], [0], [])
>>>>> +
>>>>> +reset_pcap_file hv1-vif1 hv1/vif1
>>>>> +reset_pcap_file hv1-vif2 hv1/vif2
>>>>> +rm -f 1.expected
>>>>> +rm -f 2.expected
>>>>> +
>>>>> +# Incomplete DNS packet.
>>>>> +set_lsp_dns_params ls1-lp1_incomplete
>>>>> +src_ip=`ip_to_hex 10 0 0 6`
>>>>> +dst_ip=`ip_to_hex 10 0 0 1`
>>>>> +dns_reply=0
>>>>> +test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply
>>>>> $dns_req_data
>>>>> +
>>>>> +# NXT_RESUMEs should be 7.
>>>>> +OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c
>>>>> NXT_RESUME`])
>>>>> +
>>>>> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap >
>>>>> 2.packets
>>>>> +AT_CHECK([cat 2.packets], [0], [])
>>>>> +
>>>>> +reset_pcap_file hv1-vif1 hv1/vif1
>>>>> +reset_pcap_file hv1-vif2 hv1/vif2
>>>>> +rm -f 1.expected
>>>>> +rm -f 2.expected
>>>>> +
>>>>> +as hv1
>>>>> +OVS_APP_EXIT_AND_WAIT([ovn-controller])
>>>>> +OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
>>>>> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
>>>>> +
>>>>> +as ovn-sb
>>>>> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
>>>>> +
>>>>> +as ovn-nb
>>>>> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
>>>>> +
>>>>> +as northd
>>>>> +OVS_APP_EXIT_AND_WAIT([ovn-northd])
>>>>> +
>>>>> +as main
>>>>> +OVS_APP_EXIT_AND_WAIT([ovs-vswitchd])
>>>>> +OVS_APP_EXIT_AND_WAIT([ovsdb-server])
>>>>> +AT_CLEANUP
>>>>> +
>>>>>  AT_SETUP([ovn -- 1 LR with distributed router gateway port])
>>>>>  AT_SKIP_IF([test $HAVE_PYTHON = no])
>>>>>  ovn_start
>>>>> --
>>>>> 2.9.3
>>>>>
>>>>> _______________________________________________
>>>>> dev mailing list
>>>>> d...@openvswitch.org
>>>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>>>>
>>>>
>>>>
>>>
>>
>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to