1 /*
2  * network_conf.c: network XML handling
3  *
4  * Copyright (C) 2006-2016 Red Hat, Inc.
5  * Copyright (C) 2006-2008 Daniel P. Berrange
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library.  If not, see
19  * <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <config.h>
23 
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 
28 #include "virerror.h"
29 #include "datatypes.h"
30 #include "network_conf.h"
31 #include "netdev_vport_profile_conf.h"
32 #include "netdev_bandwidth_conf.h"
33 #include "netdev_vlan_conf.h"
34 #include "viralloc.h"
35 #include "virxml.h"
36 #include "viruuid.h"
37 #include "virbuffer.h"
38 #include "virfile.h"
39 #include "virstring.h"
40 
41 #define VIR_FROM_THIS VIR_FROM_NETWORK
42 
43 VIR_ENUM_IMPL(virNetworkForward,
44               VIR_NETWORK_FORWARD_LAST,
45               "none", "nat", "route", "open",
46               "bridge", "private", "vepa", "passthrough",
47               "hostdev",
48 );
49 
50 VIR_ENUM_IMPL(virNetworkBridgeMACTableManager,
51               VIR_NETWORK_BRIDGE_MAC_TABLE_MANAGER_LAST,
52               "default", "kernel", "libvirt",
53 );
54 
55 VIR_ENUM_DECL(virNetworkForwardHostdevDevice);
56 VIR_ENUM_IMPL(virNetworkForwardHostdevDevice,
57               VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_LAST,
58               "none", "pci", "netdev",
59 );
60 
61 VIR_ENUM_IMPL(virNetworkForwardDriverName,
62               VIR_NETWORK_FORWARD_DRIVER_NAME_LAST,
63               "default",
64               "kvm",
65               "vfio",
66 );
67 
68 VIR_ENUM_IMPL(virNetworkTaint,
69               VIR_NETWORK_TAINT_LAST,
70               "hook-script",
71 );
72 
73 VIR_ENUM_IMPL(virNetworkDHCPLeaseTimeUnit,
74               VIR_NETWORK_DHCP_LEASETIME_UNIT_LAST,
75               "seconds",
76               "minutes",
77               "hours",
78 );
79 
80 static virClass *virNetworkXMLOptionClass;
81 
82 static void
virNetworkXMLOptionDispose(void * obj G_GNUC_UNUSED)83 virNetworkXMLOptionDispose(void *obj G_GNUC_UNUSED)
84 {
85     return;
86 }
87 
88 static int
virNetworkXMLOnceInit(void)89 virNetworkXMLOnceInit(void)
90 {
91     if (!VIR_CLASS_NEW(virNetworkXMLOption, virClassForObject()))
92         return -1;
93 
94     return 0;
95 }
96 
97 VIR_ONCE_GLOBAL_INIT(virNetworkXML);
98 
99 virNetworkXMLOption *
virNetworkXMLOptionNew(virXMLNamespace * xmlns)100 virNetworkXMLOptionNew(virXMLNamespace *xmlns)
101 {
102     virNetworkXMLOption *xmlopt;
103 
104     if (virNetworkXMLInitialize() < 0)
105         return NULL;
106 
107     if (!(xmlopt = virObjectNew(virNetworkXMLOptionClass)))
108         return NULL;
109 
110     if (xmlns)
111         xmlopt->ns = *xmlns;
112 
113     return xmlopt;
114 }
115 
116 static void
virPortGroupDefClear(virPortGroupDef * def)117 virPortGroupDefClear(virPortGroupDef *def)
118 {
119     VIR_FREE(def->name);
120     VIR_FREE(def->virtPortProfile);
121     virNetDevBandwidthFree(def->bandwidth);
122     virNetDevVlanClear(&def->vlan);
123     def->bandwidth = NULL;
124 }
125 
126 
127 static void
virNetworkForwardIfDefClear(virNetworkForwardIfDef * def)128 virNetworkForwardIfDefClear(virNetworkForwardIfDef *def)
129 {
130     if (def->type == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV)
131         VIR_FREE(def->device.dev);
132 }
133 
134 
135 static void
virNetworkForwardPfDefClear(virNetworkForwardPfDef * def)136 virNetworkForwardPfDefClear(virNetworkForwardPfDef *def)
137 {
138     VIR_FREE(def->dev);
139 }
140 
141 
142 static void
virNetworkDHCPLeaseTimeDefClear(virNetworkDHCPLeaseTimeDef * lease)143 virNetworkDHCPLeaseTimeDefClear(virNetworkDHCPLeaseTimeDef *lease)
144 {
145     VIR_FREE(lease);
146 }
147 
148 
149 static void
virNetworkDHCPHostDefClear(virNetworkDHCPHostDef * def)150 virNetworkDHCPHostDefClear(virNetworkDHCPHostDef *def)
151 {
152     VIR_FREE(def->mac);
153     VIR_FREE(def->id);
154     VIR_FREE(def->name);
155     VIR_FREE(def->lease);
156 }
157 
158 
159 static void
virNetworkIPDefClear(virNetworkIPDef * def)160 virNetworkIPDefClear(virNetworkIPDef *def)
161 {
162     VIR_FREE(def->family);
163 
164     while (def->nranges)
165         virNetworkDHCPLeaseTimeDefClear(def->ranges[--def->nranges].lease);
166     VIR_FREE(def->ranges);
167 
168     while (def->nhosts)
169         virNetworkDHCPHostDefClear(&def->hosts[--def->nhosts]);
170 
171     VIR_FREE(def->hosts);
172     VIR_FREE(def->tftproot);
173     VIR_FREE(def->bootfile);
174 }
175 
176 
177 static void
virNetworkDNSTxtDefClear(virNetworkDNSTxtDef * def)178 virNetworkDNSTxtDefClear(virNetworkDNSTxtDef *def)
179 {
180     VIR_FREE(def->name);
181     VIR_FREE(def->value);
182 }
183 
184 
185 static void
virNetworkDNSHostDefClear(virNetworkDNSHostDef * def)186 virNetworkDNSHostDefClear(virNetworkDNSHostDef *def)
187 {
188     while (def->nnames)
189         VIR_FREE(def->names[--def->nnames]);
190     VIR_FREE(def->names);
191 }
192 
193 
194 static void
virNetworkDNSSrvDefClear(virNetworkDNSSrvDef * def)195 virNetworkDNSSrvDefClear(virNetworkDNSSrvDef *def)
196 {
197     VIR_FREE(def->domain);
198     VIR_FREE(def->service);
199     VIR_FREE(def->protocol);
200     VIR_FREE(def->target);
201 }
202 
203 
204 static void
virNetworkDNSForwarderClear(virNetworkDNSForwarder * def)205 virNetworkDNSForwarderClear(virNetworkDNSForwarder *def)
206 {
207     VIR_FREE(def->domain);
208 }
209 
210 
211 static void
virNetworkDNSDefClear(virNetworkDNSDef * def)212 virNetworkDNSDefClear(virNetworkDNSDef *def)
213 {
214     if (def->forwarders) {
215         while (def->nfwds)
216             virNetworkDNSForwarderClear(&def->forwarders[--def->nfwds]);
217         VIR_FREE(def->forwarders);
218     }
219     if (def->txts) {
220         while (def->ntxts)
221             virNetworkDNSTxtDefClear(&def->txts[--def->ntxts]);
222         VIR_FREE(def->txts);
223     }
224     if (def->hosts) {
225         while (def->nhosts)
226             virNetworkDNSHostDefClear(&def->hosts[--def->nhosts]);
227         VIR_FREE(def->hosts);
228     }
229     if (def->srvs) {
230         while (def->nsrvs)
231             virNetworkDNSSrvDefClear(&def->srvs[--def->nsrvs]);
232         VIR_FREE(def->srvs);
233     }
234 }
235 
236 
237 static void
virNetworkForwardDefClear(virNetworkForwardDef * def)238 virNetworkForwardDefClear(virNetworkForwardDef *def)
239 {
240     size_t i;
241 
242     for (i = 0; i < def->npfs && def->pfs; i++)
243         virNetworkForwardPfDefClear(&def->pfs[i]);
244     VIR_FREE(def->pfs);
245 
246     for (i = 0; i < def->nifs && def->ifs; i++)
247         virNetworkForwardIfDefClear(&def->ifs[i]);
248     VIR_FREE(def->ifs);
249     def->nifs = def->npfs = 0;
250 }
251 
252 
253 void
virNetworkDefFree(virNetworkDef * def)254 virNetworkDefFree(virNetworkDef *def)
255 {
256     size_t i;
257 
258     if (!def)
259         return;
260 
261     g_free(def->name);
262     g_free(def->bridge);
263     g_free(def->bridgeZone);
264     g_free(def->domain);
265 
266     virNetworkForwardDefClear(&def->forward);
267 
268     for (i = 0; i < def->nips && def->ips; i++)
269         virNetworkIPDefClear(&def->ips[i]);
270     g_free(def->ips);
271 
272     for (i = 0; i < def->nroutes && def->routes; i++)
273         virNetDevIPRouteFree(def->routes[i]);
274     g_free(def->routes);
275 
276     for (i = 0; i < def->nPortGroups && def->portGroups; i++)
277         virPortGroupDefClear(&def->portGroups[i]);
278     g_free(def->portGroups);
279 
280     virNetworkDNSDefClear(&def->dns);
281 
282     g_free(def->virtPortProfile);
283 
284     virNetDevBandwidthFree(def->bandwidth);
285     virNetDevVlanClear(&def->vlan);
286 
287     xmlFreeNode(def->metadata);
288 
289     if (def->namespaceData && def->ns.free)
290         (def->ns.free)(def->namespaceData);
291     g_free(def);
292 }
293 
294 
295 /*
296  * virNetworkDefCopy:
297  * @def: NetworkDef to copy
298  * @flags: VIR_NETWORK_XML_INACTIVE if appropriate
299  *
300  * make a deep copy of the given NetworkDef
301  *
302  * Returns a new NetworkDef on success, or NULL on failure.
303  */
304 virNetworkDef *
virNetworkDefCopy(virNetworkDef * def,virNetworkXMLOption * xmlopt,unsigned int flags)305 virNetworkDefCopy(virNetworkDef *def,
306                   virNetworkXMLOption *xmlopt,
307                   unsigned int flags)
308 {
309     g_autofree char *xml = NULL;
310 
311     if (!def) {
312         virReportError(VIR_ERR_INTERNAL_ERROR,
313                        "%s", _("NULL NetworkDef"));
314         return NULL;
315     }
316 
317     /* deep copy with a format/parse cycle */
318     if (!(xml = virNetworkDefFormat(def, xmlopt, flags)))
319        return NULL;
320 
321     return virNetworkDefParseString(xml, xmlopt, false);
322 }
323 
324 
325 /* return ips[index], or NULL if there aren't enough ips */
326 virNetworkIPDef *
virNetworkDefGetIPByIndex(const virNetworkDef * def,int family,size_t n)327 virNetworkDefGetIPByIndex(const virNetworkDef *def,
328                           int family,
329                           size_t n)
330 {
331     size_t i;
332 
333     if (!def->ips || n >= def->nips)
334         return NULL;
335 
336     if (family == AF_UNSPEC)
337         return &def->ips[n];
338 
339     /* find the nth ip of type "family" */
340     for (i = 0; i < def->nips; i++) {
341         if (VIR_SOCKET_ADDR_IS_FAMILY(&def->ips[i].address, family)
342             && (n-- <= 0)) {
343             return &def->ips[i];
344         }
345     }
346     /* failed to find enough of the right family */
347     return NULL;
348 }
349 
350 
351 /* return routes[index], or NULL if there aren't enough routes */
352 virNetDevIPRoute *
virNetworkDefGetRouteByIndex(const virNetworkDef * def,int family,size_t n)353 virNetworkDefGetRouteByIndex(const virNetworkDef *def,
354                              int family,
355                              size_t n)
356 {
357     size_t i;
358 
359     if (!def->routes || n >= def->nroutes)
360         return NULL;
361 
362     if (family == AF_UNSPEC)
363         return def->routes[n];
364 
365     /* find the nth route of type "family" */
366     for (i = 0; i < def->nroutes; i++) {
367         virSocketAddr *addr = virNetDevIPRouteGetAddress(def->routes[i]);
368         if (VIR_SOCKET_ADDR_IS_FAMILY(addr, family)
369             && (n-- <= 0)) {
370             return def->routes[i];
371         }
372     }
373 
374     /* failed to find enough of the right family */
375     return NULL;
376 }
377 
378 
379 /* return number of 1 bits in netmask for the network's ipAddress,
380  * or -1 on error
381  */
382 int
virNetworkIPDefPrefix(const virNetworkIPDef * def)383 virNetworkIPDefPrefix(const virNetworkIPDef *def)
384 {
385     return virSocketAddrGetIPPrefix(&def->address,
386                                     &def->netmask,
387                                     def->prefix);
388 }
389 
390 
391 /* Fill in a virSocketAddr with the proper netmask for this
392  * definition, based on either the definition's netmask, or its
393  * prefix. Return -1 on error (and set the netmask family to AF_UNSPEC)
394  */
virNetworkIPDefNetmask(const virNetworkIPDef * def,virSocketAddr * netmask)395 int virNetworkIPDefNetmask(const virNetworkIPDef *def,
396                            virSocketAddr *netmask)
397 {
398     if (VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET)) {
399         *netmask = def->netmask;
400         return 0;
401     }
402 
403     return virSocketAddrPrefixToNetmask(virNetworkIPDefPrefix(def), netmask,
404                                         VIR_SOCKET_ADDR_FAMILY(&def->address));
405 }
406 
407 
408 static int
virNetworkDHCPLeaseTimeDefParseXML(virNetworkDHCPLeaseTimeDef ** lease,xmlNodePtr node)409 virNetworkDHCPLeaseTimeDefParseXML(virNetworkDHCPLeaseTimeDef **lease,
410                                    xmlNodePtr node)
411 {
412     virNetworkDHCPLeaseTimeDef *new_lease = NULL;
413     unsigned long long expiry;
414     virNetworkDHCPLeaseTimeUnitType unit;
415     int rc;
416 
417     if ((rc = virXMLPropULongLong(node, "expiry", 0, VIR_XML_PROP_NONE, &expiry)) < 0)
418         return -1;
419 
420     if (rc == 0)
421         return 0;
422 
423     if (virXMLPropEnumDefault(node, "unit",
424                               virNetworkDHCPLeaseTimeUnitTypeFromString,
425                               VIR_XML_PROP_NONE, &unit,
426                               VIR_NETWORK_DHCP_LEASETIME_UNIT_MINUTES) < 0)
427         return -1;
428 
429     /* infinite */
430     if (expiry > 0) {
431         /* This boundary check is related to dnsmasq man page settings:
432          * "The minimum lease time is two minutes." */
433         if ((unit == VIR_NETWORK_DHCP_LEASETIME_UNIT_SECONDS && expiry < 120) ||
434             (unit == VIR_NETWORK_DHCP_LEASETIME_UNIT_MINUTES && expiry < 2)) {
435             virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
436                            _("The minimum lease time should be greater "
437                              "than 2 minutes"));
438             return -1;
439         }
440     }
441 
442     new_lease = g_new0(virNetworkDHCPLeaseTimeDef, 1);
443     new_lease->expiry = expiry;
444     new_lease->unit = unit;
445 
446     *lease = new_lease;
447 
448     return 0;
449 }
450 
451 
452 static int
virNetworkDHCPRangeDefParseXML(const char * networkName,virNetworkIPDef * ipdef,xmlNodePtr node,virNetworkDHCPRangeDef * range)453 virNetworkDHCPRangeDefParseXML(const char *networkName,
454                                virNetworkIPDef *ipdef,
455                                xmlNodePtr node,
456                                virNetworkDHCPRangeDef *range)
457 {
458     virSocketAddrRange *addr = &range->addr;
459     xmlNodePtr cur = node->children;
460     g_autofree char *start = NULL;
461     g_autofree char *end = NULL;
462 
463     if (!(start = virXMLPropString(node, "start"))) {
464         virReportError(VIR_ERR_XML_ERROR,
465                        _("Missing 'start' attribute in dhcp range for network '%s'"),
466                        networkName);
467         return -1;
468     }
469     if (virSocketAddrParse(&addr->start, start, AF_UNSPEC) < 0)
470         return -1;
471 
472     if (!(end = virXMLPropString(node, "end"))) {
473         virReportError(VIR_ERR_XML_ERROR,
474                        _("Missing 'end' attribute in dhcp range for network '%s'"),
475                        networkName);
476         return -1;
477     }
478     if (virSocketAddrParse(&addr->end, end, AF_UNSPEC) < 0)
479         return -1;
480 
481     /* do a sanity check of the range */
482     if (virSocketAddrGetRange(&addr->start, &addr->end, &ipdef->address,
483                               virNetworkIPDefPrefix(ipdef)) < 0)
484         return -1;
485 
486     while (cur != NULL) {
487         if (cur->type == XML_ELEMENT_NODE &&
488             virXMLNodeNameEqual(cur, "lease")) {
489 
490             if (virNetworkDHCPLeaseTimeDefParseXML(&range->lease, cur) < 0)
491                 return -1;
492         }
493         cur = cur->next;
494     }
495 
496     return 0;
497 }
498 
499 
500 static int
virNetworkDHCPHostDefParseXML(const char * networkName,virNetworkIPDef * def,xmlNodePtr node,virNetworkDHCPHostDef * host,bool partialOkay)501 virNetworkDHCPHostDefParseXML(const char *networkName,
502                               virNetworkIPDef *def,
503                               xmlNodePtr node,
504                               virNetworkDHCPHostDef *host,
505                               bool partialOkay)
506 {
507     g_autofree char *mac = NULL;
508     g_autofree char *name = NULL;
509     g_autofree char *ip = NULL;
510     g_autofree char *id = NULL;
511     virMacAddr addr;
512     virSocketAddr inaddr;
513     xmlNodePtr cur = node->children;
514 
515     mac = virXMLPropString(node, "mac");
516     if (mac != NULL) {
517         if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
518             virReportError(VIR_ERR_XML_ERROR,
519                            _("Invalid to specify MAC address '%s' "
520                              "in network '%s' IPv6 static host definition"),
521                            mac, networkName);
522             return -1;
523         }
524         if (virMacAddrParse(mac, &addr) < 0) {
525             virReportError(VIR_ERR_XML_ERROR,
526                            _("Cannot parse MAC address '%s' in network '%s'"),
527                            mac, networkName);
528             return -1;
529         }
530         if (virMacAddrIsMulticast(&addr)) {
531             virReportError(VIR_ERR_XML_ERROR,
532                            _("expected unicast mac address, found "
533                              "multicast '%s' in network '%s'"),
534                            (const char *)mac, networkName);
535             return -1;
536         }
537     }
538 
539     id = virXMLPropString(node, "id");
540     if (id) {
541         char *cp = id + strspn(id, "0123456789abcdefABCDEF:");
542         if (*cp) {
543             virReportError(VIR_ERR_XML_ERROR,
544                            _("Invalid character '%c' in id '%s' of network '%s'"),
545                            *cp, id, networkName);
546             return -1;
547         }
548     }
549 
550     name = virXMLPropString(node, "name");
551     if (name && (!g_ascii_isalpha(name[0]))) {
552         virReportError(VIR_ERR_XML_ERROR,
553                        _("Cannot use host name '%s' in network '%s'"),
554                        name, networkName);
555         return -1;
556     }
557 
558     ip = virXMLPropString(node, "ip");
559     if (ip && (virSocketAddrParse(&inaddr, ip, AF_UNSPEC) < 0)) {
560         virReportError(VIR_ERR_XML_ERROR,
561                        _("Invalid IP address in static host definition "
562                          "for network '%s'"),
563                        networkName);
564         return -1;
565     }
566 
567     if (partialOkay) {
568         /* for search/match, you just need one of the three */
569         if (!(mac || name || ip)) {
570             virReportError(VIR_ERR_XML_ERROR,
571                            _("At least one of name, mac, or ip attribute "
572                              "must be specified for static host definition "
573                              "in network '%s' "),
574                            networkName);
575             return -1;
576         }
577     } else {
578         /* normal usage - you need at least name (IPv6) or one of MAC
579          * address or name (IPv4)
580          */
581         if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
582             if (!(id || name)) {
583                 virReportError(VIR_ERR_XML_ERROR,
584                            _("Static host definition in IPv6 network '%s' "
585                              "must have id or name attribute"),
586                            networkName);
587                 return -1;
588             }
589         } else if (!(mac || name)) {
590             virReportError(VIR_ERR_XML_ERROR,
591                            _("Static host definition in IPv4 network '%s' "
592                              "must have mac or name attribute"),
593                            networkName);
594             return -1;
595         }
596         if (!ip) {
597             virReportError(VIR_ERR_XML_ERROR,
598                            _("Missing IP address in static host definition "
599                              "for network '%s'"),
600                            networkName);
601             return -1;
602         }
603     }
604 
605     while (cur != NULL) {
606         if (cur->type == XML_ELEMENT_NODE &&
607             virXMLNodeNameEqual(cur, "lease")) {
608 
609             if (virNetworkDHCPLeaseTimeDefParseXML(&host->lease, cur) < 0)
610                 return -1;
611         }
612         cur = cur->next;
613     }
614 
615     host->mac = g_steal_pointer(&mac);
616     host->id = g_steal_pointer(&id);
617     host->name = g_steal_pointer(&name);
618     if (ip)
619         host->ip = inaddr;
620 
621     return 0;
622 
623 }
624 
625 
626 static int
virNetworkDHCPDefParseXML(const char * networkName,xmlNodePtr node,virNetworkIPDef * def)627 virNetworkDHCPDefParseXML(const char *networkName,
628                           xmlNodePtr node,
629                           virNetworkIPDef *def)
630 {
631     int ret = -1;
632     xmlNodePtr cur;
633     virNetworkDHCPRangeDef range;
634     virNetworkDHCPHostDef host;
635 
636     memset(&range, 0, sizeof(range));
637     memset(&host, 0, sizeof(host));
638 
639     cur = node->children;
640     while (cur != NULL) {
641         if (cur->type == XML_ELEMENT_NODE &&
642             virXMLNodeNameEqual(cur, "range")) {
643 
644             if (virNetworkDHCPRangeDefParseXML(networkName, def, cur, &range) < 0)
645                 goto cleanup;
646             VIR_APPEND_ELEMENT(def->ranges, def->nranges, range);
647 
648         } else if (cur->type == XML_ELEMENT_NODE &&
649             virXMLNodeNameEqual(cur, "host")) {
650 
651             if (virNetworkDHCPHostDefParseXML(networkName, def, cur,
652                                               &host, false) < 0)
653                 goto cleanup;
654             VIR_APPEND_ELEMENT(def->hosts, def->nhosts, host);
655         } else if (VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) &&
656                    cur->type == XML_ELEMENT_NODE &&
657                    virXMLNodeNameEqual(cur, "bootp")) {
658             g_autofree char *file = NULL;
659             g_autofree char *server = NULL;
660             virSocketAddr inaddr;
661             memset(&inaddr, 0, sizeof(inaddr));
662 
663             if (!(file = virXMLPropString(cur, "file"))) {
664                 cur = cur->next;
665                 continue;
666             }
667             server = virXMLPropString(cur, "server");
668 
669             if (server &&
670                 virSocketAddrParse(&inaddr, server, AF_UNSPEC) < 0) {
671                 goto cleanup;
672             }
673 
674             def->bootfile = g_steal_pointer(&file);
675             def->bootserver = inaddr;
676         }
677 
678         cur = cur->next;
679     }
680 
681     ret = 0;
682  cleanup:
683     virNetworkDHCPHostDefClear(&host);
684     return ret;
685 }
686 
687 
688 static int
virNetworkDNSHostDefParseXML(const char * networkName,xmlNodePtr node,virNetworkDNSHostDef * def,bool partialOkay)689 virNetworkDNSHostDefParseXML(const char *networkName,
690                              xmlNodePtr node,
691                              virNetworkDNSHostDef *def,
692                              bool partialOkay)
693 {
694     xmlNodePtr cur;
695     g_autofree char *ip = NULL;
696 
697     if (!(ip = virXMLPropString(node, "ip")) && !partialOkay) {
698         virReportError(VIR_ERR_XML_DETAIL,
699                        _("Missing IP address in network '%s' DNS HOST record"),
700                        networkName);
701         goto error;
702     }
703 
704     if (ip && (virSocketAddrParse(&def->ip, ip, AF_UNSPEC) < 0)) {
705         virReportError(VIR_ERR_XML_DETAIL,
706                        _("Invalid IP address in network '%s' DNS HOST record"),
707                        networkName);
708         goto error;
709     }
710 
711     cur = node->children;
712     while (cur != NULL) {
713         if (cur->type == XML_ELEMENT_NODE &&
714             virXMLNodeNameEqual(cur, "hostname")) {
715               if (cur->children != NULL) {
716                   g_autofree char *name = virXMLNodeContentString(cur);
717 
718                   if (!name)
719                       goto error;
720 
721                   if (!name[0]) {
722                       virReportError(VIR_ERR_XML_DETAIL,
723                                      _("Missing hostname in network '%s' DNS HOST record"),
724                                      networkName);
725                       goto error;
726                   }
727                   VIR_APPEND_ELEMENT(def->names, def->nnames, name);
728               }
729         }
730         cur = cur->next;
731     }
732     if (def->nnames == 0 && !partialOkay) {
733         virReportError(VIR_ERR_XML_DETAIL,
734                        _("Missing hostname in network '%s' DNS HOST record"),
735                        networkName);
736         goto error;
737     }
738 
739     if (!VIR_SOCKET_ADDR_VALID(&def->ip) && def->nnames == 0) {
740         virReportError(VIR_ERR_XML_DETAIL,
741                        _("Missing ip and hostname in network '%s' DNS HOST record"),
742                        networkName);
743         goto error;
744     }
745 
746     return 0;
747 
748  error:
749     virNetworkDNSHostDefClear(def);
750     return -1;
751 }
752 
753 
754 /* This includes all characters used in the names of current
755  * /etc/services and /etc/protocols files (on Fedora 20), except ".",
756  * which we can't allow because it would conflict with the use of "."
757  * as a field separator in the SRV record, there appears to be no way
758  * to escape it in, and the protocols/services that use "." in the
759  * name are obscure and unlikely to be used anyway.
760  */
761 #define PROTOCOL_CHARS \
762     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" \
763     "-+/"
764 
765 #define SERVICE_CHARS \
766     "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" \
767     "_-+/*"
768 
769 static int
virNetworkDNSSrvDefParseXML(const char * networkName,xmlNodePtr node,xmlXPathContextPtr ctxt,virNetworkDNSSrvDef * def,bool partialOkay)770 virNetworkDNSSrvDefParseXML(const char *networkName,
771                             xmlNodePtr node,
772                             xmlXPathContextPtr ctxt,
773                             virNetworkDNSSrvDef *def,
774                             bool partialOkay)
775 {
776     int ret;
777     VIR_XPATH_NODE_AUTORESTORE(ctxt)
778 
779     ctxt->node = node;
780 
781     if (!(def->service = virXMLPropString(node, "service")) && !partialOkay) {
782         virReportError(VIR_ERR_XML_DETAIL,
783                        _("missing required service attribute in DNS SRV record "
784                          "of network '%s'"), networkName);
785         goto error;
786     }
787     if (def->service) {
788         if (strlen(def->service) > DNS_RECORD_LENGTH_SRV) {
789             virReportError(VIR_ERR_XML_DETAIL,
790                            _("service attribute '%s' in network '%s' is too long, "
791                              "limit is %d bytes"),
792                            def->service, networkName, DNS_RECORD_LENGTH_SRV);
793             goto error;
794         }
795         if (strspn(def->service, SERVICE_CHARS) < strlen(def->service)) {
796             virReportError(VIR_ERR_XML_DETAIL,
797                            _("invalid character in service attribute '%s' "
798                              "in DNS SRV record of network '%s'"),
799                            def->service, networkName);
800             goto error;
801         }
802     }
803 
804     if (!(def->protocol = virXMLPropString(node, "protocol")) && !partialOkay) {
805         virReportError(VIR_ERR_XML_DETAIL,
806                        _("missing required protocol attribute "
807                          "in DNS SRV record '%s' of network '%s'"),
808                        def->service, networkName);
809         goto error;
810     }
811     if (def->protocol &&
812         strspn(def->protocol, PROTOCOL_CHARS) < strlen(def->protocol)) {
813         virReportError(VIR_ERR_XML_DETAIL,
814                        _("invalid character in protocol attribute '%s' "
815                          "in DNS SRV record of network '%s'"),
816                        def->protocol, networkName);
817         goto error;
818     }
819 
820     /* Following attributes are optional */
821     def->domain = virXMLPropString(node, "domain");
822     def->target = virXMLPropString(node, "target");
823 
824     ret = virXPathUInt("string(./@port)", ctxt, &def->port);
825     if (ret >= 0 && !def->target) {
826         virReportError(VIR_ERR_XML_DETAIL,
827                        _("DNS SRV port attribute not permitted without "
828                          "target for service '%s' in network '%s'"),
829                        def->service, networkName);
830         goto error;
831     }
832     if (ret == -2 || (ret >= 0 && (def->port < 1 || def->port > 65535))) {
833         virReportError(VIR_ERR_XML_DETAIL,
834                        _("invalid DNS SRV port attribute "
835                          "for service '%s' in network '%s'"),
836                        def->service, networkName);
837         goto error;
838     }
839 
840     ret = virXPathUInt("string(./@priority)", ctxt, &def->priority);
841     if (ret >= 0 && !def->target) {
842         virReportError(VIR_ERR_XML_DETAIL,
843                        _("DNS SRV priority attribute not permitted without "
844                          "target for service '%s' in network '%s'"),
845                        def->service, networkName);
846         goto error;
847     }
848     if (ret == -2 || (ret >= 0 && def->priority > 65535)) {
849         virReportError(VIR_ERR_XML_DETAIL,
850                        _("Invalid DNS SRV priority attribute "
851                          "for service '%s' in network '%s'"),
852                        def->service, networkName);
853         goto error;
854     }
855 
856     ret = virXPathUInt("string(./@weight)", ctxt, &def->weight);
857     if (ret >= 0 && !def->target) {
858         virReportError(VIR_ERR_XML_DETAIL,
859                        _("DNS SRV weight attribute not permitted without "
860                          "target for service '%s' in network '%s'"),
861                        def->service, networkName);
862         goto error;
863     }
864     if (ret == -2 || (ret >= 0 && def->weight > 65535)) {
865         virReportError(VIR_ERR_XML_DETAIL,
866                        _("invalid DNS SRV weight attribute "
867                          "for service '%s' in network '%s'"),
868                        def->service, networkName);
869         goto error;
870     }
871 
872     return 0;
873 
874  error:
875     virNetworkDNSSrvDefClear(def);
876     return -1;
877 }
878 
879 
880 static int
virNetworkDNSTxtDefParseXML(const char * networkName,xmlNodePtr node,virNetworkDNSTxtDef * def,bool partialOkay)881 virNetworkDNSTxtDefParseXML(const char *networkName,
882                             xmlNodePtr node,
883                             virNetworkDNSTxtDef *def,
884                             bool partialOkay)
885 {
886     const char *bad = " ,";
887 
888     if (!(def->name = virXMLPropString(node, "name"))) {
889         virReportError(VIR_ERR_XML_DETAIL,
890                        _("missing required name attribute in DNS TXT record "
891                          "of network %s"), networkName);
892         goto error;
893     }
894     if (strcspn(def->name, bad) != strlen(def->name)) {
895         virReportError(VIR_ERR_XML_DETAIL,
896                        _("prohibited character in DNS TXT record "
897                          "name '%s' of network %s"), def->name, networkName);
898         goto error;
899     }
900     if (!(def->value = virXMLPropString(node, "value")) && !partialOkay) {
901         virReportError(VIR_ERR_XML_DETAIL,
902                        _("missing required value attribute in DNS TXT record "
903                          "named '%s' of network %s"), def->name, networkName);
904         goto error;
905     }
906 
907     if (!(def->name || def->value)) {
908         virReportError(VIR_ERR_XML_DETAIL,
909                        _("Missing required name or value "
910                          "in DNS TXT record of network %s"), networkName);
911         goto error;
912     }
913     return 0;
914 
915  error:
916     virNetworkDNSTxtDefClear(def);
917     return -1;
918 }
919 
920 
921 static int
virNetworkDNSDefParseXML(const char * networkName,xmlNodePtr node,xmlXPathContextPtr ctxt,virNetworkDNSDef * def)922 virNetworkDNSDefParseXML(const char *networkName,
923                          xmlNodePtr node,
924                          xmlXPathContextPtr ctxt,
925                          virNetworkDNSDef *def)
926 {
927     g_autofree xmlNodePtr *hostNodes = NULL;
928     g_autofree xmlNodePtr *srvNodes = NULL;
929     g_autofree xmlNodePtr *txtNodes = NULL;
930     g_autofree xmlNodePtr *fwdNodes = NULL;
931     g_autofree char *forwardPlainNames = NULL;
932     g_autofree char *enable = NULL;
933     int nhosts, nsrvs, ntxts, nfwds;
934     size_t i;
935     VIR_XPATH_NODE_AUTORESTORE(ctxt)
936 
937     ctxt->node = node;
938 
939     enable = virXPathString("string(./@enable)", ctxt);
940     if (enable) {
941         def->enable = virTristateBoolTypeFromString(enable);
942         if (def->enable <= 0) {
943             virReportError(VIR_ERR_XML_ERROR,
944                            _("Invalid dns enable setting '%s' "
945                              "in network '%s'"),
946                            enable, networkName);
947             return -1;
948         }
949     }
950 
951     forwardPlainNames = virXPathString("string(./@forwardPlainNames)", ctxt);
952     if (forwardPlainNames) {
953         def->forwardPlainNames = virTristateBoolTypeFromString(forwardPlainNames);
954         if (def->forwardPlainNames <= 0) {
955             virReportError(VIR_ERR_XML_ERROR,
956                            _("Invalid dns forwardPlainNames setting '%s' "
957                              "in network '%s'"),
958                            forwardPlainNames, networkName);
959             return -1;
960         }
961     }
962 
963     nfwds = virXPathNodeSet("./forwarder", ctxt, &fwdNodes);
964     if (nfwds < 0) {
965         virReportError(VIR_ERR_XML_ERROR,
966                        _("invalid <forwarder> element found in <dns> of network %s"),
967                        networkName);
968         return -1;
969     }
970     if (nfwds > 0) {
971         def->forwarders = g_new0(virNetworkDNSForwarder, nfwds);
972 
973         for (i = 0; i < nfwds; i++) {
974             g_autofree char *addr = virXMLPropString(fwdNodes[i], "addr");
975 
976             if (addr && virSocketAddrParse(&def->forwarders[i].addr,
977                                            addr, AF_UNSPEC) < 0) {
978                 virReportError(VIR_ERR_XML_ERROR,
979                                _("Invalid forwarder IP address '%s' "
980                                  "in network '%s'"),
981                                addr, networkName);
982                 return -1;
983             }
984             def->forwarders[i].domain = virXMLPropString(fwdNodes[i], "domain");
985             if (!(addr || def->forwarders[i].domain)) {
986                 virReportError(VIR_ERR_XML_ERROR, "%s",
987                                _("Invalid forwarder element, must contain "
988                                  "at least one of addr or domain"));
989                 return -1;
990             }
991             def->nfwds++;
992         }
993     }
994 
995     nhosts = virXPathNodeSet("./host", ctxt, &hostNodes);
996     if (nhosts < 0) {
997         virReportError(VIR_ERR_XML_ERROR,
998                        _("invalid <host> element found in <dns> of network %s"),
999                        networkName);
1000         return -1;
1001     }
1002     if (nhosts > 0) {
1003         def->hosts = g_new0(virNetworkDNSHostDef, nhosts);
1004 
1005         for (i = 0; i < nhosts; i++) {
1006             if (virNetworkDNSHostDefParseXML(networkName, hostNodes[i],
1007                                              &def->hosts[def->nhosts], false) < 0) {
1008                 return -1;
1009             }
1010             def->nhosts++;
1011         }
1012     }
1013 
1014     nsrvs = virXPathNodeSet("./srv", ctxt, &srvNodes);
1015     if (nsrvs < 0) {
1016         virReportError(VIR_ERR_XML_ERROR,
1017                        _("invalid <srv> element found in <dns> of network %s"),
1018                        networkName);
1019         return -1;
1020     }
1021     if (nsrvs > 0) {
1022         def->srvs = g_new0(virNetworkDNSSrvDef, nsrvs);
1023 
1024         for (i = 0; i < nsrvs; i++) {
1025             if (virNetworkDNSSrvDefParseXML(networkName, srvNodes[i], ctxt,
1026                                             &def->srvs[def->nsrvs], false) < 0) {
1027                 return -1;
1028             }
1029             def->nsrvs++;
1030         }
1031     }
1032 
1033     ntxts = virXPathNodeSet("./txt", ctxt, &txtNodes);
1034     if (ntxts < 0) {
1035         virReportError(VIR_ERR_XML_ERROR,
1036                        _("invalid <txt> element found in <dns> of network %s"),
1037                        networkName);
1038         return -1;
1039     }
1040     if (ntxts > 0) {
1041         def->txts = g_new0(virNetworkDNSTxtDef, ntxts);
1042 
1043         for (i = 0; i < ntxts; i++) {
1044             if (virNetworkDNSTxtDefParseXML(networkName, txtNodes[i],
1045                                             &def->txts[def->ntxts], false) < 0) {
1046                 return -1;
1047             }
1048             def->ntxts++;
1049         }
1050     }
1051 
1052     if (def->enable == VIR_TRISTATE_BOOL_NO &&
1053         (nfwds || nhosts || nsrvs || ntxts)) {
1054         virReportError(VIR_ERR_XML_ERROR,
1055                        _("Extra data in disabled network '%s'"),
1056                        networkName);
1057         return -1;
1058     }
1059 
1060     return 0;
1061 }
1062 
1063 
1064 static int
virNetworkIPDefParseXML(const char * networkName,xmlNodePtr node,xmlXPathContextPtr ctxt,virNetworkIPDef * def)1065 virNetworkIPDefParseXML(const char *networkName,
1066                         xmlNodePtr node,
1067                         xmlXPathContextPtr ctxt,
1068                         virNetworkIPDef *def)
1069 {
1070     /*
1071      * virNetworkIPDef object is already allocated as part of an array.
1072      * On failure clear it out, but don't free it.
1073      */
1074 
1075     VIR_XPATH_NODE_AUTORESTORE(ctxt)
1076     xmlNodePtr dhcp;
1077     g_autofree char *address = NULL;
1078     g_autofree char *netmask = NULL;
1079     g_autofree char *localPtr = NULL;
1080     unsigned long prefix = 0;
1081     int prefixRc;
1082     int ret = -1;
1083 
1084     ctxt->node = node;
1085 
1086     /* grab raw data from XML */
1087     def->family = virXPathString("string(./@family)", ctxt);
1088 
1089     address = virXPathString("string(./@address)", ctxt);
1090     if (!address) {
1091         virReportError(VIR_ERR_XML_ERROR,
1092                        _("Missing required address attribute in network '%s'"),
1093                        networkName);
1094         goto cleanup;
1095     }
1096     if (virSocketAddrParse(&def->address, address, AF_UNSPEC) < 0) {
1097         virReportError(VIR_ERR_XML_ERROR,
1098                        _("Invalid address '%s' in network '%s'"),
1099                        address, networkName);
1100         goto cleanup;
1101     }
1102 
1103     netmask = virXPathString("string(./@netmask)", ctxt);
1104     if (netmask &&
1105         (virSocketAddrParse(&def->netmask, netmask, AF_UNSPEC) < 0)) {
1106         virReportError(VIR_ERR_XML_ERROR,
1107                        _("Invalid netmask '%s' in network '%s'"),
1108                        netmask, networkName);
1109         goto cleanup;
1110     }
1111 
1112     prefixRc = virXPathULong("string(./@prefix)", ctxt, &prefix);
1113     if (prefixRc == -2) {
1114         virReportError(VIR_ERR_XML_ERROR,
1115                        _("Invalid ULong value specified for prefix in definition of network '%s'"),
1116                        networkName);
1117         goto cleanup;
1118     }
1119     if (prefixRc < 0)
1120         def->prefix = 0;
1121     else
1122         def->prefix = prefix;
1123 
1124     localPtr = virXPathString("string(./@localPtr)", ctxt);
1125     if (localPtr) {
1126         def->localPTR = virTristateBoolTypeFromString(localPtr);
1127         if (def->localPTR <= 0) {
1128             virReportError(VIR_ERR_XML_ERROR,
1129                            _("Invalid localPtr value '%s' in network '%s'"),
1130                            localPtr, networkName);
1131             goto cleanup;
1132         }
1133     }
1134 
1135     /* validate address, etc. for each family */
1136     if ((def->family == NULL) || (STREQ(def->family, "ipv4"))) {
1137         if (!(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) ||
1138               VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_UNSPEC))) {
1139             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1140                            _("%s family specified for non-IPv4 address '%s' in network '%s'"),
1141                            def->family == NULL? "no" : "ipv4", address, networkName);
1142             goto cleanup;
1143         }
1144         if (netmask) {
1145             if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET)) {
1146                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1147                                _("Invalid netmask '%s' for address '%s' "
1148                                  "in network '%s' (both must be IPv4)"),
1149                                netmask, address, networkName);
1150                 goto cleanup;
1151             }
1152             if (def->prefix > 0) {
1153                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1154                                _("Network '%s' IP address cannot have "
1155                                  "both a prefix and a netmask"), networkName);
1156                 goto cleanup;
1157             }
1158         } else if (def->prefix > 32) {
1159             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1160                            _("Invalid IPv4 prefix '%lu' in network '%s'"),
1161                            prefix, networkName);
1162             goto cleanup;
1163         }
1164     } else if (STREQ(def->family, "ipv6")) {
1165         if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
1166             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1167                            _("Family 'ipv6' specified for non-IPv6 address '%s' in network '%s'"),
1168                            address, networkName);
1169             goto cleanup;
1170         }
1171         if (netmask) {
1172             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1173                            _("netmask not allowed for IPv6 address '%s' in network '%s'"),
1174                            address, networkName);
1175             goto cleanup;
1176         }
1177         if (def->prefix > 128) {
1178             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1179                            _("Invalid IPv6 prefix '%lu' in network '%s'"),
1180                            prefix, networkName);
1181             goto cleanup;
1182         }
1183     } else {
1184         virReportError(VIR_ERR_XML_ERROR,
1185                        _("Unrecognized family '%s' in network '%s'"),
1186                        def->family, networkName);
1187         goto cleanup;
1188     }
1189 
1190     if ((dhcp = virXPathNode("./dhcp[1]", ctxt)) &&
1191         virNetworkDHCPDefParseXML(networkName, dhcp, def) < 0)
1192         goto cleanup;
1193 
1194     if (virXPathNode("./tftp[1]", ctxt)) {
1195         if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) {
1196             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1197                            _("Unsupported <tftp> element in an IPv6 element "
1198                              "in network '%s'"),
1199                            networkName);
1200             goto cleanup;
1201         }
1202 
1203         def->tftproot = virXPathString("string(./tftp[1]/@root)", ctxt);
1204     }
1205 
1206     ret = 0;
1207 
1208  cleanup:
1209     if (ret < 0)
1210         virNetworkIPDefClear(def);
1211 
1212     return ret;
1213 }
1214 
1215 
1216 int
virNetworkPortOptionsParseXML(xmlXPathContextPtr ctxt,virTristateBool * isolatedPort)1217 virNetworkPortOptionsParseXML(xmlXPathContextPtr ctxt,
1218                               virTristateBool *isolatedPort)
1219 {
1220     g_autofree char *str = NULL;
1221     int tmp = VIR_TRISTATE_BOOL_ABSENT;
1222 
1223     if ((str = virXPathString("string(./port/@isolated)", ctxt))) {
1224         if ((tmp = virTristateBoolTypeFromString(str)) <= 0) {
1225             virReportError(VIR_ERR_XML_ERROR,
1226                            _("unknown port isolated value '%s'"), str);
1227             return -1;
1228         }
1229     }
1230 
1231     *isolatedPort = tmp;
1232     return 0;
1233 }
1234 
1235 
1236 static int
virNetworkPortGroupParseXML(virPortGroupDef * def,xmlNodePtr node,xmlXPathContextPtr ctxt)1237 virNetworkPortGroupParseXML(virPortGroupDef *def,
1238                             xmlNodePtr node,
1239                             xmlXPathContextPtr ctxt)
1240 {
1241     /*
1242      * virPortGroupDef object is already allocated as part of an array.
1243      * On failure clear it out, but don't free it.
1244      */
1245 
1246     VIR_XPATH_NODE_AUTORESTORE(ctxt)
1247     xmlNodePtr virtPortNode;
1248     xmlNodePtr vlanNode;
1249     xmlNodePtr bandwidth_node;
1250     g_autofree char *isDefault = NULL;
1251     g_autofree char *trustGuestRxFilters = NULL;
1252 
1253     int ret = -1;
1254 
1255     ctxt->node = node;
1256 
1257     /* grab raw data from XML */
1258     def->name = virXPathString("string(./@name)", ctxt);
1259     if (!def->name) {
1260         virReportError(VIR_ERR_XML_ERROR, "%s",
1261                        _("Missing required name attribute in portgroup"));
1262         goto cleanup;
1263     }
1264 
1265     isDefault = virXPathString("string(./@default)", ctxt);
1266     def->isDefault = isDefault && STRCASEEQ(isDefault, "yes");
1267 
1268     trustGuestRxFilters
1269         = virXPathString("string(./@trustGuestRxFilters)", ctxt);
1270     if (trustGuestRxFilters) {
1271         if ((def->trustGuestRxFilters
1272              = virTristateBoolTypeFromString(trustGuestRxFilters)) <= 0) {
1273             virReportError(VIR_ERR_XML_ERROR,
1274                            _("Invalid trustGuestRxFilters setting '%s' "
1275                              "in portgroup"), trustGuestRxFilters);
1276             goto cleanup;
1277         }
1278     }
1279 
1280     virtPortNode = virXPathNode("./virtualport", ctxt);
1281     if (virtPortNode &&
1282         (!(def->virtPortProfile = virNetDevVPortProfileParse(virtPortNode, 0)))) {
1283         goto cleanup;
1284     }
1285 
1286     bandwidth_node = virXPathNode("./bandwidth", ctxt);
1287     if (bandwidth_node &&
1288         virNetDevBandwidthParse(&def->bandwidth, NULL, bandwidth_node, false) < 0)
1289         goto cleanup;
1290 
1291     vlanNode = virXPathNode("./vlan", ctxt);
1292     if (vlanNode && virNetDevVlanParse(vlanNode, ctxt, &def->vlan) < 0)
1293         goto cleanup;
1294 
1295     ret = 0;
1296  cleanup:
1297     if (ret < 0)
1298         virPortGroupDefClear(def);
1299 
1300     return ret;
1301 }
1302 
1303 
1304 static int
virNetworkForwardNatDefParseXML(const char * networkName,xmlNodePtr node,xmlXPathContextPtr ctxt,virNetworkForwardDef * def)1305 virNetworkForwardNatDefParseXML(const char *networkName,
1306                                 xmlNodePtr node,
1307                                 xmlXPathContextPtr ctxt,
1308                                 virNetworkForwardDef *def)
1309 {
1310     int nNatAddrs, nNatPorts;
1311     g_autofree xmlNodePtr *natAddrNodes = NULL;
1312     g_autofree xmlNodePtr *natPortNodes = NULL;
1313     g_autofree char *addrStart = NULL;
1314     g_autofree char *addrEnd = NULL;
1315     VIR_XPATH_NODE_AUTORESTORE(ctxt)
1316 
1317     ctxt->node = node;
1318 
1319     if (def->type != VIR_NETWORK_FORWARD_NAT) {
1320         virReportError(VIR_ERR_XML_ERROR,
1321                        _("The <nat> element can only be used when <forward> 'mode' is 'nat' in network %s"),
1322                        networkName);
1323         return -1;
1324     }
1325 
1326     if (virXMLPropTristateBool(node, "ipv6", VIR_XML_PROP_NONE,
1327                                &def->natIPv6) < 0)
1328         return -1;
1329 
1330     /* addresses for SNAT */
1331     nNatAddrs = virXPathNodeSet("./address", ctxt, &natAddrNodes);
1332     if (nNatAddrs < 0) {
1333         virReportError(VIR_ERR_XML_ERROR,
1334                        _("invalid <address> element found in <forward> of "
1335                          "network %s"), networkName);
1336         return -1;
1337     } else if (nNatAddrs > 1) {
1338         virReportError(VIR_ERR_XML_ERROR,
1339                        _("Only one <address> element is allowed in <nat> in "
1340                          "<forward> in network %s"), networkName);
1341         return -1;
1342     } else if (nNatAddrs == 1) {
1343         addrStart = virXMLPropString(*natAddrNodes, "start");
1344         if (addrStart == NULL) {
1345             virReportError(VIR_ERR_XML_ERROR,
1346                            _("missing 'start' attribute in <address> element in <nat> in "
1347                              "<forward> in network %s"), networkName);
1348             return -1;
1349         }
1350         addrEnd = virXMLPropString(*natAddrNodes, "end");
1351         if (addrEnd == NULL) {
1352             virReportError(VIR_ERR_XML_ERROR,
1353                            _("missing 'end' attribute in <address> element in <nat> in "
1354                              "<forward> in network %s"), networkName);
1355             return -1;
1356         }
1357     }
1358 
1359     if (addrStart && virSocketAddrParse(&def->addr.start, addrStart, AF_INET) < 0) {
1360         virReportError(VIR_ERR_XML_ERROR,
1361                        _("Bad ipv4 start address '%s' in <nat> in <forward> in "
1362                          "network '%s'"), addrStart, networkName);
1363         return -1;
1364     }
1365 
1366     if (addrEnd && virSocketAddrParse(&def->addr.end, addrEnd, AF_INET) < 0) {
1367         virReportError(VIR_ERR_XML_ERROR,
1368                        _("Bad ipv4 end address '%s' in <nat> in <forward> in "
1369                          "network '%s'"), addrEnd, networkName);
1370         return -1;
1371     }
1372 
1373     if (addrStart && addrEnd) {
1374         /* verify that start <= end */
1375         if (virSocketAddrGetRange(&def->addr.start, &def->addr.end, NULL, 0) < 0)
1376             return -1;
1377     } else {
1378         if (addrStart) {
1379             virReportError(VIR_ERR_XML_ERROR,
1380                            _("Only start address '%s' specified in <nat> in "
1381                              "<forward> in network '%s'"),
1382                            addrStart, networkName);
1383             return -1;
1384         }
1385         if (addrEnd) {
1386             virReportError(VIR_ERR_XML_ERROR,
1387                            _("Only end address '%s' specified in <nat> in "
1388                              "<forward> in network '%s'"),
1389                            addrEnd, networkName);
1390             return -1;
1391         }
1392     }
1393 
1394     /* ports for SNAT and MASQUERADE */
1395     nNatPorts = virXPathNodeSet("./port", ctxt, &natPortNodes);
1396     if (nNatPorts < 0) {
1397         virReportError(VIR_ERR_XML_ERROR,
1398                        _("invalid <port> element found in <forward> of "
1399                          "network %s"), networkName);
1400         return -1;
1401     } else if (nNatPorts > 1) {
1402         virReportError(VIR_ERR_XML_ERROR,
1403                        _("Only one <port> element is allowed in <nat> in "
1404                          "<forward> in network %s"), networkName);
1405         return -1;
1406     } else if (nNatPorts == 1) {
1407         if (virXPathUInt("string(./port[1]/@start)", ctxt, &def->port.start) < 0
1408             || def->port.start > 65535) {
1409 
1410             virReportError(VIR_ERR_XML_DETAIL,
1411                            _("Missing or invalid 'start' attribute in <port> "
1412                              "in <nat> in <forward> in network %s"),
1413                              networkName);
1414             return -1;
1415         }
1416         if (virXPathUInt("string(./port[1]/@end)", ctxt, &def->port.end) < 0
1417             || def->port.end > 65535 || def->port.end < def->port.start) {
1418             virReportError(VIR_ERR_XML_DETAIL,
1419                            _("Missing or invalid 'end' attribute in <port> in "
1420                              "<nat> in <forward> in network %s"), networkName);
1421             return -1;
1422         }
1423     }
1424     return 0;
1425 }
1426 
1427 
1428 static int
virNetworkForwardDefParseXML(const char * networkName,xmlNodePtr node,xmlXPathContextPtr ctxt,virNetworkForwardDef * def)1429 virNetworkForwardDefParseXML(const char *networkName,
1430                              xmlNodePtr node,
1431                              xmlXPathContextPtr ctxt,
1432                              virNetworkForwardDef *def)
1433 {
1434     size_t i, j;
1435     int nForwardIfs, nForwardAddrs, nForwardPfs, nForwardNats;
1436     g_autofree xmlNodePtr *forwardIfNodes = NULL;
1437     g_autofree xmlNodePtr *forwardPfNodes = NULL;
1438     g_autofree xmlNodePtr *forwardAddrNodes = NULL;
1439     g_autofree xmlNodePtr *forwardNatNodes = NULL;
1440     g_autofree char *forwardDev = NULL;
1441     g_autofree char *forwardManaged = NULL;
1442     g_autofree char *forwardDriverName = NULL;
1443     g_autofree char *type = NULL;
1444     VIR_XPATH_NODE_AUTORESTORE(ctxt)
1445 
1446     ctxt->node = node;
1447 
1448     if (!(type = virXPathString("string(./@mode)", ctxt))) {
1449         def->type = VIR_NETWORK_FORWARD_NAT;
1450     } else {
1451         if ((def->type = virNetworkForwardTypeFromString(type)) < 0) {
1452             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1453                            _("unknown forwarding type '%s'"), type);
1454             return -1;
1455         }
1456     }
1457 
1458     forwardManaged = virXPathString("string(./@managed)", ctxt);
1459     if (forwardManaged != NULL &&
1460         STRCASEEQ(forwardManaged, "yes")) {
1461         def->managed = true;
1462     }
1463 
1464     forwardDriverName = virXPathString("string(./driver/@name)", ctxt);
1465     if (forwardDriverName) {
1466         int driverName
1467             = virNetworkForwardDriverNameTypeFromString(forwardDriverName);
1468 
1469         if (driverName <= 0) {
1470             virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1471                            _("Unknown forward <driver name='%s'/> "
1472                              "in network %s"),
1473                            forwardDriverName, networkName);
1474             return -1;
1475         }
1476         def->driverName = driverName;
1477     }
1478 
1479     /* bridge and hostdev modes can use a pool of physical interfaces */
1480     nForwardIfs = virXPathNodeSet("./interface", ctxt, &forwardIfNodes);
1481     if (nForwardIfs < 0) {
1482         virReportError(VIR_ERR_XML_ERROR,
1483                        _("invalid <interface> element found in <forward> of network %s"),
1484                        networkName);
1485         return -1;
1486     }
1487 
1488     nForwardAddrs = virXPathNodeSet("./address", ctxt, &forwardAddrNodes);
1489     if (nForwardAddrs < 0) {
1490         virReportError(VIR_ERR_XML_ERROR,
1491                        _("invalid <address> element found in <forward> of network %s"),
1492                        networkName);
1493         return -1;
1494     }
1495 
1496     nForwardPfs = virXPathNodeSet("./pf", ctxt, &forwardPfNodes);
1497     if (nForwardPfs < 0) {
1498         virReportError(VIR_ERR_XML_ERROR,
1499                        _("invalid <pf> element found in <forward> of network %s"),
1500                        networkName);
1501         return -1;
1502     }
1503 
1504     nForwardNats = virXPathNodeSet("./nat", ctxt, &forwardNatNodes);
1505     if (nForwardNats < 0) {
1506         virReportError(VIR_ERR_XML_ERROR,
1507                        _("invalid <nat> element found in <forward> of network %s"),
1508                        networkName);
1509         return -1;
1510     } else if (nForwardNats > 1) {
1511         virReportError(VIR_ERR_XML_ERROR,
1512                        _("Only one <nat> element is allowed in <forward> of network %s"),
1513                        networkName);
1514         return -1;
1515     } else if (nForwardNats == 1) {
1516         if (virNetworkForwardNatDefParseXML(networkName,
1517                                             *forwardNatNodes,
1518                                             ctxt, def) < 0)
1519             return -1;
1520     }
1521 
1522     forwardDev = virXPathString("string(./@dev)", ctxt);
1523     if (forwardDev && (nForwardAddrs > 0 || nForwardPfs > 0)) {
1524         virReportError(VIR_ERR_XML_ERROR, "%s",
1525                        _("the <forward> 'dev' attribute cannot be used when "
1526                          "<address> or <pf> sub-elements are present "
1527                          "in network %s"));
1528         return -1;
1529     }
1530 
1531     if (nForwardIfs > 0 || forwardDev) {
1532         def->ifs = g_new0(virNetworkForwardIfDef, MAX(nForwardIfs, 1));
1533 
1534         if (forwardDev) {
1535             def->ifs[0].device.dev = g_steal_pointer(&forwardDev);
1536             def->ifs[0].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV;
1537             def->nifs++;
1538         }
1539 
1540         /* parse each <interface> */
1541         for (i = 0; i < nForwardIfs; i++) {
1542             g_autofree char *forwardDevi = virXMLPropString(forwardIfNodes[i], "dev");
1543 
1544             if (!forwardDevi) {
1545                 virReportError(VIR_ERR_XML_ERROR,
1546                                _("Missing required dev attribute in "
1547                                  "<forward> <interface> element of network %s"),
1548                                networkName);
1549                 return -1;
1550             }
1551 
1552             if ((i == 0) && (def->nifs == 1)) {
1553                 /* both <forward dev='x'> and <interface dev='x'/> are
1554                  * present.  If they don't match, it's an error.
1555                  */
1556                 if (STRNEQ(forwardDevi, def->ifs[0].device.dev)) {
1557                     virReportError(VIR_ERR_XML_ERROR,
1558                                    _("<forward dev='%s'> must match first "
1559                                      "<interface dev='%s'/> in network %s"),
1560                                    def->ifs[0].device.dev,
1561                                    forwardDevi, networkName);
1562                     return -1;
1563                 }
1564                 continue;
1565             }
1566 
1567             for (j = 0; j < i; j++) {
1568                 if (STREQ_NULLABLE(def->ifs[j].device.dev, forwardDevi)) {
1569                     virReportError(VIR_ERR_XML_ERROR,
1570                                    _("interface '%s' can only be "
1571                                      "listed once in network %s"),
1572                                    forwardDevi, networkName);
1573                     return -1;
1574                 }
1575             }
1576 
1577             def->ifs[i].device.dev = g_steal_pointer(&forwardDevi);
1578             def->ifs[i].type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV;
1579             def->nifs++;
1580         }
1581 
1582     } else if (nForwardAddrs > 0) {
1583         def->ifs = g_new0(virNetworkForwardIfDef, nForwardAddrs);
1584 
1585         for (i = 0; i < nForwardAddrs; i++) {
1586             g_autofree char *addrType = NULL;
1587 
1588             if (!(addrType = virXMLPropString(forwardAddrNodes[i], "type"))) {
1589                 virReportError(VIR_ERR_XML_ERROR,
1590                                _("missing address type in network %s"),
1591                                networkName);
1592                 return -1;
1593             }
1594 
1595             if ((def->ifs[i].type = virNetworkForwardHostdevDeviceTypeFromString(addrType)) < 0) {
1596                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1597                                _("unknown address type '%s' in network %s"),
1598                                addrType, networkName);
1599                 return -1;
1600             }
1601 
1602             switch (def->ifs[i].type) {
1603             case VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI:
1604             {
1605                 virPCIDeviceAddress *addr = &def->ifs[i].device.pci;
1606 
1607                 if (virPCIDeviceAddressParseXML(forwardAddrNodes[i], addr) < 0)
1608                     return -1;
1609 
1610                 for (j = 0; j < i; j++) {
1611                     if (virPCIDeviceAddressEqual(addr, &def->ifs[j].device.pci)) {
1612                         virReportError(VIR_ERR_XML_ERROR,
1613                                        _("PCI device '%04x:%02x:%02x.%x' can "
1614                                          "only be listed once in network %s"),
1615                                        addr->domain, addr->bus,
1616                                        addr->slot, addr->function,
1617                                        networkName);
1618                         return -1;
1619                     }
1620                 }
1621                 break;
1622             }
1623             /* Add USB case here if we ever find a reason to support it */
1624 
1625             default:
1626                 virReportError(VIR_ERR_XML_ERROR,
1627                                _("unsupported address type '%s' in network %s"),
1628                                addrType, networkName);
1629                 return -1;
1630             }
1631             def->nifs++;
1632         }
1633 
1634     } else if (nForwardPfs > 1) {
1635         virReportError(VIR_ERR_XML_ERROR,
1636                        _("Only one <pf> element is allowed in <forward> of network %s"),
1637                        networkName);
1638         return -1;
1639     } else if (nForwardPfs == 1) {
1640         def->pfs = g_new0(virNetworkForwardPfDef, nForwardPfs);
1641 
1642         forwardDev = virXMLPropString(*forwardPfNodes, "dev");
1643         if (!forwardDev) {
1644             virReportError(VIR_ERR_XML_ERROR,
1645                            _("Missing required dev attribute "
1646                              "in <pf> element of network '%s'"),
1647                            networkName);
1648             return -1;
1649         }
1650 
1651         def->pfs->dev = g_steal_pointer(&forwardDev);
1652         def->npfs++;
1653     }
1654 
1655     return 0;
1656 }
1657 
1658 
1659 virNetworkDef *
virNetworkDefParseXML(xmlXPathContextPtr ctxt,virNetworkXMLOption * xmlopt)1660 virNetworkDefParseXML(xmlXPathContextPtr ctxt,
1661                       virNetworkXMLOption *xmlopt)
1662 {
1663     g_autoptr(virNetworkDef) def = NULL;
1664     g_autofree char *uuid = NULL;
1665     g_autofree char *localOnly = NULL;
1666     g_autofree char *stp = NULL;
1667     g_autofree char *stpDelay = NULL;
1668     g_autofree char *macTableManager = NULL;
1669     g_autofree char *macAddr = NULL;
1670     g_autofree char *mtuSize = NULL;
1671     g_autofree xmlNodePtr *ipNodes = NULL;
1672     g_autofree xmlNodePtr *routeNodes = NULL;
1673     g_autofree xmlNodePtr *portGroupNodes = NULL;
1674     int nips, nPortGroups, nRoutes;
1675     xmlNodePtr dnsNode = NULL;
1676     xmlNodePtr virtPortNode = NULL;
1677     xmlNodePtr forwardNode = NULL;
1678     g_autofree char *ipv6nogwStr = NULL;
1679     g_autofree char *trustGuestRxFilters = NULL;
1680     VIR_XPATH_NODE_AUTORESTORE(ctxt)
1681     xmlNodePtr bandwidthNode = NULL;
1682     xmlNodePtr vlanNode;
1683     xmlNodePtr metadataNode = NULL;
1684 
1685     def = g_new0(virNetworkDef, 1);
1686 
1687     /* Extract network name */
1688     def->name = virXPathString("string(./name[1])", ctxt);
1689     if (!def->name) {
1690         virReportError(VIR_ERR_NO_NAME, NULL);
1691         return NULL;
1692     }
1693 
1694     if (virXMLCheckIllegalChars("name", def->name, "/") < 0)
1695         return NULL;
1696 
1697     /* Extract network uuid */
1698     uuid = virXPathString("string(./uuid[1])", ctxt);
1699     if (!uuid) {
1700         if (virUUIDGenerate(def->uuid) < 0) {
1701             virReportError(VIR_ERR_INTERNAL_ERROR,
1702                            "%s", _("Failed to generate UUID"));
1703             return NULL;
1704         }
1705     } else {
1706         if (virUUIDParse(uuid, def->uuid) < 0) {
1707             virReportError(VIR_ERR_INTERNAL_ERROR,
1708                            "%s", _("malformed uuid element"));
1709             return NULL;
1710         }
1711         def->uuid_specified = true;
1712     }
1713 
1714     /* check if definitions with no IPv6 gateway addresses is to
1715      * allow guest-to-guest communications.
1716      */
1717     ipv6nogwStr = virXPathString("string(./@ipv6)", ctxt);
1718     if (ipv6nogwStr) {
1719         if (virStringParseYesNo(ipv6nogwStr, &def->ipv6nogw) < 0) {
1720             virReportError(VIR_ERR_XML_ERROR,
1721                            _("Invalid ipv6 setting '%s' in network '%s'"),
1722                            ipv6nogwStr, def->name);
1723             return NULL;
1724         }
1725     }
1726 
1727     trustGuestRxFilters
1728         = virXPathString("string(./@trustGuestRxFilters)", ctxt);
1729     if (trustGuestRxFilters) {
1730         if ((def->trustGuestRxFilters
1731              = virTristateBoolTypeFromString(trustGuestRxFilters)) <= 0) {
1732             virReportError(VIR_ERR_XML_ERROR,
1733                            _("Invalid trustGuestRxFilters setting '%s' "
1734                              "in network '%s'"),
1735                            trustGuestRxFilters, def->name);
1736             return NULL;
1737         }
1738     }
1739 
1740     /* Parse network domain information */
1741     def->domain = virXPathString("string(./domain[1]/@name)", ctxt);
1742     localOnly = virXPathString("string(./domain[1]/@localOnly)", ctxt);
1743     if (localOnly) {
1744         def->domainLocalOnly = virTristateBoolTypeFromString(localOnly);
1745         if (def->domainLocalOnly <= 0) {
1746             virReportError(VIR_ERR_XML_ERROR,
1747                            _("Invalid domain localOnly setting '%s' "
1748                              "in network '%s'"),
1749                            localOnly, def->name);
1750             return NULL;
1751         }
1752     }
1753 
1754     if ((bandwidthNode = virXPathNode("./bandwidth", ctxt)) &&
1755         virNetDevBandwidthParse(&def->bandwidth, NULL, bandwidthNode, false) < 0)
1756         return NULL;
1757 
1758     vlanNode = virXPathNode("./vlan", ctxt);
1759     if (vlanNode && virNetDevVlanParse(vlanNode, ctxt, &def->vlan) < 0)
1760         return NULL;
1761 
1762     if (virNetworkPortOptionsParseXML(ctxt, &def->isolatedPort) < 0)
1763         return NULL;
1764 
1765     /* Parse bridge information */
1766     def->bridge = virXPathString("string(./bridge[1]/@name)", ctxt);
1767     def->bridgeZone = virXPathString("string(./bridge[1]/@zone)", ctxt);
1768     stp = virXPathString("string(./bridge[1]/@stp)", ctxt);
1769     def->stp = (stp && STREQ(stp, "off")) ? false : true;
1770 
1771     stpDelay = virXPathString("string(./bridge[1]/@delay)", ctxt);
1772     if (stpDelay) {
1773         if (virStrToLong_ulp(stpDelay, NULL, 10, &def->delay) < 0) {
1774             virReportError(VIR_ERR_XML_ERROR,
1775                            _("Invalid delay value in network '%s'"),
1776                            def->name);
1777             return NULL;
1778         }
1779     }
1780 
1781     macTableManager = virXPathString("string(./bridge[1]/@macTableManager)", ctxt);
1782     if (macTableManager) {
1783         if ((def->macTableManager
1784              = virNetworkBridgeMACTableManagerTypeFromString(macTableManager)) <= 0) {
1785             virReportError(VIR_ERR_XML_ERROR,
1786                            _("Invalid macTableManager setting '%s' "
1787                              "in network '%s'"), macTableManager, def->name);
1788             return NULL;
1789         }
1790     }
1791 
1792     macAddr = virXPathString("string(./mac[1]/@address)", ctxt);
1793     if (macAddr) {
1794         if (virMacAddrParse(macAddr, &def->mac) < 0) {
1795             virReportError(VIR_ERR_XML_ERROR,
1796                            _("Invalid bridge mac address '%s' in network '%s'"),
1797                            macAddr, def->name);
1798             return NULL;
1799         }
1800         if (virMacAddrIsMulticast(&def->mac)) {
1801             virReportError(VIR_ERR_XML_ERROR,
1802                            _("Invalid multicast bridge mac address '%s' in network '%s'"),
1803                            macAddr, def->name);
1804             return NULL;
1805         }
1806         def->mac_specified = true;
1807     }
1808 
1809     mtuSize = virXPathString("string(./mtu/@size)", ctxt);
1810     if (mtuSize) {
1811         if (virStrToLong_ui(mtuSize, NULL, 10, &def->mtu) < 0) {
1812             virReportError(VIR_ERR_XML_ERROR,
1813                            _("Invalid mtu size '%s' in network '%s'"),
1814                            mtuSize, def->name);
1815             return NULL;
1816         }
1817     }
1818 
1819     dnsNode = virXPathNode("./dns", ctxt);
1820     if (dnsNode != NULL &&
1821         virNetworkDNSDefParseXML(def->name, dnsNode, ctxt, &def->dns) < 0) {
1822         return NULL;
1823     }
1824 
1825     virtPortNode = virXPathNode("./virtualport", ctxt);
1826     if (virtPortNode &&
1827         (!(def->virtPortProfile = virNetDevVPortProfileParse(virtPortNode,
1828                                                              VIR_VPORT_XML_REQUIRE_TYPE)))) {
1829         return NULL;
1830     }
1831 
1832     nPortGroups = virXPathNodeSet("./portgroup", ctxt, &portGroupNodes);
1833     if (nPortGroups < 0)
1834         return NULL;
1835 
1836     if (nPortGroups > 0) {
1837         size_t i;
1838 
1839         /* allocate array to hold all the portgroups */
1840         def->portGroups = g_new0(virPortGroupDef, nPortGroups);
1841         /* parse each portgroup */
1842         for (i = 0; i < nPortGroups; i++) {
1843             if (virNetworkPortGroupParseXML(&def->portGroups[i],
1844                                             portGroupNodes[i],
1845                                             ctxt) < 0)
1846                 return NULL;
1847             def->nPortGroups++;
1848         }
1849     }
1850 
1851     nips = virXPathNodeSet("./ip", ctxt, &ipNodes);
1852     if (nips < 0)
1853         return NULL;
1854 
1855     if (nips > 0) {
1856         size_t i;
1857 
1858         /* allocate array to hold all the addrs */
1859         def->ips = g_new0(virNetworkIPDef, nips);
1860         /* parse each addr */
1861         for (i = 0; i < nips; i++) {
1862             if (virNetworkIPDefParseXML(def->name,
1863                                         ipNodes[i],
1864                                         ctxt,
1865                                         &def->ips[i]) < 0)
1866                 return NULL;
1867             def->nips++;
1868         }
1869     }
1870 
1871     nRoutes = virXPathNodeSet("./route", ctxt, &routeNodes);
1872     if (nRoutes < 0)
1873         return NULL;
1874 
1875     if (nRoutes > 0) {
1876         size_t i;
1877 
1878         /* allocate array to hold all the route definitions */
1879         def->routes = g_new0(virNetDevIPRoute *, nRoutes);
1880         /* parse each definition */
1881         for (i = 0; i < nRoutes; i++) {
1882             virNetDevIPRoute *route = NULL;
1883 
1884             if (!(route = virNetDevIPRouteParseXML(def->name,
1885                                                    routeNodes[i],
1886                                                    ctxt)))
1887                 return NULL;
1888             def->routes[i] = route;
1889             def->nroutes++;
1890         }
1891 
1892         /* now validate the correctness of any static route gateways specified
1893          *
1894          * note: the parameters within each definition are verified/assumed valid;
1895          * the question being asked and answered here is if the specified gateway
1896          * is directly reachable from this bridge.
1897          */
1898         nRoutes = def->nroutes;
1899         nips = def->nips;
1900         for (i = 0; i < nRoutes; i++) {
1901             size_t j;
1902             virSocketAddr testAddr, testGw;
1903             bool addrMatch;
1904             virNetDevIPRoute *gwdef = def->routes[i];
1905             virSocketAddr *gateway = virNetDevIPRouteGetGateway(gwdef);
1906             addrMatch = false;
1907             for (j = 0; j < nips; j++) {
1908                 virNetworkIPDef *def2 = &def->ips[j];
1909                 int prefix;
1910 
1911                 if (VIR_SOCKET_ADDR_FAMILY(gateway)
1912                     != VIR_SOCKET_ADDR_FAMILY(&def2->address)) {
1913                     continue;
1914                 }
1915                 prefix = virNetworkIPDefPrefix(def2);
1916                 virSocketAddrMaskByPrefix(&def2->address, prefix, &testAddr);
1917                 virSocketAddrMaskByPrefix(gateway, prefix, &testGw);
1918                 if (VIR_SOCKET_ADDR_VALID(&testAddr) &&
1919                     VIR_SOCKET_ADDR_VALID(&testGw) &&
1920                     virSocketAddrEqual(&testAddr, &testGw)) {
1921                     addrMatch = true;
1922                     break;
1923                 }
1924             }
1925             if (!addrMatch) {
1926                 g_autofree char *gw = virSocketAddrFormat(gateway);
1927                 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
1928                                _("unreachable static route gateway '%s' specified for network '%s'"),
1929                                gw, def->name);
1930                 return NULL;
1931             }
1932         }
1933     }
1934 
1935     forwardNode = virXPathNode("./forward", ctxt);
1936     if (forwardNode &&
1937         virNetworkForwardDefParseXML(def->name, forwardNode, ctxt, &def->forward) < 0) {
1938         return NULL;
1939     }
1940 
1941     /* Validate some items in the main NetworkDef that need to align
1942      * with the chosen forward mode.
1943      */
1944     switch ((virNetworkForwardType) def->forward.type) {
1945     case VIR_NETWORK_FORWARD_NONE:
1946         break;
1947 
1948     case VIR_NETWORK_FORWARD_ROUTE:
1949     case VIR_NETWORK_FORWARD_NAT:
1950     case VIR_NETWORK_FORWARD_OPEN:
1951         /* It's pointless to specify L3 forwarding without specifying
1952          * the network we're on.
1953          */
1954         if (def->nips == 0) {
1955             virReportError(VIR_ERR_XML_ERROR,
1956                            _("%s forwarding requested, "
1957                              "but no IP address provided for network '%s'"),
1958                            virNetworkForwardTypeToString(def->forward.type),
1959                            def->name);
1960             return NULL;
1961         }
1962         if (def->forward.nifs > 1) {
1963             virReportError(VIR_ERR_XML_ERROR,
1964                            _("multiple forwarding interfaces specified "
1965                              "for network '%s', only one is supported"),
1966                            def->name);
1967             return NULL;
1968         }
1969 
1970         if (def->forward.type == VIR_NETWORK_FORWARD_OPEN && def->forward.nifs) {
1971             /* an open network by definition can't place any restrictions
1972              * on what traffic is allowed or where it goes, so specifying
1973              * a forwarding device is nonsensical.
1974              */
1975             virReportError(VIR_ERR_XML_ERROR,
1976                            _("forward dev not allowed for "
1977                              "network '%s' with forward mode='%s'"),
1978                            def->name,
1979                            virNetworkForwardTypeToString(def->forward.type));
1980             return NULL;
1981         }
1982         break;
1983 
1984     case VIR_NETWORK_FORWARD_PRIVATE:
1985     case VIR_NETWORK_FORWARD_VEPA:
1986     case VIR_NETWORK_FORWARD_PASSTHROUGH:
1987     case VIR_NETWORK_FORWARD_HOSTDEV:
1988         if (def->bridge) {
1989             virReportError(VIR_ERR_XML_ERROR,
1990                            _("bridge name not allowed in %s mode (network '%s')"),
1991                            virNetworkForwardTypeToString(def->forward.type),
1992                            def->name);
1993             return NULL;
1994         }
1995         if (def->bridgeZone) {
1996             virReportError(VIR_ERR_XML_ERROR,
1997                            _("bridge zone not allowed in %s mode (network '%s')"),
1998                            virNetworkForwardTypeToString(def->forward.type),
1999                            def->name);
2000             return NULL;
2001         }
2002         if (def->macTableManager) {
2003             virReportError(VIR_ERR_XML_ERROR,
2004                            _("bridge macTableManager setting not allowed "
2005                              "in %s mode (network '%s')"),
2006                            virNetworkForwardTypeToString(def->forward.type),
2007                            def->name);
2008             return NULL;
2009         }
2010         G_GNUC_FALLTHROUGH;
2011 
2012     case VIR_NETWORK_FORWARD_BRIDGE:
2013         if (def->delay || stp || def->bridgeZone) {
2014             virReportError(VIR_ERR_XML_ERROR,
2015                            _("bridge delay/stp/zone options only allowed in "
2016                              "route, nat, and isolated mode, not in %s "
2017                              "(network '%s')"),
2018                            virNetworkForwardTypeToString(def->forward.type),
2019                            def->name);
2020             return NULL;
2021         }
2022         if (def->bridge && (def->forward.nifs || def->forward.npfs)) {
2023             virReportError(VIR_ERR_XML_ERROR,
2024                            _("A network with forward mode='%s' can specify "
2025                              "a bridge name or a forward dev, but not "
2026                              "both (network '%s')"),
2027                            virNetworkForwardTypeToString(def->forward.type),
2028                            def->name);
2029             return NULL;
2030         }
2031         break;
2032 
2033     case VIR_NETWORK_FORWARD_LAST:
2034     default:
2035         virReportEnumRangeError(virNetworkForwardType, def->forward.type);
2036         return NULL;
2037     }
2038 
2039     if (def->mtu) {
2040         switch ((virNetworkForwardType) def->forward.type) {
2041         case VIR_NETWORK_FORWARD_NONE:
2042         case VIR_NETWORK_FORWARD_NAT:
2043         case VIR_NETWORK_FORWARD_ROUTE:
2044         case VIR_NETWORK_FORWARD_OPEN:
2045             break;
2046 
2047         case VIR_NETWORK_FORWARD_BRIDGE:
2048         case VIR_NETWORK_FORWARD_PRIVATE:
2049         case VIR_NETWORK_FORWARD_VEPA:
2050         case VIR_NETWORK_FORWARD_PASSTHROUGH:
2051         case VIR_NETWORK_FORWARD_HOSTDEV:
2052             virReportError(VIR_ERR_XML_ERROR,
2053                            _("mtu size only allowed in open, route, nat, "
2054                              "and isolated mode, not in %s (network '%s')"),
2055                            virNetworkForwardTypeToString(def->forward.type),
2056                            def->name);
2057             return NULL;
2058 
2059         case VIR_NETWORK_FORWARD_LAST:
2060         default:
2061             virReportEnumRangeError(virNetworkForwardType, def->forward.type);
2062             return NULL;
2063         }
2064     }
2065 
2066     /* Extract custom metadata */
2067     if ((metadataNode = virXPathNode("./metadata[1]", ctxt)) != NULL) {
2068         def->metadata = xmlCopyNode(metadataNode, 1);
2069         virXMLNodeSanitizeNamespaces(def->metadata);
2070     }
2071 
2072     if (xmlopt)
2073         def->ns = xmlopt->ns;
2074     if (def->ns.parse) {
2075         if (virXMLNamespaceRegister(ctxt, &def->ns) < 0)
2076             return NULL;
2077         if ((def->ns.parse)(ctxt, &def->namespaceData) < 0)
2078             return NULL;
2079     }
2080 
2081     return g_steal_pointer(&def);
2082 }
2083 
2084 
2085 static virNetworkDef *
virNetworkDefParse(const char * xmlStr,const char * filename,virNetworkXMLOption * xmlopt,bool validate)2086 virNetworkDefParse(const char *xmlStr,
2087                    const char *filename,
2088                    virNetworkXMLOption *xmlopt,
2089                    bool validate)
2090 {
2091     g_autoptr(xmlDoc) xml = NULL;
2092     virNetworkDef *def = NULL;
2093     int keepBlanksDefault = xmlKeepBlanksDefault(0);
2094 
2095     if ((xml = virXMLParse(filename, xmlStr, _("(network_definition)"),
2096                            "network.rng", validate)))
2097         def = virNetworkDefParseNode(xml, xmlDocGetRootElement(xml), xmlopt);
2098 
2099     xmlKeepBlanksDefault(keepBlanksDefault);
2100     return def;
2101 }
2102 
2103 
2104 virNetworkDef *
virNetworkDefParseString(const char * xmlStr,virNetworkXMLOption * xmlopt,bool validate)2105 virNetworkDefParseString(const char *xmlStr,
2106                          virNetworkXMLOption *xmlopt,
2107                          bool validate)
2108 {
2109     return virNetworkDefParse(xmlStr, NULL, xmlopt, validate);
2110 }
2111 
2112 
2113 virNetworkDef *
virNetworkDefParseFile(const char * filename,virNetworkXMLOption * xmlopt)2114 virNetworkDefParseFile(const char *filename,
2115                        virNetworkXMLOption *xmlopt)
2116 {
2117     return virNetworkDefParse(NULL, filename, xmlopt, false);
2118 }
2119 
2120 
2121 virNetworkDef *
virNetworkDefParseNode(xmlDocPtr xml,xmlNodePtr root,virNetworkXMLOption * xmlopt)2122 virNetworkDefParseNode(xmlDocPtr xml,
2123                        xmlNodePtr root,
2124                        virNetworkXMLOption *xmlopt)
2125 {
2126     g_autoptr(xmlXPathContext) ctxt = NULL;
2127 
2128     if (!virXMLNodeNameEqual(root, "network")) {
2129         virReportError(VIR_ERR_XML_ERROR,
2130                        _("unexpected root element <%s>, "
2131                          "expecting <network>"),
2132                        root->name);
2133         return NULL;
2134     }
2135 
2136     if (!(ctxt = virXMLXPathContextNew(xml)))
2137         return NULL;
2138 
2139     ctxt->node = root;
2140     return virNetworkDefParseXML(ctxt, xmlopt);
2141 }
2142 
2143 
2144 static int
virNetworkDNSDefFormat(virBuffer * buf,const virNetworkDNSDef * def)2145 virNetworkDNSDefFormat(virBuffer *buf,
2146                        const virNetworkDNSDef *def)
2147 {
2148     size_t i, j;
2149 
2150     if (!(def->enable || def->forwardPlainNames || def->nfwds || def->nhosts ||
2151           def->nsrvs || def->ntxts))
2152         return 0;
2153 
2154     virBufferAddLit(buf, "<dns");
2155     if (def->enable) {
2156         const char *fwd = virTristateBoolTypeToString(def->enable);
2157 
2158         if (!fwd) {
2159             virReportError(VIR_ERR_INTERNAL_ERROR,
2160                            _("Unknown enable type %d in network"),
2161                            def->enable);
2162             return -1;
2163         }
2164         virBufferAsprintf(buf, " enable='%s'", fwd);
2165     }
2166     if (def->forwardPlainNames) {
2167         const char *fwd = virTristateBoolTypeToString(def->forwardPlainNames);
2168 
2169         if (!fwd) {
2170             virReportError(VIR_ERR_INTERNAL_ERROR,
2171                            _("Unknown forwardPlainNames type %d in network"),
2172                            def->forwardPlainNames);
2173             return -1;
2174         }
2175         virBufferAsprintf(buf, " forwardPlainNames='%s'", fwd);
2176     }
2177     if (!(def->nfwds || def->nhosts || def->nsrvs || def->ntxts)) {
2178         virBufferAddLit(buf, "/>\n");
2179         return 0;
2180     }
2181 
2182     virBufferAddLit(buf, ">\n");
2183     virBufferAdjustIndent(buf, 2);
2184 
2185     for (i = 0; i < def->nfwds; i++) {
2186 
2187         virBufferAddLit(buf, "<forwarder");
2188         if (def->forwarders[i].domain) {
2189             virBufferEscapeString(buf, " domain='%s'",
2190                                   def->forwarders[i].domain);
2191         }
2192         if (VIR_SOCKET_ADDR_VALID(&def->forwarders[i].addr)) {
2193             g_autofree char *addr = virSocketAddrFormat(&def->forwarders[i].addr);
2194 
2195             if (!addr)
2196                 return -1;
2197 
2198             virBufferAsprintf(buf, " addr='%s'", addr);
2199         }
2200         virBufferAddLit(buf, "/>\n");
2201     }
2202 
2203     for (i = 0; i < def->ntxts; i++) {
2204         virBufferEscapeString(buf, "<txt name='%s' ", def->txts[i].name);
2205         virBufferEscapeString(buf, "value='%s'/>\n", def->txts[i].value);
2206     }
2207 
2208     for (i = 0; i < def->nsrvs; i++) {
2209         if (def->srvs[i].service && def->srvs[i].protocol) {
2210             virBufferEscapeString(buf, "<srv service='%s' ",
2211                                   def->srvs[i].service);
2212             virBufferEscapeString(buf, "protocol='%s'", def->srvs[i].protocol);
2213 
2214             if (def->srvs[i].domain)
2215                 virBufferEscapeString(buf, " domain='%s'", def->srvs[i].domain);
2216             if (def->srvs[i].target)
2217                 virBufferEscapeString(buf, " target='%s'", def->srvs[i].target);
2218             if (def->srvs[i].port)
2219                 virBufferAsprintf(buf, " port='%d'", def->srvs[i].port);
2220             if (def->srvs[i].priority)
2221                 virBufferAsprintf(buf, " priority='%d'", def->srvs[i].priority);
2222             if (def->srvs[i].weight)
2223                 virBufferAsprintf(buf, " weight='%d'", def->srvs[i].weight);
2224 
2225             virBufferAddLit(buf, "/>\n");
2226         }
2227     }
2228 
2229     if (def->nhosts) {
2230         for (i = 0; i < def->nhosts; i++) {
2231             g_autofree char *ip = virSocketAddrFormat(&def->hosts[i].ip);
2232 
2233             virBufferAsprintf(buf, "<host ip='%s'>\n", ip);
2234             virBufferAdjustIndent(buf, 2);
2235             for (j = 0; j < def->hosts[i].nnames; j++)
2236                 virBufferEscapeString(buf, "<hostname>%s</hostname>\n",
2237                                       def->hosts[i].names[j]);
2238 
2239             virBufferAdjustIndent(buf, -2);
2240             virBufferAddLit(buf, "</host>\n");
2241         }
2242     }
2243     virBufferAdjustIndent(buf, -2);
2244     virBufferAddLit(buf, "</dns>\n");
2245     return 0;
2246 }
2247 
2248 
2249 static int
virNetworkIPDefFormat(virBuffer * buf,const virNetworkIPDef * def)2250 virNetworkIPDefFormat(virBuffer *buf,
2251                       const virNetworkIPDef *def)
2252 {
2253     virBufferAddLit(buf, "<ip");
2254 
2255     if (def->family)
2256         virBufferAsprintf(buf, " family='%s'", def->family);
2257     if (VIR_SOCKET_ADDR_VALID(&def->address)) {
2258         g_autofree char *addr = virSocketAddrFormat(&def->address);
2259         if (!addr)
2260             return -1;
2261         virBufferAsprintf(buf, " address='%s'", addr);
2262     }
2263     if (VIR_SOCKET_ADDR_VALID(&def->netmask)) {
2264         g_autofree char *addr = virSocketAddrFormat(&def->netmask);
2265         if (!addr)
2266             return -1;
2267         virBufferAsprintf(buf, " netmask='%s'", addr);
2268     }
2269     if (def->prefix > 0)
2270         virBufferAsprintf(buf, " prefix='%u'", def->prefix);
2271 
2272     if (def->localPTR) {
2273         virBufferAsprintf(buf, " localPtr='%s'",
2274                           virTristateBoolTypeToString(def->localPTR));
2275     }
2276 
2277     virBufferAddLit(buf, ">\n");
2278     virBufferAdjustIndent(buf, 2);
2279 
2280     if (def->tftproot) {
2281         virBufferEscapeString(buf, "<tftp root='%s'/>\n",
2282                               def->tftproot);
2283     }
2284     if ((def->nranges || def->nhosts)) {
2285         size_t i;
2286         virBufferAddLit(buf, "<dhcp>\n");
2287         virBufferAdjustIndent(buf, 2);
2288 
2289         for (i = 0; i < def->nranges; i++) {
2290             virSocketAddrRange addr = def->ranges[i].addr;
2291             virNetworkDHCPLeaseTimeDef *lease = def->ranges[i].lease;
2292             g_autofree char *saddr = NULL;
2293             g_autofree char *eaddr = NULL;
2294 
2295             if (!(saddr = virSocketAddrFormat(&addr.start)))
2296                 return -1;
2297 
2298             if (!(eaddr = virSocketAddrFormat(&addr.end)))
2299                 return -1;
2300 
2301             virBufferAsprintf(buf, "<range start='%s' end='%s'",
2302                               saddr, eaddr);
2303             if (lease) {
2304                 virBufferAddLit(buf, ">\n");
2305                 virBufferAdjustIndent(buf, 2);
2306                 if (!lease->expiry) {
2307                     virBufferAddLit(buf, "<lease expiry='0'/>\n");
2308                 } else {
2309                     virBufferAsprintf(buf, "<lease expiry='%llu' unit='%s'/>\n",
2310                                       lease->expiry,
2311                                       virNetworkDHCPLeaseTimeUnitTypeToString(lease->unit));
2312                 }
2313                 virBufferAdjustIndent(buf, -2);
2314                 virBufferAddLit(buf, "</range>\n");
2315             } else {
2316                 virBufferAddLit(buf, "/>\n");
2317             }
2318         }
2319         for (i = 0; i < def->nhosts; i++) {
2320             virNetworkDHCPLeaseTimeDef *lease = def->hosts[i].lease;
2321             virBufferAddLit(buf, "<host");
2322             if (def->hosts[i].mac)
2323                 virBufferAsprintf(buf, " mac='%s'", def->hosts[i].mac);
2324             if (def->hosts[i].id)
2325                 virBufferAsprintf(buf, " id='%s'", def->hosts[i].id);
2326             if (def->hosts[i].name)
2327                 virBufferAsprintf(buf, " name='%s'", def->hosts[i].name);
2328             if (VIR_SOCKET_ADDR_VALID(&def->hosts[i].ip)) {
2329                 g_autofree char *ipaddr = virSocketAddrFormat(&def->hosts[i].ip);
2330                 if (!ipaddr)
2331                     return -1;
2332 
2333                 virBufferAsprintf(buf, " ip='%s'", ipaddr);
2334             }
2335             if (lease) {
2336                 virBufferAddLit(buf, ">\n");
2337                 virBufferAdjustIndent(buf, 2);
2338                 if (!lease->expiry) {
2339                     virBufferAddLit(buf, "<lease expiry='0'/>\n");
2340                 } else {
2341                     virBufferAsprintf(buf, "<lease expiry='%llu' unit='%s'/>\n",
2342                                       lease->expiry,
2343                                       virNetworkDHCPLeaseTimeUnitTypeToString(lease->unit));
2344                 }
2345                 virBufferAdjustIndent(buf, -2);
2346                 virBufferAddLit(buf, "</host>\n");
2347             } else {
2348                 virBufferAddLit(buf, "/>\n");
2349             }
2350         }
2351         if (def->bootfile) {
2352             virBufferEscapeString(buf, "<bootp file='%s'",
2353                                   def->bootfile);
2354             if (VIR_SOCKET_ADDR_VALID(&def->bootserver)) {
2355                 g_autofree char *ipaddr = virSocketAddrFormat(&def->bootserver);
2356                 if (!ipaddr)
2357                     return -1;
2358 
2359                 virBufferEscapeString(buf, " server='%s'", ipaddr);
2360             }
2361             virBufferAddLit(buf, "/>\n");
2362 
2363         }
2364         virBufferAdjustIndent(buf, -2);
2365         virBufferAddLit(buf, "</dhcp>\n");
2366     }
2367 
2368     virBufferAdjustIndent(buf, -2);
2369     virBufferAddLit(buf, "</ip>\n");
2370 
2371     return 0;
2372 }
2373 
2374 void
virNetworkPortOptionsFormat(virTristateBool isolatedPort,virBuffer * buf)2375 virNetworkPortOptionsFormat(virTristateBool isolatedPort,
2376                             virBuffer *buf)
2377 {
2378     if (isolatedPort != VIR_TRISTATE_BOOL_ABSENT)
2379         virBufferAsprintf(buf, "<port isolated='%s'/>\n",
2380                           virTristateBoolTypeToString(isolatedPort));
2381 }
2382 
2383 static int
virPortGroupDefFormat(virBuffer * buf,const virPortGroupDef * def)2384 virPortGroupDefFormat(virBuffer *buf,
2385                       const virPortGroupDef *def)
2386 {
2387     virBufferAsprintf(buf, "<portgroup name='%s'", def->name);
2388     if (def->isDefault)
2389         virBufferAddLit(buf, " default='yes'");
2390     if (def->trustGuestRxFilters)
2391         virBufferAsprintf(buf, " trustGuestRxFilters='%s'",
2392                           virTristateBoolTypeToString(def->trustGuestRxFilters));
2393     virBufferAddLit(buf, ">\n");
2394     virBufferAdjustIndent(buf, 2);
2395     if (virNetDevVlanFormat(&def->vlan, buf) < 0)
2396         return -1;
2397     if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
2398         return -1;
2399     virNetDevBandwidthFormat(def->bandwidth, 0, buf);
2400     virBufferAdjustIndent(buf, -2);
2401     virBufferAddLit(buf, "</portgroup>\n");
2402     return 0;
2403 }
2404 
2405 
2406 static int
virNetworkForwardNatDefFormat(virBuffer * buf,const virNetworkForwardDef * fwd)2407 virNetworkForwardNatDefFormat(virBuffer *buf,
2408                               const virNetworkForwardDef *fwd)
2409 {
2410     g_autofree char *addrStart = NULL;
2411     g_autofree char *addrEnd = NULL;
2412 
2413     if (VIR_SOCKET_ADDR_VALID(&fwd->addr.start)) {
2414         addrStart = virSocketAddrFormat(&fwd->addr.start);
2415         if (!addrStart)
2416             return -1;
2417     }
2418 
2419     if (VIR_SOCKET_ADDR_VALID(&fwd->addr.end)) {
2420         addrEnd = virSocketAddrFormat(&fwd->addr.end);
2421         if (!addrEnd)
2422             return -1;
2423     }
2424 
2425     if (!addrEnd && !addrStart && !fwd->port.start && !fwd->port.end && !fwd->natIPv6)
2426         return 0;
2427 
2428     virBufferAddLit(buf, "<nat");
2429     if (fwd->natIPv6)
2430         virBufferAsprintf(buf, " ipv6='%s'", virTristateBoolTypeToString(fwd->natIPv6));
2431 
2432     if (!addrEnd && !addrStart && !fwd->port.start && !fwd->port.end) {
2433         virBufferAddLit(buf, "/>\n");
2434         return 0;
2435     }
2436     virBufferAddLit(buf, ">\n");
2437     virBufferAdjustIndent(buf, 2);
2438 
2439     if (addrStart) {
2440         virBufferAsprintf(buf, "<address start='%s'", addrStart);
2441         if (addrEnd)
2442             virBufferAsprintf(buf, " end='%s'", addrEnd);
2443         virBufferAddLit(buf, "/>\n");
2444     }
2445 
2446     if (fwd->port.start || fwd->port.end) {
2447         virBufferAsprintf(buf, "<port start='%d'", fwd->port.start);
2448         if (fwd->port.end)
2449             virBufferAsprintf(buf, " end='%d'", fwd->port.end);
2450         virBufferAddLit(buf, "/>\n");
2451     }
2452 
2453     virBufferAdjustIndent(buf, -2);
2454     virBufferAddLit(buf, "</nat>\n");
2455     return 0;
2456 }
2457 
2458 
2459 int
virNetworkDefFormatBuf(virBuffer * buf,const virNetworkDef * def,virNetworkXMLOption * xmlopt G_GNUC_UNUSED,unsigned int flags)2460 virNetworkDefFormatBuf(virBuffer *buf,
2461                        const virNetworkDef *def,
2462                        virNetworkXMLOption *xmlopt G_GNUC_UNUSED,
2463                        unsigned int flags)
2464 {
2465     const unsigned char *uuid;
2466     char uuidstr[VIR_UUID_STRING_BUFLEN];
2467     size_t i;
2468     bool shortforward;
2469     bool hasbridge = false;
2470 
2471     virBufferAddLit(buf, "<network");
2472     if (def->namespaceData && def->ns.format)
2473         virXMLNamespaceFormatNS(buf, &def->ns);
2474     if (!(flags & VIR_NETWORK_XML_INACTIVE) && (def->connections > 0))
2475         virBufferAsprintf(buf, " connections='%d'", def->connections);
2476     if (def->ipv6nogw)
2477         virBufferAddLit(buf, " ipv6='yes'");
2478     if (def->trustGuestRxFilters)
2479         virBufferAsprintf(buf, " trustGuestRxFilters='%s'",
2480                           virTristateBoolTypeToString(def->trustGuestRxFilters));
2481     virBufferAddLit(buf, ">\n");
2482     virBufferAdjustIndent(buf, 2);
2483     virBufferEscapeString(buf, "<name>%s</name>\n", def->name);
2484 
2485     uuid = def->uuid;
2486     virUUIDFormat(uuid, uuidstr);
2487     virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuidstr);
2488 
2489     if (virXMLFormatMetadata(buf, def->metadata) < 0)
2490         return -1;
2491 
2492     if (def->forward.type != VIR_NETWORK_FORWARD_NONE) {
2493         const char *dev = NULL;
2494         const char *mode = virNetworkForwardTypeToString(def->forward.type);
2495 
2496         if (!def->forward.npfs)
2497             dev = virNetworkDefForwardIf(def, 0);
2498 
2499         if (!mode) {
2500             virReportError(VIR_ERR_INTERNAL_ERROR,
2501                            _("Unknown forward type %d in network '%s'"),
2502                            def->forward.type, def->name);
2503             return -1;
2504         }
2505         virBufferAddLit(buf, "<forward");
2506         virBufferEscapeString(buf, " dev='%s'", dev);
2507         virBufferAsprintf(buf, " mode='%s'", mode);
2508         if (def->forward.type == VIR_NETWORK_FORWARD_HOSTDEV) {
2509             if (def->forward.managed)
2510                 virBufferAddLit(buf, " managed='yes'");
2511             else
2512                 virBufferAddLit(buf, " managed='no'");
2513         }
2514         shortforward = !(def->forward.nifs || def->forward.npfs
2515                          || VIR_SOCKET_ADDR_VALID(&def->forward.addr.start)
2516                          || VIR_SOCKET_ADDR_VALID(&def->forward.addr.end)
2517                          || def->forward.port.start
2518                          || def->forward.port.end
2519                          || (def->forward.driverName
2520                              != VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT)
2521                          || def->forward.natIPv6);
2522         virBufferAsprintf(buf, "%s>\n", shortforward ? "/" : "");
2523         virBufferAdjustIndent(buf, 2);
2524 
2525         if (def->forward.driverName
2526             != VIR_NETWORK_FORWARD_DRIVER_NAME_DEFAULT) {
2527             const char *driverName
2528                 = virNetworkForwardDriverNameTypeToString(def->forward.driverName);
2529             if (!driverName) {
2530                 virReportError(VIR_ERR_INTERNAL_ERROR,
2531                                _("unexpected hostdev driver name type %d "),
2532                                def->forward.driverName);
2533                 return -1;
2534             }
2535             virBufferAsprintf(buf, "<driver name='%s'/>\n", driverName);
2536         }
2537         if (def->forward.type == VIR_NETWORK_FORWARD_NAT) {
2538             if (virNetworkForwardNatDefFormat(buf, &def->forward) < 0)
2539                 return -1;
2540         }
2541 
2542         /* For now, hard-coded to at most 1 forward.pfs */
2543         if (def->forward.npfs)
2544             virBufferEscapeString(buf, "<pf dev='%s'/>\n",
2545                                   def->forward.pfs[0].dev);
2546 
2547         if (def->forward.nifs &&
2548             (!def->forward.npfs || !(flags & VIR_NETWORK_XML_INACTIVE))) {
2549             for (i = 0; i < def->forward.nifs; i++) {
2550                 if (def->forward.ifs[i].type == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV) {
2551                     virBufferEscapeString(buf, "<interface dev='%s'",
2552                                           def->forward.ifs[i].device.dev);
2553                     if (!(flags & VIR_NETWORK_XML_INACTIVE) &&
2554                         (def->forward.ifs[i].connections > 0)) {
2555                         virBufferAsprintf(buf, " connections='%d'",
2556                                           def->forward.ifs[i].connections);
2557                     }
2558                     virBufferAddLit(buf, "/>\n");
2559                 } else {
2560                     if (def->forward.ifs[i].type ==  VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_PCI) {
2561                         virPCIDeviceAddressFormat(buf,
2562                                                   def->forward.ifs[i].device.pci,
2563                                                   true);
2564                     }
2565                 }
2566             }
2567         }
2568         virBufferAdjustIndent(buf, -2);
2569         if (!shortforward)
2570             virBufferAddLit(buf, "</forward>\n");
2571     }
2572 
2573     switch ((virNetworkForwardType) def->forward.type) {
2574     case VIR_NETWORK_FORWARD_NONE:
2575     case VIR_NETWORK_FORWARD_NAT:
2576     case VIR_NETWORK_FORWARD_ROUTE:
2577     case VIR_NETWORK_FORWARD_OPEN:
2578         hasbridge = true;
2579         break;
2580 
2581     case VIR_NETWORK_FORWARD_BRIDGE:
2582     case VIR_NETWORK_FORWARD_PRIVATE:
2583     case VIR_NETWORK_FORWARD_VEPA:
2584     case VIR_NETWORK_FORWARD_PASSTHROUGH:
2585     case VIR_NETWORK_FORWARD_HOSTDEV:
2586         break;
2587 
2588     case VIR_NETWORK_FORWARD_LAST:
2589     default:
2590         virReportEnumRangeError(virNetworkForwardType, def->forward.type);
2591         return -1;
2592     }
2593 
2594     if (hasbridge || def->bridge || def->macTableManager) {
2595         virBufferAddLit(buf, "<bridge");
2596         virBufferEscapeString(buf, " name='%s'", def->bridge);
2597         virBufferEscapeString(buf, " zone='%s'", def->bridgeZone);
2598         if (hasbridge)
2599             virBufferAsprintf(buf, " stp='%s' delay='%ld'",
2600                               def->stp ? "on" : "off", def->delay);
2601         if (def->macTableManager) {
2602             virBufferAsprintf(buf, " macTableManager='%s'",
2603                              virNetworkBridgeMACTableManagerTypeToString(def->macTableManager));
2604         }
2605         virBufferAddLit(buf, "/>\n");
2606     }
2607 
2608     if (def->mtu)
2609         virBufferAsprintf(buf, "<mtu size='%u'/>\n", def->mtu);
2610 
2611     if (def->mac_specified) {
2612         char macaddr[VIR_MAC_STRING_BUFLEN];
2613         virMacAddrFormat(&def->mac, macaddr);
2614         virBufferAsprintf(buf, "<mac address='%s'/>\n", macaddr);
2615     }
2616 
2617     if (def->domain) {
2618         virBufferAsprintf(buf, "<domain name='%s'", def->domain);
2619 
2620         /* default to "no", but don't format it in the XML */
2621         if (def->domainLocalOnly) {
2622             const char *local = virTristateBoolTypeToString(def->domainLocalOnly);
2623 
2624             if (!local) {
2625                 virReportError(VIR_ERR_INTERNAL_ERROR,
2626                                _("Unknown localOnly type %d in network"),
2627                                def->domainLocalOnly);
2628                 return -1;
2629             }
2630             virBufferAsprintf(buf, " localOnly='%s'", local);
2631         }
2632 
2633         virBufferAddLit(buf, "/>\n");
2634     }
2635 
2636     if (virNetworkDNSDefFormat(buf, &def->dns) < 0)
2637         return -1;
2638 
2639     if (virNetDevVlanFormat(&def->vlan, buf) < 0)
2640         return -1;
2641     if (virNetDevBandwidthFormat(def->bandwidth, 0, buf) < 0)
2642         return -1;
2643     virNetworkPortOptionsFormat(def->isolatedPort, buf);
2644 
2645     for (i = 0; i < def->nips; i++) {
2646         if (virNetworkIPDefFormat(buf, &def->ips[i]) < 0)
2647             return -1;
2648     }
2649 
2650     for (i = 0; i < def->nroutes; i++) {
2651         if (virNetDevIPRouteFormat(buf, def->routes[i]) < 0)
2652             return -1;
2653     }
2654 
2655     if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
2656         return -1;
2657 
2658     for (i = 0; i < def->nPortGroups; i++)
2659         if (virPortGroupDefFormat(buf, &def->portGroups[i]) < 0)
2660             return -1;
2661 
2662     if (def->namespaceData && def->ns.format) {
2663         if ((def->ns.format)(buf, def->namespaceData) < 0)
2664             return -1;
2665     }
2666 
2667     virBufferAdjustIndent(buf, -2);
2668     virBufferAddLit(buf, "</network>\n");
2669 
2670     return 0;
2671 }
2672 
2673 
2674 char *
virNetworkDefFormat(const virNetworkDef * def,virNetworkXMLOption * xmlopt,unsigned int flags)2675 virNetworkDefFormat(const virNetworkDef *def,
2676                     virNetworkXMLOption *xmlopt,
2677                     unsigned int flags)
2678 {
2679     g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
2680 
2681     if (virNetworkDefFormatBuf(&buf, def, xmlopt, flags) < 0)
2682         return NULL;
2683 
2684     return virBufferContentAndReset(&buf);
2685 }
2686 
2687 
2688 const char *
virNetworkDefForwardIf(const virNetworkDef * def,size_t n)2689 virNetworkDefForwardIf(const virNetworkDef *def,
2690                        size_t n)
2691 {
2692     return ((def->forward.ifs && (def->forward.nifs > n) &&
2693              def->forward.ifs[n].type == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV)
2694             ? def->forward.ifs[n].device.dev : NULL);
2695 }
2696 
2697 
2698 virPortGroupDef *
virPortGroupFindByName(virNetworkDef * net,const char * portgroup)2699 virPortGroupFindByName(virNetworkDef *net,
2700                        const char *portgroup)
2701 {
2702     size_t i;
2703     for (i = 0; i < net->nPortGroups; i++) {
2704         if (portgroup) {
2705             if (STREQ(portgroup, net->portGroups[i].name))
2706                 return &net->portGroups[i];
2707         } else {
2708             if (net->portGroups[i].isDefault)
2709                 return &net->portGroups[i];
2710         }
2711     }
2712     return NULL;
2713 }
2714 
2715 
2716 int
virNetworkSaveXML(const char * configDir,virNetworkDef * def,const char * xml)2717 virNetworkSaveXML(const char *configDir,
2718                   virNetworkDef *def,
2719                   const char *xml)
2720 {
2721     char uuidstr[VIR_UUID_STRING_BUFLEN];
2722     g_autofree char *configFile = NULL;
2723 
2724     if ((configFile = virNetworkConfigFile(configDir, def->name)) == NULL)
2725         return -1;
2726 
2727     if (g_mkdir_with_parents(configDir, 0777) < 0) {
2728         virReportSystemError(errno,
2729                              _("cannot create config directory '%s'"),
2730                              configDir);
2731         return -1;
2732     }
2733 
2734     virUUIDFormat(def->uuid, uuidstr);
2735     return virXMLSaveFile(configFile,
2736                           virXMLPickShellSafeComment(def->name, uuidstr),
2737                           "net-edit", xml);
2738 }
2739 
2740 
2741 int
virNetworkSaveConfig(const char * configDir,virNetworkDef * def,virNetworkXMLOption * xmlopt)2742 virNetworkSaveConfig(const char *configDir,
2743                      virNetworkDef *def,
2744                      virNetworkXMLOption *xmlopt)
2745 {
2746     g_autofree char *xml = NULL;
2747 
2748     if (!(xml = virNetworkDefFormat(def, xmlopt, VIR_NETWORK_XML_INACTIVE)))
2749         return -1;
2750 
2751     if (virNetworkSaveXML(configDir, def, xml))
2752         return -1;
2753 
2754     return 0;
2755 }
2756 
2757 
2758 char *
virNetworkConfigFile(const char * dir,const char * name)2759 virNetworkConfigFile(const char *dir,
2760                      const char *name)
2761 {
2762     return g_strdup_printf("%s/%s.xml", dir, name);
2763 }
2764 
2765 
2766 void
virNetworkSetBridgeMacAddr(virNetworkDef * def)2767 virNetworkSetBridgeMacAddr(virNetworkDef *def)
2768 {
2769     if (!def->mac_specified) {
2770         /* if the bridge doesn't have a mac address explicitly defined,
2771          * autogenerate a random one.
2772          */
2773         virMacAddrGenerate((unsigned char[]){ 0x52, 0x54, 0 },
2774                            &def->mac);
2775         def->mac_specified = true;
2776     }
2777 }
2778 
2779 
2780 /* NetworkObj backend of the virNetworkUpdate API */
2781 
2782 static void
virNetworkDefUpdateNoSupport(virNetworkDef * def,const char * section)2783 virNetworkDefUpdateNoSupport(virNetworkDef *def, const char *section)
2784 {
2785     virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
2786                    _("can't update '%s' section of network '%s'"),
2787                    section, def->name);
2788 }
2789 
2790 
2791 static void
virNetworkDefUpdateUnknownCommand(unsigned int command)2792 virNetworkDefUpdateUnknownCommand(unsigned int command)
2793 {
2794     virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
2795                    _("unrecognized network update command code %d"), command);
2796 }
2797 
2798 
2799 static int
virNetworkDefUpdateCheckElementName(virNetworkDef * def,xmlNodePtr node,const char * section)2800 virNetworkDefUpdateCheckElementName(virNetworkDef *def,
2801                                     xmlNodePtr node,
2802                                     const char *section)
2803 {
2804     if (!virXMLNodeNameEqual(node, section)) {
2805         virReportError(VIR_ERR_XML_ERROR,
2806                        _("unexpected element <%s>, expecting <%s>, "
2807                          "while updating network '%s'"),
2808                        node->name, section, def->name);
2809         return -1;
2810     }
2811     return 0;
2812 }
2813 
2814 
2815 static int
virNetworkDefUpdateBridge(virNetworkDef * def,unsigned int command G_GNUC_UNUSED,int parentIndex G_GNUC_UNUSED,xmlXPathContextPtr ctxt G_GNUC_UNUSED,unsigned int fflags G_GNUC_UNUSED)2816 virNetworkDefUpdateBridge(virNetworkDef *def,
2817                           unsigned int command G_GNUC_UNUSED,
2818                           int parentIndex G_GNUC_UNUSED,
2819                           xmlXPathContextPtr ctxt G_GNUC_UNUSED,
2820                           /* virNetworkUpdateFlags */
2821                           unsigned int fflags G_GNUC_UNUSED)
2822 {
2823     virNetworkDefUpdateNoSupport(def, "bridge");
2824     return -1;
2825 }
2826 
2827 
2828 static int
virNetworkDefUpdateDomain(virNetworkDef * def,unsigned int command G_GNUC_UNUSED,int parentIndex G_GNUC_UNUSED,xmlXPathContextPtr ctxt G_GNUC_UNUSED,unsigned int fflags G_GNUC_UNUSED)2829 virNetworkDefUpdateDomain(virNetworkDef *def,
2830                           unsigned int command G_GNUC_UNUSED,
2831                           int parentIndex G_GNUC_UNUSED,
2832                           xmlXPathContextPtr ctxt G_GNUC_UNUSED,
2833                           /* virNetworkUpdateFlags */
2834                           unsigned int fflags G_GNUC_UNUSED)
2835 {
2836     virNetworkDefUpdateNoSupport(def, "domain");
2837     return -1;
2838 }
2839 
2840 
2841 static int
virNetworkDefUpdateIP(virNetworkDef * def,unsigned int command G_GNUC_UNUSED,int parentIndex G_GNUC_UNUSED,xmlXPathContextPtr ctxt G_GNUC_UNUSED,unsigned int fflags G_GNUC_UNUSED)2842 virNetworkDefUpdateIP(virNetworkDef *def,
2843                       unsigned int command G_GNUC_UNUSED,
2844                       int parentIndex G_GNUC_UNUSED,
2845                       xmlXPathContextPtr ctxt G_GNUC_UNUSED,
2846                       /* virNetworkUpdateFlags */
2847                       unsigned int fflags G_GNUC_UNUSED)
2848 {
2849     virNetworkDefUpdateNoSupport(def, "ip");
2850     return -1;
2851 }
2852 
2853 
2854 static virNetworkIPDef *
virNetworkIPDefByIndex(virNetworkDef * def,int parentIndex)2855 virNetworkIPDefByIndex(virNetworkDef *def, int parentIndex)
2856 {
2857     virNetworkIPDef *ipdef = NULL;
2858     size_t i;
2859 
2860     /* first find which ip element's dhcp host list to work on */
2861     if (parentIndex >= 0) {
2862         ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, parentIndex);
2863         if (!(ipdef)) {
2864             virReportError(VIR_ERR_OPERATION_INVALID,
2865                            _("couldn't update dhcp host entry - no <ip> "
2866                              "element found at index %d in network '%s'"),
2867                            parentIndex, def->name);
2868         }
2869         return ipdef;
2870     }
2871 
2872     /* -1 means "find the most appropriate", which in this case
2873      * means the one and only <ip> that has <dhcp> element
2874      */
2875     for (i = 0;
2876          (ipdef = virNetworkDefGetIPByIndex(def, AF_UNSPEC, i));
2877          i++) {
2878         if (ipdef->nranges || ipdef->nhosts)
2879             break;
2880     }
2881     if (!ipdef) {
2882         ipdef = virNetworkDefGetIPByIndex(def, AF_INET, 0);
2883         if (!ipdef)
2884             ipdef = virNetworkDefGetIPByIndex(def, AF_INET6, 0);
2885     }
2886     if (!ipdef) {
2887         virReportError(VIR_ERR_OPERATION_INVALID,
2888                        _("couldn't update dhcp host entry - no <ip> "
2889                          "element found in network '%s'"), def->name);
2890     }
2891     return ipdef;
2892 }
2893 
2894 
2895 static int
virNetworkDefUpdateCheckMultiDHCP(virNetworkDef * def,virNetworkIPDef * ipdef)2896 virNetworkDefUpdateCheckMultiDHCP(virNetworkDef *def,
2897                                   virNetworkIPDef *ipdef)
2898 {
2899     int family = VIR_SOCKET_ADDR_FAMILY(&ipdef->address);
2900     size_t i;
2901     virNetworkIPDef *ip;
2902 
2903     for (i = 0; (ip = virNetworkDefGetIPByIndex(def, family, i)); i++) {
2904         if (ip != ipdef) {
2905             if (ip->nranges || ip->nhosts) {
2906                 virReportError(VIR_ERR_OPERATION_INVALID,
2907                                _("dhcp is supported only for a "
2908                                  "single %s address on each network"),
2909                                (family == AF_INET) ? "IPv4" : "IPv6");
2910                 return -1;
2911             }
2912         }
2913     }
2914     return 0;
2915 }
2916 
2917 
2918 static int
virNetworkDefUpdateIPDHCPHost(virNetworkDef * def,unsigned int command,int parentIndex,xmlXPathContextPtr ctxt,unsigned int fflags G_GNUC_UNUSED)2919 virNetworkDefUpdateIPDHCPHost(virNetworkDef *def,
2920                               unsigned int command,
2921                               int parentIndex,
2922                               xmlXPathContextPtr ctxt,
2923                               /* virNetworkUpdateFlags */
2924                               unsigned int fflags G_GNUC_UNUSED)
2925 {
2926     size_t i;
2927     int ret = -1;
2928     virNetworkIPDef *ipdef = virNetworkIPDefByIndex(def, parentIndex);
2929     virNetworkDHCPHostDef host;
2930     bool partialOkay = (command == VIR_NETWORK_UPDATE_COMMAND_DELETE);
2931 
2932     memset(&host, 0, sizeof(host));
2933 
2934     if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "host") < 0)
2935         goto cleanup;
2936 
2937     /* ipdef is the ip element that needs its host array updated */
2938     if (!ipdef)
2939         goto cleanup;
2940 
2941     if (virNetworkDHCPHostDefParseXML(def->name, ipdef, ctxt->node,
2942                                       &host, partialOkay) < 0)
2943         goto cleanup;
2944 
2945     if (!partialOkay &&
2946         VIR_SOCKET_ADDR_FAMILY(&ipdef->address)
2947         != VIR_SOCKET_ADDR_FAMILY(&host.ip)) {
2948         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2949                        _("the address family of a host entry IP must match "
2950                          "the address family of the dhcp element's parent"));
2951         goto cleanup;
2952     }
2953 
2954     if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
2955 
2956         /* search for the entry with this (ip|mac|name),
2957          * and update the IP+(mac|name) */
2958         for (i = 0; i < ipdef->nhosts; i++) {
2959             if ((host.mac && ipdef->hosts[i].mac &&
2960                  !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) ||
2961                 (VIR_SOCKET_ADDR_VALID(&host.ip) &&
2962                  virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip)) ||
2963                 (host.name &&
2964                  STREQ_NULLABLE(host.name, ipdef->hosts[i].name))) {
2965                 break;
2966             }
2967         }
2968 
2969         if (i == ipdef->nhosts) {
2970             g_autofree char *ip = virSocketAddrFormat(&host.ip);
2971             virReportError(VIR_ERR_OPERATION_INVALID,
2972                            _("couldn't locate an existing dhcp host entry with "
2973                              "\"mac='%s'\" \"name='%s'\" \"ip='%s'\" in"
2974                              " network '%s'"),
2975                            host.mac ? host.mac : _("unknown"), host.name,
2976                            ip ? ip : _("unknown"), def->name);
2977             goto cleanup;
2978         }
2979 
2980         /* clear the existing hosts entry, move the new one in its place,
2981          * then clear out the extra copy to get rid of the duplicate pointers
2982          * to its data (mac and name strings).
2983          */
2984         virNetworkDHCPHostDefClear(&ipdef->hosts[i]);
2985         ipdef->hosts[i] = host;
2986         memset(&host, 0, sizeof(host));
2987 
2988     } else if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
2989                (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)) {
2990 
2991         if (virNetworkDefUpdateCheckMultiDHCP(def, ipdef) < 0)
2992             goto cleanup;
2993 
2994         /* log error if an entry with same name/address/ip already exists */
2995         for (i = 0; i < ipdef->nhosts; i++) {
2996             if ((host.mac && ipdef->hosts[i].mac &&
2997                  !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) ||
2998                 (host.name &&
2999                  STREQ_NULLABLE(host.name, ipdef->hosts[i].name)) ||
3000                 (VIR_SOCKET_ADDR_VALID(&host.ip) &&
3001                  virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip))) {
3002                 g_autofree char *ip = virSocketAddrFormat(&host.ip);
3003 
3004                 virReportError(VIR_ERR_OPERATION_INVALID,
3005                                _("there is an existing dhcp host entry in "
3006                                  "network '%s' that matches "
3007                                  "\"<host mac='%s' name='%s' ip='%s'/>\""),
3008                                def->name, host.mac ? host.mac : _("unknown"),
3009                                host.name, ip ? ip : _("unknown"));
3010                 goto cleanup;
3011             }
3012         }
3013 
3014         /* add to beginning/end of list */
3015         if (VIR_INSERT_ELEMENT(ipdef->hosts,
3016                                command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
3017                                ? 0 : ipdef->nhosts,
3018                                ipdef->nhosts, host) < 0)
3019             goto cleanup;
3020     } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
3021 
3022         /* find matching entry - all specified attributes must match */
3023         for (i = 0; i < ipdef->nhosts; i++) {
3024             if ((!host.mac || !ipdef->hosts[i].mac ||
3025                  !virMacAddrCompare(host.mac, ipdef->hosts[i].mac)) &&
3026                 (!host.name ||
3027                  STREQ_NULLABLE(host.name, ipdef->hosts[i].name)) &&
3028                 (!VIR_SOCKET_ADDR_VALID(&host.ip) ||
3029                  virSocketAddrEqual(&host.ip, &ipdef->hosts[i].ip))) {
3030                 break;
3031             }
3032         }
3033         if (i == ipdef->nhosts) {
3034             virReportError(VIR_ERR_OPERATION_INVALID,
3035                            _("couldn't locate a matching dhcp host entry "
3036                              "in network '%s'"), def->name);
3037             goto cleanup;
3038         }
3039 
3040         /* remove it */
3041         virNetworkDHCPHostDefClear(&ipdef->hosts[i]);
3042         VIR_DELETE_ELEMENT(ipdef->hosts, i, ipdef->nhosts);
3043 
3044     } else {
3045         virNetworkDefUpdateUnknownCommand(command);
3046         goto cleanup;
3047     }
3048 
3049     ret = 0;
3050  cleanup:
3051     virNetworkDHCPHostDefClear(&host);
3052     return ret;
3053 }
3054 
3055 
3056 static int
virNetworkDefUpdateIPDHCPRange(virNetworkDef * def,unsigned int command,int parentIndex,xmlXPathContextPtr ctxt,unsigned int fflags G_GNUC_UNUSED)3057 virNetworkDefUpdateIPDHCPRange(virNetworkDef *def,
3058                                unsigned int command,
3059                                int parentIndex,
3060                                xmlXPathContextPtr ctxt,
3061                                /* virNetworkUpdateFlags */
3062                                unsigned int fflags G_GNUC_UNUSED)
3063 {
3064     size_t i;
3065     virNetworkIPDef *ipdef = virNetworkIPDefByIndex(def, parentIndex);
3066     virNetworkDHCPRangeDef range;
3067 
3068     memset(&range, 0, sizeof(range));
3069 
3070     if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "range") < 0)
3071         return -1;
3072 
3073     /* ipdef is the ip element that needs its range array updated */
3074     if (!ipdef)
3075         return -1;
3076 
3077     /* parse the xml into a virSocketAddrRange */
3078     if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
3079 
3080         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3081                        _("dhcp ranges cannot be modified, "
3082                          "only added or deleted"));
3083         return -1;
3084     }
3085 
3086     if (virNetworkDHCPRangeDefParseXML(def->name, ipdef, ctxt->node, &range) < 0)
3087         return -1;
3088 
3089     if (VIR_SOCKET_ADDR_FAMILY(&ipdef->address)
3090         != VIR_SOCKET_ADDR_FAMILY(&range.addr.start)) {
3091         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
3092                        _("the address family of a dhcp range must match "
3093                          "the address family of the dhcp element's parent"));
3094         return -1;
3095     }
3096 
3097     /* check if an entry with same name/address/ip already exists */
3098     for (i = 0; i < ipdef->nranges; i++) {
3099         virSocketAddrRange addr = ipdef->ranges[i].addr;
3100         if (virSocketAddrEqual(&range.addr.start, &addr.start) &&
3101             virSocketAddrEqual(&range.addr.end, &addr.end)) {
3102             break;
3103         }
3104     }
3105 
3106     if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
3107         (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)) {
3108 
3109         if (virNetworkDefUpdateCheckMultiDHCP(def, ipdef) < 0)
3110             return -1;
3111 
3112         if (i < ipdef->nranges) {
3113             g_autofree char *startip = virSocketAddrFormat(&range.addr.start);
3114             g_autofree char *endip = virSocketAddrFormat(&range.addr.end);
3115 
3116             virReportError(VIR_ERR_OPERATION_INVALID,
3117                            _("there is an existing dhcp range entry in "
3118                              "network '%s' that matches "
3119                              "\"<range start='%s' end='%s'/>\""),
3120                            def->name,
3121                            startip ? startip : "unknown",
3122                            endip ? endip : "unknown");
3123             return -1;
3124         }
3125 
3126         /* add to beginning/end of list */
3127         if (VIR_INSERT_ELEMENT(ipdef->ranges,
3128                                command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
3129                                ? 0 : ipdef->nranges,
3130                                ipdef->nranges, range) < 0)
3131             return -1;
3132     } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
3133 
3134         if (i == ipdef->nranges) {
3135             virReportError(VIR_ERR_OPERATION_INVALID,
3136                            _("couldn't locate a matching dhcp range entry "
3137                              "in network '%s'"), def->name);
3138             return -1;
3139         }
3140 
3141         /* remove it */
3142         /* NB: nothing to clear from a RangeDef that's being freed */
3143         VIR_DELETE_ELEMENT(ipdef->ranges, i, ipdef->nranges);
3144 
3145     } else {
3146         virNetworkDefUpdateUnknownCommand(command);
3147         return -1;
3148     }
3149 
3150     return 0;
3151 }
3152 
3153 
3154 static int
virNetworkDefUpdateForward(virNetworkDef * def,unsigned int command G_GNUC_UNUSED,int parentIndex G_GNUC_UNUSED,xmlXPathContextPtr ctxt G_GNUC_UNUSED,unsigned int fflags G_GNUC_UNUSED)3155 virNetworkDefUpdateForward(virNetworkDef *def,
3156                            unsigned int command G_GNUC_UNUSED,
3157                            int parentIndex G_GNUC_UNUSED,
3158                            xmlXPathContextPtr ctxt G_GNUC_UNUSED,
3159                            /* virNetworkUpdateFlags */
3160                            unsigned int fflags G_GNUC_UNUSED)
3161 {
3162     virNetworkDefUpdateNoSupport(def, "forward");
3163     return -1;
3164 }
3165 
3166 
3167 static int
virNetworkDefUpdateForwardInterface(virNetworkDef * def,unsigned int command,int parentIndex G_GNUC_UNUSED,xmlXPathContextPtr ctxt,unsigned int fflags G_GNUC_UNUSED)3168 virNetworkDefUpdateForwardInterface(virNetworkDef *def,
3169                                     unsigned int command,
3170                                     int parentIndex G_GNUC_UNUSED,
3171                                     xmlXPathContextPtr ctxt,
3172                                     /* virNetworkUpdateFlags */
3173                                     unsigned int fflags G_GNUC_UNUSED)
3174 {
3175     size_t i;
3176     int ret = -1;
3177     virNetworkForwardIfDef iface;
3178 
3179     memset(&iface, 0, sizeof(iface));
3180 
3181     if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "interface") < 0)
3182         goto cleanup;
3183 
3184     if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
3185         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3186                        _("forward interface entries cannot be modified, "
3187                          "only added or deleted"));
3188         goto cleanup;
3189     }
3190 
3191     /* parsing this is so simple that it doesn't have its own function */
3192     iface.type = VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV;
3193     if (!(iface.device.dev = virXMLPropString(ctxt->node, "dev"))) {
3194         virReportError(VIR_ERR_XML_ERROR, "%s",
3195                        _("missing dev attribute in <interface> element"));
3196         goto cleanup;
3197     }
3198 
3199     /* check if an <interface> with same dev name already exists */
3200     for (i = 0; i < def->forward.nifs; i++) {
3201         if (def->forward.ifs[i].type
3202             == VIR_NETWORK_FORWARD_HOSTDEV_DEVICE_NETDEV &&
3203             STREQ(iface.device.dev, def->forward.ifs[i].device.dev))
3204             break;
3205     }
3206 
3207     if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
3208         (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)) {
3209 
3210         if (i < def->forward.nifs) {
3211             virReportError(VIR_ERR_OPERATION_INVALID,
3212                            _("there is an existing interface entry "
3213                              "in network '%s' that matches "
3214                              "\"<interface dev='%s'>\""),
3215                            def->name, iface.device.dev);
3216             goto cleanup;
3217         }
3218 
3219         /* add to beginning/end of list */
3220         if (VIR_INSERT_ELEMENT(def->forward.ifs,
3221                                command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
3222                                ? 0 : def->forward.nifs,
3223                                def->forward.nifs, iface) < 0)
3224             goto cleanup;
3225     } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
3226 
3227         if (i == def->forward.nifs) {
3228             virReportError(VIR_ERR_OPERATION_INVALID,
3229                            _("couldn't find an interface entry "
3230                              "in network '%s' matching <interface dev='%s'>"),
3231                            def->name, iface.device.dev);
3232             goto cleanup;
3233         }
3234 
3235         /* fail if the interface is being used */
3236         if (def->forward.ifs[i].connections > 0) {
3237             virReportError(VIR_ERR_OPERATION_INVALID,
3238                            _("unable to delete interface '%s' "
3239                              "in network '%s'. It is currently being used "
3240                              " by %d domains."),
3241                            iface.device.dev, def->name,
3242                            def->forward.ifs[i].connections);
3243             goto cleanup;
3244         }
3245 
3246         /* remove it */
3247         virNetworkForwardIfDefClear(&def->forward.ifs[i]);
3248         VIR_DELETE_ELEMENT(def->forward.ifs, i, def->forward.nifs);
3249 
3250     } else {
3251         virNetworkDefUpdateUnknownCommand(command);
3252         goto cleanup;
3253     }
3254 
3255     ret = 0;
3256  cleanup:
3257     virNetworkForwardIfDefClear(&iface);
3258     return ret;
3259 }
3260 
3261 
3262 static int
virNetworkDefUpdateForwardPF(virNetworkDef * def,unsigned int command G_GNUC_UNUSED,int parentIndex G_GNUC_UNUSED,xmlXPathContextPtr ctxt G_GNUC_UNUSED,unsigned int fflags G_GNUC_UNUSED)3263 virNetworkDefUpdateForwardPF(virNetworkDef *def,
3264                              unsigned int command G_GNUC_UNUSED,
3265                              int parentIndex G_GNUC_UNUSED,
3266                              xmlXPathContextPtr ctxt G_GNUC_UNUSED,
3267                              /* virNetworkUpdateFlags */
3268                              unsigned int fflags G_GNUC_UNUSED)
3269 {
3270     virNetworkDefUpdateNoSupport(def, "forward pf");
3271     return -1;
3272 }
3273 
3274 
3275 static int
virNetworkDefUpdatePortGroup(virNetworkDef * def,unsigned int command,int parentIndex G_GNUC_UNUSED,xmlXPathContextPtr ctxt,unsigned int fflags G_GNUC_UNUSED)3276 virNetworkDefUpdatePortGroup(virNetworkDef *def,
3277                              unsigned int command,
3278                              int parentIndex G_GNUC_UNUSED,
3279                              xmlXPathContextPtr ctxt,
3280                              /* virNetworkUpdateFlags */
3281                              unsigned int fflags G_GNUC_UNUSED)
3282 {
3283     size_t i;
3284     int foundName = -1, foundDefault = -1;
3285     int ret = -1;
3286     virPortGroupDef portgroup;
3287 
3288     memset(&portgroup, 0, sizeof(portgroup));
3289 
3290     if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "portgroup") < 0)
3291         goto cleanup;
3292 
3293     if (virNetworkPortGroupParseXML(&portgroup, ctxt->node, ctxt) < 0)
3294         goto cleanup;
3295 
3296     /* check if a portgroup with same name already exists */
3297     for (i = 0; i < def->nPortGroups; i++) {
3298         if (STREQ(portgroup.name, def->portGroups[i].name))
3299             foundName = i;
3300         if (def->portGroups[i].isDefault)
3301             foundDefault = i;
3302     }
3303     if (foundName == -1 &&
3304         ((command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) ||
3305          (command == VIR_NETWORK_UPDATE_COMMAND_DELETE))) {
3306         virReportError(VIR_ERR_OPERATION_INVALID,
3307                        _("couldn't find a portgroup entry "
3308                          "in network '%s' matching <portgroup name='%s'>"),
3309                        def->name, portgroup.name);
3310         goto cleanup;
3311     } else if (foundName >= 0 &&
3312                ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
3313                 (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST))) {
3314         virReportError(VIR_ERR_OPERATION_INVALID,
3315                        _("there is an existing portgroup entry in "
3316                          "network '%s' that matches "
3317                          "\"<portgroup name='%s'>\""),
3318                        def->name, portgroup.name);
3319         goto cleanup;
3320     }
3321 
3322     /* if there is already a different default, we can't make this
3323      * one the default.
3324      */
3325     if (command != VIR_NETWORK_UPDATE_COMMAND_DELETE &&
3326         portgroup.isDefault &&
3327         foundDefault >= 0 && foundDefault != foundName) {
3328         virReportError(VIR_ERR_OPERATION_INVALID,
3329                        _("a different portgroup entry in "
3330                          "network '%s' is already set as the default. "
3331                          "Only one default is allowed."),
3332                        def->name);
3333         goto cleanup;
3334     }
3335 
3336     if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
3337 
3338         /* replace existing entry */
3339         virPortGroupDefClear(&def->portGroups[foundName]);
3340         def->portGroups[foundName] = portgroup;
3341         memset(&portgroup, 0, sizeof(portgroup));
3342 
3343     } else if ((command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST) ||
3344         (command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST)) {
3345 
3346         /* add to beginning/end of list */
3347         if (VIR_INSERT_ELEMENT(def->portGroups,
3348                                command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
3349                                ? 0 : def->nPortGroups,
3350                                def->nPortGroups, portgroup) < 0)
3351             goto cleanup;
3352     } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
3353 
3354         /* remove it */
3355         virPortGroupDefClear(&def->portGroups[foundName]);
3356         VIR_DELETE_ELEMENT(def->portGroups, foundName, def->nPortGroups);
3357 
3358     } else {
3359         virNetworkDefUpdateUnknownCommand(command);
3360         goto cleanup;
3361     }
3362 
3363     ret = 0;
3364  cleanup:
3365     virPortGroupDefClear(&portgroup);
3366     return ret;
3367 }
3368 
3369 
3370 static int
virNetworkDefUpdateDNSHost(virNetworkDef * def,unsigned int command G_GNUC_UNUSED,int parentIndex G_GNUC_UNUSED,xmlXPathContextPtr ctxt G_GNUC_UNUSED,unsigned int fflags G_GNUC_UNUSED)3371 virNetworkDefUpdateDNSHost(virNetworkDef *def,
3372                            unsigned int command G_GNUC_UNUSED,
3373                            int parentIndex G_GNUC_UNUSED,
3374                            xmlXPathContextPtr ctxt G_GNUC_UNUSED,
3375                            /* virNetworkUpdateFlags */
3376                            unsigned int fflags G_GNUC_UNUSED)
3377 {
3378     size_t i, j, k;
3379     int foundIdx = -1, ret = -1;
3380     virNetworkDNSDef *dns = &def->dns;
3381     virNetworkDNSHostDef host;
3382     bool isAdd = (command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
3383                   command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST);
3384     int foundCt = 0;
3385 
3386     memset(&host, 0, sizeof(host));
3387 
3388     if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
3389         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3390                        _("DNS HOST records cannot be modified, "
3391                          "only added or deleted"));
3392         goto cleanup;
3393     }
3394 
3395     if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "host") < 0)
3396         goto cleanup;
3397 
3398     if (virNetworkDNSHostDefParseXML(def->name, ctxt->node, &host, !isAdd) < 0)
3399         goto cleanup;
3400 
3401     for (i = 0; i < dns->nhosts; i++) {
3402         bool foundThisTime = false;
3403 
3404         if (virSocketAddrEqual(&host.ip, &dns->hosts[i].ip))
3405             foundThisTime = true;
3406 
3407         /* when adding we want to only check duplicates of address since having
3408          * multiple addresses with the same hostname is a legitimate configuration */
3409         if (!isAdd) {
3410             for (j = 0; j < host.nnames && !foundThisTime; j++) {
3411                 for (k = 0; k < dns->hosts[i].nnames && !foundThisTime; k++) {
3412                     if (STREQ(host.names[j], dns->hosts[i].names[k]))
3413                         foundThisTime = true;
3414                 }
3415             }
3416         }
3417 
3418         if (foundThisTime) {
3419             foundCt++;
3420             foundIdx = i;
3421         }
3422     }
3423 
3424     if (isAdd) {
3425 
3426         if (foundCt > 0) {
3427             virReportError(VIR_ERR_OPERATION_INVALID,
3428                            _("there is already at least one DNS HOST "
3429                              "record with a matching field in network %s"),
3430                            def->name);
3431             goto cleanup;
3432         }
3433 
3434         /* add to beginning/end of list */
3435         if (VIR_INSERT_ELEMENT(dns->hosts,
3436                                command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
3437                                ? 0 : dns->nhosts, dns->nhosts, host) < 0)
3438             goto cleanup;
3439     } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
3440 
3441         if (foundCt == 0) {
3442             virReportError(VIR_ERR_OPERATION_INVALID,
3443                            _("couldn't locate a matching DNS HOST "
3444                              "record in network %s"), def->name);
3445             goto cleanup;
3446         }
3447         if (foundCt > 1) {
3448             virReportError(VIR_ERR_OPERATION_INVALID,
3449                            _("multiple matching DNS HOST records were "
3450                              "found in network %s"), def->name);
3451             goto cleanup;
3452         }
3453 
3454         /* remove it */
3455         virNetworkDNSHostDefClear(&dns->hosts[foundIdx]);
3456         VIR_DELETE_ELEMENT(dns->hosts, foundIdx, dns->nhosts);
3457 
3458     } else {
3459         virNetworkDefUpdateUnknownCommand(command);
3460         goto cleanup;
3461     }
3462 
3463     ret = 0;
3464  cleanup:
3465     virNetworkDNSHostDefClear(&host);
3466     return ret;
3467 }
3468 
3469 
3470 static int
virNetworkDefUpdateDNSSrv(virNetworkDef * def,unsigned int command G_GNUC_UNUSED,int parentIndex G_GNUC_UNUSED,xmlXPathContextPtr ctxt G_GNUC_UNUSED,unsigned int fflags G_GNUC_UNUSED)3471 virNetworkDefUpdateDNSSrv(virNetworkDef *def,
3472                           unsigned int command G_GNUC_UNUSED,
3473                           int parentIndex G_GNUC_UNUSED,
3474                           xmlXPathContextPtr ctxt G_GNUC_UNUSED,
3475                           /* virNetworkUpdateFlags */
3476                           unsigned int fflags G_GNUC_UNUSED)
3477 {
3478     size_t i;
3479     int foundIdx = -1, ret = -1;
3480     virNetworkDNSDef *dns = &def->dns;
3481     virNetworkDNSSrvDef srv;
3482     bool isAdd = (command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
3483                   command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST);
3484     int foundCt = 0;
3485 
3486     memset(&srv, 0, sizeof(srv));
3487 
3488     if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
3489         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3490                        _("DNS SRV records cannot be modified, "
3491                          "only added or deleted"));
3492         goto cleanup;
3493     }
3494 
3495     if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "srv") < 0)
3496         goto cleanup;
3497 
3498     if (virNetworkDNSSrvDefParseXML(def->name, ctxt->node, ctxt, &srv, !isAdd) < 0)
3499         goto cleanup;
3500 
3501     for (i = 0; i < dns->nsrvs; i++) {
3502         if ((!srv.domain || STREQ_NULLABLE(srv.domain, dns->srvs[i].domain)) &&
3503             (!srv.service || STREQ_NULLABLE(srv.service, dns->srvs[i].service)) &&
3504             (!srv.protocol || STREQ_NULLABLE(srv.protocol, dns->srvs[i].protocol)) &&
3505             (!srv.target || STREQ_NULLABLE(srv.target, dns->srvs[i].target))) {
3506             foundCt++;
3507             foundIdx = i;
3508         }
3509     }
3510 
3511     if (isAdd) {
3512 
3513         if (foundCt > 0) {
3514             virReportError(VIR_ERR_OPERATION_INVALID,
3515                            _("there is already at least one DNS SRV "
3516                              "record matching all specified fields in network %s"),
3517                            def->name);
3518             goto cleanup;
3519         }
3520 
3521         /* add to beginning/end of list */
3522         if (VIR_INSERT_ELEMENT(dns->srvs,
3523                                command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
3524                                ? 0 : dns->nsrvs, dns->nsrvs, srv) < 0)
3525             goto cleanup;
3526     } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
3527 
3528         if (foundCt == 0) {
3529             virReportError(VIR_ERR_OPERATION_INVALID,
3530                            _("couldn't locate a matching DNS SRV "
3531                              "record in network %s"), def->name);
3532             goto cleanup;
3533         }
3534         if (foundCt > 1) {
3535             virReportError(VIR_ERR_OPERATION_INVALID,
3536                            _("multiple DNS SRV records matching all specified "
3537                              "fields were found in network %s"), def->name);
3538             goto cleanup;
3539         }
3540 
3541         /* remove it */
3542         virNetworkDNSSrvDefClear(&dns->srvs[foundIdx]);
3543         VIR_DELETE_ELEMENT(dns->srvs, foundIdx, dns->nsrvs);
3544 
3545     } else {
3546         virNetworkDefUpdateUnknownCommand(command);
3547         goto cleanup;
3548     }
3549 
3550     ret = 0;
3551  cleanup:
3552     virNetworkDNSSrvDefClear(&srv);
3553     return ret;
3554 }
3555 
3556 
3557 static int
virNetworkDefUpdateDNSTxt(virNetworkDef * def,unsigned int command G_GNUC_UNUSED,int parentIndex G_GNUC_UNUSED,xmlXPathContextPtr ctxt G_GNUC_UNUSED,unsigned int fflags G_GNUC_UNUSED)3558 virNetworkDefUpdateDNSTxt(virNetworkDef *def,
3559                           unsigned int command G_GNUC_UNUSED,
3560                           int parentIndex G_GNUC_UNUSED,
3561                           xmlXPathContextPtr ctxt G_GNUC_UNUSED,
3562                           /* virNetworkUpdateFlags */
3563                           unsigned int fflags G_GNUC_UNUSED)
3564 {
3565     int foundIdx, ret = -1;
3566     virNetworkDNSDef *dns = &def->dns;
3567     virNetworkDNSTxtDef txt;
3568     bool isAdd = (command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST ||
3569                   command == VIR_NETWORK_UPDATE_COMMAND_ADD_LAST);
3570 
3571     memset(&txt, 0, sizeof(txt));
3572 
3573     if (command == VIR_NETWORK_UPDATE_COMMAND_MODIFY) {
3574         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3575                        _("DNS TXT records cannot be modified, "
3576                          "only added or deleted"));
3577         goto cleanup;
3578     }
3579 
3580     if (virNetworkDefUpdateCheckElementName(def, ctxt->node, "txt") < 0)
3581         goto cleanup;
3582 
3583     if (virNetworkDNSTxtDefParseXML(def->name, ctxt->node, &txt, !isAdd) < 0)
3584         goto cleanup;
3585 
3586     for (foundIdx = 0; foundIdx < dns->ntxts; foundIdx++) {
3587         if (STREQ(txt.name, dns->txts[foundIdx].name))
3588             break;
3589     }
3590 
3591     if (isAdd) {
3592 
3593         if (foundIdx < dns->ntxts) {
3594             virReportError(VIR_ERR_OPERATION_INVALID,
3595                            _("there is already a DNS TXT record "
3596                              "with name '%s' in network %s"),
3597                            txt.name, def->name);
3598             goto cleanup;
3599         }
3600 
3601         /* add to beginning/end of list */
3602         if (VIR_INSERT_ELEMENT(dns->txts,
3603                                command == VIR_NETWORK_UPDATE_COMMAND_ADD_FIRST
3604                                ? 0 : dns->ntxts, dns->ntxts, txt) < 0)
3605             goto cleanup;
3606     } else if (command == VIR_NETWORK_UPDATE_COMMAND_DELETE) {
3607 
3608         if (foundIdx == dns->ntxts) {
3609             virReportError(VIR_ERR_OPERATION_INVALID,
3610                            _("couldn't locate a matching DNS TXT "
3611                              "record in network %s"), def->name);
3612             goto cleanup;
3613         }
3614 
3615         /* remove it */
3616         virNetworkDNSTxtDefClear(&dns->txts[foundIdx]);
3617         VIR_DELETE_ELEMENT(dns->txts, foundIdx, dns->ntxts);
3618 
3619     } else {
3620         virNetworkDefUpdateUnknownCommand(command);
3621         goto cleanup;
3622     }
3623 
3624     ret = 0;
3625  cleanup:
3626     virNetworkDNSTxtDefClear(&txt);
3627     return ret;
3628 }
3629 
3630 
3631 int
virNetworkDefUpdateSection(virNetworkDef * def,unsigned int command,unsigned int section,int parentIndex,const char * xml,unsigned int flags)3632 virNetworkDefUpdateSection(virNetworkDef *def,
3633                            unsigned int command, /* virNetworkUpdateCommand */
3634                            unsigned int section, /* virNetworkUpdateSection */
3635                            int parentIndex,
3636                            const char *xml,
3637                            unsigned int flags)  /* virNetworkUpdateFlags */
3638 {
3639     g_autoptr(xmlDoc) doc = NULL;
3640     g_autoptr(xmlXPathContext) ctxt = NULL;
3641 
3642     if (!(doc = virXMLParseStringCtxt(xml, _("network_update_xml"), &ctxt)))
3643         return -1;
3644 
3645     switch (section) {
3646     case VIR_NETWORK_SECTION_BRIDGE:
3647         return virNetworkDefUpdateBridge(def, command, parentIndex, ctxt, flags);
3648 
3649     case VIR_NETWORK_SECTION_DOMAIN:
3650         return virNetworkDefUpdateDomain(def, command, parentIndex, ctxt, flags);
3651     case VIR_NETWORK_SECTION_IP:
3652         return virNetworkDefUpdateIP(def, command, parentIndex, ctxt, flags);
3653     case VIR_NETWORK_SECTION_IP_DHCP_HOST:
3654         return virNetworkDefUpdateIPDHCPHost(def, command,
3655                                              parentIndex, ctxt, flags);
3656     case VIR_NETWORK_SECTION_IP_DHCP_RANGE:
3657         return virNetworkDefUpdateIPDHCPRange(def, command,
3658                                               parentIndex, ctxt, flags);
3659     case VIR_NETWORK_SECTION_FORWARD:
3660         return virNetworkDefUpdateForward(def, command,
3661                                           parentIndex, ctxt, flags);
3662     case VIR_NETWORK_SECTION_FORWARD_INTERFACE:
3663         return virNetworkDefUpdateForwardInterface(def, command,
3664                                                    parentIndex, ctxt, flags);
3665     case VIR_NETWORK_SECTION_FORWARD_PF:
3666         return virNetworkDefUpdateForwardPF(def, command,
3667                                             parentIndex, ctxt, flags);
3668     case VIR_NETWORK_SECTION_PORTGROUP:
3669         return virNetworkDefUpdatePortGroup(def, command,
3670                                             parentIndex, ctxt, flags);
3671     case VIR_NETWORK_SECTION_DNS_HOST:
3672         return virNetworkDefUpdateDNSHost(def, command,
3673                                           parentIndex, ctxt, flags);
3674     case VIR_NETWORK_SECTION_DNS_TXT:
3675         return virNetworkDefUpdateDNSTxt(def, command, parentIndex, ctxt, flags);
3676     case VIR_NETWORK_SECTION_DNS_SRV:
3677         return virNetworkDefUpdateDNSSrv(def, command, parentIndex, ctxt, flags);
3678     default:
3679         virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3680                        _("can't update unrecognized section of network"));
3681         break;
3682     }
3683 
3684     return -1;
3685 }
3686