On 10/1/23 21:27, Mohammad Heib wrote: > Currently OVN allows users to create DNS records > and define domains within these records. > > These domains can be associated with IPV4 or IPv6 > or both, when the user creates a domain with both > IPv4 and IPv6 ovn will answer each query for this > domain immediately and everything works as expected. > > But if the user only creates a domain with only IPv4 > or IPv6 this will cause the DNS queries respond take > longer than the usual since OVN will forward query and > user will keep waiting for an answer until someone else > replies for this query or timeout occur. > > The above behavior is a bit problematic if the user knows > that this domain is only configured in OVN we should not > forward queries for this domain to the outside. > > This patch adds an option:ovn-owned for the DNS table > that can be set to "true" when creating a DNS. > > When setting this option to "true" all the domains within > this table will be treated as local domains only, > and queries for domains within this table that don't have > an accurate IP will be refused immediately to save the time > of waiting for timeout. > > Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1946662 > Signed-off-by: Mohammad Heib <mh...@redhat.com> > ---
Hi Mohammad, Thanks for the patch. It looks OK overall, I have a few remark inline. > NEWS | 5 ++++ > controller/pinctrl.c | 47 ++++++++++++++++++++++++++++++-- > northd/northd.c | 11 ++++++++ > ovn-nb.ovsschema | 9 ++++-- > ovn-nb.xml | 14 ++++++++++ > ovn-sb.ovsschema | 9 ++++-- > ovn-sb.xml | 6 ++++ > tests/ovn.at | 65 ++++++++++++++++++++++++++++++++++++++++++++ > 8 files changed, 160 insertions(+), 6 deletions(-) > > diff --git a/NEWS b/NEWS > index 425dfe0a8..465649430 100644 > --- a/NEWS > +++ b/NEWS > @@ -1,5 +1,10 @@ > Post v23.09.0 > ------------- > + - DNS now have an "options" column for configuration of extra options. > + - A new DNS option "ovn-owned" has been added to allow defining domains > + that are owned only by ovn, queries for that domain will not be processed > + externally. > + > > OVN v23.09.0 - 15 Sep 2023 > -------------------------- > diff --git a/controller/pinctrl.c b/controller/pinctrl.c > index ff5a3444c..e1e558595 100644 > --- a/controller/pinctrl.c > +++ b/controller/pinctrl.c > @@ -179,6 +179,7 @@ struct pinctrl { > struct latch pinctrl_thread_exit; > bool mac_binding_can_timestamp; > bool fdb_can_timestamp; > + bool dns_can_ovn_owned; I think I'd call this "dns_supports_ovn_owned". > }; > > static struct pinctrl pinctrl; > @@ -2709,6 +2710,7 @@ struct dns_data { > uint64_t *dps; > size_t n_dps; > struct smap records; > + struct smap options; > bool delete; > }; > > @@ -2737,6 +2739,7 @@ sync_dns_cache(const struct sbrec_dns_table *dns_table) > if (!dns_data) { > dns_data = xmalloc(sizeof *dns_data); > smap_init(&dns_data->records); > + smap_init(&dns_data->options); > shash_add(&dns_cache, dns_id, dns_data); > dns_data->n_dps = 0; > dns_data->dps = NULL; > @@ -2751,6 +2754,12 @@ sync_dns_cache(const struct sbrec_dns_table *dns_table) > smap_clone(&dns_data->records, &sbrec_dns->records); > } > > + if (pinctrl.dns_can_ovn_owned > + && !smap_equal(&dns_data->options, &sbrec_dns->options)) { > + smap_destroy(&dns_data->options); > + smap_clone(&dns_data->options, &sbrec_dns->options); > + } > + > dns_data->n_dps = sbrec_dns->n_datapaths; > dns_data->dps = xcalloc(dns_data->n_dps, sizeof(uint64_t)); > for (size_t i = 0; i < sbrec_dns->n_datapaths; i++) { > @@ -2763,6 +2772,7 @@ sync_dns_cache(const struct sbrec_dns_table *dns_table) > if (d->delete) { > shash_delete(&dns_cache, iter); > smap_destroy(&d->records); > + smap_destroy(&d->options); > free(d->dps); > free(d); > } > @@ -2777,6 +2787,7 @@ destroy_dns_cache(void) > struct dns_data *d = iter->data; > shash_delete(&dns_cache, iter); > smap_destroy(&d->records); > + smap_destroy(&d->options); > free(d->dps); > free(d); > } > @@ -2850,6 +2861,8 @@ dns_build_ptr_answer( > free(encoded); > } > > +#define DNS_RCODE_SERVER_REFUSE 0x5 > + > /* Called with in the pinctrl_handler thread context. */ > static void > pinctrl_handle_dns_lookup( > @@ -2863,6 +2876,7 @@ pinctrl_handle_dns_lookup( > enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version); > struct dp_packet *pkt_out_ptr = NULL; > uint32_t success = 0; > + bool send_query_rejection = false; Nit: I think I'd rename this to 'send_refuse'. Nit: reverse xmas tree. > > /* Parse result field. */ > const struct mf_field *f; > @@ -2962,6 +2976,7 @@ pinctrl_handle_dns_lookup( > > uint64_t dp_key = ntohll(pin->flow_metadata.flow.metadata); > const char *answer_data = NULL; > + bool ovn_owned = false; > struct shash_node *iter; > SHASH_FOR_EACH (iter, &dns_cache) { > struct dns_data *d = iter->data; > @@ -2974,6 +2989,7 @@ pinctrl_handle_dns_lookup( > answer_data = smap_get(&d->records, query_name_lower); > free(query_name_lower); > if (answer_data) { > + ovn_owned = smap_get_bool(&d->options, "ovn-owned", > false); > break; > } > } > @@ -3020,10 +3036,22 @@ pinctrl_handle_dns_lookup( > ancount++; > } > } > + > + /* DNS is configured with a record for this domain with > + * an IPv4/IPV6 only, so instead of ignoring this A/AAAA query, > + * we can reply with RCODE = 5 (server refuses) and that > + * will speed up the DNS process by not letting the customer > + * wait for a timeout. > + */ > + if (ovn_owned && (query_type == DNS_QUERY_TYPE_AAAA || > + query_type == DNS_QUERY_TYPE_A) && !ancount) { > + send_query_rejection = true; > + } > + > destroy_lport_addresses(&ip_addrs); > } > > - if (!ancount) { > + if (!ancount && !send_query_rejection) { > ofpbuf_uninit(&dns_answer); > goto exit; > } > @@ -3058,13 +3086,19 @@ pinctrl_handle_dns_lookup( > > /* Set the answer RRs. */ > out_dns_header->ancount = htons(ancount); > + if (send_query_rejection) { > + /* set RCODE = 5 (server refuses). */ > + out_dns_header->hi_flag |= DNS_RCODE_SERVER_REFUSE; > + } > out_dns_header->arcount = 0; > > /* Copy the Query section. */ > dp_packet_put(&pkt_out, dp_packet_data(pkt_in), dp_packet_size(pkt_in)); > > /* Copy the answer sections. */ > - dp_packet_put(&pkt_out, dns_answer.data, dns_answer.size); > + if (!send_query_rejection) { We don't really need the "if", right? "dp_packet_put(&packet_out, foo, 0)" basically a no-op. > + dp_packet_put(&pkt_out, dns_answer.data, dns_answer.size); > + } > ofpbuf_uninit(&dns_answer); > > out_udp->udp_len = htons(new_l4_size); > @@ -3521,6 +3555,15 @@ pinctrl_update(const struct ovsdb_idl *idl, const char > *br_int_name) > notify_pinctrl_handler(); > } > > + bool dns_can_ovn_owned = sbrec_server_has_dns_table_col_options(idl); > + if (dns_can_ovn_owned != pinctrl.dns_can_ovn_owned) { > + pinctrl.dns_can_ovn_owned = dns_can_ovn_owned; > + > + /* Notify pinctrl_handler that fdb timestamp column > + * availability has changed. */ > + notify_pinctrl_handler(); > + } > + > ovs_mutex_unlock(&pinctrl_mutex); > } > > diff --git a/northd/northd.c b/northd/northd.c > index 528027d07..70a2922f2 100644 > --- a/northd/northd.c > +++ b/northd/northd.c > @@ -17196,6 +17196,17 @@ sync_dns_entries(struct ovsdb_idl_txn *ovnsb_txn, > free(dns_id); > } > > + > + /* Copy DNS options to SB*/ > + struct smap options; > + smap_clone(&options, &dns_info->sb_dns->options); > + > + bool ovn_owned = smap_get_bool(&dns_info->nb_dns->options, > + "ovn-owned", false); > + smap_replace(&options, "ovn-owned", > + ovn_owned? "true" : "false"); > + sbrec_dns_set_options(dns_info->sb_dns, &options); > + We leak "options" here, CI caught this: https://github.com/ovsrobot/ovn/actions/runs/6372957589/job/17296298390#step:8:5644 > /* Set the datapaths and records. If nothing has changed, then > * this will be a no-op. > */ > diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema > index e103360ec..b2e0993e0 100644 > --- a/ovn-nb.ovsschema > +++ b/ovn-nb.ovsschema > @@ -1,7 +1,7 @@ > { > "name": "OVN_Northbound", > - "version": "7.1.0", > - "cksum": "217362582 33949", > + "version": "7.2.0", > + "cksum": "1069338687 34162", > "tables": { > "NB_Global": { > "columns": { > @@ -560,6 +560,11 @@ > "value": "string", > "min": 0, > "max": "unlimited"}}, > + "options": { > + "type": {"key": "string", > + "value": "string", > + "min": 0, > + "max": "unlimited"}}, > "external_ids": {"type": {"key": "string", > "value": "string", > "min": 0, > diff --git a/ovn-nb.xml b/ovn-nb.xml > index 1de0c3041..4aa8107a5 100644 > --- a/ovn-nb.xml > +++ b/ovn-nb.xml > @@ -4542,6 +4542,20 @@ or > <p><b>Example: </b> "4.0.0.10.in-addr.arpa" = "vm1.ovn.org"</p> > </column> > > + <column name="options" key="ovn-owned"> > + If set to true, then the OVN will be the main responsible for > + <code>DNS Records</code> within this Table. > + > + <p> A <code>DNS Table</code> with this option set to <code>true</code> > + can be created for domains that the user needs to configure > + locally and don't care about IPv6 only interested in IPv4 or > + vice versa. > + > + This will let ovn send IPv4 DNS reply and reject/ignore IPv6 > + queries to save the waiting for a timeout on those uninteresting > + queries.</p> > + </column> > + > <column name="external_ids"> > See <em>External IDs</em> at the beginning of this document. > </column> > diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema > index 7b20aa21b..b5a16d231 100644 > --- a/ovn-sb.ovsschema > +++ b/ovn-sb.ovsschema > @@ -1,7 +1,7 @@ > { > "name": "OVN_Southbound", > - "version": "20.27.4", > - "cksum": "3194181501 30531", > + "version": "20.28.0", > + "cksum": "160983021 30744", > "tables": { > "SB_Global": { > "columns": { > @@ -363,6 +363,11 @@ > "refTable": > "Datapath_Binding"}, > "min": 1, > "max": "unlimited"}}, > + "options": { > + "type": {"key": "string", > + "value": "string", > + "min": 0, > + "max": "unlimited"}}, > "external_ids": {"type": {"key": "string", > "value": "string", > "min": 0, > diff --git a/ovn-sb.xml b/ovn-sb.xml > index 46aedf973..55fcf59b2 100644 > --- a/ovn-sb.xml > +++ b/ovn-sb.xml > @@ -4500,6 +4500,12 @@ tcp.flags = RST; > in this column. > </column> > > + <column name="options" key="ovn-owned"> > + This column indicates that all the <code>Domains</code> in this table > + are owned by OVN, and all <code>DNS queries</code> for those domains > + will be answered locally by either an IP address or > + <code>DNS rejection</code>. > +</column> > <group title="Common Columns"> > <column name="external_ids"> > See <em>External IDs</em> at the beginning of this document. > diff --git a/tests/ovn.at b/tests/ovn.at > index dfe535f36..88357fd33 100644 > --- a/tests/ovn.at > +++ b/tests/ovn.at > @@ -11302,6 +11302,71 @@ reset_pcap_file hv1-vif2 hv1/vif2 > rm -f 1.expected > rm -f 2.expected > > +# send AAAA query for a server known domain that don't have > +# any IPV6 address associated with this domain, and expected > +# server refused DNS reply to save the sender time of waiting for timeout. > +AS_BOX([Test IPv6 (AAAA records) NO timeout.]) > +# Add back the DNS options for ls1-lp1 without ipv6. > +check ovn-nbctl remove DNS $DNS1 records vm1.ovn.org > +check ovn-nbctl set DNS $DNS1 records:vm1.ovn.org="10.0.0.4" > +check ovn-nbctl --wait=hv set DNS $DNS1 options:ovn-owned=true > +ovn-sbctl list DNS > dns6 > +AT_CAPTURE_FILE([dns6]) > +ovn-sbctl dump-flows > sbflows6 > +AT_CAPTURE_FILE([sbflows6]) > + > +set_dns_params vm1_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 13. > +OVS_WAIT_UNTIL([test 13 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > + > +$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets > +# dns hdr with server refuse RCODE > +echo "01028125" > expout > +#only check for the DNS HDR flags since we are not getting any DNS answer > +AT_CHECK([cat 2.packets | cut -c -92 | cut -c 85-], [0], [expout]) > + > +reset_pcap_file hv1-vif1 hv1/vif1 > +reset_pcap_file hv1-vif2 hv1/vif2 > +rm -f 1.expected > +rm -f 2.expected > + > +# send A query for a server known domain that don't have > +# any IPv4 address associated with this domain, and expected > +# server refused DNS reply to save the sender time of waiting for timeout. > +AS_BOX([Test IPv4 (A records) NO timeout.]) > +# Add back the DNS options for ls1-lp1 without ipv4. > +check ovn-nbctl remove DNS $DNS1 records vm1.ovn.org > +check ovn-nbctl set DNS $DNS1 records:vm1.ovn.org="aef0::4" > +check ovn-nbctl --wait=hv set DNS $DNS1 options:ovn-owned=true > +ovn-sbctl list DNS > dns7 > +AT_CAPTURE_FILE([dns7]) > +ovn-sbctl dump-flows > sbflows7 > +AT_CAPTURE_FILE([sbflows7]) > + > +set_dns_params vm1 > +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 14. > +OVS_WAIT_UNTIL([test 14 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`]) > + > +$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets > +# dns hdr with server refuse RCODE > +echo "01028125" > expout > +#only check for the DNS HDR flags since we are not getting any DNS answer > +AT_CHECK([cat 2.packets | cut -c -92 | cut -c 85-], [0], [expout]) > + > +reset_pcap_file hv1-vif1 hv1/vif1 > +reset_pcap_file hv1-vif2 hv1/vif2 > +rm -f 1.expected > +rm -f 2.expected > OVN_CLEANUP([hv1]) > > AT_CLEANUP Regards, Dumitru _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev