Merge ~fnordahl/ubuntu/+source/ovn:bug/1857026-focal into ~ubuntu-server-dev/ubuntu/+source/ovn:ubuntu/focal

Proposed by Frode Nordahl
Status: Merged
Merged at revision: 1272554ada5e7ecfcc9b090d696d7b092779bdb6
Proposed branch: ~fnordahl/ubuntu/+source/ovn:bug/1857026-focal
Merge into: ~ubuntu-server-dev/ubuntu/+source/ovn:ubuntu/focal
Diff against target: 803 lines (+775/-0)
4 files modified
debian/changelog (+8/-0)
debian/patches/lp-1857026-0001-DNS-Make-DNS-lookups-case-insensitive.patch (+274/-0)
debian/patches/lp-1857026-0002-controller-Add-support-for-PTR-DNS-requests.patch (+491/-0)
debian/patches/series (+2/-0)
Reviewer Review Type Date Requested Status
James Page Pending
Review via email: mp+413737@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Frode Nordahl (fnordahl) wrote :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index c0af91d..2094609 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,11 @@
6+ovn (20.03.2-0ubuntu0.20.04.3) focal; urgency=medium
7+
8+ * Add support for PTR DNS requests (LP: #1857026)
9+ - d/p/lp-1857026-0001-DNS-Make-DNS-lookups-case-insensitive.patch
10+ - d/p/lp-1857026-0002-controller-Add-support-for-PTR-DNS-requests.patch
11+
12+ -- Frode Nordahl <frode.nordahl@canonical.com> Thu, 06 Jan 2022 10:00:00 +0100
13+
14 ovn (20.03.2-0ubuntu0.20.04.2) focal; urgency=medium
15
16 * Add RBAC rules for IGMP_Group table (LP: #1914988):
17diff --git a/debian/patches/lp-1857026-0001-DNS-Make-DNS-lookups-case-insensitive.patch b/debian/patches/lp-1857026-0001-DNS-Make-DNS-lookups-case-insensitive.patch
18new file mode 100644
19index 0000000..bfb394a
20--- /dev/null
21+++ b/debian/patches/lp-1857026-0001-DNS-Make-DNS-lookups-case-insensitive.patch
22@@ -0,0 +1,274 @@
23+Origin: backport, https://github.com/ovn-org/ovn/commit/9287f425e8bc5781728b2ff1c60413d3c39c33a8
24+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ovn/+bug/1857026
25+Last-Update: 2022-01-06
26+
27+From 815d4c04992d994bcd75b3d642fe6cc694ec99b3 Mon Sep 17 00:00:00 2001
28+From: Mark Michelson <mmichels@redhat.com>
29+Date: Mon, 20 Apr 2020 09:25:09 -0400
30+Subject: [PATCH 1/2] DNS: Make DNS lookups case insensitive.
31+
32+From RFC 1035 Section 2.3.3:
33+
34+"For all parts of the DNS that are part of the official protocol, all
35+comparisons between character strings (e.g., labels, domain names, etc.)
36+are done in a case-insensitive manner."
37+
38+OVN was using case-sensitive lookups and therefore was not complying.
39+This change makes lookups case insensitive by storing lowercase record
40+names in the southbound database and converting incoming query names to
41+lowercase.
42+
43+Signed-off-by: Mark Michelson <mmichels@redhat.com>
44+Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=1819069
45+Reported-by: Jianlin Shi <jishi@redhat.com>
46+Acked-by: Numan Siddique <numans@ovn.org>
47+(cherry picked from commit 9287f425e8bc5781728b2ff1c60413d3c39c33a8)
48+---
49+ controller/pinctrl.c | 7 ++++-
50+ lib/ovn-util.c | 15 +++++++++++
51+ lib/ovn-util.h | 5 ++++
52+ northd/ovn-northd.c | 15 ++++++++++-
53+ ovn-sb.xml | 3 ++-
54+ tests/ovn.at | 61 ++++++++++++++++++++++++++++++++------------
55+ 6 files changed, 87 insertions(+), 19 deletions(-)
56+
57+diff --git a/controller/pinctrl.c b/controller/pinctrl.c
58+index 5822f03ef..4879dcc45 100644
59+--- a/controller/pinctrl.c
60++++ b/controller/pinctrl.c
61+@@ -1767,7 +1767,12 @@ pinctrl_handle_dns_lookup(
62+ struct dns_data *d = iter->data;
63+ for (size_t i = 0; i < d->n_dps; i++) {
64+ if (d->dps[i] == dp_key) {
65+- answer_ips = smap_get(&d->records, ds_cstr(&query_name));
66++ /* DNS records in SBDB are stored in lowercase. Convert to
67++ * lowercase to perform case insensitive lookup
68++ */
69++ char *query_name_lower = str_tolower(ds_cstr(&query_name));
70++ answer_ips = smap_get(&d->records, query_name_lower);
71++ free(query_name_lower);
72+ if (answer_ips) {
73+ break;
74+ }
75+diff --git a/lib/ovn-util.c b/lib/ovn-util.c
76+index 514e2489f..1b30c2e9a 100644
77+--- a/lib/ovn-util.c
78++++ b/lib/ovn-util.c
79+@@ -21,6 +21,7 @@
80+ #include "openvswitch/ofp-parse.h"
81+ #include "ovn-nb-idl.h"
82+ #include "ovn-sb-idl.h"
83++#include <ctype.h>
84+
85+ VLOG_DEFINE_THIS_MODULE(ovn_util);
86+
87+@@ -550,3 +551,17 @@ ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2)
88+ (addr1->family == AF_INET ? addr1->ipv4 == addr2->ipv4 :
89+ IN6_ARE_ADDR_EQUAL(&addr1->ipv6, &addr2->ipv6)));
90+ }
91++
92++char *
93++str_tolower(const char *orig)
94++{
95++ char *copy = xmalloc(strlen(orig) + 1);
96++ char *p = copy;
97++
98++ while (*orig) {
99++ *p++ = tolower(*orig++);
100++ }
101++ *p = '\0';
102++
103++ return copy;
104++}
105+diff --git a/lib/ovn-util.h b/lib/ovn-util.h
106+index 11238f61c..4076e8b9a 100644
107+--- a/lib/ovn-util.h
108++++ b/lib/ovn-util.h
109+@@ -124,4 +124,9 @@ struct v46_ip {
110+ bool ip46_parse_cidr(const char *str, struct v46_ip *prefix,
111+ unsigned int *plen);
112+ bool ip46_equals(const struct v46_ip *addr1, const struct v46_ip *addr2);
113++
114++/* Returns a lowercase copy of orig.
115++ * Caller must free the returned string.
116++ */
117++char *str_tolower(const char *orig);
118+ #endif
119+diff --git a/northd/ovn-northd.c b/northd/ovn-northd.c
120+index 9cc2c04bb..4ced1b48f 100644
121+--- a/northd/ovn-northd.c
122++++ b/northd/ovn-northd.c
123+@@ -10634,7 +10634,20 @@ sync_dns_entries(struct northd_context *ctx, struct hmap *datapaths)
124+ dns_info->sb_dns,
125+ (struct sbrec_datapath_binding **)dns_info->sbs,
126+ dns_info->n_sbs);
127+- sbrec_dns_set_records(dns_info->sb_dns, &dns_info->nb_dns->records);
128++
129++ /* DNS lookups are case-insensitive. Convert records to lowercase so
130++ * we can do consistent lookups when DNS requests arrive
131++ */
132++ struct smap lower_records = SMAP_INITIALIZER(&lower_records);
133++ struct smap_node *node;
134++ SMAP_FOR_EACH (node, &dns_info->nb_dns->records) {
135++ smap_add_nocopy(&lower_records, xstrdup(node->key),
136++ str_tolower(node->value));
137++ }
138++
139++ sbrec_dns_set_records(dns_info->sb_dns, &lower_records);
140++
141++ smap_destroy(&lower_records);
142+ free(dns_info->sbs);
143+ free(dns_info);
144+ }
145+diff --git a/ovn-sb.xml b/ovn-sb.xml
146+index 2703e6d0c..64c33d2df 100644
147+--- a/ovn-sb.xml
148++++ b/ovn-sb.xml
149+@@ -3581,7 +3581,8 @@ tcp.flags = RST;
150+ <column name="records">
151+ Key-value pair of DNS records with <code>DNS query name</code> as the key
152+ and a string of IP address(es) separated by comma or space as the
153+- value.
154++ value. ovn-northd stores the DNS query name in all lowercase in order to
155++ facilitate case-insensitive lookups.
156+
157+ <p><b>Example: </b> "vm1.ovn.org" = "10.0.0.4 aef0::4"</p>
158+ </column>
159+diff --git a/tests/ovn.at b/tests/ovn.at
160+index 4d9ee1256..b6eff4349 100644
161+--- a/tests/ovn.at
162++++ b/tests/ovn.at
163+@@ -8317,6 +8317,12 @@ set_dns_params() {
164+ # IPv4 address - 10.0.0.4
165+ expected_dns_answer=${query_name}00010001${ttl}00040a000004
166+ ;;
167++ VM1)
168++ # VM1.OVN.ORG
169++ query_name=03564d31034f564e034f524700
170++ # IPv4 address - 10.0.0.4
171++ expected_dns_answer=${query_name}00010001${ttl}00040a000004
172++ ;;
173+ vm2)
174+ # vm2.ovn.org
175+ query_name=03766d32036f766e036f726700
176+@@ -8479,6 +8485,29 @@ reset_pcap_file hv1-vif2 hv1/vif2
177+ rm -f 1.expected
178+ rm -f 2.expected
179+
180++# Try vm1 again but an all-caps query name
181++
182++set_dns_params VM1
183++src_ip=`ip_to_hex 10 0 0 6`
184++dst_ip=`ip_to_hex 10 0 0 1`
185++dns_reply=1
186++test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
187++
188++# NXT_RESUMEs should be 3.
189++OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
190++
191++$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
192++cat 2.expected | cut -c -48 > expout
193++AT_CHECK([cat 2.packets | cut -c -48], [0], [expout])
194++# Skipping the IPv4 checksum.
195++cat 2.expected | cut -c 53- > expout
196++AT_CHECK([cat 2.packets | cut -c 53-], [0], [expout])
197++
198++reset_pcap_file hv1-vif1 hv1/vif1
199++reset_pcap_file hv1-vif2 hv1/vif2
200++rm -f 1.expected
201++rm -f 2.expected
202++
203+ # Clear the query name options for ls1-lp2
204+ ovn-nbctl --wait=hv remove DNS $DNS1 records vm2.ovn.org
205+
206+@@ -8488,8 +8517,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
207+ dns_reply=0
208+ test_dns 1 f00000000001 f00000000002 $src_ip $dst_ip $dns_reply $dns_req_data
209+
210+-# NXT_RESUMEs should be 3.
211+-OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
212++# NXT_RESUMEs should be 4.
213++OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
214+
215+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
216+ AT_CHECK([cat 1.packets], [0], [])
217+@@ -8510,8 +8539,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
218+ dns_reply=0
219+ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data
220+
221+-# NXT_RESUMEs should be 3 only.
222+-OVS_WAIT_UNTIL([test 3 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
223++# NXT_RESUMEs should be 4 only.
224++OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
225+
226+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
227+ AT_CHECK([cat 2.packets], [0], [])
228+@@ -8531,8 +8560,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
229+ dns_reply=1
230+ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
231+
232+-# NXT_RESUMEs should be 4.
233+-OVS_WAIT_UNTIL([test 4 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
234++# NXT_RESUMEs should be 5.
235++OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
236+
237+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
238+ cat 2.expected | cut -c -48 > expout
239+@@ -8553,8 +8582,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
240+ dns_reply=1
241+ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
242+
243+-# NXT_RESUMEs should be 5.
244+-OVS_WAIT_UNTIL([test 5 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
245++# NXT_RESUMEs should be 6.
246++OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
247+
248+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
249+ cat 2.expected | cut -c -48 > expout
250+@@ -8575,8 +8604,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
251+ dns_reply=0
252+ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data
253+
254+-# NXT_RESUMEs should be 6.
255+-OVS_WAIT_UNTIL([test 6 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
256++# NXT_RESUMEs should be 7.
257++OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
258+
259+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
260+ AT_CHECK([cat 2.packets], [0], [])
261+@@ -8593,8 +8622,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
262+ dns_reply=0
263+ test_dns 2 f00000000002 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data
264+
265+-# NXT_RESUMEs should be 7.
266+-OVS_WAIT_UNTIL([test 7 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
267++# NXT_RESUMEs should be 8.
268++OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
269+
270+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif2-tx.pcap > 2.packets
271+ AT_CHECK([cat 2.packets], [0], [])
272+@@ -8613,8 +8642,8 @@ dst_ip=`ip_to_hex 10 0 0 1`
273+ dns_reply=1
274+ test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
275+
276+-# NXT_RESUMEs should be 8.
277+-OVS_WAIT_UNTIL([test 8 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
278++# NXT_RESUMEs should be 9.
279++OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
280+
281+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
282+ cat 1.expected | cut -c -48 > expout
283+@@ -8635,8 +8664,8 @@ dst_ip=aef00000000000000000000000000001
284+ dns_reply=1
285+ test_dns6 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
286+
287+-# NXT_RESUMEs should be 9.
288+-OVS_WAIT_UNTIL([test 9 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
289++# NXT_RESUMEs should be 10
290++OVS_WAIT_UNTIL([test 10 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
291+
292+ $PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
293+ # Skipping the UDP checksum.
294+--
295+2.33.1
296+
297diff --git a/debian/patches/lp-1857026-0002-controller-Add-support-for-PTR-DNS-requests.patch b/debian/patches/lp-1857026-0002-controller-Add-support-for-PTR-DNS-requests.patch
298new file mode 100644
299index 0000000..4386c6c
300--- /dev/null
301+++ b/debian/patches/lp-1857026-0002-controller-Add-support-for-PTR-DNS-requests.patch
302@@ -0,0 +1,491 @@
303+Origin: backport, https://github.com/ovn-org/ovn/commit/82a4e44e308171cb545211eb2534475ef16a4c0e
304+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ovn/+bug/1857026
305+Last-Update: 2022-01-06
306+
307+From e612a270f789af616e98cc204eee42b8b114de41 Mon Sep 17 00:00:00 2001
308+From: Vladislav Odintsov <odivlad@gmail.com>
309+Date: Fri, 19 Feb 2021 11:57:59 +0300
310+Subject: [PATCH 2/2] controller: Add support for PTR DNS requests.
311+
312+The native OVN DNS support doesn't yet support for PTR DNS requests.
313+This patch adds the support for it. If suppose there is a dns record
314+as - "vm1.ovn.org"="10.0.0.4", then a normal DNS request will query for
315+"vm1.ovn.org" and the reply will be the IP address - 10.0.0.4.
316+PTR DNS request helps in getting the domain name of the IP address.
317+For the above example, the PTR DNS request will have a query name as
318+- "4.0.0.10.in-addr.arpa". And the response will have "vm1.ovn.org".
319+In order to support this feature, this patch expects the CMS to define
320+an another entry in the DNS record as - "4.0.0.10.in-addr.arpa"="vm1.ovn.org".
321+
322+This makes the job of ovn-controller easier to support this feature.
323+
324+Submitted-at: https://github.com/ovn-org/ovn/pull/74
325+Signed-off-by: Vladislav Odintsov <odivlad@gmail.com>
326+Signed-off-by: Numan Siddique <numans@ovn.org>
327+(cherry picked from commit 82a4e44e308171cb545211eb2534475ef16a4c0e)
328+---
329+ controller/pinctrl.c | 181 +++++++++++++++++++++++++++++++------------
330+ lib/ovn-l7.h | 8 ++
331+ ovn-nb.xml | 6 ++
332+ tests/ovn.at | 83 +++++++++++++++++++-
333+ 4 files changed, 228 insertions(+), 50 deletions(-)
334+
335+diff --git a/controller/pinctrl.c b/controller/pinctrl.c
336+index 4879dcc45..c505077e0 100644
337+--- a/controller/pinctrl.c
338++++ b/controller/pinctrl.c
339+@@ -1658,6 +1658,106 @@ destroy_dns_cache(void)
340+ }
341+ }
342+
343++/* Populates dns_answer struct with base data.
344++ * Copy the answer section
345++ * Format of the answer section is
346++ * - NAME -> The domain name
347++ * - TYPE -> 2 octets containing one of the RR type codes
348++ * - CLASS -> 2 octets which specify the class of the data
349++ * in the RDATA field.
350++ * - TTL -> 32 bit unsigned int specifying the time
351++ * interval (in secs) that the resource record
352++ * may be cached before it should be discarded.
353++ * - RDLENGTH -> 16 bit integer specifying the length of the
354++ * RDATA field.
355++ * - RDATA -> a variable length string of octets that
356++ * describes the resource.
357++ */
358++static void
359++dns_build_base_answer(
360++ struct ofpbuf *dns_answer, const uint8_t *in_queryname,
361++ uint16_t query_length, int query_type)
362++{
363++ ofpbuf_put(dns_answer, in_queryname, query_length);
364++ put_be16(dns_answer, htons(query_type));
365++ put_be16(dns_answer, htons(DNS_CLASS_IN));
366++ put_be32(dns_answer, htonl(DNS_DEFAULT_RR_TTL));
367++}
368++
369++/* Populates dns_answer struct with a TYPE A answer. */
370++static void
371++dns_build_a_answer(
372++ struct ofpbuf *dns_answer, const uint8_t *in_queryname,
373++ uint16_t query_length, const ovs_be32 addr)
374++{
375++ dns_build_base_answer(dns_answer, in_queryname, query_length,
376++ DNS_QUERY_TYPE_A);
377++ put_be16(dns_answer, htons(sizeof(ovs_be32)));
378++ put_be32(dns_answer, addr);
379++}
380++
381++/* Populates dns_answer struct with a TYPE AAAA answer. */
382++static void
383++dns_build_aaaa_answer(
384++ struct ofpbuf *dns_answer, const uint8_t *in_queryname,
385++ uint16_t query_length, const struct in6_addr *addr)
386++{
387++ dns_build_base_answer(dns_answer, in_queryname, query_length,
388++ DNS_QUERY_TYPE_AAAA);
389++ put_be16(dns_answer, htons(sizeof(*addr)));
390++ ofpbuf_put(dns_answer, addr, sizeof(*addr));
391++}
392++
393++/* Populates dns_answer struct with a TYPE PTR answer. */
394++static void
395++dns_build_ptr_answer(
396++ struct ofpbuf *dns_answer, const uint8_t *in_queryname,
397++ uint16_t query_length, const char *answer_data)
398++{
399++ char *encoded_answer;
400++ uint16_t encoded_answer_length;
401++
402++ dns_build_base_answer(dns_answer, in_queryname, query_length,
403++ DNS_QUERY_TYPE_PTR);
404++
405++ /* Initialize string 2 chars longer than real answer:
406++ * first label length and terminating zero-length label.
407++ * If the answer_data is - vm1tst.ovn.org, it will be encoded as
408++ * - 0010 (Total length which is 16)
409++ * - 06766d31747374 (vm1tst)
410++ * - 036f766e (ovn)
411++ * - 036f7267 (org
412++ * - 00 (zero length field) */
413++ encoded_answer_length = strlen(answer_data) + 2;
414++ encoded_answer = (char *)xzalloc(encoded_answer_length);
415++
416++ put_be16(dns_answer, htons(encoded_answer_length));
417++ uint8_t label_len_index = 0;
418++ uint16_t label_len = 0;
419++ char *encoded_answer_ptr = (char *)encoded_answer + 1;
420++ while (*answer_data) {
421++ if (*answer_data == '.') {
422++ /* Label has ended. Update the length of the label. */
423++ encoded_answer[label_len_index] = label_len;
424++ label_len_index += (label_len + 1);
425++ label_len = 0; /* Init to 0 for the next label. */
426++ } else {
427++ *encoded_answer_ptr = *answer_data;
428++ label_len++;
429++ }
430++ encoded_answer_ptr++;
431++ answer_data++;
432++ }
433++
434++ /* This is required for the last label if it doesn't end with '.' */
435++ if (label_len) {
436++ encoded_answer[label_len_index] = label_len;
437++ }
438++
439++ ofpbuf_put(dns_answer, encoded_answer, encoded_answer_length);
440++ free(encoded_answer);
441++}
442++
443+ /* Called with in the pinctrl_handler thread context. */
444+ static void
445+ pinctrl_handle_dns_lookup(
446+@@ -1753,15 +1853,16 @@ pinctrl_handle_dns_lookup(
447+ }
448+
449+ uint16_t query_type = ntohs(*ALIGNED_CAST(const ovs_be16 *, in_dns_data));
450+- /* Supported query types - A, AAAA and ANY */
451++ /* Supported query types - A, AAAA, ANY and PTR */
452+ if (!(query_type == DNS_QUERY_TYPE_A || query_type == DNS_QUERY_TYPE_AAAA
453+- || query_type == DNS_QUERY_TYPE_ANY)) {
454++ || query_type == DNS_QUERY_TYPE_ANY
455++ || query_type == DNS_QUERY_TYPE_PTR)) {
456+ ds_destroy(&query_name);
457+ goto exit;
458+ }
459+
460+ uint64_t dp_key = ntohll(pin->flow_metadata.flow.metadata);
461+- const char *answer_ips = NULL;
462++ const char *answer_data = NULL;
463+ struct shash_node *iter;
464+ SHASH_FOR_EACH (iter, &dns_cache) {
465+ struct dns_data *d = iter->data;
466+@@ -1771,76 +1872,58 @@ pinctrl_handle_dns_lookup(
467+ * lowercase to perform case insensitive lookup
468+ */
469+ char *query_name_lower = str_tolower(ds_cstr(&query_name));
470+- answer_ips = smap_get(&d->records, query_name_lower);
471++ answer_data = smap_get(&d->records, query_name_lower);
472+ free(query_name_lower);
473+- if (answer_ips) {
474++ if (answer_data) {
475+ break;
476+ }
477+ }
478+ }
479+
480+- if (answer_ips) {
481++ if (answer_data) {
482+ break;
483+ }
484+ }
485+
486+ ds_destroy(&query_name);
487+- if (!answer_ips) {
488++ if (!answer_data) {
489+ goto exit;
490+ }
491+
492+- struct lport_addresses ip_addrs;
493+- if (!extract_ip_addresses(answer_ips, &ip_addrs)) {
494+- goto exit;
495+- }
496+
497+ uint16_t ancount = 0;
498+ uint64_t dns_ans_stub[128 / 8];
499+ struct ofpbuf dns_answer = OFPBUF_STUB_INITIALIZER(dns_ans_stub);
500+
501+- if (query_type == DNS_QUERY_TYPE_A || query_type == DNS_QUERY_TYPE_ANY) {
502+- for (size_t i = 0; i < ip_addrs.n_ipv4_addrs; i++) {
503+- /* Copy the answer section */
504+- /* Format of the answer section is
505+- * - NAME -> The domain name
506+- * - TYPE -> 2 octets containing one of the RR type codes
507+- * - CLASS -> 2 octets which specify the class of the data
508+- * in the RDATA field.
509+- * - TTL -> 32 bit unsigned int specifying the time
510+- * interval (in secs) that the resource record
511+- * may be cached before it should be discarded.
512+- * - RDLENGTH -> 16 bit integer specifying the length of the
513+- * RDATA field.
514+- * - RDATA -> a variable length string of octets that
515+- * describes the resource. In our case it will
516+- * be IP address of the domain name.
517+- */
518+- ofpbuf_put(&dns_answer, in_queryname, idx);
519+- put_be16(&dns_answer, htons(DNS_QUERY_TYPE_A));
520+- put_be16(&dns_answer, htons(DNS_CLASS_IN));
521+- put_be32(&dns_answer, htonl(DNS_DEFAULT_RR_TTL));
522+- put_be16(&dns_answer, htons(sizeof(ovs_be32)));
523+- put_be32(&dns_answer, ip_addrs.ipv4_addrs[i].addr);
524+- ancount++;
525++ if (query_type == DNS_QUERY_TYPE_PTR) {
526++ dns_build_ptr_answer(&dns_answer, in_queryname, idx, answer_data);
527++ ancount++;
528++ } else {
529++ struct lport_addresses ip_addrs;
530++ if (!extract_ip_addresses(answer_data, &ip_addrs)) {
531++ goto exit;
532++ }
533++
534++ if (query_type == DNS_QUERY_TYPE_A ||
535++ query_type == DNS_QUERY_TYPE_ANY) {
536++ for (size_t i = 0; i < ip_addrs.n_ipv4_addrs; i++) {
537++ dns_build_a_answer(&dns_answer, in_queryname, idx,
538++ ip_addrs.ipv4_addrs[i].addr);
539++ ancount++;
540++ }
541+ }
542+- }
543+
544+- if (query_type == DNS_QUERY_TYPE_AAAA ||
545+- query_type == DNS_QUERY_TYPE_ANY) {
546+- for (size_t i = 0; i < ip_addrs.n_ipv6_addrs; i++) {
547+- ofpbuf_put(&dns_answer, in_queryname, idx);
548+- put_be16(&dns_answer, htons(DNS_QUERY_TYPE_AAAA));
549+- put_be16(&dns_answer, htons(DNS_CLASS_IN));
550+- put_be32(&dns_answer, htonl(DNS_DEFAULT_RR_TTL));
551+- const struct in6_addr *ip6 = &ip_addrs.ipv6_addrs[i].addr;
552+- put_be16(&dns_answer, htons(sizeof *ip6));
553+- ofpbuf_put(&dns_answer, ip6, sizeof *ip6);
554+- ancount++;
555++ if (query_type == DNS_QUERY_TYPE_AAAA ||
556++ query_type == DNS_QUERY_TYPE_ANY) {
557++ for (size_t i = 0; i < ip_addrs.n_ipv6_addrs; i++) {
558++ dns_build_aaaa_answer(&dns_answer, in_queryname, idx,
559++ &ip_addrs.ipv6_addrs[i].addr);
560++ ancount++;
561++ }
562+ }
563++ destroy_lport_addresses(&ip_addrs);
564+ }
565+
566+- destroy_lport_addresses(&ip_addrs);
567+-
568+ if (!ancount) {
569+ ofpbuf_uninit(&dns_answer);
570+ goto exit;
571+diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h
572+index 507949c28..899162866 100644
573+--- a/lib/ovn-l7.h
574++++ b/lib/ovn-l7.h
575+@@ -26,6 +26,14 @@
576+ #include "hash.h"
577+ #include "ovn/logical-fields.h"
578+
579++#define DNS_QUERY_TYPE_A 0x01
580++#define DNS_QUERY_TYPE_AAAA 0x1c
581++#define DNS_QUERY_TYPE_ANY 0xff
582++#define DNS_QUERY_TYPE_PTR 0x0c
583++
584++#define DNS_CLASS_IN 0x01
585++#define DNS_DEFAULT_RR_TTL 3600
586++
587+ /* Generic options map which is used to store dhcpv4 opts and dhcpv6 opts. */
588+ struct gen_opts_map {
589+ struct hmap_node hmap_node;
590+diff --git a/ovn-nb.xml b/ovn-nb.xml
591+index f30cc9ee9..a57e7498f 100644
592+--- a/ovn-nb.xml
593++++ b/ovn-nb.xml
594+@@ -3188,7 +3188,13 @@
595+ Key-value pair of DNS records with <code>DNS query name</code> as the key
596+ and value as a string of IP address(es) separated by comma or space.
597+
598++ For PTR requests, the key-value pair can be
599++ <code>Reverse IPv4 address.in-addr.arpa</code> and the value
600++ <code>DNS domain name</code>. For IPv6 addresses, the key
601++ has to be <code>Reverse IPv6 address.ip6.arpa</code>.
602++
603+ <p><b>Example: </b> "vm1.ovn.org" = "10.0.0.4 aef0::4"</p>
604++ <p><b>Example: </b> "4.0.0.10.in-addr.arpa" = "vm1.ovn.org"</p>
605+ </column>
606+
607+ <column name="external_ids">
608+diff --git a/tests/ovn.at b/tests/ovn.at
609+index b6eff4349..87d0bd4fc 100644
610+--- a/tests/ovn.at
611++++ b/tests/ovn.at
612+@@ -8256,10 +8256,13 @@ ovn-nbctl lsp-set-port-security ls1-lp2 "f0:00:00:00:00:02 10.0.0.6 20.0.0.4"
613+
614+ DNS1=`ovn-nbctl create DNS records={}`
615+ DNS2=`ovn-nbctl create DNS records={}`
616++DNS3=`ovn-nbctl create DNS records={}`
617+
618+ ovn-nbctl set DNS $DNS1 records:vm1.ovn.org="10.0.0.4 aef0::4"
619+ ovn-nbctl set DNS $DNS1 records:vm2.ovn.org="10.0.0.6 20.0.0.4"
620+ ovn-nbctl set DNS $DNS2 records:vm3.ovn.org="40.0.0.4"
621++ovn-nbctl set DNS $DNS3 records:4.0.0.10.in-addr.arpa="vm1.ovn.org"
622++ovn-nbctl set DNS $DNS3 records:4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.e.a.ip6.arpa="vm1.ovn.org"
623+
624+ ovn-nbctl set Logical_switch ls1 dns_records="$DNS1"
625+
626+@@ -8365,6 +8368,21 @@ set_dns_params() {
627+ vm1_incomplete)
628+ # set type to none
629+ type=''
630++ ;;
631++ vm1_ipv4_ptr)
632++ # 4.0.0.10.in-addr.arpa
633++ query_name=01340130013002313007696e2d61646472046172706100
634++ type=000c
635++ # vm1.ovn.org
636++ expected_dns_answer=${query_name}${type}0001${ttl}000d03766d31036f766e036f726700
637++ ;;
638++ vm1_ipv6_ptr)
639++ # 4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.f.e.a.ip6.arpa
640++ query_name=0134013001300130013001300130013001300130013001300130013001300130013001300130013001300130013001300130013001300130013001660165016103697036046172706100
641++ type=000c
642++ # vm1.ovn.org
643++ expected_dns_answer=${query_name}${type}0001${ttl}000d03766d31036f766e036f726700
644++ ;;
645+ esac
646+ # TTL - 3600
647+ local dns_req_header=010201200001000000000000
648+@@ -8464,6 +8482,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
649+ rm -f 1.expected
650+ rm -f 2.expected
651+
652++
653+ set_dns_params vm1
654+ src_ip=`ip_to_hex 10 0 0 6`
655+ dst_ip=`ip_to_hex 10 0 0 1`
656+@@ -8485,8 +8504,8 @@ reset_pcap_file hv1-vif2 hv1/vif2
657+ rm -f 1.expected
658+ rm -f 2.expected
659+
660+-# Try vm1 again but an all-caps query name
661+
662++# Try vm1 again but an all-caps query name
663+ set_dns_params VM1
664+ src_ip=`ip_to_hex 10 0 0 6`
665+ dst_ip=`ip_to_hex 10 0 0 1`
666+@@ -8508,6 +8527,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
667+ rm -f 1.expected
668+ rm -f 2.expected
669+
670++
671+ # Clear the query name options for ls1-lp2
672+ ovn-nbctl --wait=hv remove DNS $DNS1 records vm2.ovn.org
673+
674+@@ -8528,6 +8548,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
675+ rm -f 1.expected
676+ rm -f 2.expected
677+
678++
679+ # Clear the query name for ls1-lp1
680+ # Since ls1 has no query names configued,
681+ # ovn-northd should not add the DNS flows.
682+@@ -8550,6 +8571,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
683+ rm -f 1.expected
684+ rm -f 2.expected
685+
686++
687+ # Test IPv6 (AAAA records) using IPv4 packet.
688+ # Add back the DNS options for ls1-lp1.
689+ ovn-nbctl --wait=hv set DNS $DNS1 records:vm1.ovn.org="10.0.0.4 aef0::4"
690+@@ -8575,6 +8597,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
691+ rm -f 1.expected
692+ rm -f 2.expected
693+
694++
695+ # Test both IPv4 (A) and IPv6 (AAAA records) using IPv4 packet.
696+ set_dns_params vm1_ipv4_v6
697+ src_ip=`ip_to_hex 10 0 0 6`
698+@@ -8597,6 +8620,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
699+ rm -f 1.expected
700+ rm -f 2.expected
701+
702++
703+ # Invalid type.
704+ set_dns_params vm1_invalid_type
705+ src_ip=`ip_to_hex 10 0 0 6`
706+@@ -8615,6 +8639,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
707+ rm -f 1.expected
708+ rm -f 2.expected
709+
710++
711+ # Incomplete DNS packet.
712+ set_dns_params vm1_incomplete
713+ src_ip=`ip_to_hex 10 0 0 6`
714+@@ -8633,6 +8658,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
715+ rm -f 1.expected
716+ rm -f 2.expected
717+
718++
719+ # Add one more DNS record to the ls1.
720+ ovn-nbctl --wait=hv set Logical_switch ls1 dns_records="$DNS1 $DNS2"
721+
722+@@ -8657,6 +8683,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
723+ rm -f 1.expected
724+ rm -f 2.expected
725+
726++
727+ # Try DNS query over IPv6
728+ set_dns_params vm1
729+ src_ip=aef00000000000000000000000000004
730+@@ -8677,6 +8704,60 @@ reset_pcap_file hv1-vif2 hv1/vif2
731+ rm -f 1.expected
732+ rm -f 2.expected
733+
734++
735++# Add one more DNS record to the ls1.
736++ovn-nbctl --wait=hv set Logical_switch ls1 dns_records="$DNS1 $DNS2 $DNS3"
737++echo "*************************"
738++ovn-sbctl list DNS
739++echo "*************************"
740++ovn-nbctl list DNS
741++echo "*************************"
742++
743++# Test PTR record for IPv4 address using IPv4 packet.
744++set_dns_params vm1_ipv4_ptr
745++src_ip=`ip_to_hex 10 0 0 4`
746++dst_ip=`ip_to_hex 10 0 0 1`
747++dns_reply=1
748++test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
749++
750++# NXT_RESUMEs should be 11.
751++OVS_WAIT_UNTIL([test 11 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
752++
753++$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
754++cat 1.expected | cut -c -48 > expout
755++AT_CHECK([cat 1.packets | cut -c -48], [0], [expout])
756++# Skipping the IPv4 checksum.
757++cat 1.expected | cut -c 53- > expout
758++AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout])
759++
760++reset_pcap_file hv1-vif1 hv1/vif1
761++reset_pcap_file hv1-vif2 hv1/vif2
762++rm -f 1.expected
763++rm -f 2.expected
764++
765++
766++# Test PTR record for IPv6 address using IPv4 packet.
767++set_dns_params vm1_ipv6_ptr
768++src_ip=`ip_to_hex 10 0 0 4`
769++dst_ip=`ip_to_hex 10 0 0 1`
770++dns_reply=1
771++test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
772++
773++# NXT_RESUMEs should be 12.
774++OVS_WAIT_UNTIL([test 12 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
775++
776++$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
777++cat 1.expected | cut -c -48 > expout
778++AT_CHECK([cat 1.packets | cut -c -48], [0], [expout])
779++# Skipping the IPv4 checksum.
780++cat 1.expected | cut -c 53- > expout
781++AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout])
782++
783++reset_pcap_file hv1-vif1 hv1/vif1
784++reset_pcap_file hv1-vif2 hv1/vif2
785++rm -f 1.expected
786++rm -f 2.expected
787++
788+ OVN_CLEANUP([hv1])
789+
790+ AT_CLEANUP
791+--
792+2.33.1
793+
794diff --git a/debian/patches/series b/debian/patches/series
795index fbe5db9..ba80c08 100644
796--- a/debian/patches/series
797+++ b/debian/patches/series
798@@ -4,3 +4,5 @@ lp-1914988-tests-Use-ovn_start-in-tests-ovn-controller.at.patch
799 lp-1914988-tests-Make-certificate-generation-extendable.patch
800 lp-1914988-tests-Test-with-SSL-and-RBAC-for-controller-by-defau.patch
801 lp-1943266-physical-do-not-forward-traffic-from-localport-to-a-.patch
802+lp-1857026-0001-DNS-Make-DNS-lookups-case-insensitive.patch
803+lp-1857026-0002-controller-Add-support-for-PTR-DNS-requests.patch

Subscribers

People subscribed via source and target branches