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

Proposed by Frode Nordahl
Status: Merged
Merged at revision: 33d2dee39ed672aa04061714cb3b665bbf0d19da
Proposed branch: ~fnordahl/ubuntu/+source/ovn:bug/1857026-hirsute
Merge into: ~ubuntu-server-dev/ubuntu/+source/ovn:ubuntu/hirsute
Diff against target: 512 lines (+490/-0)
3 files modified
debian/changelog (+7/-0)
debian/patches/lp-1857026-controller-Add-support-for-PTR-DNS-requests.patch (+482/-0)
debian/patches/series (+1/-0)
Reviewer Review Type Date Requested Status
James Page Pending
Review via email: mp+413736@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
diff --git a/debian/changelog b/debian/changelog
index 18f4a10..085a9c6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
1ovn (20.12.0-0ubuntu3~cloud1) focal-wallaby; urgency=medium
2
3 * Add support for PTR DNS requests (LP: #1857026)
4 - d/p/lp-1857026-controller-Add-support-for-PTR-DNS-requests.patch
5
6 -- Frode Nordahl <frode.nordahl@canonical.com> Fri, 25 Feb 2022 10:03:00 +0100
7
1ovn (20.12.0-0ubuntu3) hirsute; urgency=medium8ovn (20.12.0-0ubuntu3) hirsute; urgency=medium
29
3 * Add RBAC rules for IGMP_Group table (LP: #1914988):10 * Add RBAC rules for IGMP_Group table (LP: #1914988):
diff --git a/debian/patches/lp-1857026-controller-Add-support-for-PTR-DNS-requests.patch b/debian/patches/lp-1857026-controller-Add-support-for-PTR-DNS-requests.patch
4new file mode 10064411new file mode 100644
index 0000000..244e836
--- /dev/null
+++ b/debian/patches/lp-1857026-controller-Add-support-for-PTR-DNS-requests.patch
@@ -0,0 +1,482 @@
1Origin: backport, https://github.com/ovn-org/ovn/commit/82a4e44e308171cb545211eb2534475ef16a4c0e
2Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ovn/+bug/1857026
3Last-Update: 2022-01-06
4
5From 3adbef871f64523b18e75c19dab0aabc435b30e9 Mon Sep 17 00:00:00 2001
6From: Vladislav Odintsov <odivlad@gmail.com>
7Date: Fri, 19 Feb 2021 11:57:59 +0300
8Subject: [PATCH] controller: Add support for PTR DNS requests.
9
10The native OVN DNS support doesn't yet support for PTR DNS requests.
11This patch adds the support for it. If suppose there is a dns record
12as - "vm1.ovn.org"="10.0.0.4", then a normal DNS request will query for
13"vm1.ovn.org" and the reply will be the IP address - 10.0.0.4.
14PTR DNS request helps in getting the domain name of the IP address.
15For the above example, the PTR DNS request will have a query name as
16- "4.0.0.10.in-addr.arpa". And the response will have "vm1.ovn.org".
17In order to support this feature, this patch expects the CMS to define
18an another entry in the DNS record as - "4.0.0.10.in-addr.arpa"="vm1.ovn.org".
19
20This makes the job of ovn-controller easier to support this feature.
21
22Submitted-at: https://github.com/ovn-org/ovn/pull/74
23Signed-off-by: Vladislav Odintsov <odivlad@gmail.com>
24Signed-off-by: Numan Siddique <numans@ovn.org>
25(cherry picked from commit 82a4e44e308171cb545211eb2534475ef16a4c0e)
26
27Index: ovn-20.12.0/controller/pinctrl.c
28===================================================================
29--- ovn-20.12.0.orig/controller/pinctrl.c
30+++ ovn-20.12.0/controller/pinctrl.c
31@@ -2545,6 +2545,106 @@ destroy_dns_cache(void)
32 }
33 }
34
35+/* Populates dns_answer struct with base data.
36+ * Copy the answer section
37+ * Format of the answer section is
38+ * - NAME -> The domain name
39+ * - TYPE -> 2 octets containing one of the RR type codes
40+ * - CLASS -> 2 octets which specify the class of the data
41+ * in the RDATA field.
42+ * - TTL -> 32 bit unsigned int specifying the time
43+ * interval (in secs) that the resource record
44+ * may be cached before it should be discarded.
45+ * - RDLENGTH -> 16 bit integer specifying the length of the
46+ * RDATA field.
47+ * - RDATA -> a variable length string of octets that
48+ * describes the resource.
49+ */
50+static void
51+dns_build_base_answer(
52+ struct ofpbuf *dns_answer, const uint8_t *in_queryname,
53+ uint16_t query_length, int query_type)
54+{
55+ ofpbuf_put(dns_answer, in_queryname, query_length);
56+ put_be16(dns_answer, htons(query_type));
57+ put_be16(dns_answer, htons(DNS_CLASS_IN));
58+ put_be32(dns_answer, htonl(DNS_DEFAULT_RR_TTL));
59+}
60+
61+/* Populates dns_answer struct with a TYPE A answer. */
62+static void
63+dns_build_a_answer(
64+ struct ofpbuf *dns_answer, const uint8_t *in_queryname,
65+ uint16_t query_length, const ovs_be32 addr)
66+{
67+ dns_build_base_answer(dns_answer, in_queryname, query_length,
68+ DNS_QUERY_TYPE_A);
69+ put_be16(dns_answer, htons(sizeof(ovs_be32)));
70+ put_be32(dns_answer, addr);
71+}
72+
73+/* Populates dns_answer struct with a TYPE AAAA answer. */
74+static void
75+dns_build_aaaa_answer(
76+ struct ofpbuf *dns_answer, const uint8_t *in_queryname,
77+ uint16_t query_length, const struct in6_addr *addr)
78+{
79+ dns_build_base_answer(dns_answer, in_queryname, query_length,
80+ DNS_QUERY_TYPE_AAAA);
81+ put_be16(dns_answer, htons(sizeof(*addr)));
82+ ofpbuf_put(dns_answer, addr, sizeof(*addr));
83+}
84+
85+/* Populates dns_answer struct with a TYPE PTR answer. */
86+static void
87+dns_build_ptr_answer(
88+ struct ofpbuf *dns_answer, const uint8_t *in_queryname,
89+ uint16_t query_length, const char *answer_data)
90+{
91+ char *encoded_answer;
92+ uint16_t encoded_answer_length;
93+
94+ dns_build_base_answer(dns_answer, in_queryname, query_length,
95+ DNS_QUERY_TYPE_PTR);
96+
97+ /* Initialize string 2 chars longer than real answer:
98+ * first label length and terminating zero-length label.
99+ * If the answer_data is - vm1tst.ovn.org, it will be encoded as
100+ * - 0010 (Total length which is 16)
101+ * - 06766d31747374 (vm1tst)
102+ * - 036f766e (ovn)
103+ * - 036f7267 (org
104+ * - 00 (zero length field) */
105+ encoded_answer_length = strlen(answer_data) + 2;
106+ encoded_answer = (char *)xzalloc(encoded_answer_length);
107+
108+ put_be16(dns_answer, htons(encoded_answer_length));
109+ uint8_t label_len_index = 0;
110+ uint16_t label_len = 0;
111+ char *encoded_answer_ptr = (char *)encoded_answer + 1;
112+ while (*answer_data) {
113+ if (*answer_data == '.') {
114+ /* Label has ended. Update the length of the label. */
115+ encoded_answer[label_len_index] = label_len;
116+ label_len_index += (label_len + 1);
117+ label_len = 0; /* Init to 0 for the next label. */
118+ } else {
119+ *encoded_answer_ptr = *answer_data;
120+ label_len++;
121+ }
122+ encoded_answer_ptr++;
123+ answer_data++;
124+ }
125+
126+ /* This is required for the last label if it doesn't end with '.' */
127+ if (label_len) {
128+ encoded_answer[label_len_index] = label_len;
129+ }
130+
131+ ofpbuf_put(dns_answer, encoded_answer, encoded_answer_length);
132+ free(encoded_answer);
133+}
134+
135 /* Called with in the pinctrl_handler thread context. */
136 static void
137 pinctrl_handle_dns_lookup(
138@@ -2640,15 +2740,16 @@ pinctrl_handle_dns_lookup(
139 }
140
141 uint16_t query_type = ntohs(*ALIGNED_CAST(const ovs_be16 *, in_dns_data));
142- /* Supported query types - A, AAAA and ANY */
143+ /* Supported query types - A, AAAA, ANY and PTR */
144 if (!(query_type == DNS_QUERY_TYPE_A || query_type == DNS_QUERY_TYPE_AAAA
145- || query_type == DNS_QUERY_TYPE_ANY)) {
146+ || query_type == DNS_QUERY_TYPE_ANY
147+ || query_type == DNS_QUERY_TYPE_PTR)) {
148 ds_destroy(&query_name);
149 goto exit;
150 }
151
152 uint64_t dp_key = ntohll(pin->flow_metadata.flow.metadata);
153- const char *answer_ips = NULL;
154+ const char *answer_data = NULL;
155 struct shash_node *iter;
156 SHASH_FOR_EACH (iter, &dns_cache) {
157 struct dns_data *d = iter->data;
158@@ -2658,76 +2759,58 @@ pinctrl_handle_dns_lookup(
159 * lowercase to perform case insensitive lookup
160 */
161 char *query_name_lower = str_tolower(ds_cstr(&query_name));
162- answer_ips = smap_get(&d->records, query_name_lower);
163+ answer_data = smap_get(&d->records, query_name_lower);
164 free(query_name_lower);
165- if (answer_ips) {
166+ if (answer_data) {
167 break;
168 }
169 }
170 }
171
172- if (answer_ips) {
173+ if (answer_data) {
174 break;
175 }
176 }
177
178 ds_destroy(&query_name);
179- if (!answer_ips) {
180+ if (!answer_data) {
181 goto exit;
182 }
183
184- struct lport_addresses ip_addrs;
185- if (!extract_ip_addresses(answer_ips, &ip_addrs)) {
186- goto exit;
187- }
188
189 uint16_t ancount = 0;
190 uint64_t dns_ans_stub[128 / 8];
191 struct ofpbuf dns_answer = OFPBUF_STUB_INITIALIZER(dns_ans_stub);
192
193- if (query_type == DNS_QUERY_TYPE_A || query_type == DNS_QUERY_TYPE_ANY) {
194- for (size_t i = 0; i < ip_addrs.n_ipv4_addrs; i++) {
195- /* Copy the answer section */
196- /* Format of the answer section is
197- * - NAME -> The domain name
198- * - TYPE -> 2 octets containing one of the RR type codes
199- * - CLASS -> 2 octets which specify the class of the data
200- * in the RDATA field.
201- * - TTL -> 32 bit unsigned int specifying the time
202- * interval (in secs) that the resource record
203- * may be cached before it should be discarded.
204- * - RDLENGTH -> 16 bit integer specifying the length of the
205- * RDATA field.
206- * - RDATA -> a variable length string of octets that
207- * describes the resource. In our case it will
208- * be IP address of the domain name.
209- */
210- ofpbuf_put(&dns_answer, in_queryname, idx);
211- put_be16(&dns_answer, htons(DNS_QUERY_TYPE_A));
212- put_be16(&dns_answer, htons(DNS_CLASS_IN));
213- put_be32(&dns_answer, htonl(DNS_DEFAULT_RR_TTL));
214- put_be16(&dns_answer, htons(sizeof(ovs_be32)));
215- put_be32(&dns_answer, ip_addrs.ipv4_addrs[i].addr);
216- ancount++;
217+ if (query_type == DNS_QUERY_TYPE_PTR) {
218+ dns_build_ptr_answer(&dns_answer, in_queryname, idx, answer_data);
219+ ancount++;
220+ } else {
221+ struct lport_addresses ip_addrs;
222+ if (!extract_ip_addresses(answer_data, &ip_addrs)) {
223+ goto exit;
224+ }
225+
226+ if (query_type == DNS_QUERY_TYPE_A ||
227+ query_type == DNS_QUERY_TYPE_ANY) {
228+ for (size_t i = 0; i < ip_addrs.n_ipv4_addrs; i++) {
229+ dns_build_a_answer(&dns_answer, in_queryname, idx,
230+ ip_addrs.ipv4_addrs[i].addr);
231+ ancount++;
232+ }
233 }
234- }
235
236- if (query_type == DNS_QUERY_TYPE_AAAA ||
237- query_type == DNS_QUERY_TYPE_ANY) {
238- for (size_t i = 0; i < ip_addrs.n_ipv6_addrs; i++) {
239- ofpbuf_put(&dns_answer, in_queryname, idx);
240- put_be16(&dns_answer, htons(DNS_QUERY_TYPE_AAAA));
241- put_be16(&dns_answer, htons(DNS_CLASS_IN));
242- put_be32(&dns_answer, htonl(DNS_DEFAULT_RR_TTL));
243- const struct in6_addr *ip6 = &ip_addrs.ipv6_addrs[i].addr;
244- put_be16(&dns_answer, htons(sizeof *ip6));
245- ofpbuf_put(&dns_answer, ip6, sizeof *ip6);
246- ancount++;
247+ if (query_type == DNS_QUERY_TYPE_AAAA ||
248+ query_type == DNS_QUERY_TYPE_ANY) {
249+ for (size_t i = 0; i < ip_addrs.n_ipv6_addrs; i++) {
250+ dns_build_aaaa_answer(&dns_answer, in_queryname, idx,
251+ &ip_addrs.ipv6_addrs[i].addr);
252+ ancount++;
253+ }
254 }
255+ destroy_lport_addresses(&ip_addrs);
256 }
257
258- destroy_lport_addresses(&ip_addrs);
259-
260 if (!ancount) {
261 ofpbuf_uninit(&dns_answer);
262 goto exit;
263Index: ovn-20.12.0/lib/ovn-l7.h
264===================================================================
265--- ovn-20.12.0.orig/lib/ovn-l7.h
266+++ ovn-20.12.0/lib/ovn-l7.h
267@@ -26,6 +26,14 @@
268 #include "hash.h"
269 #include "ovn/logical-fields.h"
270
271+#define DNS_QUERY_TYPE_A 0x01
272+#define DNS_QUERY_TYPE_AAAA 0x1c
273+#define DNS_QUERY_TYPE_ANY 0xff
274+#define DNS_QUERY_TYPE_PTR 0x0c
275+
276+#define DNS_CLASS_IN 0x01
277+#define DNS_DEFAULT_RR_TTL 3600
278+
279 /* Generic options map which is used to store dhcpv4 opts and dhcpv6 opts. */
280 struct gen_opts_map {
281 struct hmap_node hmap_node;
282Index: ovn-20.12.0/ovn-nb.xml
283===================================================================
284--- ovn-20.12.0.orig/ovn-nb.xml
285+++ ovn-20.12.0/ovn-nb.xml
286@@ -3549,7 +3549,13 @@
287 Key-value pair of DNS records with <code>DNS query name</code> as the key
288 and value as a string of IP address(es) separated by comma or space.
289
290+ For PTR requests, the key-value pair can be
291+ <code>Reverse IPv4 address.in-addr.arpa</code> and the value
292+ <code>DNS domain name</code>. For IPv6 addresses, the key
293+ has to be <code>Reverse IPv6 address.ip6.arpa</code>.
294+
295 <p><b>Example: </b> "vm1.ovn.org" = "10.0.0.4 aef0::4"</p>
296+ <p><b>Example: </b> "4.0.0.10.in-addr.arpa" = "vm1.ovn.org"</p>
297 </column>
298
299 <column name="external_ids">
300Index: ovn-20.12.0/tests/ovn.at
301===================================================================
302--- ovn-20.12.0.orig/tests/ovn.at
303+++ ovn-20.12.0/tests/ovn.at
304@@ -9349,10 +9349,13 @@ ovn-nbctl lsp-set-port-security ls1-lp2
305
306 DNS1=`ovn-nbctl create DNS records={}`
307 DNS2=`ovn-nbctl create DNS records={}`
308+DNS3=`ovn-nbctl create DNS records={}`
309
310 ovn-nbctl set DNS $DNS1 records:vm1.ovn.org="10.0.0.4 aef0::4"
311 ovn-nbctl set DNS $DNS1 records:vm2.ovn.org="10.0.0.6 20.0.0.4"
312 ovn-nbctl set DNS $DNS2 records:vm3.ovn.org="40.0.0.4"
313+ovn-nbctl set DNS $DNS3 records:4.0.0.10.in-addr.arpa="vm1.ovn.org"
314+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"
315
316 ovn-nbctl set Logical_switch ls1 dns_records="$DNS1"
317
318@@ -9454,6 +9457,21 @@ set_dns_params() {
319 vm1_incomplete)
320 # set type to none
321 type=''
322+ ;;
323+ vm1_ipv4_ptr)
324+ # 4.0.0.10.in-addr.arpa
325+ query_name=01340130013002313007696e2d61646472046172706100
326+ type=000c
327+ # vm1.ovn.org
328+ expected_dns_answer=${query_name}${type}0001${ttl}000d03766d31036f766e036f726700
329+ ;;
330+ vm1_ipv6_ptr)
331+ # 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
332+ query_name=0134013001300130013001300130013001300130013001300130013001300130013001300130013001300130013001300130013001300130013001660165016103697036046172706100
333+ type=000c
334+ # vm1.ovn.org
335+ expected_dns_answer=${query_name}${type}0001${ttl}000d03766d31036f766e036f726700
336+ ;;
337 esac
338 # TTL - 3600
339 local dns_req_header=010201200001000000000000
340@@ -9553,6 +9571,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
341 rm -f 1.expected
342 rm -f 2.expected
343
344+
345 set_dns_params vm1
346 src_ip=`ip_to_hex 10 0 0 6`
347 dst_ip=`ip_to_hex 10 0 0 1`
348@@ -9574,8 +9593,8 @@ reset_pcap_file hv1-vif2 hv1/vif2
349 rm -f 1.expected
350 rm -f 2.expected
351
352-# Try vm1 again but an all-caps query name
353
354+# Try vm1 again but an all-caps query name
355 set_dns_params VM1
356 src_ip=`ip_to_hex 10 0 0 6`
357 dst_ip=`ip_to_hex 10 0 0 1`
358@@ -9597,6 +9616,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
359 rm -f 1.expected
360 rm -f 2.expected
361
362+
363 # Clear the query name options for ls1-lp2
364 ovn-nbctl --wait=hv remove DNS $DNS1 records vm2.ovn.org
365
366@@ -9617,6 +9637,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
367 rm -f 1.expected
368 rm -f 2.expected
369
370+
371 # Clear the query name for ls1-lp1
372 # Since ls1 has no query names configued,
373 # ovn-northd should not add the DNS flows.
374@@ -9639,6 +9660,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
375 rm -f 1.expected
376 rm -f 2.expected
377
378+
379 # Test IPv6 (AAAA records) using IPv4 packet.
380 # Add back the DNS options for ls1-lp1.
381 ovn-nbctl --wait=hv set DNS $DNS1 records:vm1.ovn.org="10.0.0.4 aef0::4"
382@@ -9664,6 +9686,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
383 rm -f 1.expected
384 rm -f 2.expected
385
386+
387 # Test both IPv4 (A) and IPv6 (AAAA records) using IPv4 packet.
388 set_dns_params vm1_ipv4_v6
389 src_ip=`ip_to_hex 10 0 0 6`
390@@ -9686,6 +9709,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
391 rm -f 1.expected
392 rm -f 2.expected
393
394+
395 # Invalid type.
396 set_dns_params vm1_invalid_type
397 src_ip=`ip_to_hex 10 0 0 6`
398@@ -9704,6 +9728,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
399 rm -f 1.expected
400 rm -f 2.expected
401
402+
403 # Incomplete DNS packet.
404 set_dns_params vm1_incomplete
405 src_ip=`ip_to_hex 10 0 0 6`
406@@ -9722,6 +9747,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
407 rm -f 1.expected
408 rm -f 2.expected
409
410+
411 # Add one more DNS record to the ls1.
412 ovn-nbctl --wait=hv set Logical_switch ls1 dns_records="$DNS1 $DNS2"
413
414@@ -9746,6 +9772,7 @@ reset_pcap_file hv1-vif2 hv1/vif2
415 rm -f 1.expected
416 rm -f 2.expected
417
418+
419 # Try DNS query over IPv6
420 set_dns_params vm1
421 src_ip=aef00000000000000000000000000004
422@@ -9763,6 +9790,60 @@ AT_CHECK([cat 1.packets | cut -c 1-120,1
423
424 reset_pcap_file hv1-vif1 hv1/vif1
425 reset_pcap_file hv1-vif2 hv1/vif2
426+rm -f 1.expected
427+rm -f 2.expected
428+
429+
430+# Add one more DNS record to the ls1.
431+ovn-nbctl --wait=hv set Logical_switch ls1 dns_records="$DNS1 $DNS2 $DNS3"
432+echo "*************************"
433+ovn-sbctl list DNS
434+echo "*************************"
435+ovn-nbctl list DNS
436+echo "*************************"
437+
438+# Test PTR record for IPv4 address using IPv4 packet.
439+set_dns_params vm1_ipv4_ptr
440+src_ip=`ip_to_hex 10 0 0 4`
441+dst_ip=`ip_to_hex 10 0 0 1`
442+dns_reply=1
443+test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
444+
445+# NXT_RESUMEs should be 11.
446+OVS_WAIT_UNTIL([test 11 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
447+
448+$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
449+cat 1.expected | cut -c -48 > expout
450+AT_CHECK([cat 1.packets | cut -c -48], [0], [expout])
451+# Skipping the IPv4 checksum.
452+cat 1.expected | cut -c 53- > expout
453+AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout])
454+
455+reset_pcap_file hv1-vif1 hv1/vif1
456+reset_pcap_file hv1-vif2 hv1/vif2
457+rm -f 1.expected
458+rm -f 2.expected
459+
460+
461+# Test PTR record for IPv6 address using IPv4 packet.
462+set_dns_params vm1_ipv6_ptr
463+src_ip=`ip_to_hex 10 0 0 4`
464+dst_ip=`ip_to_hex 10 0 0 1`
465+dns_reply=1
466+test_dns 1 f00000000001 f000000000f0 $src_ip $dst_ip $dns_reply $dns_req_data $dns_resp_data
467+
468+# NXT_RESUMEs should be 12.
469+OVS_WAIT_UNTIL([test 12 = `cat ofctl_monitor*.log | grep -c NXT_RESUME`])
470+
471+$PYTHON "$ovs_srcdir/utilities/ovs-pcap.in" hv1/vif1-tx.pcap > 1.packets
472+cat 1.expected | cut -c -48 > expout
473+AT_CHECK([cat 1.packets | cut -c -48], [0], [expout])
474+# Skipping the IPv4 checksum.
475+cat 1.expected | cut -c 53- > expout
476+AT_CHECK([cat 1.packets | cut -c 53-], [0], [expout])
477+
478+reset_pcap_file hv1-vif1 hv1/vif1
479+reset_pcap_file hv1-vif2 hv1/vif2
480 rm -f 1.expected
481 rm -f 2.expected
482
diff --git a/debian/patches/series b/debian/patches/series
index 495c2d2..e6ab792 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -10,3 +10,4 @@ lp-1914988-tests-Make-certificate-generation-extendable.patch
10lp-1914988-tests-Test-with-SSL-and-RBAC-for-controller-by-defau.patch10lp-1914988-tests-Test-with-SSL-and-RBAC-for-controller-by-defau.patch
11lp-1943266-pinctrl-Don-t-send-gARPs-for-localports.patch11lp-1943266-pinctrl-Don-t-send-gARPs-for-localports.patch
12lp-1943266-physical-do-not-forward-traffic-from-localport-to-a-.patch12lp-1943266-physical-do-not-forward-traffic-from-localport-to-a-.patch
13lp-1857026-controller-Add-support-for-PTR-DNS-requests.patch

Subscribers

People subscribed via source and target branches