[libvirt] [libvirt-test-API][PATCH] Rewrite case for listAllInterfaces() API
by jiahu
Using actual python API to validate test case, rather than use
virsh iface-* command lines.
---
cases/basic_interface.conf | 12 ++
repos/interface/iface_list.py | 299 ++++++++++++------------------------------
2 files changed, 99 insertions(+), 212 deletions(-)
diff --git a/cases/basic_interface.conf b/cases/basic_interface.conf
index e2125bb..43e37e8 100644
--- a/cases/basic_interface.conf
+++ b/cases/basic_interface.conf
@@ -15,3 +15,15 @@ interface:define
interface:create
ifacename
$testnic
+
+interface:iface_list
+ flags
+ all
+
+interface:iface_list
+ flags
+ active
+
+interface:iface_list
+ flags
+ inactive
diff --git a/repos/interface/iface_list.py b/repos/interface/iface_list.py
index 49f0c05..85f9df9 100644
--- a/repos/interface/iface_list.py
+++ b/repos/interface/iface_list.py
@@ -1,65 +1,26 @@
#!/usr/bin/env python
+# test listAllInterfaces() API
import os
-import sys
-import re
-import commands
+import libvirt
-required_params = ('ifaceopt',)
-optional_params = {}
-
-VIRSH_QUIET_IFACE_LIST = "virsh --quiet iface-list %s | awk '{print ""$%s""}'"
-NETWORK_CONFIG = "/etc/sysconfig/network-scripts/"
-IFCONFIG_DRIVER = "ifconfig %s | sed 's/[ \t].*//;/^$/d'"
-GET_MAC = "ip link show %s |sed -n '2p'| awk '{print $2}'"
-VIRSH_IFACE_LIST = "virsh iface-list %s"
-
-names = []
-state = []
-macs = []
-
-def get_option_list(params):
- """return options we need to test
- """
- logger = params['logger']
- option_list=[]
+from libvirt import libvirtError
+from src import sharedmod
+from utils import utils
- value = params['ifaceopt']
- if value == 'all':
- option_list = [' ', '--all', '--inactive']
- elif value == '--all' or value == '--inactive':
- option_list.append(value)
- else:
- logger.error("value %s is not supported" % value)
- return 1, option_list
+required_params = ('flags',)
+optional_params = {}
- return 0, option_list
+NETWORK_CONFIG = "/etc/sysconfig/network-scripts/"
+IFCONFIG_DRIVER = "ifconfig %s | sed 's/[ \t].*//;/^$/d'| cut -d \":\" -f -1"
-def get_output(command, logger):
- """execute shell command
+def get_inteface_list_from_ifcfg(logger):
+ """
+ return host interface list from ifcfg-*
"""
- status, ret = commands.getstatusoutput(command)
- if status:
- logger.error("executing "+ "\"" + command + "\"" + " failed")
- logger.error(ret)
- return status, ret
-
-def get_interface_list(option, logger):
- """ return active host interface list """
- interface_list = []
- status, interface_str = get_output(IFCONFIG_DRIVER % option, logger)
- if not status:
- interface_list = interface_str.split('\n')
- return interface_list
- else:
- logger.error("\"" + IFCONFIG_DRIVER % option + "\"" + "error")
- logger.error(interface_str)
- return interface_list
-
-def check_ifacename(names, option, logger):
- """ verify the validity of output data """
ifcfg_files = []
+ nic_names = []
for f in os.listdir(NETWORK_CONFIG):
if f.startswith("ifcfg-"):
f_path = os.path.join(NETWORK_CONFIG, f)
@@ -67,18 +28,6 @@ def check_ifacename(names, option, logger):
ifcfg_files.append(f_path)
else:
logger.warn("%s is not a regular file" % f_path)
-
- interface_active = get_interface_list('', logger)
- logger.debug("list of active host interface: %s" % interface_active)
- if interface_active == None:
- return 1
-
- interface_all = get_interface_list('-a', logger)
- logger.debug("list of all host interface: %s" % interface_all)
- if interface_all == None:
- return 1
-
-
for ifcfg_file in ifcfg_files:
fp = open(ifcfg_file, 'r')
fp.seek(0,0)
@@ -87,165 +36,91 @@ def check_ifacename(names, option, logger):
device_str = eachLine.rstrip()
nic_string = device_str.split("=")[1]
if nic_string.startswith("\""):
- nic_name = nic_string[1:-1]
+ nic_names = nic_string[1:-1]
else:
- nic_name = nic_string
+ nic_names.append(nic_string)
break
-
fp.close()
+ return list(set(nic_names))
- if option == ' ':
- if nic_name not in interface_active:
- continue
- else:
- if nic_name in names:
- logger.info("it contains interface %s in %s" % (nic_name, ifcfg_file))
- else:
- logger.error("interface %s in %s couldn't \n\
- be in the output of virsh iface-list with option %s" % \
- (nic_name, ifcfg_file, option))
- return 1
- elif option == '--all':
- if nic_name in names:
- logger.info("it contains interface %s in %s" % (nic_name, ifcfg_file))
- else:
- logger.error("interface %s in %s couldn't \n\
- be in the output of virsh iface-list with option %s" % \
- (nic_name, ifcfg_file, option))
-
- return 1
- elif option == '--inactive':
- if nic_name in interface_active:
- continue
- else:
- if nic_name in names:
- logger.info("it contains interface %s in %s" % (nic_name, ifcfg_file))
- else:
- logger.error("interface %s in %s couldn't \n\
- be in the output of virsh iface-list with option %s" % \
- (nic_name, ifcfg_file, option))
- return 1
-
- return 0
-
-def check_ifacestate(names, state, logger):
- """ check the state of give host interface """
-
- interface_active = get_interface_list('', logger)
- if interface_active == None:
- return 1
-
- interface_all = get_interface_list('-a', logger)
- if interface_all == None:
- return 1
-
- index = 0
- count = len(names)
- while(index < count):
- if names[index] in interface_active and state[index] == 'active':
- logger.info("interface %s is %s" % (names[index], state[index]))
- elif names[index] not in interface_active and \
- names[index] in interface_all and \
- state[index] == 'inactive':
- logger.info("interface %s is %s" % (names[index], state[index]))
- else:
- logger.error("interface %s is %s, but not we expected" % \
- (names[index], state[index]))
- return 1
-
- index = index + 1
-
- return 0
-
-def check_ifacemac(names, macs, logger):
- """ check if the mac corresponding to approriate name is correct """
- index = 0
- count = len(names)
- while(index < count):
- status, mac_shell = get_output(GET_MAC % names[index], logger)
- if not status:
- if mac_shell == macs[index]:
- logger.info("interface %s's mac address is %s" % \
- (names[index], macs[index]))
- else:
- logger.error("interface %s's mac address from iface-list: %s \
- is different from one from ip link show: %s" % \
- (name[index], macs[indesx], mac_shell))
- return 1
- index = index + 1
-
- return 0
-
-def iface_list_output(option, logger):
- """ check the output of virsh iface-list with appropriate option """
- global names, state, macs
-
- status, ret = get_output(VIRSH_QUIET_IFACE_LIST % (option, 1), logger)
- if not status:
- names = ret.split('\n')
- logger.info("interface names from option '%s' : %s" % (option, names))
-
- else:
- return 1
-
- status, ret = get_output(VIRSH_QUIET_IFACE_LIST % (option, 2), logger)
- if not status:
- state = ret.split('\n')
- logger.info("interface state from option '%s' : %s" % (option, state))
- else:
- return 1
-
- status, ret = get_output(VIRSH_QUIET_IFACE_LIST % (option, 3), logger)
+def get_interface_list(option, logger):
+ """
+ return host interface list
+ """
+ nic_names = []
+ status, nic_names = utils.exec_cmd(IFCONFIG_DRIVER % option, shell=True)
if not status:
- macs = ret.split('\n')
- logger.info("interface macs from option '%s' : %s" % (option, macs))
+ return nic_names
else:
- return 1
+ logger.error("\"" + IFCONFIG_DRIVER % option + "\"" + "error")
+ logger.error(nic_names)
+ return nic_names
- return 0
+def iface_list_output_from_ifconfig(flags, logger):
+ """
+ get all host interface using ifconfig command
+ """
+ nic_names = []
+ if flags == 0:
+ nic_names = get_interface_list('-a', logger)
+ elif flags == 1:
+ interface_all = get_interface_list('-a', logger)
+ interface_active = get_interface_list('', logger)
+ nic_names = list(set(interface_all) - set(interface_active))
+ elif flags == 2:
+ nic_names = get_interface_list('', logger)
+
+ if nic_names == None:
+ return False
+ return nic_names
+
+def iface_list_output_from_api(flags,logger):
+ """
+ get interface list using listAllInterfaces()
+ """
+ nic_names_api = []
+ for interface in conn.listAllInterfaces(flags):
+ nic_names_api.append(str(interface.name()))
+ return nic_names_api
def iface_list(params):
- """ test the validity of the output of iface_list with
- default, --all, --inactive option, including
- interface name, state, and mac
+ """
+ test listAllInterfaces() api
"""
+ global conn
logger = params['logger']
- ret, option_list = get_option_list(params)
- global names, state, macs
-
- if ret:
- return 1
-
- for option in option_list:
- logger.info("CHECK the output of virsh pool-list with option '%s'" % option)
- logger.info("get the name, corresponding state and mac address of interfaces")
- if iface_list_output(option, logger):
- logger.error("faied to name, state, and mac from iface-list")
- return 1
+ flags = params['flags']
+ conn = sharedmod.libvirtobj['conn']
+ logger.info("The given flags is %s " % flags)
+ if flags == "all":
+ flag = 0
+ elif flags == "inactive":
+ flag = 1
+ elif flags == "active":
+ flag = 2
+ try:
+ iface_list = iface_list_output_from_api(flag, logger)
+ iface_list_ifconfig = iface_list_output_from_ifconfig(flag, logger)
+ if iface_list_ifconfig == False:
+ return 1
+ ifcfg = get_inteface_list_from_ifcfg(logger)
+ logger.info("interface list from API: %s" % iface_list)
+ logger.debug("interface list from ifcfg: %s" % ifcfg)
+ for interface in iface_list_ifconfig:
+ if interface not in ifcfg:
+ iface_list_ifconfig.remove(interface)
+ logger.debug("%s has not regular ifcfg file" % interface)
+
+ logger.info("interface list from ifconfig cmd: %s" % iface_list_ifconfig)
+ for interface in iface_list:
+ if interface in iface_list_ifconfig:
+ logger.debug("%s :Pass" % interface)
else:
- logger.info("then, check the validity of these interface names")
- if check_ifacename(names, option, logger):
- logger.error("checking interface names FAILED")
- return 1
- else:
- logger.info("checking interface names SUCCESSFULLY")
-
- logger.info("check the state of these interfaces")
- if check_ifacestate(names, state, logger):
- logger.error("checking interface state FAILED")
- return 1
- else:
- logger.info("checking interface state SUCCESSFULLY")
-
- logger.info("check the interface mac address")
- if check_ifacemac(names, macs, logger):
- logger.error("checking interface mac address FAILED")
- return 1
- else:
- logger.info("checking interface mac address SUCESSFULLY")
-
- status, ret = get_output(VIRSH_IFACE_LIST % option, logger)
- if not status:
- logger.info("\n" + ret)
+ logger.debug("%s :Fail" % interface)
+ return 1
+
+ except libvirtError, e:
+ logger.error("API error message: %s" % e.message)
+ return 1
return 0
--
1.8.3.1
9 years, 8 months
[libvirt] [RFC PATCH v2 0/4] Enable spapr-pci-vfio-host-bridge controllers for VFIO passthrough support
by Shivaprasad G Bhat
The following series of patches enable spapr-pci-vfio-host-bridge
controllers on PPC64-pseries machine which is required for supporting
host device passthrough using VFIO.
There were some initial enablement work on the same at
http://www.redhat.com/archives/libvir-list/2013-September/msg00838.html.
On pseries(ppc64), the vfio host devices(will refer as
hostdevs here on) cannot be assigned to the default emulated pci-host-bus(phb)
controller(like the default pci.0). The hostdevs goto spapr-pci-vfio-host-bridge.
The hostdevs belonging to the same iommu group share the same
spapr-pci-vfio-host-bridge. Henceforth, new spapr-pci-host-bridge needs to be
added for every hostdev belonging to any new iommu group. The hostdevs should
be attached to their respective spapr-pci-vfio-host-bridge.
Libvirt today adds all the devices to the default pci domain. The patch series
take care to add the new controller. A new pci domain in the guest per
controller is created. The hostdevs get their pci address in the respective
domain. The patch series taskes care of device addressing in vfio hostdevs,
SR-IOV interfaces and network interfaces from SRIOV virtual function pools.
Reference:
======
v1: http://www.redhat.com/archives/libvir-list/2014-October/msg00500.html
Changes Since v1:
* Some minor code clean up and rebase to latest code base after review with Prerna
* Patch 2 : Added logic to remove redundant spapr-vfio controllers.
* : Moved domaincommon.rng from Patch 4 to Patch 2.
---
Shivaprasad G Bhat (4):
qemu: Add SPAPR_VFIO_HOST_BRIDGE capability for PPC platform
qemu: parse spapr-vfio-pci controller from xml
qemu: assign addresses for spapr vfio hostdevices and generate cli
qemu: add test case for spapr-pci-vfio-host-bridge
docs/schemas/domaincommon.rng | 28 ++
src/bhyve/bhyve_domain.c | 2
src/conf/domain_addr.c | 8 -
src/conf/domain_addr.h | 2
src/conf/domain_conf.c | 165 +++++++++++-
src/conf/domain_conf.h | 19 +
src/libvirt_private.syms | 2
src/qemu/qemu_capabilities.c | 2
src/qemu/qemu_capabilities.h | 1
src/qemu/qemu_command.c | 276 +++++++++++++++++++-
src/qemu/qemu_command.h | 17 +
src/qemu/qemu_domain.c | 12 -
src/qemu/qemu_driver.c | 6
tests/qemuhotplugtest.c | 2
.../qemuxml2argv-hostdev-spapr-vfio.args | 20 +
.../qemuxml2argv-hostdev-spapr-vfio.xml | 75 +++++
tests/qemuxml2argvtest.c | 8 +
17 files changed, 609 insertions(+), 36 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-spapr-vfio.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-spapr-vfio.xml
--
Signature
9 years, 8 months
[libvirt] [PATCH v8 0/4] Introduce API to query IP addresses for given domain
by Nehal J Wani
This feature has been requested for a very long time. Since qemu guest
agent and leaseshelper give us reliable results, now the wait is over.
The RFC was first proposed by Michal Privoznik:
http://www.redhat.com/archives/libvir-list/2012-February/msg00437.html
A patch was submitted, using structs:
https://www.redhat.com/archives/libvir-list/2012-June/msg00220.html
Another patch was submitted, using XML:
https://www.redhat.com/archives/libvir-list/2012-June/msg00904.html
Neither of the patches were accepted, probably due to lack of extensibility
and usability. Hence, we thought of using virTypedParameters for reporting
list of interfaces along with their MAC address and IP addresses. The RFC
can be found here:
https://www.redhat.com/archives/libvir-list/2013-July/msg00084.html
The idea of extensibility was rejected and rendered out of scope of
libvirt. Hence, we were back to structs.
This API is called virDomainInterfaceAddresses which returns a dynamically
allocated array of virDomainInterface struct. The great disadvantage is
once this gets released, it's written in stone and we cannot change
or add an item into it.
The virsh CLI supports two methods:
* Return information (list of all associated interfaces with MAC address
and IP addresses) of all of the domain interfaces by default (if
no interface name is provided)
* Return information for the specified interface (if an interface name
is provided)
v8:
* qemuDomainInterfaceAddresses: redo logic related to flags
* Make sure that NIC(s) on guest is/are using libvirt virtual network
before querying leaseshelper
* domifaddr: change --network option from VSH_OT_DATA to VSH_OT_STRING
v7:
* Enable support for DHCP lease file parsing method
* http://www.redhat.com/archives/libvir-list/2014-December/msg00866.html
v6:
* Inclusion of flags, readonly check for guest agent connection
* Correction of memory leaks, other small nits.
* https://www.redhat.com/archives/libvir-list/2013-September/msg00350.html
v5:
* s/virDomainInterfacesAddresses/virDomainInterfaceAddresses.
* Case for IP aliasing handled using virHashTable.
* New test cases added, involving multiple and 0 IP addresse(s)
per interface.
* IP prefix changed from int to unsigned int.
* Changes to practice libvirt habits.
* https://www.redhat.com/archives/libvir-list/2013-September/msg00003.html
v4:
* Various style nits, indentation errors, memory leaks fixed.
* https://www.redhat.com/archives/libvir-list/2013-August/msg01265.html
v3:
* Upper bounds to number of interfaces and addresses per interface
introduced.
* Change from array of structs to array of pointers
* ifaces_count moved from function argument to return value
* Changes in variable names
* Test cases added for qemuAgentGetInterfaces.
* https://www.redhat.com/archives/libvir-list/2013-August/msg01215.html
v2:
* Logical errors, memory leaks and few other errors fixed.
* https://www.redhat.com/archives/libvir-list/2013-August/msg00631.html
v1:
* http://www.redhat.com/archives/libvir-list/2013-July/msg01553.html
Nehal J Wani (4):
domifaddr: Implement the public APIs
domifaddr: Implement the remote protocol
domifaddr: Implement the API for qemu
domifaddr: Add virsh support
daemon/remote.c | 134 ++++++++++++++++++++++++++
include/libvirt/libvirt-domain.h | 27 ++++++
src/driver-hypervisor.h | 5 +
src/libvirt-domain.c | 129 +++++++++++++++++++++++++
src/libvirt_public.syms | 6 ++
src/qemu/qemu_agent.c | 202 +++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_agent.h | 4 +
src/qemu/qemu_driver.c | 173 +++++++++++++++++++++++++++++++++
src/remote/remote_driver.c | 100 +++++++++++++++++++
src/remote/remote_protocol.x | 36 ++++++-
src/remote_protocol-structs | 24 +++++
tests/qemuagenttest.c | 188 ++++++++++++++++++++++++++++++++++++
tools/virsh-domain-monitor.c | 141 +++++++++++++++++++++++++++
tools/virsh.pod | 16 ++++
14 files changed, 1184 insertions(+), 1 deletion(-)
--
2.1.0
9 years, 8 months
[libvirt] [PATCH] Add ability to set rlimits at container boot
by Ryan Cleere
---
docs/formatdomain.html.in | 49 +++++++++++++++++++++++
docs/schemas/domaincommon.rng | 89 +++++++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.c | 92 +++++++++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 33 ++++++++++++++++
src/libvirt_private.syms | 1 +
src/lxc/lxc_controller.c | 32 +++++++++++++++
src/util/virprocess.c | 4 +-
src/util/virprocess.h | 2 +
8 files changed, 300 insertions(+), 2 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index f8d5f89..5aec51c 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -348,6 +348,55 @@
</pre>
+ <p>
+ If you want to set an rlimit of the containter init process instead of
+ inheriting from the host init, set the <code>rlimits</code> element. You
+ are able to set any of the rlimits that setrlimits is able to set using
+ any of the following sub-elements:
+ </p>
+
+ <dl>
+ <dt><code>as</code></dt>
+ <dd>Used to set RLIMIT_AS.</dd>
+ <dt><code>core</code></dt>
+ <dd>Used to set RLIMIT_CORE.</dd>
+ <dt><code>cpu</code></dt>
+ <dd>Used to set RLIMIT_CPU.</dd>
+ <dt><code>data</code></dt>
+ <dd>Used to set RLIMIT_DATA.</dd>
+ <dt><code>fsize</code></dt>
+ <dd>Used to set RLIMIT_FSIZE.</dd>
+ <dt><code>locks</code></dt>
+ <dd>Used to set RLIMIT_LOCKS.</dd>
+ <dt><code>memlock</code></dt>
+ <dd>Used to set RLIMIT_MEMLOCK.</dd>
+ <dt><code>msgqueue</code></dt>
+ <dd>Used to set RLIMIT_MSGQUEUE.</dd>
+ <dt><code>nice</code></dt>
+ <dd>Used to set RLIMIT_NICE.</dd>
+ <dt><code>nofile</code></dt>
+ <dd>Used to set RLIMIT_NOFILE.</dd>
+ <dt><code>nproc</code></dt>
+ <dd>Used to set RLIMIT_NPROC.</dd>
+ <dt><code>rss</code></dt>
+ <dd>Used to set RLIMIT_RSS.</dd>
+ <dt><code>rtprio</code></dt>
+ <dd>Used to set RLIMIT_RTPRIO.</dd>
+ <dt><code>rttime</code></dt>
+ <dd>Used to set RLIMIT_RTTIME.</dd>
+ <dt><code>sigpending</code></dt>
+ <dd>Used to set RLIMIT_SIGPENDING.</dd>
+ <dt><code>stack</code></dt>
+ <dd>Used to set RLIMIT_STACK.</dd>
+ </dl>
+
+ <pre>
+ <rlimits>
+ <nofile>10240</nofile>
+ </rlimits>
+ </pre>
+
+
<h3><a name="elementsSysinfo">SMBIOS System Information</a></h3>
<p>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index d467dce..b98f8d5 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -59,6 +59,9 @@
<ref name="idmap"/>
</optional>
<optional>
+ <ref name="rlimits"/>
+ </optional>
+ <optional>
<ref name="devices"/>
</optional>
<zeroOrMore>
@@ -570,6 +573,92 @@
</interleave>
</element>
</define>
+ <define name="rlimits">
+ <element name="rlimits">
+ <interleave>
+ <optional>
+ <element name="cpu">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="fsize">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="data">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="stack">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="core">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="rss">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="nproc">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="nofile">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="memlock">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="as">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="locks">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="sigpending">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="msgqueue">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="nice">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="rtprio">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ <optional>
+ <element name="rttime">
+ <ref name='scaledInteger'/>
+ </element>
+ </optional>
+ </interleave>
+ </element>
+ </define>
<!--
Resources usage defines the amount of memory (maximum and possibly
current usage) and number of virtual CPUs used by that domain.
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index d562e1a..399976e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -772,6 +772,24 @@ VIR_ENUM_IMPL(virDomainLoader,
"rom",
"pflash")
+VIR_ENUM_IMPL(virDomainRLimit, VIR_DOMAIN_RLIMIT_LAST,
+ "cpu",
+ "fsize",
+ "data",
+ "stack",
+ "core",
+ "rss",
+ "nproc",
+ "nofile",
+ "memlock",
+ "as",
+ "locks",
+ "sigpending",
+ "msgqueue",
+ "nice",
+ "rtprio",
+ "rttime")
+
/* Internal mapping: subset of block job types that can be present in
* <mirror> XML (remaining types are not two-phase). */
VIR_ENUM_DECL(virDomainBlockJob)
@@ -979,7 +997,40 @@ virDomainBlkioDeviceParseXML(xmlNodePtr root,
return -1;
}
+static virDomainRLimitsPtr
+virDomainRLimitParseXML(xmlNodePtr node)
+{
+ char *c = NULL;
+ long long val;
+ virDomainRLimitsPtr def;
+
+ if (VIR_ALLOC(def) < 0)
+ return NULL;
+ if (node->type == XML_ELEMENT_NODE) {
+ c = (char *)xmlNodeGetContent(node);
+ if (virStrToLong_ll(c, NULL, 10, &val) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("could not parse rlimit value of %s"),
+ c);
+ goto error;
+ }
+ VIR_FREE(c);
+
+ def->limit = val;
+ if ((def->resource = virDomainRLimitTypeFromString((const char *)node->name)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("could not determine resource type of '%s'"),
+ node->name);
+ goto error;
+ }
+ }
+ return def;
+ error:
+ VIR_FREE(c);
+ VIR_FREE(def);
+ return NULL;
+}
static void
virDomainObjListDataFree(void *payload, const void *name ATTRIBUTE_UNUSED)
@@ -14423,6 +14474,34 @@ virDomainDefParseXML(xmlDocPtr xml,
virHashFree(bootHash);
+ if ((node = virXPathNode("./rlimits[1]", ctxt)) != NULL && (n = virXMLChildElementCount(node)) > 0) {
+ xmlNodePtr cur = node->children;
+ if (n && VIR_ALLOC_N(def->rlimits, n) < 0)
+ goto error;
+
+ for (i = 0; i < n; i++) {
+ if (!(def->rlimits[i] = virDomainRLimitParseXML(cur))) {
+ for (j = 0; j < i; j++)
+ VIR_FREE(def->rlimits[j]);
+ VIR_FREE(def->rlimits);
+ goto error;
+ }
+ def->nrlimits++;
+ for (j = 0; j < i; j++) {
+ if (def->rlimits[j]->resource == def->rlimits[i]->resource) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("duplicate rlimit resources '%s'"),
+ virDomainRLimitTypeToString(def->rlimits[j]->resource));
+ for (int k = 0; k < i; k++)
+ VIR_FREE(def->rlimits[k]);
+ VIR_FREE(def->rlimits);
+ goto error;
+ }
+ }
+ cur = cur->next;
+ }
+ }
+
return def;
error:
@@ -20048,6 +20127,19 @@ virDomainDefFormatInternal(virDomainDefPtr def,
goto error;
}
+ if (def->nrlimits > 0) {
+ virBufferAddLit(buf, "<rlimits>\n");
+ virBufferAdjustIndent(buf, 2);
+ for (n = 0; n < def->nrlimits; n++) {
+ virBufferAsprintf(buf, "<%s>%lld</%s>\n",
+ virDomainRLimitTypeToString(def->rlimits[n]->resource),
+ def->rlimits[n]->limit,
+ virDomainRLimitTypeToString(def->rlimits[n]->resource));
+ }
+ virBufferAdjustIndent(buf, -2);
+ virBufferAddLit(buf, "</rlimits>\n");
+ }
+
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</domain>\n");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 93f2314..b032202 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1851,6 +1851,27 @@ typedef enum {
VIR_DOMAIN_CLOCK_BASIS_LAST
} virDomainClockBasis;
+typedef enum {
+ VIR_DOMAIN_RLIMIT_CPU,
+ VIR_DOMAIN_RLIMIT_FSIZE,
+ VIR_DOMAIN_RLIMIT_DATA,
+ VIR_DOMAIN_RLIMIT_STACK,
+ VIR_DOMAIN_RLIMIT_CORE,
+ VIR_DOMAIN_RLIMIT_RSS,
+ VIR_DOMAIN_RLIMIT_NPROC,
+ VIR_DOMAIN_RLIMIT_NOFILE,
+ VIR_DOMAIN_RLIMIT_MEMLOCK,
+ VIR_DOMAIN_RLIMIT_AS,
+ VIR_DOMAIN_RLIMIT_LOCKS,
+ VIR_DOMAIN_RLIMIT_SIGPENDING,
+ VIR_DOMAIN_RLIMIT_MSGQUEUE,
+ VIR_DOMAIN_RLIMIT_NICE,
+ VIR_DOMAIN_RLIMIT_RTPRIO,
+ VIR_DOMAIN_RLIMIT_RTTIME,
+
+ VIR_DOMAIN_RLIMIT_LAST
+} virDomainRLimit;
+
typedef struct _virDomainClockDef virDomainClockDef;
typedef virDomainClockDef *virDomainClockDefPtr;
struct _virDomainClockDef {
@@ -2039,6 +2060,14 @@ struct _virDomainPowerManagement {
int s4;
};
+typedef struct _virDomainRLimits virDomainRLimits;
+typedef virDomainRLimits *virDomainRLimitsPtr;
+
+struct _virDomainRLimits {
+ int resource;
+ long long limit;
+};
+
/*
* Guest VM main configuration
*
@@ -2156,6 +2185,9 @@ struct _virDomainDef {
size_t nshmems;
virDomainShmemDefPtr *shmems;
+ size_t nrlimits;
+ virDomainRLimitsPtr *rlimits;
+
/* Only 1 */
virDomainWatchdogDefPtr watchdog;
virDomainMemballoonDefPtr memballoon;
@@ -2844,6 +2876,7 @@ VIR_ENUM_DECL(virDomainRNGModel)
VIR_ENUM_DECL(virDomainRNGBackend)
VIR_ENUM_DECL(virDomainTPMModel)
VIR_ENUM_DECL(virDomainTPMBackend)
+VIR_ENUM_DECL(virDomainRLimit)
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainNostateReason)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index bd7870f..7b71ff1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1896,6 +1896,7 @@ virProcessGetNamespaces;
virProcessGetStartTime;
virProcessKill;
virProcessKillPainfully;
+virProcessPrLimit;
virProcessRunInMountNamespace;
virProcessSetAffinity;
virProcessSetMaxFiles;
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index 8a7c7e8..5c63a1b 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -798,6 +798,35 @@ static int virLXCControllerSetupCgroupLimits(virLXCControllerPtr ctrl)
return ret;
}
+static int virLXCControllerSetupRLimits(virLXCControllerPtr ctrl)
+{
+ int i, ret = -1;
+ struct rlimit rlim;
+
+ VIR_DEBUG("Setting up rlimits");
+
+ VIR_DEBUG("nrlimits = %d", (int)ctrl->def->nrlimits);
+ VIR_DEBUG("setting limits on process %d", ctrl->initpid);
+ if (ctrl->def->nrlimits > 0) {
+ for (i = 0; i < ctrl->def->nrlimits; i++) {
+ rlim.rlim_max = rlim.rlim_cur = ctrl->def->rlimits[i]->limit;
+ VIR_DEBUG("Setting rlimit %s(%d) on pid %d to %lld",
+ virDomainRLimitTypeToString(ctrl->def->rlimits[i]->resource),
+ ctrl->def->rlimits[i]->resource,
+ ctrl->initpid,
+ ctrl->def->rlimits[i]->limit);
+ if (virProcessPrLimit(ctrl->initpid, ctrl->def->rlimits[i]->resource, &rlim) < 0) {
+ virReportSystemError(errno, "%s",
+ _("Unable to set rlimit"));
+ goto cleanup;
+ }
+ }
+ }
+ ret = 0;
+ cleanup:
+ return ret;
+}
+
static void virLXCControllerClientCloseHook(virNetServerClientPtr client)
{
@@ -2318,6 +2347,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
if (virLXCControllerSetupCgroupLimits(ctrl) < 0)
goto cleanup;
+ if (virLXCControllerSetupRLimits(ctrl) < 0)
+ goto cleanup;
+
if (virLXCControllerSetupUserns(ctrl) < 0)
goto cleanup;
diff --git a/src/util/virprocess.c b/src/util/virprocess.c
index d0a1500..d83ae28 100644
--- a/src/util/virprocess.c
+++ b/src/util/virprocess.c
@@ -676,13 +676,13 @@ int virProcessSetNamespaces(size_t nfdlist,
}
#if HAVE_PRLIMIT
-static int
+int
virProcessPrLimit(pid_t pid, int resource, struct rlimit *rlim)
{
return prlimit(pid, resource, rlim, NULL);
}
#elif HAVE_SETRLIMIT
-static int
+int
virProcessPrLimit(pid_t pid ATTRIBUTE_UNUSED,
int resource ATTRIBUTE_UNUSED,
struct rlimit *rlim ATTRIBUTE_UNUSED)
diff --git a/src/util/virprocess.h b/src/util/virprocess.h
index bcaede5..c40b41a 100644
--- a/src/util/virprocess.h
+++ b/src/util/virprocess.h
@@ -22,6 +22,7 @@
#ifndef __VIR_PROCESS_H__
# define __VIR_PROCESS_H__
+# include <sys/resource.h>
# include <sys/types.h>
# include "internal.h"
@@ -73,4 +74,5 @@ typedef int (*virProcessNamespaceCallback)(pid_t pid, void *opaque);
int virProcessRunInMountNamespace(pid_t pid,
virProcessNamespaceCallback cb,
void *opaque);
+int virProcessPrLimit(pid_t pid, int resource, struct rlimit *rlim);
#endif /* __VIR_PROCESS_H__ */
--
1.9.3 (Apple Git-50)
9 years, 8 months
[libvirt] [PATCH] Fix reporting of i/o errors by iohelper process
by Jason J. Herne
From: "Jason J. Herne" <jjherne(a)us.ibm.com>
libvirt_iohelper is a helper process that is exec'ed and used to handle I/O
during a Qemu managed save operation. Due to a missing call to
virFileWrapperFdClose, all I/O error messages reported by iohelper are lost.
This patch adds a call to virFileWrapperFdClose to the cleanup phase of
qemuDomainSaveMemory.
This patch also modifies virFileWrapperFdClose such that errors are only
reported when the length of the err_msg buffer is > 0. Before now, the
existence of the buffer would trigger error reporting in virFileWrapperFdClose.
Signed-off-by: Jason J. Herne <jjherne(a)us.ibm.com>
---
src/qemu/qemu_driver.c | 1 +
src/util/virfile.c | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index ecccf6c..8d78805 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3015,6 +3015,7 @@ qemuDomainSaveMemory(virQEMUDriverPtr driver,
cleanup:
VIR_FORCE_CLOSE(fd);
+ virFileWrapperFdClose(wrapperFd);
virFileWrapperFdFree(wrapperFd);
VIR_FREE(xml);
diff --git a/src/util/virfile.c b/src/util/virfile.c
index 463064c..813b4f5 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -322,7 +322,7 @@ virFileWrapperFdClose(virFileWrapperFdPtr wfd)
return 0;
ret = virCommandWait(wfd->cmd, NULL);
- if (wfd->err_msg)
+ if (wfd->err_msg && strlen(wfd->err_msg))
VIR_WARN("iohelper reports: %s", wfd->err_msg);
return ret;
--
1.8.3.2
9 years, 9 months
[libvirt] Tunnelled post-copy live migration - support of bidirectional communication over the tunnel
by Vojtech Cima
Hello everyone,
we are very interested about the post-copy live migration mechanism in
libvirt [1] using QEMU. Mentioning post-copy in this context means the
setup with the first full iteration of standard pre-copy and then
switching to the post-copy. VIR_MIGRATE_ENABLE_POSTCOPY,
VIR_MIGRATE_POSTCOPY_AFTER_PRECOPY together with VIR_MIGRATE_TUNNELLED flag.
Recently we have noticed the issue that post-copy live migration doesn't
work over the tunnel since since current tunnel implementation in
libvirt supports only uni-directional communication. I spent some time
trying to enable bidirectional communication over the tunnel but still
facing several issues and I would appreciate any hints how to move forward.
The idea is to add a function (probably a callback function) responsible
for handling the traffic in the opposite direction (dest->src) reading
from the virStream and writing to the QEMU [2]. To be able to do so I
replaced the current 'pipe' calls with the 'socketpair' calls to create
bidirectional paths.
Now, trying to use tunnelled post-copy live migration, it gets
initiated, there is some traffic going from source to destination
(obviously the pre-copy phase) but at some point it gets stuck on the
'saferead' function [3] which is now blocking. Can this issue issue be
linked with the default socket blocking policy?
Trying to use standard 'read' function instead of 'saferead' results
that the lower data transfers and it seems it's missing significant part
of information.
Another point is that we suppose that the virStream on its own supports
bidirectional communication, is that correct?
[1] https://github.com/orbitfp7/qemu/tree/wp3-postcopy
[2]
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/qemu/qemu_migration.c;...
[3]
http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/qemu/qemu_migration.c;...
Thank you very much for any ideas on this topic.
Regards,
Vojtech
9 years, 9 months
[libvirt] [RFC PATCH 00/12] Add support for memory hotplug
by Peter Krempa
!! this series applies on top of the cleanup series posted earlier !!
Hi,
this is my try to implement memory hotplug in libvirt (for the qemu) driver.
This series is almost code-complete but is lacking tests and docs as I wanted
to agree on design first before attempting to write the documentation.
Additionally this series is also lacking code that would fix memballoon
handling but I'm waiting on a clousure how it's supposed to work from qemu's
side as it appears to be broken there too.
The basic XML used to add a memory device:
<memory model='acpi-dimm'>
<target>
<size unit='KiB'>524287</size>
<node>0</node>
</target>
</memory>
The <target> subelement is mandatory, whereas the <source> subelement (that
contains source numa nodes, source page size ) is optional and is inferred
from the NUMA tuning for given target numa node.
Please note that at least one guest numa node has to be configured for the
guest for this to work (limitation of qemu).
What's missing in this series:
- tests
- docs
- commit message touch-up
- code to audit the memory size changes
- code to make memory balloning working with correct size
Peter Krempa (12):
qemu: caps: Add capability bit for the "pc-dimm" device
conf: Add support for parsing and formatting max memory and slot count
qemu: Implement setup of memory hotplug parameters
conf: Add device address type for dimm devices
conf: Add interface to parse and format memory device information
qemu: memdev: Add infrastructure to load memory device information
qemu: migration: Forbid migration with memory modules lacking info
qemu: add support for memory devices
conf: Introduce helper to find duplicate device address
qemu: conf: Add support for memory device cold(un)plug
qemu: Implement memory device hotplug
qemu: Implement memory device hotunplug
docs/formatdomain.html.in | 19 +
docs/schemas/domaincommon.rng | 76 +++
src/bhyve/bhyve_domain.c | 9 +-
src/conf/domain_conf.c | 655 ++++++++++++++++++++-
src/conf/domain_conf.h | 63 ++
src/libvirt_private.syms | 7 +
src/libxl/libxl_domain.c | 8 +
src/lxc/lxc_domain.c | 8 +
src/openvz/openvz_driver.c | 14 +-
src/parallels/parallels_driver.c | 6 +-
src/phyp/phyp_driver.c | 6 +-
src/qemu/qemu_capabilities.c | 2 +
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 157 ++++-
src/qemu/qemu_command.h | 15 +
src/qemu/qemu_domain.c | 58 ++
src/qemu/qemu_domain.h | 6 +
src/qemu/qemu_driver.c | 29 +
src/qemu/qemu_hotplug.c | 178 ++++++
src/qemu/qemu_hotplug.h | 6 +
src/qemu/qemu_migration.c | 14 +
src/qemu/qemu_monitor.c | 45 ++
src/qemu/qemu_monitor.h | 14 +
src/qemu/qemu_monitor_json.c | 116 ++++
src/qemu/qemu_monitor_json.h | 5 +
src/qemu/qemu_process.c | 4 +
src/uml/uml_driver.c | 9 +-
src/vbox/vbox_common.c | 6 +-
src/vmware/vmware_driver.c | 6 +-
src/vmx/vmx.c | 6 +-
src/xen/xen_driver.c | 7 +
src/xenapi/xenapi_driver.c | 9 +-
tests/domainschemadata/maxMemory.xml | 19 +
tests/qemucapabilitiesdata/caps_2.1.1-1.caps | 1 +
.../qemuxml2argv-memory-hotplug-dimm.xml | 47 ++
.../qemuxml2argv-memory-hotplug-nonuma.xml | 22 +
.../qemuxml2argv-memory-hotplug.args | 6 +
.../qemuxml2argv-memory-hotplug.xml | 34 ++
tests/qemuxml2argvtest.c | 4 +
tests/qemuxml2xmltest.c | 4 +
40 files changed, 1682 insertions(+), 19 deletions(-)
create mode 100644 tests/domainschemadata/maxMemory.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-dimm.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug-nonuma.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-memory-hotplug.xml
--
2.2.2
9 years, 9 months
[libvirt] [PATCH v3] qemu: Pass file descriptor when using TPM passthrough
by Stefan Berger
Pass the TPM file descriptor to QEMU via command line.
Instead of passing /dev/tpm0 we now pass /dev/fdset/10 and the additional
parameters -add-fd set=10,fd=20.
This addresses the use case when QEMU is started with non-root privileges
and QEMU cannot open /dev/tpm0 for example.
One problem is that for the passing of the file descriptor set to work,
virCommandReorderFDs must not be called on the virCommand. This is prevented
by setting a flag in the virCommandPassFDGetFDIndex that is checked to be
clear when virCommandReorderFDs is run.
Signed-off-by: Stefan Berger <stefanb(a)linux.vnet.ibm.com>
v2->v3: Fixed some memory leaks
---
src/libvirt_private.syms | 1 +
src/qemu/qemu_command.c | 136 ++++++++++++++++++++++++++++++++++++++++++++---
src/util/vircommand.c | 33 ++++++++++++
src/util/vircommand.h | 3 ++
4 files changed, 166 insertions(+), 7 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index aeec440..3194e8b 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1164,6 +1164,7 @@ virCommandNewArgList;
virCommandNewArgs;
virCommandNonblockingFDs;
virCommandPassFD;
+virCommandPassFDGetFDIndex;
virCommandPassListenFDs;
virCommandRawStatus;
virCommandRequireHandshake;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 8ed7934..17debba 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -159,6 +159,58 @@ VIR_ENUM_IMPL(qemuNumaPolicy, VIR_DOMAIN_NUMATUNE_MEM_LAST,
"interleave");
/**
+ * qemuVirCommandGetFDSet:
+ * @cmd: the command to modify
+ * @fd: fd to reassign to the child
+ *
+ * Get the parameters for the QEMU -add-fd command line option
+ * for the given file descriptor. The file descriptor must previously
+ * have been 'transferred' in a virCommandPassFD() call.
+ * This function for example returns "set=10,fd=20".
+ */
+static char *
+qemuVirCommandGetFDSet(virCommandPtr cmd, int fd)
+{
+ char *result = NULL;
+ int idx = virCommandPassFDGetFDIndex(cmd, fd);
+
+ if (idx >= 0) {
+ ignore_value(virAsprintf(&result, "set=%d,fd=%d", idx, fd) < 0);
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("file descriptor %d has not been transferred"), fd);
+ }
+
+ return result;
+}
+
+/**
+ * qemuVirCommandGetDevSet:
+ * @cmd: the command to modify
+ * @fd: fd to reassign to the child
+ *
+ * Get the parameters for the QEMU path= parameter where a file
+ * descriptor is accessed via a file descriptor set, for example
+ * /dev/fdset/10. The file descriptor must previously have been
+ * 'transferred' in a virCommandPassFD() call.
+ */
+static char *
+qemuVirCommandGetDevSet(virCommandPtr cmd, int fd)
+{
+ char *result = NULL;
+ int idx = virCommandPassFDGetFDIndex(cmd, fd);
+
+ if (idx >= 0) {
+ ignore_value(virAsprintf(&result, "/dev/fdset/%d", idx) < 0);
+ } else {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("file descriptor %d has not been transferred"), fd);
+ }
+ return result;
+}
+
+
+/**
* qemuPhysIfaceConnect:
* @def: the definition of the VM (needed by 802.1Qbh and audit)
* @driver: pointer to the driver instance
@@ -5926,14 +5978,20 @@ qemuBuildRNGDeviceArgs(virCommandPtr cmd,
static char *qemuBuildTPMBackendStr(const virDomainDef *def,
+ virCommandPtr cmd,
virQEMUCapsPtr qemuCaps,
- const char *emulator)
+ const char *emulator,
+ int *tpmfd, int *cancelfd)
{
const virDomainTPMDef *tpm = def->tpm;
virBuffer buf = VIR_BUFFER_INITIALIZER;
const char *type = virDomainTPMBackendTypeToString(tpm->type);
- char *cancel_path;
+ char *cancel_path = NULL;
const char *tpmdev;
+ char *devset = NULL, *cancel_devset = NULL;
+
+ *tpmfd = -1;
+ *cancelfd = -1;
virBufferAsprintf(&buf, "%s,id=tpm-%s", type, tpm->info.alias);
@@ -5946,11 +6004,49 @@ static char *qemuBuildTPMBackendStr(const virDomainDef *def,
if (!(cancel_path = virTPMCreateCancelPath(tpmdev)))
goto error;
- virBufferAddLit(&buf, ",path=");
- virBufferEscape(&buf, ',', ",", "%s", tpmdev);
+ if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_ADD_FD)) {
+ *tpmfd = open(tpmdev, O_RDWR);
+ if (*tpmfd < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not open TPM device %s"), tpmdev);
+ goto error;
+ }
+
+ virCommandPassFD(cmd, *tpmfd,
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
+ devset = qemuVirCommandGetDevSet(cmd, *tpmfd);
+ if (devset == NULL)
+ goto error;
+
+ *cancelfd = open(cancel_path, O_WRONLY);
+ if (*cancelfd < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not open TPM device's cancel path "
+ "%s"), cancel_path);
+ goto error;
+ }
+
+ virCommandPassFD(cmd, *cancelfd,
+ VIR_COMMAND_PASS_FD_CLOSE_PARENT);
+ cancel_devset = qemuVirCommandGetDevSet(cmd, *cancelfd);
+ if (cancel_devset == NULL)
+ goto error;
+
+ virBufferAddLit(&buf, ",path=");
+ virBufferEscape(&buf, ',', ",", "%s", devset);
+ VIR_FREE(devset);
- virBufferAddLit(&buf, ",cancel-path=");
- virBufferEscape(&buf, ',', ",", "%s", cancel_path);
+ virBufferAddLit(&buf, ",cancel-path=");
+ virBufferEscape(&buf, ',', ",", "%s", cancel_devset);
+ VIR_FREE(cancel_devset);
+ } else {
+ /* all test cases will use this path */
+ virBufferAddLit(&buf, ",path=");
+ virBufferEscape(&buf, ',', ",", "%s", tpmdev);
+
+ virBufferAddLit(&buf, ",cancel-path=");
+ virBufferEscape(&buf, ',', ",", "%s", cancel_path);
+ }
VIR_FREE(cancel_path);
break;
@@ -5970,6 +6066,10 @@ static char *qemuBuildTPMBackendStr(const virDomainDef *def,
emulator, type);
error:
+ VIR_FREE(devset);
+ VIR_FREE(cancel_devset);
+ VIR_FREE(cancel_path);
+
virBufferFreeAndReset(&buf);
return NULL;
}
@@ -9223,13 +9323,35 @@ qemuBuildCommandLine(virConnectPtr conn,
if (def->tpm) {
char *optstr;
+ int tpmfd = -1;
+ int cancelfd = -1;
+ char *fdset;
- if (!(optstr = qemuBuildTPMBackendStr(def, qemuCaps, emulator)))
+ if (!(optstr = qemuBuildTPMBackendStr(def, cmd, qemuCaps, emulator,
+ &tpmfd, &cancelfd)))
goto error;
virCommandAddArgList(cmd, "-tpmdev", optstr, NULL);
VIR_FREE(optstr);
+ if (tpmfd >= 0) {
+ fdset = qemuVirCommandGetFDSet(cmd, tpmfd);
+ if (!fdset)
+ goto error;
+
+ virCommandAddArgList(cmd, "-add-fd", fdset, NULL);
+ VIR_FREE(fdset);
+ }
+
+ if (cancelfd >= 0) {
+ fdset = qemuVirCommandGetFDSet(cmd, cancelfd);
+ if (!fdset)
+ goto error;
+
+ virCommandAddArgList(cmd, "-add-fd", fdset, NULL);
+ VIR_FREE(fdset);
+ }
+
if (!(optstr = qemuBuildTPMDevStr(def, qemuCaps, emulator)))
goto error;
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index 6527d85..2616446 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -67,6 +67,7 @@ enum {
VIR_EXEC_RUN_SYNC = (1 << 3),
VIR_EXEC_ASYNC_IO = (1 << 4),
VIR_EXEC_LISTEN_FDS = (1 << 5),
+ VIR_EXEC_FIXED_FDS = (1 << 6),
};
typedef struct _virCommandFD virCommandFD;
@@ -214,6 +215,12 @@ virCommandReorderFDs(virCommandPtr cmd)
if (!cmd || cmd->has_error || !cmd->npassfd)
return;
+ if ((cmd->flags & VIR_EXEC_FIXED_FDS)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("The fds are fixed and cannot be reordered"));
+ goto error;
+ }
+
for (i = 0; i < cmd->npassfd; i++)
maxfd = MAX(cmd->passfd[i].fd, maxfd);
@@ -1019,6 +1026,32 @@ virCommandPassListenFDs(virCommandPtr cmd)
cmd->flags |= VIR_EXEC_LISTEN_FDS;
}
+/*
+ * virCommandPassFDGetFDIndex:
+ * @cmd: pointer to virCommand
+ * @fd: FD to get index of
+ *
+ * Determine the index of the FD in the transfer set.
+ *
+ * Returns index >= 0 if @set contains @fd,
+ * -1 otherwise.
+ */
+int
+virCommandPassFDGetFDIndex(virCommandPtr cmd, int fd)
+{
+ size_t i = 0;
+
+ while (i < cmd->npassfd) {
+ if (cmd->passfd[i].fd == fd) {
+ cmd->flags |= VIR_EXEC_FIXED_FDS;
+ return i;
+ }
+ i++;
+ }
+
+ return -1;
+}
+
/**
* virCommandSetPidFile:
* @cmd: the command to modify
diff --git a/src/util/vircommand.h b/src/util/vircommand.h
index bf65de4..198da2f 100644
--- a/src/util/vircommand.h
+++ b/src/util/vircommand.h
@@ -62,6 +62,9 @@ void virCommandPassFD(virCommandPtr cmd,
void virCommandPassListenFDs(virCommandPtr cmd);
+int virCommandPassFDGetFDIndex(virCommandPtr cmd,
+ int fd);
+
void virCommandSetPidFile(virCommandPtr cmd,
const char *pidfile) ATTRIBUTE_NONNULL(2);
--
1.9.3
9 years, 9 months