1 /*
2 * device_conf.c: device XML handling
3 *
4 * Copyright (C) 2006-2016 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22 #include "virerror.h"
23 #include "datatypes.h"
24 #include "viralloc.h"
25 #include "virxml.h"
26 #include "viruuid.h"
27 #include "virbuffer.h"
28 #include "device_conf.h"
29 #include "domain_addr.h"
30 #include "virstring.h"
31
32 #define VIR_FROM_THIS VIR_FROM_DEVICE
33
34 VIR_ENUM_IMPL(virDomainDeviceAddress,
35 VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
36 "none",
37 "pci",
38 "drive",
39 "virtio-serial",
40 "ccid",
41 "usb",
42 "spapr-vio",
43 "virtio-s390",
44 "ccw",
45 "virtio-mmio",
46 "isa",
47 "dimm",
48 "unassigned",
49 );
50
51 static int
virZPCIDeviceAddressParseXML(xmlNodePtr node,virPCIDeviceAddress * addr)52 virZPCIDeviceAddressParseXML(xmlNodePtr node,
53 virPCIDeviceAddress *addr)
54 {
55 int retUid;
56 int retFid;
57
58 if ((retUid = virXMLPropUInt(node, "uid", 0, VIR_XML_PROP_NONE,
59 &addr->zpci.uid.value)) < 0)
60 return -1;
61
62 if (retUid > 0)
63 addr->zpci.uid.isSet = true;
64
65 if ((retFid = virXMLPropUInt(node, "fid", 0, VIR_XML_PROP_NONE,
66 &addr->zpci.fid.value)) < 0)
67 return -1;
68
69 if (retFid > 0)
70 addr->zpci.fid.isSet = true;
71
72 return 0;
73 }
74
75 void
virDomainDeviceInfoClear(virDomainDeviceInfo * info)76 virDomainDeviceInfoClear(virDomainDeviceInfo *info)
77 {
78 VIR_FREE(info->alias);
79 memset(&info->addr, 0, sizeof(info->addr));
80 info->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE;
81 VIR_FREE(info->romfile);
82 VIR_FREE(info->loadparm);
83 info->isolationGroup = 0;
84 info->isolationGroupLocked = false;
85 }
86
87 void
virDomainDeviceInfoFree(virDomainDeviceInfo * info)88 virDomainDeviceInfoFree(virDomainDeviceInfo *info)
89 {
90 if (info) {
91 virDomainDeviceInfoClear(info);
92 g_free(info);
93 }
94 }
95
96 bool
virDomainDeviceInfoAddressIsEqual(const virDomainDeviceInfo * a,const virDomainDeviceInfo * b)97 virDomainDeviceInfoAddressIsEqual(const virDomainDeviceInfo *a,
98 const virDomainDeviceInfo *b)
99 {
100 if (a->type != b->type)
101 return false;
102
103 switch ((virDomainDeviceAddressType) a->type) {
104 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE:
105 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST:
106 /* address types below don't have any specific data */
107 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
108 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
109 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_UNASSIGNED:
110 break;
111
112 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
113 /* the 'multi' field shouldn't be checked */
114 if (a->addr.pci.domain != b->addr.pci.domain ||
115 a->addr.pci.bus != b->addr.pci.bus ||
116 a->addr.pci.slot != b->addr.pci.slot ||
117 a->addr.pci.function != b->addr.pci.function)
118 return false;
119 break;
120
121 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
122 if (a->addr.drive.controller != b->addr.drive.controller ||
123 a->addr.drive.unit != b->addr.drive.unit ||
124 a->addr.drive.bus != b->addr.drive.bus ||
125 a->addr.drive.target != b->addr.drive.target)
126 return false;
127 break;
128
129 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_SERIAL:
130 if (memcmp(&a->addr.vioserial, &b->addr.vioserial, sizeof(a->addr.vioserial)))
131 return false;
132 break;
133
134 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCID:
135 if (memcmp(&a->addr.ccid, &b->addr.ccid, sizeof(a->addr.ccid)))
136 return false;
137 break;
138
139 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
140 if (memcmp(&a->addr.usb, &b->addr.usb, sizeof(a->addr.usb)))
141 return false;
142 break;
143
144 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_SPAPRVIO:
145 if (memcmp(&a->addr.spaprvio, &b->addr.spaprvio, sizeof(a->addr.spaprvio)))
146 return false;
147 break;
148
149 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
150 /* the 'assigned' field denotes that the address was generated */
151 if (a->addr.ccw.cssid != b->addr.ccw.cssid ||
152 a->addr.ccw.ssid != b->addr.ccw.ssid ||
153 a->addr.ccw.devno != b->addr.ccw.devno)
154 return false;
155 break;
156
157 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_ISA:
158 if (memcmp(&a->addr.isa, &b->addr.isa, sizeof(a->addr.isa)))
159 return false;
160 break;
161
162 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DIMM:
163 if (memcmp(&a->addr.dimm, &b->addr.dimm, sizeof(a->addr.dimm)))
164 return false;
165 break;
166 }
167
168 return true;
169 }
170
171 bool
virDeviceInfoPCIAddressIsWanted(const virDomainDeviceInfo * info)172 virDeviceInfoPCIAddressIsWanted(const virDomainDeviceInfo *info)
173 {
174 return info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE ||
175 (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
176 virPCIDeviceAddressIsEmpty(&info->addr.pci));
177 }
178
179 bool
virDeviceInfoPCIAddressIsPresent(const virDomainDeviceInfo * info)180 virDeviceInfoPCIAddressIsPresent(const virDomainDeviceInfo *info)
181 {
182 return info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
183 !virPCIDeviceAddressIsEmpty(&info->addr.pci);
184 }
185
186 bool
virDeviceInfoPCIAddressExtensionIsWanted(const virDomainDeviceInfo * info)187 virDeviceInfoPCIAddressExtensionIsWanted(const virDomainDeviceInfo *info)
188 {
189 return (info->addr.pci.extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) &&
190 virZPCIDeviceAddressIsIncomplete(&info->addr.pci.zpci);
191 }
192
193 bool
virDeviceInfoPCIAddressExtensionIsPresent(const virDomainDeviceInfo * info)194 virDeviceInfoPCIAddressExtensionIsPresent(const virDomainDeviceInfo *info)
195 {
196 return (info->addr.pci.extFlags & VIR_PCI_ADDRESS_EXTENSION_ZPCI) &&
197 virZPCIDeviceAddressIsPresent(&info->addr.pci.zpci);
198 }
199
200 int
virPCIDeviceAddressParseXML(xmlNodePtr node,virPCIDeviceAddress * addr)201 virPCIDeviceAddressParseXML(xmlNodePtr node,
202 virPCIDeviceAddress *addr)
203 {
204 xmlNodePtr cur;
205 xmlNodePtr zpci = NULL;
206
207 memset(addr, 0, sizeof(*addr));
208
209 if (virXMLPropUInt(node, "domain", 0, VIR_XML_PROP_NONE,
210 &addr->domain) < 0)
211 return -1;
212
213 if (virXMLPropUInt(node, "bus", 0, VIR_XML_PROP_NONE,
214 &addr->bus) < 0)
215 return -1;
216
217 if (virXMLPropUInt(node, "slot", 0, VIR_XML_PROP_NONE,
218 &addr->slot) < 0)
219 return -1;
220
221 if (virXMLPropUInt(node, "function", 0, VIR_XML_PROP_NONE,
222 &addr->function) < 0)
223 return -1;
224
225 if (virXMLPropTristateSwitch(node, "multifunction", VIR_XML_PROP_NONE,
226 &addr->multi) < 0)
227 return -1;
228
229 if (!virPCIDeviceAddressIsEmpty(addr) && !virPCIDeviceAddressIsValid(addr, true))
230 return -1;
231
232 cur = node->children;
233 while (cur) {
234 if (cur->type == XML_ELEMENT_NODE &&
235 virXMLNodeNameEqual(cur, "zpci")) {
236 zpci = cur;
237 }
238 cur = cur->next;
239 }
240
241 if (zpci && virZPCIDeviceAddressParseXML(zpci, addr) < 0)
242 return -1;
243
244 return 0;
245 }
246
247 void
virPCIDeviceAddressFormat(virBuffer * buf,virPCIDeviceAddress addr,bool includeTypeInAddr)248 virPCIDeviceAddressFormat(virBuffer *buf,
249 virPCIDeviceAddress addr,
250 bool includeTypeInAddr)
251 {
252 virBufferAsprintf(buf, "<address %sdomain='0x%04x' bus='0x%02x' "
253 "slot='0x%02x' function='0x%d'/>\n",
254 includeTypeInAddr ? "type='pci' " : "",
255 addr.domain,
256 addr.bus,
257 addr.slot,
258 addr.function);
259 }
260
261 bool
virDomainDeviceCCWAddressIsValid(virDomainDeviceCCWAddress * addr)262 virDomainDeviceCCWAddressIsValid(virDomainDeviceCCWAddress *addr)
263 {
264 return addr->cssid <= VIR_DOMAIN_DEVICE_CCW_MAX_CSSID &&
265 addr->ssid <= VIR_DOMAIN_DEVICE_CCW_MAX_SSID &&
266 addr->devno <= VIR_DOMAIN_DEVICE_CCW_MAX_DEVNO;
267 }
268
269 int
virDomainDeviceCCWAddressParseXML(xmlNodePtr node,virDomainDeviceCCWAddress * addr)270 virDomainDeviceCCWAddressParseXML(xmlNodePtr node,
271 virDomainDeviceCCWAddress *addr)
272 {
273 int cssid;
274 int ssid;
275 int devno;
276
277 memset(addr, 0, sizeof(*addr));
278
279 if ((cssid = virXMLPropUInt(node, "cssid", 0, VIR_XML_PROP_NONE,
280 &addr->cssid)) < 0)
281 return -1;
282
283 if ((ssid = virXMLPropUInt(node, "ssid", 0, VIR_XML_PROP_NONE,
284 &addr->ssid)) < 0)
285 return -1;
286
287 if ((devno = virXMLPropUInt(node, "devno", 0, VIR_XML_PROP_NONE,
288 &addr->devno)) < 0)
289 return -1;
290
291 if (!virDomainDeviceCCWAddressIsValid(addr)) {
292 virReportError(VIR_ERR_INTERNAL_ERROR,
293 _("Invalid specification for virtio ccw address: cssid='0x%x' ssid='0x%x' devno='0x%04x'"),
294 addr->cssid, addr->ssid, addr->devno);
295 return -1;
296 }
297
298 if (cssid && ssid && devno) {
299 addr->assigned = true;
300 } else if (cssid || ssid || devno) {
301 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
302 _("Invalid partial specification for virtio ccw address"));
303 return -1;
304 }
305
306 return 0;
307 }
308
309 bool
virDomainDeviceCCWAddressEqual(virDomainDeviceCCWAddress * addr1,virDomainDeviceCCWAddress * addr2)310 virDomainDeviceCCWAddressEqual(virDomainDeviceCCWAddress *addr1,
311 virDomainDeviceCCWAddress *addr2)
312 {
313 if (addr1->cssid == addr2->cssid &&
314 addr1->ssid == addr2->ssid &&
315 addr1->devno == addr2->devno) {
316 return true;
317 }
318 return false;
319 }
320
321 int
virDomainDeviceDriveAddressParseXML(xmlNodePtr node,virDomainDeviceDriveAddress * addr)322 virDomainDeviceDriveAddressParseXML(xmlNodePtr node,
323 virDomainDeviceDriveAddress *addr)
324 {
325 memset(addr, 0, sizeof(*addr));
326
327 if (virXMLPropUInt(node, "controller", 10, VIR_XML_PROP_NONE,
328 &addr->controller) < 0)
329 return -1;
330
331 if (virXMLPropUInt(node, "bus", 10, VIR_XML_PROP_NONE, &addr->bus) < 0)
332 return -1;
333
334 if (virXMLPropUInt(node, "target", 10, VIR_XML_PROP_NONE,
335 &addr->target) < 0)
336 return -1;
337
338 if (virXMLPropUInt(node, "unit", 10, VIR_XML_PROP_NONE, &addr->unit) < 0)
339 return -1;
340
341 return 0;
342 }
343
344 int
virDomainDeviceVirtioSerialAddressParseXML(xmlNodePtr node,virDomainDeviceVirtioSerialAddress * addr)345 virDomainDeviceVirtioSerialAddressParseXML(xmlNodePtr node,
346 virDomainDeviceVirtioSerialAddress *addr)
347 {
348 memset(addr, 0, sizeof(*addr));
349
350 if (virXMLPropUInt(node, "controller", 10, VIR_XML_PROP_NONE,
351 &addr->controller) < 0)
352 return -1;
353
354 if (virXMLPropUInt(node, "bus", 10, VIR_XML_PROP_NONE, &addr->bus) < 0)
355 return -1;
356
357 if (virXMLPropUInt(node, "port", 10, VIR_XML_PROP_NONE, &addr->port) < 0)
358 return -1;
359
360 return 0;
361 }
362
363 int
virDomainDeviceCcidAddressParseXML(xmlNodePtr node,virDomainDeviceCcidAddress * addr)364 virDomainDeviceCcidAddressParseXML(xmlNodePtr node,
365 virDomainDeviceCcidAddress *addr)
366 {
367 memset(addr, 0, sizeof(*addr));
368
369 if (virXMLPropUInt(node, "controller", 10, VIR_XML_PROP_NONE,
370 &addr->controller) < 0)
371 return -1;
372
373 if (virXMLPropUInt(node, "slot", 10, VIR_XML_PROP_NONE, &addr->slot) < 0)
374 return -1;
375
376 return 0;
377 }
378
379 static int
virDomainDeviceUSBAddressParsePort(virDomainDeviceUSBAddress * addr,char * port)380 virDomainDeviceUSBAddressParsePort(virDomainDeviceUSBAddress *addr,
381 char *port)
382 {
383 char *tmp = port;
384 size_t i;
385
386 for (i = 0; i < VIR_DOMAIN_DEVICE_USB_MAX_PORT_DEPTH; i++) {
387 if (virStrToLong_uip(tmp, &tmp, 10, &addr->port[i]) < 0)
388 break;
389
390 if (*tmp == '\0')
391 return 0;
392
393 if (*tmp == '.')
394 tmp++;
395 }
396
397 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
398 _("Cannot parse <address> 'port' attribute"));
399 return -1;
400 }
401
402 int
virDomainDeviceUSBAddressParseXML(xmlNodePtr node,virDomainDeviceUSBAddress * addr)403 virDomainDeviceUSBAddressParseXML(xmlNodePtr node,
404 virDomainDeviceUSBAddress *addr)
405 {
406 g_autofree char *port = virXMLPropString(node, "port");
407
408 memset(addr, 0, sizeof(*addr));
409
410 if (port && virDomainDeviceUSBAddressParsePort(addr, port) < 0)
411 return -1;
412
413 if (virXMLPropUInt(node, "bus", 10, VIR_XML_PROP_NONE, &addr->bus) < 0)
414 return -1;
415
416 return 0;
417 }
418
419 int
virDomainDeviceSpaprVioAddressParseXML(xmlNodePtr node,virDomainDeviceSpaprVioAddress * addr)420 virDomainDeviceSpaprVioAddressParseXML(xmlNodePtr node,
421 virDomainDeviceSpaprVioAddress *addr)
422 {
423 int reg;
424
425 memset(addr, 0, sizeof(*addr));
426
427 if ((reg = virXMLPropULongLong(node, "reg", 16, VIR_XML_PROP_NONE,
428 &addr->reg)) < 0)
429 return -1;
430
431 if (reg != 0)
432 addr->has_reg = true;
433
434 return 0;
435 }
436
437 bool
virDomainDeviceAddressIsValid(virDomainDeviceInfo * info,int type)438 virDomainDeviceAddressIsValid(virDomainDeviceInfo *info,
439 int type)
440 {
441 if (info->type != type)
442 return false;
443
444 switch (info->type) {
445 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
446 return virPCIDeviceAddressIsValid(&info->addr.pci, false);
447
448 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
449 return true;
450
451 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_S390:
452 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_VIRTIO_MMIO:
453 return true;
454
455 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW:
456 return virDomainDeviceCCWAddressIsValid(&info->addr.ccw);
457
458 case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_USB:
459 return true;
460 }
461
462 return false;
463 }
464
465 int
virInterfaceLinkParseXML(xmlNodePtr node,virNetDevIfLink * lnk)466 virInterfaceLinkParseXML(xmlNodePtr node,
467 virNetDevIfLink *lnk)
468 {
469 if (virXMLPropEnum(node, "state", virNetDevIfStateTypeFromString,
470 VIR_XML_PROP_NONE, &lnk->state) < 0)
471 return -1;
472
473 if (virXMLPropUInt(node, "speed", 10, VIR_XML_PROP_NONE, &lnk->speed) < 0)
474 return -1;
475
476 return 0;
477 }
478
479 int
virInterfaceLinkFormat(virBuffer * buf,const virNetDevIfLink * lnk)480 virInterfaceLinkFormat(virBuffer *buf,
481 const virNetDevIfLink *lnk)
482 {
483 if (!lnk->speed && !lnk->state) {
484 /* If there's nothing to format, return early. */
485 return 0;
486 }
487
488 virBufferAddLit(buf, "<link");
489 if (lnk->speed)
490 virBufferAsprintf(buf, " speed='%u'", lnk->speed);
491 if (lnk->state)
492 virBufferAsprintf(buf, " state='%s'",
493 virNetDevIfStateTypeToString(lnk->state));
494 virBufferAddLit(buf, "/>\n");
495 return 0;
496 }
497