[libvirt] [PATCH 3/7] network: backend functions for updating network dns host/srv/txt

Laine Stump laine at laine.org
Fri Dec 7 18:56:13 UTC 2012


These three functions are very similar - none allow a MODIFY
operation; you can only add or delete.

The biggest difference between them (other than the data itself) is in
the criteria for determining a match, and whether or not multiple
matches are possible:

1) for HOST records, it's considered a match if the IP address or any
of the hostnames of an existing record matches.

2) for SRV records, it's a match if all of
domain+service+protocol+target *which have been specified* are
matched.

3) for TXT records, there is only a single field to match - name
(value can be the same for multiple records, and isn't considered a
search term), so by definition there can be no ambiguous matches.

In all three cases, if any matches are found, ADD will fail; if
multiple matches are found, it means the search term was ambiguous,
and a DELETE will fail.

The upper level code in bridge_driver.c is already implemented for
these functions - appropriate conf files will be re-written, and
dnsmasq will be SIGHUPed or restarted as appropriate.
---
 src/conf/network_conf.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 232 insertions(+), 8 deletions(-)

diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 3b28b5e..a71c2d9 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -2915,32 +2915,256 @@ virNetworkDefUpdateDNSHost(virNetworkDefPtr def,
                            /* virNetworkUpdateFlags */
                            unsigned int fflags ATTRIBUTE_UNUSED)
 {
-    virNetworkDefUpdateNoSupport(def, "dns host");
-    return -1;
+    int ii, jj, kk, foundIdx, ret = -1;
+    virNetworkDNSDefPtr dns = &def->dns;
+    virNetworkDNSHostDef host;
+    bool isAdd = (command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
+                  command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST);
+    bool foundCt = 0;
+
+    memset(&host, 0, sizeof(host));
+
+    if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
+        virReportError(VIR_ERR_NO_SUPPORT, "%s",
+                       _("DNS HOST records cannot be modified, "
+                         "only added or deleted"));
+        goto cleanup;
+    }
+
+    if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "host") < 0)
+        goto cleanup;
+
+    if (virNetworkDNSHostDefParseXML(def->name, ctxt->node, &host, !isAdd) < 0)
+        goto cleanup;
+
+    for (ii = 0; ii < dns->nhosts; ii++) {
+        bool foundThisTime = false;
+
+        if (virSocketAddrEqual(&host.ip, &dns->hosts[ii].ip))
+            foundThisTime = true;
+
+        for (jj = 0; jj < host.nnames && !foundThisTime; jj++) {
+            for (kk = 0; kk < dns->hosts[ii].nnames && !foundThisTime; kk++) {
+                if (STREQ(host.names[jj], dns->hosts[ii].names[kk]))
+                    foundThisTime = true;
+            }
+        }
+        if (foundThisTime) {
+            foundCt++;
+            foundIdx = ii;
+        }
+    }
+
+    if (isAdd) {
+
+        if (foundCt > 0) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("there is already at least one DNS HOST "
+                             "record with a matching field in network %s"),
+                           def->name);
+            goto cleanup;
+        }
+
+        /* add to beginning/end of list */
+        if (VIR_INSERT_ELEMENT(dns->hosts,
+                               command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
+                               ? 0 : dns->nhosts, dns->nhosts, &host) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+    } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
+
+        if (foundCt == 0) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("couldn't locate a matching DNS HOST "
+                             "record in network %s"), def->name);
+            goto cleanup;
+        }
+        if (foundCt > 1) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("multiple matching DNS HOST records were "
+                             "found in network %s"), def->name);
+            goto cleanup;
+        }
+
+        /* remove it */
+        virNetworkDNSHostDefClear(&dns->hosts[foundIdx]);
+        VIR_DELETE_ELEMENT(dns->hosts, foundIdx, dns->nhosts);
+
+    } else {
+        virNetworkDefUpdateUnknownCommand(command);
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+    virNetworkDNSHostDefClear(&host);
+    return ret;
 }
 
 static int
