[libvirt] [PATCHv2 9/9] network: implement backend of virNetworkUpdate(IP_DHCP_HOST)
Daniel Veillard
veillard at redhat.com
Tue Sep 18 08:08:01 UTC 2012
On Tue, Sep 18, 2012 at 03:39:05AM -0400, Laine Stump wrote:
> This patch fills in the first implementation for one of the
> virNetworkUpdate sections. With this code, you can now add/delete/edit
> <host> entries in a network's <ip> address <dhcp> element (by
> specifying a section of VIR_NETWORK_SECTION_IP_DHCP_HOST).
>
> If you pass in a parentIndex of -1, the code will automatically find
> the one ip element that has a <dhcp> section and make the updates
> there. Otherwise, you can specify an index >= 0, and libvirt will look
> for that particular instance of <ip> in the network, and modify its
> <dhcp> element. (This currently isn't very useful, because libvirt
> only supports having dhcp information on a single IP address, but that
> could change in the future).
>
> When adding a new host entry
> (VIR_NETWORK_UPDATE_COMMAND_ADD_(FIRST|LAST)), the existing entries
> will be compared to the new entry, and if any non-empty attribute
> matches, the add will fail. When updating an existing entry
> (VIR_NETWORK_UPDATE_COMMAND_MODIFY), the mac address or name will be
> used to find the existing entry, and other fields will only be updated
> (note there is some potential for ambiguity here if you specify the
> mac address from one entry and the name from another). When deleting
> an existing entry (VIR_NETWORK_UPDATE_COMMAND_DELETE), all non-empty
> attributes in the supplied xml arg will be compared - all of them must
> match before libvirt will delete the host.
>
> The xml should be a fully formed <host> element as it would appear in
> a network definition, e.g. "<host mac=00:11:22:33:44:55 ip=10.1.23.22
> name='testbox'/>" (when adding/updating, ip and one of mac|name is
> required; when deleting, you can specify any one, two, or all
> attributes, but they all must match the target element).
>
> As with the update of any other section, you can choose to affect the
> live config (with flag VIR_NETWORK_UPDATE_AFFECT_LIVE), the persistent
> config (VIR_NETWORK_UPDATE_AFFECT_CONFIG), or both. If you've chosen
> to affect the live config, those changes will take effect immediately,
> with no need to destroy/restart the network.
>
> An example of adding a host entry:
>
> virNetworkUpdate(net, VIR_NETWORK_UPDATE_COMMAND_ADD_LAST,
> VIR_NETWORK_SECTION_IP_DHCP_HOST, -1,
> "<host mac='00:11:22:33:44:55' ip='192.168.122.5'/>",
> VIR_NETWORK_UPDATE_AFFECT_LIVE
> | VIR_NETWORK_UPDATE_AFFECT_CONFIG);
>
> To delete that same entry:
>
> virNetworkUpdate(net, VIR_NETWORK_UPDATE_COMMAND_DELETE,
> VIR_NETWORK_SECTION_IP_DHCP_HOST, -1,
> "<host mac='00:11:22:33:44:55'/>",
> VIR_NETWORK_UPDATE_AFFECT_LIVE
> | VIR_NETWORK_UPDATE_AFFECT_CONFIG);
>
> (you could also delete it by replacing "mac='00:11:22:33:44:55'" with
> "ip='192.168.122.5'".)
We need to move that documentation outside of the git commit log,
I mean keep it here but this need to go on the web site !
> src/conf/network_conf.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 174 insertions(+), 7 deletions(-)
>
> diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
> index 2a65f1d..4f40c10 100644
> --- a/src/conf/network_conf.c
> +++ b/src/conf/network_conf.c
> @@ -2261,7 +2261,6 @@ virNetworkDefUpdateNoSupport(virNetworkDefPtr def, const char *section)
> section, def->name);
> }
>
> -#if 0
> static int
> virNetworkDefUpdateCheckElementName(virNetworkDefPtr def,
> xmlNodePtr node,
> @@ -2276,7 +2275,6 @@ virNetworkDefUpdateCheckElementName(virNetworkDefPtr def,
> }
> return 0;
> }
> -#endif
>
> static int
> virNetworkDefUpdateBridge(virNetworkDefPtr def,
> @@ -2314,16 +2312,185 @@ virNetworkDefUpdateIP(virNetworkDefPtr def,
> return -1;
> }
>
> +static virNetworkIpDefPtr
> +virNetworkIpDefByIndex(virNetworkDefPtr def, int parentIndex)
> +{
> + virNetworkIpDefPtr ipdef = NULL;
> +
> + /* first find which ip element's dhcp host list to work on */
> + if (parentIndex >= 0) {
> + ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, parentIndex);
> + if (!(ipdef &&
> + VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("couldn't update dhcp host entry - "
> + "no <ip family='ipv4'> "
> + "element found at index %d in network '%s'"),
> + parentIndex, def->name);
> + }
> + return ipdef;
> + }
> +
> + /* -1 means "find the most appropriate", which in this case
> + * means the one and only <ip> that has <dhcp> element
> + */
> + int ii;
<grin/> can you move that up to be block start ?
> +
> + for (ii = 0;
> + (ipdef = virNetworkDefGetIpByIndex(def, AF_UNSPEC, ii));
> + ii++) {
> + if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET) &&
> + (ipdef->nranges || ipdef->nhosts)) {
> + break;
> + }
> + }
> + if (!ipdef)
> + ipdef = virNetworkDefGetIpByIndex(def, AF_INET, 0);
> + if (!ipdef) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("couldn't update dhcp host entry - "
> + "no <ip family='ipv4'> "
> + "element found in network '%s'"), def->name);
> + }
> + return ipdef;
> +}
> +
> static int
> virNetworkDefUpdateIPDHCPHost(virNetworkDefPtr def,
> - unsigned int command ATTRIBUTE_UNUSED,
> - int parentIndex ATTRIBUTE_UNUSED,
> - xmlXPathContextPtr ctxt ATTRIBUTE_UNUSED,
> + unsigned int command,
> + int parentIndex,
> + xmlXPathContextPtr ctxt,
> /* virNetworkUpdateFlags */
> unsigned int fflags ATTRIBUTE_UNUSED)
> {
> - virNetworkDefUpdateNoSupport(def, "ip dhcp host");
> - return -1;
> + int ii, ret = -1;
> + virNetworkIpDefPtr ipdef = virNetworkIpDefByIndex(def, parentIndex);
> + virNetworkDHCPHostDef host;
> +
> + memset(&host, 0, sizeof(host));
> +
> + if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "host") < 0)
> + goto cleanup;
> +
> + /* ipdef is the ip element that needs its host array updated */
> + if (!ipdef)
> + goto cleanup;
> +
> + /* parse the xml into a virNetworkDHCPHostDef */
> + if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
> +
> + if (virNetworkDHCPHostDefParse(def->name, ctxt->node, &host, false) < 0)
> + goto cleanup;
> +
> + /* search for the entry with this (mac|name),
> + * and update the IP+(mac|name) */
> + for (ii = 0; ii < ipdef->nhosts; ii++) {
> + if ((host.mac &&
> + !virMacAddrCompare(host.mac, ipdef->hosts[ii].mac)) ||
> + (host.name &&
> + STREQ_NULLABLE(host.name, ipdef->hosts[ii].name))) {
> + break;
> + }
> + }
> +
> + if (ii == ipdef->nhosts) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("couldn't locate an existing dhcp host entry with "
> + "\"mac='%s'\" in network '%s'"),
> + host.mac, def->name);
> + goto cleanup;
> + }
> +
> + /* eliminate the old */
> + virNetworkDHCPHostDefClear(&ipdef->hosts[ii]);
> + /* replace with new */
> + ipdef->hosts[ii] = host;
> + /* eliminate the extra copy of the new */
> + memset(&host, 0, sizeof(host));
> + /* Success! */
Hum, those comments are fine in development mode, but maybe a bit of
cleanup or more synthetic comment would be better :-)
> + } else if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
> + (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)) {
> +
> + if (virNetworkDHCPHostDefParse(def->name, ctxt->node, &host, true) < 0)
> + goto cleanup;
> +
> + /* log error if an entry with same name/address/ip already exists */
> + for (ii = 0; ii < ipdef->nhosts; ii++) {
> + if ((host.mac &&
> + !virMacAddrCompare(host.mac, ipdef->hosts[ii].mac)) ||
> + (host.name &&
> + STREQ_NULLABLE(host.name, ipdef->hosts[ii].name)) ||
> + (VIR_SOCKET_ADDR_VALID(&host.ip) &&
> + virSocketAddrEqual(&host.ip, &ipdef->hosts[ii].ip))) {
> + char *ip = virSocketAddrFormat(&host.ip);
> +
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("there is an existing dhcp host entry in "
> + "network '%s' that matches "
> + "\"<host mac='%s' name='%s' ip='%s'/>\""),
> + def->name, host.mac, host.name,
> + ip ? ip : "unknown");
> + VIR_FREE(ip);
> + goto cleanup;
> + }
> + }
> + /* add to beginning/end of list */
> + if (VIR_REALLOC_N(ipdef->hosts, ipdef->nhosts +1) < 0) {
> + virReportOOMError();
> + goto cleanup;
> + }
> +
> + if (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST) {
> +
> + ipdef->hosts[ipdef->nhosts] = host;
> + ipdef->nhosts++;
> + memset(&host, 0, sizeof(host));
> +
> + } else { /* implied (command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) */
> +
> + memmove(ipdef->hosts + 1, ipdef->hosts,
> + sizeof(ipdef->hosts) * ipdef->nhosts);
> + ipdef->hosts[0] = host;
> + ipdef->nhosts++;
> + memset(&host, 0, sizeof(host));
> + }
> +
> + } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
> +
> + if (virNetworkDHCPHostDefParse(def->name, ctxt->node, &host, false) < 0)
> + goto cleanup;
> +
> + /* find matching entry - all specified attributes must match */
> + for (ii = 0; ii < ipdef->nhosts; ii++) {
> + if ((!host.mac ||
> + !virMacAddrCompare(host.mac, ipdef->hosts[ii].mac)) &&
> + (!host.name ||
> + STREQ_NULLABLE(host.name, ipdef->hosts[ii].name)) &&
> + (!VIR_SOCKET_ADDR_VALID(&host.ip) ||
> + virSocketAddrEqual(&host.ip, &ipdef->hosts[ii].ip))) {
> + break;
> + }
> + }
> + if (ii == ipdef->nhosts) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + _("couldn't locate a matching dhcp host entry "
> + "in network '%s'"), def->name);
> + goto cleanup;
> + }
> +
> + /* remove it */
> + virNetworkDHCPHostDefClear(&ipdef->hosts[ii]);
> + memmove(ipdef->hosts + ii, ipdef->hosts + ii + 1,
> + sizeof(ipdef->hosts) * ipdef->nhosts - ii - 1);
> + ipdef->nhosts--;
> + ignore_value(VIR_REALLOC_N(ipdef->hosts, ipdef->nhosts));
> + }
> +
> + ret = 0;
> +cleanup:
> + virNetworkDHCPHostDefClear(&host);
> + return ret;
> }
>
> static int
Okay, i think we need to add that patch to be able to actually test
the new API, ACK but if possible clean the 2 things above
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
More information about the libvir-list
mailing list