[PATCH] network: allow "modify" option for DNS-Srv records

Adam Julis posted 1 patch 2 months ago
Failed in applying to current master (apply log)
src/conf/network_conf.c                       | 27 ++++++++++++++-----
.../srv-not-existing.xml                      |  1 +
.../srv-record-modify-few.xml                 |  1 +
.../nat-network-dns-srv-modify-few.xml        | 26 ++++++++++++++++++
tests/networkxml2xmlupdatetest.c              | 10 ++++++-
5 files changed, 58 insertions(+), 7 deletions(-)
create mode 100644 tests/networkxml2xmlupdatein/srv-not-existing.xml
create mode 100644 tests/networkxml2xmlupdatein/srv-record-modify-few.xml
create mode 100644 tests/networkxml2xmlupdateout/nat-network-dns-srv-modify-few.xml
[PATCH] network: allow "modify" option for DNS-Srv records
Posted by Adam Julis 2 months ago
The "modify" command allows to replace an existing Srv record
(some of its elements respectively: port, priority and weight).
The primary key used to choose the modify record is the remaining
parameters, only one of them is required. Not using some of these
parameters may cause duplicate records and error message. This
logic is there because of the previous implementation (Add and
Delete options) in the function.

Tests in networkxml2xmlupdatetest.c contain replacements of an
existing DNS-Srv record and failure due to non-existing record.

Resolves: https://gitlab.com/libvirt/libvirt/-/issues/639
Signed-off-by: Adam Julis <ajulis@redhat.com>
---
 src/conf/network_conf.c                       | 27 ++++++++++++++-----
 .../srv-not-existing.xml                      |  1 +
 .../srv-record-modify-few.xml                 |  1 +
 .../nat-network-dns-srv-modify-few.xml        | 26 ++++++++++++++++++
 tests/networkxml2xmlupdatetest.c              | 10 ++++++-
 5 files changed, 58 insertions(+), 7 deletions(-)
 create mode 100644 tests/networkxml2xmlupdatein/srv-not-existing.xml
 create mode 100644 tests/networkxml2xmlupdatein/srv-record-modify-few.xml
 create mode 100644 tests/networkxml2xmlupdateout/nat-network-dns-srv-modify-few.xml

diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 2a541cd5b0..fc387f9566 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -3255,12 +3255,6 @@ virNetworkDefUpdateDNSSrv(virNetworkDef *def,
                   command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST);
     int foundCt = 0;
 
-    if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
-        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
-                       _("DNS SRV records cannot be modified, only added or deleted"));
-        goto cleanup;
-    }
-
     if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "srv") < 0)
         goto cleanup;
 
