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