[ovs-dev] [PATCH v2 2/2] ovn-northd: Add logical flows to support native DNS

Numan Siddique nusiddiq at redhat.com
Thu Mar 23 04:25:52 UTC 2017


On Wed, Mar 22, 2017 at 10:43 PM, Guru Shetty <guru at ovn.org> wrote:

>
>
> On 22 March 2017 at 09:51, Guru Shetty <guru at ovn.org> wrote:
>
>>
>>
>> On 13 March 2017 at 00:32, <nusiddiq at redhat.com> wrote:
>>
>>> From: Numan Siddique <nusiddiq at 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 <nusiddiq at 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.

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_txn);
>>> +        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}0800450000${ip_len}0000000080110
>>> 000
>>> +    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
>>> dev at openvswitch.org
>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>>
>>
>>
>


More information about the dev mailing list