-virNetworkDefUpdateDNSTxt(virNetworkDefPtr def,
+virNetworkDefUpdateDNSSrv(virNetworkDefPtr def,
                           unsigned int command ATTRIBUTE_UNUSED,
                           int parentIndex ATTRIBUTE_UNUSED,
                           xmlXPathContextPtr ctxt ATTRIBUTE_UNUSED,
                           /* virNetworkUpdateFlags */
                           unsigned int fflags ATTRIBUTE_UNUSED)
 {
-    virNetworkDefUpdateNoSupport(def, "dns txt");
-    return -1;
+    int ii, foundIdx, ret = -1;
+    virNetworkDNSDefPtr dns = &def->dns;
+    virNetworkDNSSrvDef srv;
+    bool isAdd = (command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
+                  command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST);
+    bool foundCt = 0;
+
+    memset(&srv, 0, sizeof(srv));
+
+    if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
+        virReportError(VIR_ERR_NO_SUPPORT, "%s",
+                       _("DNS SRV records cannot be modified, "
+                         "only added or deleted"));
+        goto cleanup;
+    }
+
+    if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "srv") < 0)
+        goto cleanup;
+
+    if (virNetworkDNSSrvDefParseXML(def->name, ctxt->node, ctxt, &srv, !isAdd) < 0)
+        goto cleanup;
+
+    for (ii = 0; ii < dns->nsrvs; ii++) {
+        if ((!srv.domain || STREQ_NULLABLE(srv.domain, dns->srvs[ii].domain)) &&
+            (!srv.service || STREQ_NULLABLE(srv.service, dns->srvs[ii].service)) &&
+            (!srv.protocol || STREQ_NULLABLE(srv.protocol, dns->srvs[ii].protocol)) &&
+            (!srv.target || STREQ_NULLABLE(srv.target, dns->srvs[ii].target))) {
+            foundCt++;
+            foundIdx = ii;
+        }
+    }
+
+    if (isAdd) {
+
+        if (foundCt > 0) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("there is already at least one DNS SRV "
+                             "record matching all specified fields in network %s"),
+                           def->name);
+            goto cleanup;
+        }
+
+        /* add to beginning/end of list */
+        if (VIR_INSERT_ELEMENT(dns->srvs,
+                               command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
+                               ? 0 : dns->nsrvs, dns->nsrvs, &srv) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+    } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
+
+        if (foundCt == 0) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("couldn't locate a matching DNS SRV "
+                             "record in network %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 %s"), def->name);
+            goto cleanup;
+        }
+
+        /* remove it */
+        virNetworkDNSSrvDefClear(&dns->srvs[foundIdx]);
+        VIR_DELETE_ELEMENT(dns->srvs, foundIdx, dns->nsrvs);
+
+    } else {
+        virNetworkDefUpdateUnknownCommand(command);
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+    virNetworkDNSSrvDefClear(&srv);
+    return ret;
 }
 
 static int
-virNetworkDefUpdateDNSSrv(virNetworkDefPtr def,
+virNetworkDefUpdateDNSTxt(virNetworkDefPtr def,
                           unsigned int command ATTRIBUTE_UNUSED,
                           int parentIndex ATTRIBUTE_UNUSED,
                           xmlXPathContextPtr ctxt ATTRIBUTE_UNUSED,
                           /* virNetworkUpdateFlags */
                           unsigned int fflags ATTRIBUTE_UNUSED)
 {
-    virNetworkDefUpdateNoSupport(def, "dns txt");
-    return -1;
+    int foundIdx, ret = -1;
+    virNetworkDNSDefPtr dns = &def->dns;
+    virNetworkDNSTxtDef txt;
+    bool isAdd = (command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
+                  command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST);
+
+    memset(&txt, 0, sizeof(txt));
+
+    if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
+        virReportError(VIR_ERR_NO_SUPPORT, "%s",
+                       _("DNS TXT records cannot be modified, "
+                         "only added or deleted"));
+        goto cleanup;
+    }
+
+    if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "txt") < 0)
+        goto cleanup;
+
+    if (virNetworkDNSTxtDefParseXML(def->name, ctxt->node, &txt, !isAdd) < 0)
+        goto cleanup;
+
+    for (foundIdx = 0; foundIdx < dns->ntxts; foundIdx++) {
+        if (STREQ(txt.name, dns->txts[foundIdx].name))
+            break;
+    }
+
+    if (isAdd) {
+
+        if (foundIdx < dns->ntxts) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("there is already a DNS TXT record "
+                             "with name '%s' in network %s"),
+                           txt.name, def->name);
+            goto cleanup;
+        }
+
+        /* add to beginning/end of list */
+        if (VIR_INSERT_ELEMENT(dns->txts,
+                               command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
+                               ? 0 : dns->ntxts, dns->ntxts, &txt) < 0) {
+            virReportOOMError();
+            goto cleanup;
+        }
+
+    } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
+
+        if (foundIdx == dns->ntxts) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           _("couldn't locate a matching DNS TXT "
+                             "record in network %s"), def->name);
+            goto cleanup;
+        }
+
+        /* remove it */
+        virNetworkDNSTxtDefClear(&dns->txts[foundIdx]);
+        VIR_DELETE_ELEMENT(dns->txts, foundIdx, dns->ntxts);
+
+    } else {
+        virNetworkDefUpdateUnknownCommand(command);
+        goto cleanup;
+    }
+
+    ret = 0;
+cleanup:
+    virNetworkDNSTxtDefClear(&txt);
+    return ret;
 }
 
 static int
-- 
1.7.11.7




More information about the libvir-list mailing list