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 f45de26..0edf0ee 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list