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