[ovs-dev] [PATCH v2 2/2] ovn-northd: Add logical flows to support native DNS
Guru Shetty
guru at ovn.org
Thu Mar 23 15:22:36 UTC 2017
On 22 March 2017 at 21:25, Numan Siddique <nusiddiq at redhat.com> wrote:
>
>
> 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.
>
How would we be able to provide DNS names to VIPs of load-balancers in this
case?
>
> 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 && 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 <-> eth.src;
>>>> +ip4.src <-> 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( ->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}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