@@ -3310,6 +3304,27 @@ virNetworkDefUpdateDNSSrv(virNetworkDef *def,
         virNetworkDNSSrvDefClear(&dns->srvs[foundIdx]);
         VIR_DELETE_ELEMENT(dns->srvs, foundIdx, dns->nsrvs);
 
+    } else if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
+
+        if (foundCt == 0) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("couldn't locate a matching DNS SRV record in network %1$s"),
+                           def->name);
+            goto cleanup;
+        }
+
+        if (foundCt > 1) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("multiple DNS SRV records matching all specified fields were found in network %1$s"),
+                           def->name);
+            goto cleanup;
+        }
+
+        virNetworkDNSSrvDefClear(&dns->srvs[foundIdx]);
+
+        memcpy(&dns->srvs[foundIdx], &srv, sizeof(virNetworkDNSSrvDef));
+        memset(&srv, 0, sizeof(virNetworkDNSSrvDef));
+
     } else {
         virNetworkDefUpdateUnknownCommand(command);
         goto cleanup;
diff --git a/tests/networkxml2xmlupdatein/srv-not-existing.xml b/tests/networkxml2xmlupdatein/srv-not-existing.xml
new file mode 100644
index 0000000000..401e14c616
--- /dev/null
+++ b/tests/networkxml2xmlupdatein/srv-not-existing.xml
@@ -0,0 +1 @@
+<srv service='name' protocol='tcp' domain='unknown-domain' target='.' port='666' priority='99' weight='10'/>
diff --git a/tests/networkxml2xmlupdatein/srv-record-modify-few.xml b/tests/networkxml2xmlupdatein/srv-record-modify-few.xml
new file mode 100644
index 0000000000..88ec1b97d9
--- /dev/null
+++ b/tests/networkxml2xmlupdatein/srv-record-modify-few.xml
@@ -0,0 +1 @@
+<srv service='name' protocol='tcp' domain='test-domain-name' target='.' port='1221' priority='42' weight='69'/>
diff --git a/tests/networkxml2xmlupdateout/nat-network-dns-srv-modify-few.xml b/tests/networkxml2xmlupdateout/nat-network-dns-srv-modify-few.xml
new file mode 100644
index 0000000000..a7e5fcffa6
--- /dev/null
+++ b/tests/networkxml2xmlupdateout/nat-network-dns-srv-modify-few.xml
@@ -0,0 +1,26 @@
+<network>
+  <name>default</name>
+  <uuid>81ff0d90-c91e-6742-64da-4a736edb9a9b</uuid>
+  <forward dev='eth1' mode='nat'>
+    <interface dev='eth1'/>
+  </forward>
+  <bridge name='virbr0' stp='on' delay='0'/>
+  <dns>
+    <srv service='name' protocol='tcp' domain='test-domain-name' target='.' port='1221' priority='42' weight='69'/>
+  </dns>
+  <ip address='192.168.122.1' netmask='255.255.255.0'>
+    <dhcp>
+      <range start='192.168.122.2' end='192.168.122.254'/>
+      <host mac='00:16:3e:77:e2:ed' name='a.example.com' ip='192.168.122.10'/>
+      <host mac='00:16:3e:3e:a9:1a' name='b.example.com' ip='192.168.122.11'/>
+    </dhcp>
+  </ip>
+  <ip family='ipv4' address='192.168.123.1' netmask='255.255.255.0'>
+  </ip>
+  <ip family='ipv6' address='2001:db8:ac10:fe01::1' prefix='64'>
+  </ip>
+  <ip family='ipv6' address='2001:db8:ac10:fd01::1' prefix='64'>
+  </ip>
+  <ip family='ipv4' address='10.24.10.1'>
+  </ip>
+</network>
diff --git a/tests/networkxml2xmlupdatetest.c b/tests/networkxml2xmlupdatetest.c
index 383cbf85ce..59e6ce98e5 100644
--- a/tests/networkxml2xmlupdatetest.c
+++ b/tests/networkxml2xmlupdatetest.c
@@ -328,7 +328,6 @@ mymain(void)
             "nat-network-dns-srv-record",
             "nat-network-dns-srv-records",
             VIR_NETWORK_UPDATE_COMMAND_ADD_LAST);
-
     DO_TEST_FAIL("delete-missing-srv-record-service",
                  "srv-record-service",
                  "nat-network",
@@ -351,6 +350,15 @@ mymain(void)
             "nat-network-dns-srv-record",
             "nat-network",
             VIR_NETWORK_UPDATE_COMMAND_DELETE);
+    DO_TEST("modify-srv-record-protocol",
+            "srv-record-modify-few",
+            "nat-network-dns-srv-record",
+            "nat-network-dns-srv-modify-few",
+            VIR_NETWORK_UPDATE_COMMAND_MODIFY);
+    DO_TEST_FAIL("modify-not-existing-srv-record",
+                 "srv-not-existing",
+                 "nat-network-dns-srv-record",
+                 VIR_NETWORK_UPDATE_COMMAND_MODIFY);
 
 
     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
-- 
2.45.2
Re: [PATCH] network: allow "modify" option for DNS-Srv records
Posted by Michal Prívozník 1 month, 4 weeks ago
On 7/9/24 17:23, Adam Julis wrote:
> The "modify" command allows to replace an existing Srv record
> (some of its elements respectively: port, priority and weight).
> The primary key used to choose the modify record is the remaining
> parameters, only one of them is required. Not using some of these
> parameters may cause duplicate records and error message. This
> logic is there because of the previous implementation (Add and
> Delete options) in the function.
> 
> Tests in networkxml2xmlupdatetest.c contain replacements of an
> existing DNS-Srv record and failure due to non-existing record.
> 
> Resolves: https://gitlab.com/libvirt/libvirt/-/issues/639
> Signed-off-by: Adam Julis <ajulis@redhat.com>
> ---
>  src/conf/network_conf.c                       | 27 ++++++++++++++-----
>  .../srv-not-existing.xml                      |  1 +
>  .../srv-record-modify-few.xml                 |  1 +
>  .../nat-network-dns-srv-modify-few.xml        | 26 ++++++++++++++++++
>  tests/networkxml2xmlupdatetest.c              | 10 ++++++-
>  5 files changed, 58 insertions(+), 7 deletions(-)
>  create mode 100644 tests/networkxml2xmlupdatein/srv-not-existing.xml
>  create mode 100644 tests/networkxml2xmlupdatein/srv-record-modify-few.xml
>  create mode 100644 tests/networkxml2xmlupdateout/nat-network-dns-srv-modify-few.xml

Reviewed-by: Michal Privoznik <mprivozn@redhat.com>

Michal
Re: [PATCH] network: allow "modify" option for DNS-Srv records
Posted by Martin Kletzander 1 month ago
On Wed, Jul 10, 2024 at 10:30:31AM +0200, Michal Prívozník wrote:
>On 7/9/24 17:23, Adam Julis wrote:
>> The "modify" command allows to replace an existing Srv record
>> (some of its elements respectively: port, priority and weight).
>> The primary key used to choose the modify record is the remaining
>> parameters, only one of them is required. Not using some of these
>> parameters may cause duplicate records and error message. This
>> logic is there because of the previous implementation (Add and
>> Delete options) in the function.
>>
>> Tests in networkxml2xmlupdatetest.c contain replacements of an
>> existing DNS-Srv record and failure due to non-existing record.
>>
>> Resolves: https://gitlab.com/libvirt/libvirt/-/issues/639
>> Signed-off-by: Adam Julis <ajulis@redhat.com>
>> ---
>>  src/conf/network_conf.c                       | 27 ++++++++++++++-----
>>  .../srv-not-existing.xml                      |  1 +
>>  .../srv-record-modify-few.xml                 |  1 +
>>  .../nat-network-dns-srv-modify-few.xml        | 26 ++++++++++++++++++
>>  tests/networkxml2xmlupdatetest.c              | 10 ++++++-
>>  5 files changed, 58 insertions(+), 7 deletions(-)
>>  create mode 100644 tests/networkxml2xmlupdatein/srv-not-existing.xml
>>  create mode 100644 tests/networkxml2xmlupdatein/srv-record-modify-few.xml
>>  create mode 100644 tests/networkxml2xmlupdateout/nat-network-dns-srv-modify-few.xml
>
>Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
>

I would urge against this for a few reasons.  The already-existing logic
for finding records (for delete or duplicates during add) is already
flawed, and by adding "modify" this makes it even more complicated.

The explanation might be a bit long, so bear with me.  Consider this:

# virsh net-update default add dns-srv '<srv service="asdf" protocol="tcp"/>'
Updated network default live state
# virsh net-update default add dns-srv '<srv service="asdf" protocol="tcp" domain="libvirt.org"/>'
Updated network default live state

The above works (it's the same without `target`), because the SRV record
is being added for two different domains.  One for the default domain of
the network and one for libvirt.org.

Let's try another service, but in different order:

# virsh net-update default add dns-srv '<srv service="aaa" protocol="tcp" domain="libvirt.org"/>'
Updated network default live state
# virsh net-update default add dns-srv '<srv service="aaa" protocol="tcp"/>'
error: Failed to update network default
error: Requested operation is not valid: there is already at least one DNS SRV record matching all specified fields in network default

This does not work, even though it should have the same exact effect as
the previous example.  The issue is we do some heuristic guesswork to
figure out what maybe makes sense and what does not.

And the same (and more) will happen with the modify command.  It's not
that difficult to see how the above will mess up "modify", but let's see
something more.  We currently support what dnsmasq supports, multiple
SRV records for the same domain/service (see dnsmasq(8) man page).  That
means this is perfectly valid configuration, even though it is heavily
constructed to show the exact issue I have with it, so does not make
*that* much sense:

<srv service="a" protocol="tcp" target="asdf.com" domain="libvirt.org" priority="0" weight="10"/>
<srv service="a" protocol="tcp" target="asdf.com" domain="libvirt.org" priority="0" weight="10" port="2"/>
<srv service="a" protocol="tcp" target="asdf.com" domain="libvirt.org" priority="0" weight="10" port="3"/>

That is, three SRV records with the only difference being they are
pointing to different ports, 1, 2 and 3 (the first one defaults to 1).

With net-update modify dns-srv how do you change the port for any of
them?  How do you remove the weight and priority from the second one?
And on top of that, how do you delete the first one (or any for that
matter)?  The last is still an issue even without this patch, but we'll
get to that.

The only way to do this properly would be to have an API that accepts
two strings, one that is the exact equivalent of the current record to
modify and second which is the new "look" of the to-be-modified record.
At that point it is clear to see these should just be two commands,
"add" and "delete" one after each other.  Since I cannot think of any
reason why we should provide an atomic modify operation, the add->delete
ought to be enough without requiring us to document the specificities of
"modify" and the added support burden thereof.

Having said that, "add" and "delete" operations should work in a more
straightforward fashion.  Add should only complain about adding
something that is already there, but with different priority/weight
(for that one I am willing to accept that there's probably no use for)
and delete should similarly only look for the exact replicas of the
records passed as input and not trying to be helpful.  This is IMHO the
best way to "fix" the current situation.  I just hope we will revert
this patch before the release so that we do not have to support
`net-update modify dns-srv` till the end of times =D

@Adam would you be willing to send a revert for this, please?
@Jiri can you wait a little bit with the release for this?

Thank you all.

My way more than 2 cents,
Martin