[libvirt] [PATCH v2] qemu: Don't fail to shutdown domains with unresponsive agent
by Michal Privoznik
Currently, qemuDomainShutdownFlags() chooses the agent method of
shutdown whenever the agent is configured. However, this
assumption is not enough as the guest agent may be unresponsive
at the moment. So unless guest agent method has been explicitly
requested, we should fall back to the ACPI method.
---
diff to v1:
- Rework some conditions as Eric suggested in v1
src/qemu/qemu_driver.c | 38 ++++++++++++++++++++++----------------
1 file changed, 22 insertions(+), 16 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1e96915..1e96aa4 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1702,40 +1702,40 @@ static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags) {
virDomainObjPtr vm;
int ret = -1;
qemuDomainObjPrivatePtr priv;
- bool useAgent = false;
+ bool useAgent = false, agentRequested, acpiRequested;
virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, -1);
- /* At most one of these two flags should be set. */
- if ((flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) &&
- (flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT)) {
- virReportInvalidArg(flags, "%s",
- _("flags for acpi power button and guest agent are mutually exclusive"));
- return -1;
- }
-
if (!(vm = qemuDomObjFromDomain(dom)))
goto cleanup;
priv = vm->privateData;
+ agentRequested = flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT;
+ acpiRequested = flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN;
- if ((flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT) ||
- (!(flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) &&
- priv->agent))
+ /* Prefer agent unless we were requested to not to. */
+ if (agentRequested || (!flags && priv->agent))
useAgent = true;
- if (useAgent) {
- if (priv->agentError) {
+ if (priv->agentError) {
+ if (agentRequested && !acpiRequested) {
virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
_("QEMU guest agent is not "
"available due to an error"));
goto cleanup;
+ } else {
+ useAgent = false;
}
- if (!priv->agent) {
+ }
+
+ if (!priv->agent) {
+ if (agentRequested && !acpiRequested) {
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
_("QEMU guest agent is not configured"));
goto cleanup;
+ } else {
+ useAgent = false;
}
}
@@ -1752,7 +1752,13 @@ static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags) {
qemuDomainObjEnterAgent(vm);
ret = qemuAgentShutdown(priv->agent, QEMU_AGENT_SHUTDOWN_POWERDOWN);
qemuDomainObjExitAgent(vm);
- } else {
+ }
+
+ /* If we are not enforced to use just an agent, try ACPI
+ * shutdown as well in case agent did not succeed.
+ */
+ if (!useAgent ||
+ (ret < 0 && (acpiRequested || !flags))) {
qemuDomainSetFakeReboot(driver, vm, false);
qemuDomainObjEnterMonitor(driver, vm);
--
1.8.1.4
11 years, 7 months
[libvirt] a script for libvirt-llxc + systemd on Fedora18
by Kamezawa Hiroyuki
Hi.
At playing libvirt-lxc on Fedora18, I found that the user needs
some workarounds to run /sbin/init as the root process of container.
With Fedora15, I found this https://gist.github.com/peo3/1142202.
And I know virt-sandbox-service have some clever way to understand RPM
to make domain running with a service.
Here is a script I wrote for F18 inspired by above two. Creating
LXC domain running systemd as /init program. I'd like to get
some feedback....and ...can't this kind of scripts be maintained by some
virt-tools project ?
Anyway, playing with lxc is fun. I'm glad if someone makes this script better :)
==
A user can create a lxc container by
# ./lxc_systemd_setup.py -r -n Test
This will generate my.xml and lxc file tree on /opt/lxc/Test
# virsh -c lxc:/// define my.xml
# virsh -c lxc:/// start my.xml
This domain has following characteristics
- /usr is bind mounted to host's /usr
- all files other than files in /usr are copied
- systemd and pam modules are tweaked a bit
- eth0 is up by dhcp.
- systemd, rsyslog, sshd is running.
Users can add rpm package as
# ./lxc_systemd_setup.py -r -n Test -a httpd
some options may not work because of my bad skills.
==lxc_systemd_setup.py==
#!/usr/bin/python
#
# A scripts for creating LXC domain where some daemons are running under systemd.
# Tested with Fedora18, running systemd, rsyslog, sshd in a container at default.
#
# Most config files, including all security settings as passwd, selinux,
# ssl/pki files are copied from the host. So, please fix them before
# running a domain.
#
# New root dir will be /opt/lxc/<domain name> at default and domain XML
# definition will be saved as my.xml
#
# All instllation under /usr is shared among containres/host, binaries are
# not copied at all. /etc and /var are copied. So, you can adjust config files
# under container as you like.
#
# for easy creation, run
# # lxc_systemd_setup.py -n Test -r
# # virsh -c lxc:/// define my.xml
# # virsh -c lxc:/// start Test --console
#
# This will build a lxc root filesystem under /opt/lxc/Test and copy
# required files under it. /usr will be shared with the host.
#
# to add some packages, pass package name with '-a' option. But this script doesn't
# handle dependency of RPM, at all. please take care of it.
#
# for running httpd.
# # lxc_systemd_setup.py -n Test -r -a httpd
# _and_ you need to fix hostname lookup problem to run httpd. i.e. you may need to fix
# some files under /etc....
#
# please see
# # lxc_systemd_setup.py --help
# for other options. some may not work ;)
#
import sys, os, shutil
from subprocess import Popen, PIPE
from optparse import OptionParser,OptionGroup
import re
import rpm
parser = OptionParser()
parser.add_option('-p', '--prefix', action='store', default='/opt/lxc',
type='string', dest='pathname', help='prefix of guest root path')
parser.add_option('-n', '--name', action='store', default='_unknown',
type='string', dest='domain_name', help='name of domain')
parser.add_option('-o', '--out', action='store', default='my.xml',
type='string', dest='def_file', help='name of generated xml def')
parser.add_option('-r', '--renew', action='store_true', default=False,
dest='renew_tree', help='delete existing tree if exists')
parser.add_option('-D', '--destroy', action='store_true', default=False,
dest='destroy_tree', help='destroy existing tree and quit')
parser.add_option('-f', '--force', action='store_true', default=False,
dest='force', help='update all files without checking timestamp')
parser.add_option('-a','--add-packages', action='append',
type='string', dest='package_list', help='copy package config to container')
parser.add_option('-s','--skip-packages', action='append',
type='string', dest='skip_list', help='skip packages')
parser.add_option('-m','--memory', action='store', default='1024000',
type='str', dest='memory', help='memory size of domain')
parser.add_option('-H','--hostname', action='store', default='lxc',
type='str', dest='hostname', help='hostname of domain')
(options, args) = parser.parse_args(sys.argv)
#
# Utility functions.
#
#
# Remove all files under domain ROOT.
#
def destroy_all(path) :
if (not os.path.exists(path)) :
return
shutil.rmtree(path, ignore_errors=True)
#
# Check a file in a container is newer than hosts.
#
def file_is_newer(a, b) :
time_a = os.stat(a).st_mtime
time_b = os.stat(b).st_mtime
return a > b
#
# Check Host's distro.
#
def check_version() :
useRPM=True
version="unknown"
if (os.path.exists('/etc/redhat-release')) :
with open('/etc/redhat-release') as f:
version_string = f.readline()
if (re.match("Fedora release 18.+$", version_string)) :
version = "Fedora18"
else :
useRPM=False
return (version, useRPM)
#
# directories created at domain creation (tested with Fedora 18)
#
ROOTDIR= options.pathname + "/" + options.domain_name
class InstallInfo :
def __init__(self) :
self.DIRS = []
self.BINDDIRS = []
self.SYMLINKS=[]
self.PACKAGES = []
self.FILES = []
self.MERGED = []
def add_dirs(self, x) :
if (isinstance(x, str)) :
x = [x]
self.DIRS = self.DIRS + x
def dirs(self) :
return self.DIRS
def add_files(self, x) :
if (isinstance(x, str)) :
x = [x]
self.FILES += x
def files(self) :
return self.FILES
def add_binds(self, x) :
if (isinstance(x, str)) :
x = [x]
self.BINDDIRS = self.BINDDIRS + x
def binds(self) :
return self.BINDDIRS
def add_links(self, x) :
self.SYMLINKS = self.SYMLINKS + x
def links(self) :
return self.SYMLINKS
def add_packages(self, x) :
self.PACKAGES = self.PACKAGES + x
def packages(self) :
return self.PACKAGES
def merge(self) :
self.DIRS = list(set(self.DIRS))
self.FILES = list(set(self.FILES))
self.BINDDIRS = sorted(list(set(self.BINDDIRS)))
ret = True
ents =[]
paths = []
for ent in self.DIRS :
ents.append((ent, 'dir', ''))
paths.append(ent)
for ent in self.FILES :
ents.append((ent, 'file', ''))
paths.append(ent)
for ent in self.SYMLINKS :
ents.append((ent[0], 'link', ent[1]))
paths.append(ent[0])
if (len(paths) - len(list(set(paths)))) :
ret = False
self.MERGED = sorted(ents)
return ret
def merged(self) :
return self.MERGED
#
# Gather RPM information and copy config files to proper place.
#
class CopyRPMHandler:
def __init__(self, name) :
self.name = name
self.files = []
self.service = ""
def verify(self) :
ts = rpm.TransactionSet()
mi = ts.dbMatch('name', self.name)
if not mi :
return False
# get list of files.
for h in mi :
myhead = h
break
fi = myhead.fiFromHeader()
for x in fi :
self.files.append(x[0]);
self.test_service()
self.strip_binds()
return True
def paths(self) :
return self.files
#
# check all files in RPM which are not under bind-mount.
#
def strip_binds(self) :
# remove all ents under /usr for avoiding copy.
temp = self.files
self.files = []
for file in temp :
if (file == '') :
continue
if (re.match("/usr/.+$", file)) :
continue
if (re.match("/bin/.+$", file)) :
continue
if (re.match("/lib/.+$", file)) :
continue
if (re.match("/sbin/.+$", file)) :
continue
if (re.match("/lib64/.+$", file)) :
continue
self.files.append(file)
self.files.sort()
return
def test_service(self) :
for file in self.files :
if (re.match("/usr/lib/systemd/system.+\.service$", file)) :
ent.service = file
#
# Functions for workarounds.
#
#
# systemd: create our own basic.target for avoiding some startups.
#
def systemd_tune() :
#
# we need to avoid some special services by systemd.
# modify basic.target and avoid them.
#
filename = ROOTDIR + "/etc/systemd/system/basic.target"
data="""[Unit]
Description=Basic System
Documentation=man:systemd.special(7)
Requires=systemd-tmpfiles-setup.service sockets.target
After=systemd-tmpfiles-setup.service sockets.target
RefuseManualStart=yes
"""
with open(filename,"w") as f:
f.write(data)
#
# we need getty only with tty1
#
os.symlink("/usr/lib/systemd/system/getty@.service",
ROOTDIR + "/etc/systemd/system/getty.target.wants/getty(a)tty1.service")
#
# Create ifcfg-eth0 and add service to bring up it.
#
def eth0_service() :
#
# /etc/sysconfig/network is generated by annaconda and we cannot
# find it by rpms.
#
filename = ROOTDIR + "/etc/sysconfig/network"
shutil.copy("/etc/sysconfig/network", filename);
#
# ifconfig setting for eth0
#
filename = ROOTDIR + "/etc/sysconfig/network-scripts/ifcfg-eth0"
data="""DEVICE=eth0
BOOTPROTO=dhcp
ONBOOT=yes
NAME=eth0
TYPE=Ethernet
"""
with open(filename, "w") as f:
f.write(data)
print "Creating %s" % filename
filename = ROOTDIR + "/etc/systemd/system/lxc-eth0.service"
data="""[Unit]
Before=multi-user.target
Conflicts=shutdown.target
Description=bring up eth0 in this container
[Service]
ExecStart=/usr/sbin/ifup eth0
Type=simple
"""
with open(filename, "w") as f:
f.write(data)
print "Creating %s" % filename
#
# Bring up this.
#
filename = ROOTDIR + "/etc/systemd/system/basic.target.wants/lxc-eth0.service"
src = "/etc/systemd/system/lxc-eth0.service"
os.symlink(src, filename)
#
# Make fstab empty
#
def empty_fstab() :
filename = ROOTDIR + "/etc/fstab"
with open(filename, "w") as f:
f.truncate(0)
#
# in Fedora18, pam's pam_loginuid.so doesn't work under container
# we need to disable it.
#
def pam_tune() :
pamdir = ROOTDIR + "/etc/pam.d"
for root, dirs, files in os.walk(pamdir) :
for path in files :
path = root + "/" + path
if (os.path.islink(path)) :
continue
data =""
with open(path) as f:
for line in f :
if (re.match("^.+pam_loginuid.so.*$", line)) :
line = "#" + line
data += line
with open(path, "w") as f:
f.write(data)
#
# securetty set up for login via system console.
#
def securetty_tune() :
path = ROOTDIR + "/etc/securetty"
with open(path, "a") as f:
f.write("pts/0\n")
#
# set hostname of guest domain.
#
def hostname_modify() :
path = ROOTDIR + "/etc/hostname"
with open(path, "w") as f:
f.write(options.hostname + "\n")
#
# parse memory size.
#
def parse_memory(data) :
if data[-1] == 'K' :
x = int(data[0:-1])
return str(x * 1024)
elif data[-1] == 'M' :
x = int(data[0:-1])
return str(x * 1024 * 1024)
elif data[-1] == 'G' :
x = int(data[0:-1])
return str(x * 1024 * 1024 * 1024)
else :
return data
#
# Main routine starts here !
#
version, useRPM = check_version()
if (not useRPM) :
print 'now, we can handle RPM only'
exit(1)
info = InstallInfo()
# Build a information.
#
# At first, gather required RPM information and some tweaks for distro.
#
if (version == 'Fedora18') :
#
# now, dont'handle yum and rpm info in container, so create fake dirs
# instead of copying yum info by RPM.
#
info.add_dirs(["/etc/yum", "/etc/yum/protected.d",
"/etc/yum/pluginconf.d","/etc/yum/vars"])
#
# We share /usr between host and guest.
#
info.add_binds(["/usr"])
#
# For Fedora18, we need following copies of configs packages at least.
#
info.add_packages(["filesystem","setup","rpm", "selinux-policy"])
info.add_packages(["systemd", "dbus", "initscripts","util-linux"])
info.add_packages(["pam","passwd", "crontabs","kmod","logrotate","rsyslog"])
info.add_packages(["openssh","openssh-server", "chkconfig","authconfig"])
info.add_packages(["glibc", "mailcap"])
# symlink and dirs for systemd
info.add_links([["/etc/systemd/system/default.target",
"/lib/systemd/system/multi-user.target"]])
info.add_dirs(["/etc/systemd/system/basic.target.wants"])
info.add_dirs(["/etc/systemd/system/default.target.wants"])
info.add_dirs(["/etc/systemd/system/getty.target.wants"])
info.add_dirs(["/etc/systemd/system/multi-user.target.wants"])
info.add_dirs(["/etc/systemd/system/sockets.target.wants"])
info.add_dirs(["/etc/systemd/system/sysinit.target.wants"])
info.add_dirs(["/etc/systemd/system/system-update.target.wants"])
#
# Merge package list
#
package_names = info.packages()
if (options.package_list) :
package_names += options.package_list
# Uniq.
package_names = list(set(package_names))
#
# delete unnecessary packages from list.
#
if (options.skip_list) :
for name in options.skip_list :
if (name in package_names) :
package_names.remove(name)
#
# Verify package list (check installation of packages)
#
packages = []
error = False
if (useRPM) :
for name in package_names :
ent = CopyRPMHandler(name)
if (ent.verify()) :
packages.append(ent)
else :
print "Couldn't find a package [%s] in RPM DB." % (name)
error = True
if (error) :
exit(1)
#
# Now, we confirmed all RPMS required are installed in the host.
#
service_files = []
#
# Extract dir,symlink,file information from RPMS. Later, we'll copy all
# files other than /usr.
#
for ent in packages :
for path in ent.paths() :
if (not os.path.exists(path)) :
continue
if (os.path.islink(path)) :
src = os.readlink(path)
info.add_links([[path, src]])
elif (os.path.isfile(path)) :
info.add_files(path)
elif (os.path.isdir(path)) :
info.add_dirs(path)
if (ent.service != ""):
service_files.append(ent.service)
#
# Uniq and sort it.
#
if (not info.merge()) :
print "some confilction of files may happen..."
#
# Check Domain name is passed.
#
if (options.domain_name == '_unknown') :
print "Guest Domain name must be specified"
exit(1)
#
# Destroy tree.
#
if (options.destroy_tree) :
destroy_all(ROOTDIR)
exit(0)
#
# At first, clear tree if required.
# (*) the scirpt may not work if we don't destroy the tree ....
#
if (os.path.exists(ROOTDIR)) :
if (options.renew_tree) :
destroy_all(ROOTDIR)
# Create root dir
try:
os.mkdir(ROOTDIR)
except:
print "cannot create root dir %s" % ROOTDIR
exit(1)
# Ok, make world based on information gathered from RPMS.
for ents in info.merged() :
guestpath = ROOTDIR + ents[0]
try:
if (ents[1] == 'dir') :
if (not os.path.exists(guestpath)) :
print "Creating dir %s" % (guestpath)
os.makedirs(guestpath)
elif (ents[1] == 'link') :
if (not os.path.exists(guestpath)) :
print "Creating symlink %s => %s" % (guestpath, ents[2])
os.symlink(ents[2], guestpath)
elif (ents[1] == 'file') :
if (options.force or
not os.path.exists(guestpath) or
file_is_newer(ents[0], guestpath)) :
print "Copyfile %s" % (guestpath)
shutil.copy(ents[0], guestpath)
except:
print "error at creating tree %s" % guestpath
exit(1)
#
# setup service files if necessary.
#
for file in service_files :
service = os.path.basename(file)
p = re.compile('WantedBy=(.+)$')
for line in open(file, 'r') :
m = p.match(line)
if (m) :
target = m.group(1)
pathname = ROOTDIR + "/etc/systemd/system/" + target + ".wants/" + service
print "%s=>%s" % (pathname, file)
os.symlink(file, pathname)
#
# Tweak system settings.
#
if (version == "Fedora18") :
# diable some services.
dir = ROOTDIR + "/etc/systemd/system/"
os.symlink("/dev/null", dir + "sysinit.target")
os.symlink("/dev/null", dir + "console-shell.service")
os.symlink("/dev/null", dir + "fedora-readonly.service")
os.symlink("/dev/null", dir + "fedora-storage-init.service")
systemd_tune() # modify basic.target etc...
eth0_service() # bringup eth0 without udev
empty_fstab() # make /etc/fstab empty
pam_tune() # disable some pam module
securetty_tune() # add pts/0 to securetty
hostname_modify()
#
# Generate a Domain Def.
#
domain = r"""
<domain type='lxc'>
<name>%(NAME)s</name>
<memory unit='bytes'>%(MEMORY)s</memory>
<vcpu>1</vcpu>
<os>
<type arch='x86_64'>exe</type>
<init>/sbin/init</init>
</os>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<devices>
<emulator>/usr/libexec/libvirt_lxc</emulator>
<filesystem type='mount' accessmode='passthrough'>
<source dir='%(ROOTDIR)s'/>
<target dir='/'/>
</filesystem>
<filesystem type='mount' accessmode='passthrough'>
<source dir='/usr'/>
<target dir='/usr'/>
</filesystem>
<filesystem type='ram'>
<source usage='%(MEMORY)s'/>
<target dir='/tmp'/>
</filesystem>
<filesystem type='ram'>
<source usage='%(MEMORY)s'/>
<target dir='/dev/shm'/>
</filesystem>
<interface type="network">
<source network="default"/>
</interface>
<console type='pty'>
<target type='lxc' port='0'/>
</console>
</devices>
</domain>
""" % {'NAME':options.domain_name,
'MEMORY': parse_memory(options.memory),
'ROOTDIR':ROOTDIR}
with open(options.def_file, "w") as f :
f.write(domain)
11 years, 7 months
[libvirt] [PATCH] qemu: virConnectGetVersion returns bogus value
by Viktor Mihajlovski
The unitialized local variable qemuVersion can cause an random value
to be returned for the hypervisor version, observable with virsh version.
Introduced by commit b46f7f4a0b96c2d2d01d64d960bd7bc90dc16b0c
Signed-off-by: Viktor Mihajlovski <mihajlov(a)linux.vnet.ibm.com>
---
src/qemu/qemu_driver.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0f6a431..825babd 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1382,7 +1382,7 @@ cleanup:
static int qemuGetVersion(virConnectPtr conn, unsigned long *version) {
virQEMUDriverPtr driver = conn->privateData;
int ret = -1;
- unsigned int qemuVersion;
+ unsigned int qemuVersion = 0;
virCapsPtr caps = NULL;
if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
--
1.7.9.5
11 years, 7 months
[libvirt] [PATCH 1/1] Remove contiguous CPU indexes assumption
by Li Zhang
From: Li Zhang <zhlcindy(a)linux.vnet.ibm.com>
When getting CPUs' information, it assumes that CPU indexes
are not contiguous. But for ppc64 platform, CPU indexes are not
contiguous because SMT is needed to be disabled, so CPU information
is not right on ppc64 and vpuinfo, vcpupin can't work corretly.
This patch is to remove the assumption to be compatible with ppc64.
Test:
4 vcpus are assigned to one VM and execute vcpuinfo command.
Without patch: There is only one vcpu informaion can be listed.
With patch: All vcpus' information can be listed correctly.
Signed-off-by: Li Zhang <zhlcindy(a)linux.vnet.ibm.com>
---
src/qemu/qemu_monitor_json.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 9991a0a..e130f8c 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -1230,13 +1230,6 @@ qemuMonitorJSONExtractCPUInfo(virJSONValuePtr reply,
goto cleanup;
}
- if (cpu != i) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("unexpected cpu index %d expecting %d"),
- i, cpu);
- goto cleanup;
- }
-
threads[i] = thread;
}
--
1.7.10.1
11 years, 7 months
[libvirt] [PATCH 0/4] Add cpuset support for LXC
by Gao feng
This patchset intend to add cpuset support for LXC.
in order to don't create too many redundant codes,
this patchset also rename some functions.
Gao feng (4):
rename qemuGetNumadAdvice to virDomainGetNumadAdvice
LXC: allow uses advisory nodeset from querying numad
remove the redundant codes
LXC: add cpuset support for lxc
src/conf/domain_conf.c | 144 ++++++++++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 4 ++
src/libvirt_private.syms | 3 +-
src/lxc/lxc_cgroup.c | 58 ++++++++++++++++-
src/lxc/lxc_cgroup.h | 2 +-
src/lxc/lxc_controller.c | 117 +++++++++--------------------------
src/qemu/qemu_process.c | 158 ++---------------------------------------------
7 files changed, 242 insertions(+), 244 deletions(-)
--
1.7.11.7
11 years, 7 months
[libvirt] [PATCH] maint: fix typo in network docs
by Eric Blake
* docs/formatnetwork.html.in: Spell variation correctly.
---
Pushing under the trivial rule.
docs/formatnetwork.html.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 41a83fa..4dd0415 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -780,7 +780,7 @@
</network></pre>
<p>
- Below is another IPv6 varition. Instead of a dhcp range being
+ Below is another IPv6 variation. Instead of a dhcp range being
specified, this example has a couple of IPv6 host definitions.
Note that most of the dhcp host definitions use an "id" (client
id or DUID) since this has proven to be a more reliable way
--
1.8.1.2
11 years, 7 months
[libvirt] Compile libvirt V1.0.1 error
by harryxiyou
Hi all,
When i compiled libvirt like following
1. git clone git://libvirt.org/libvirt.git;cd libvirt
2. git reset --hard v1.0.1
3. wget http://cloudxy.googlecode.com/svn/branches/hlfs/person/harry/hlfs/patches...
4. wget http://cloudxy.googlecode.com/svn/branches/hlfs/person/harry/hlfs/patches...
5. git apply hlfs_driver_for_libvirt_network_disk.patch
6. git apply hlfs_driver_for_libvirt_add_classpath.patch
7. ./autogen.sh
8. ./configure
9. make
i got following errors.
[...]
cc1: error: AVA_HOME/include: No such file or directory [-Werror]
cc1: error: AVA_HOME/include/linux: No such file or directory [-Werror]
cc1: all warnings being treated as errors
make[3]: *** [libvirt_driver_storage_impl_la-storage_driver.lo] Error 1
make[3]: Leaving directory `/home/jiawei/workshop1/libvirt/src'
make[2]: *** [all] Error 2
make[2]: Leaving directory `/home/jiawei/workshop1/libvirt/src'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/home/jiawei/workshop1/libvirt'
make: *** [all] Error 2
It seems that the errors have no relationship with HLFS(the patches i patched)
but AVA_HOME.
Could anyone give me some suggestions? Thanks in advance ;-)
--
Thanks
Harry Wei
11 years, 7 months
Re: [libvirt] [Dnsmasq-discuss] Chaining instances?
by Laine Stump
This discussion should really be taking place on libvir-list - I'm
Cc'ing it there.
On 02/24/2013 04:11 PM, TJ wrote:
> On 24/02/13 19:19, Laine Stump wrote:
>> On 02/24/2013 05:09 AM, TJ wrote:
>>> I wondered if maybe configuring the libvirtd dnsmasq instances to be dhcp proxies for the LAN dnsmasq, and use multiple dhcp-range's with tags might do it?
>>>
>>> My brain is a bit fried right now having had to fix several bugs in vmbuilder and libvirt, plus add new functionality to libvirtd to allow its dnsmasq instance to read a conf-file and use a separate log-facility,
>> What you're talking about doing sounds *very* useful to have supported
>> directly in libvirt, but you may want to contact libvirt's upstream
>> developers (at libvir-list(a)redhat.com, or on irc.oftc.net in #virt)
>> prior to expending a lot of effort on libvirt code - in general a
>> problem may already be solved in a different manner, or somebody else
>> may already be working on it. Failing that, there may have already been
>> considerable debate on a particular subject, and a path to a solution
>> generally agreed on, but with nobody yet working on the code.
> It turns out that what I need(ed) to do was completely *disable* libvirt's use of dnsmasq
> and instead use Simon's related "dhcp-helper" program which acts as a full dhcp-relay using, f.e:
>
> /usr/sbin/dhcp-helper -u libvirt-dnsmasq -i virbr1 -b eth0
>
> This forwards all requests to the primary dnsmasq DHCP server on the LAN which matches against the
> appropriate dhcp-range:
>
> # physical network leases
> dhcp-range=set:phys,10.254.251.50,10.254.251.199,255.255.255.0,1440m
> # subnet for VMs on server1
> dhcp-range=set:vmlan1,10.254.1.100,10.254.1.199,255.255.255.0,1440m
> # default route (gateway)
> dhcp-option=tag:phys,option:router,10.254.251.1
> dhcp-option=tag:vmlan1,option:router,10.254.1.1
> # DNS server
> dhcp-option=6,10.254.251.1
>
>
> To that end this evening I added two additional options to libvirt:
>
> <dnsmasq enabled='true'/>
> <dhcphelper enabled='false'/>
libvirt's XML should remain implementation-agnostic. We don't want to
have an option to disable the specific implementation of dns+dhcp called
"dnsmasq"; rather we want to be able to enable/disable a network's dhcp
server and/or dns server. (The reason for this is that we want to leave
the door open for someone to implement a different backend using a
different dhcp server and/or dns server and be able to use the same
configuration.)
We have actually previously discussed disabling dns and/or dhcp (see
http://www.redhat.com/archives/libvir-list/2012-November/msg00861.html).
It is already possible to completely disable dhcp - simply don't include
a <dhcp> element in the network definition. As for dns, from the very
beginning dns has been *always* enabled on all networks, so even though
there is a <dns> element, simply having not having one is not a valid
way to say "no dns server" (as it would cause backward compatibility
problems with existing installations).
Instead, the conclusion of the above-mentioned thread was that the
proper way to handle this would be to add an "enable" element to the
existing <dns> element, which would default to "yes". To disable
libvirt-supplied dns services for a subnet, you would just put:
<dns enable='no'/>
in the network definition. In the case that dns had enable='no' AND
there was no <dhcp> element, dnsmasq simply wouldn't be started at all.
That hasn't been implemented yet, but shouldn't be too complex to do.
As for dhcp-helper, aside from the fact that again you've created an
option that is specific to a particular implementation of what is
needed, that command isn't universally available anyway (it's not in any
package for Fedora/RHEL, for example), and I'm not sure that it's really
necessary to have it started up by libvirt anyway - can it detect newly
created/upped interfaces as dnsmasq can? If so, it could be started up
by regular host system config even before libvirt was started.
>
> These are the default values when the options are *not* defined. They allow the admin to disable dnsmasq entirely:
>
> <dnsmasq enabled='false'/>
>
> and to enable dhcp-helper:
>
> <dhcphelper enabled='true'/>
>
> Using two new functions:
>
> int networkBuildDhcphelperArgv(...)
> int networkBuildDhcpHelperCommandLine(...)
>
> the existing function:
>
> int networkStartDhcpDaemon(...)
>
> is able to launch either or both of dnsmasq and dhcp-helper with the correct options.
>
> dhcp-helper's "-i" option is filled from network->def->bridge and its "-b" option is taken from
> the first forward device declared in a <forward dev='?'/> or <interface dev='?'/>. If no forward
> device is declared it throws a VIR_ERR_INVALID_INTERFACE error with appropriate explanatory text.
>
>
>
11 years, 7 months
[libvirt] q35 machine type and libvirt.
by Laine Stump
Now that qemu is getting the q35 machine type, libvirt needs to support it.
As far as I understand, from libvirt's point of view, q35 is just another x86_64 system, but with a different set of implicit devices, and possibly some extra rules limiting which devices can be plugged into which bus/slot on the guest. That means that in order to support it, we will need to recognize when a q35-based machine type is being created, and auto-add all the implicit devices to libvirt's config model for that domain, then pay attention to the extra rules when assigning addresses for all the user-added devices.
We already add implicit controllers/devices for pc-based machine types; as a matter of fact, currently, libvirt improperly assumes (for the purposes of adding implicit devices) that *every* virtual machine is based on the "pc" machine type (or rather it just doesn't pay attention), so it always adds all the implicit devices for a pc machine type for every domain. This of course is already incorrect for many (probably all?) non-x86 machine types, even before we add q35 into the mix. To fix this, it might be reasonable (and arguably, it's necessary to fix the problem in a backward-compatible manner) to just setup a table of machinetype ==> implicit device lists, look up the machine type in this table, and add the devices needed for that machine type. This goes against libvirt's longstanding view of machinetype as being an opaque value that it merely passes through to qemu, but it's manageable for the existing machine types (even including q35), since it's a finite set. But it starts to be a pain to maintain when you think about future additions - yet another case where new functionality in qemu will require an update to libvirt before it can be fully used via libvirt.
In the long term, it would be very useful / more easily maintainable to have a qemu status command available via QMP which would return the list of implicit devices (and their PCI addresses) for any requested machine type. It would be necessary that this command be callable multiple times within a single execution of qemu, giving it a different machinetype each time. This way libvirt could first query the list of available machinetypes in this particular qemu binary, then request the list of implicit devices for each machine type (libvirt runs each available qemu binary *once* the first time it's requested, and caches all such capabilities information so that it doesn't need to re-run qemu again and again). My limited understanding of qemu's code is that qemu itself doesn't have a table of this information as data, but instead has lines of code that are executed to create it, thus making it impractical to provide the list of devices for a machinetype without actually instantiating a machine of that type. What's the feasibility of adding such a capability (and in the process likely making the list of implicit devices in qemu itself table/data driven rather than constructed with lines of code).
More questions:
1) It seems that the exact list of devices for the basic q35 machine type hasn't been settled on yet, is that correct?
2) Are there other issues aside from implicit controller devices I need to consider for q35? For example, are there any devices that (as I recall is the case for some devices on "pc") may or may not be present, but if they are present they are always at a particular PCI address (meaning that address must be reserved)? I've also just learned that certain types of PCIe devices must be plugged into certain locations on the guest bus? ("root complex" devices - is there a good source of background info to learn the meaning of terms like that, and the rules of engagement? libvirt will need to know/follow these rules.)
3) What new types of devices/controllers must be supported for a properly functioning q35 machine?
11 years, 7 months
[libvirt] [PATCH RESEND] Add support for <option> tag in network config
by Pieter Hollants
This patch adds support for a new <option>-Tag in the <dhcp> block of network configs,
based on a subset of the fifth proposal by Laine Stump in the mailing list discussion at
https://www.redhat.com/archives/libvir-list/2012-November/msg01054.html. Any such defined
option will result in a dhcp-option=<number>,"<value>" statement in the generated dnsmasq
configuration file.
Currently, DHCP options can be specified by number only and there is no whitelisting or
blacklisting of option numbers, which should probably be added.
Signed-off-by: Pieter Hollants <pieter(a)hollants.com>
---
AUTHORS.in | 1 +
docs/schemas/network.rng | 6 +++
docs/schemas/networkcommon.rng | 6 +++
src/conf/network_conf.c | 54 +++++++++++++++++++++
src/conf/network_conf.h | 10 ++++
src/network/bridge_driver.c | 10 ++++
tests/networkxml2xmlin/netboot-network.xml | 1 +
tests/networkxml2xmlin/netboot-proxy-network.xml | 1 +
tests/networkxml2xmlout/netboot-network.xml | 1 +
tests/networkxml2xmlout/netboot-proxy-network.xml | 1 +
10 Dateien geändert, 91 Zeilen hinzugefügt(+)
diff --git a/AUTHORS.in b/AUTHORS.in
index 39fe68d..074185e 100644
--- a/AUTHORS.in
+++ b/AUTHORS.in
@@ -74,6 +74,7 @@ Michel Ponceau <michel.ponceau(a)bull.net>
Nobuhiro Itou <fj0873gn(a)aa.jp.fujitsu.com>
Pete Vetere <pvetere(a)redhat.com>
Philippe Berthault <philippe.berthault(a)Bull.net>
+Pieter Hollants <pieter(a)hollants.com>
Saori Fukuta <fukuta.saori(a)jp.fujitsu.com>
Shigeki Sakamoto <fj0588di(a)aa.jp.fujitsu.com>
Shuveb Hussain <shuveb(a)binarykarma.com>
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 09d7c73..a2ce1c9 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -293,6 +293,12 @@
</optional>
</element>
</optional>
+ <zeroOrMore>
+ <element name="option">
+ <attribute name="number"><ref name="unsignedByte"/></attribute>
+ <attribute name="value"><text/></attribute>
+ </element>
+ </zeroOrMore>
</element>
</optional>
</element>
diff --git a/docs/schemas/networkcommon.rng b/docs/schemas/networkcommon.rng
index 51ff759..3510928 100644
--- a/docs/schemas/networkcommon.rng
+++ b/docs/schemas/networkcommon.rng
@@ -173,6 +173,12 @@
</data>
</define>
+ <define name='unsignedByte'>
+ <data type='integer'>
+ <param name="minInclusive">0</param>
+ <param name="maxInclusive">255</param>
+ </data>
+ </define>
<define name='unsignedShort'>
<data type='integer'>
<param name="minInclusive">0</param>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 3604ff7..9d84c7e 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -777,6 +777,45 @@ cleanup:
}
static int
+virNetworkDHCPOptionDefParseXML(const char *networkName,
+ xmlNodePtr node,
+ virNetworkDHCPOptionDefPtr option)
+{
+ char *number = NULL;
+ int ret = -1;
+
+ if (!(number = virXMLPropString(node, "number"))) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Option definition in IPv4 network '%s' "
+ "must have number attribute"),
+ networkName);
+ goto cleanup;
+ }
+ if (number &&
+ virStrToLong_ui(number, NULL, 10, &option->number) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Cannot parse <option> 'number' attribute"));
+ goto cleanup;
+ }
+ /* TODO: either whitelist numbers or blacklist numbers already occupied
+ * by other XML statements (eg. submask) */
+ if (!(option->value = virXMLPropString(node, "value"))) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Option definition in IPv4 network '%s' "
+ "must have value attribute"),
+ networkName);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(number);
+ return ret;
+}
+
+
+static int
virNetworkDHCPDefParseXML(const char *networkName,
xmlNodePtr node,
virNetworkIpDefPtr def)
@@ -837,6 +876,17 @@ virNetworkDHCPDefParseXML(const char *networkName,
def->bootfile = file;
def->bootserver = inaddr;
VIR_FREE(server);
+ } else if (cur->type == XML_ELEMENT_NODE &&
+ xmlStrEqual(cur->name, BAD_CAST "option")) {
+ if (VIR_REALLOC_N(def->options, def->noptions + 1) < 0) {
+ virReportOOMError();
+ return -1;
+ }
+ if (virNetworkDHCPOptionDefParseXML(networkName, cur,
+ &def->options[def->noptions])) {
+ return -1;
+ }
+ def->noptions++;
}
cur = cur->next;
@@ -2045,6 +2095,10 @@ virNetworkIpDefFormat(virBufferPtr buf,
virBufferAddLit(buf, "/>\n");
}
+ for (ii = 0 ; ii < def->noptions ; ii++) {
+ virBufferAsprintf(buf, "<option number='%u' value='%s' />\n",
+ def->options[ii].number, def->options[ii].value);
+ }
virBufferAdjustIndent(buf, -2);
virBufferAddLit(buf, "</dhcp>\n");
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 4c634ed..14f852a 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -77,6 +77,13 @@ struct _virNetworkDHCPHostDef {
virSocketAddr ip;
};
+typedef struct _virNetworkDHCPOptionDef virNetworkDHCPOptionDef;
+typedef virNetworkDHCPOptionDef *virNetworkDHCPOptionDefPtr;
+struct _virNetworkDHCPOptionDef {
+ unsigned int number;
+ char *value;
+};
+
typedef struct _virNetworkDNSTxtDef virNetworkDNSTxtDef;
typedef virNetworkDNSTxtDef *virNetworkDNSTxtDefPtr;
struct _virNetworkDNSTxtDef {
@@ -139,6 +146,9 @@ struct _virNetworkIpDef {
char *tftproot;
char *bootfile;
virSocketAddr bootserver;
+
+ size_t noptions; /* Zero or more additional dhcp options */
+ virNetworkDHCPOptionDefPtr options;
};
typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index c834f83..c7c0a9e 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -926,6 +926,15 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
virBufferAsprintf(&configbuf, "dhcp-boot=%s\n", ipdef->bootfile);
}
}
+
+ /* Any additional DHCP options? */
+ if (ipdef->noptions > 0) {
+ for (r = 0 ; r < ipdef->noptions ; r++) {
+ virBufferAsprintf(&configbuf, "dhcp-option=%u,\"%s\"\n",
+ ipdef->options[r].number,
+ ipdef->options[r].value);
+ }
+ }
}
ipdef = (ipdef == ipv6def) ? NULL : ipv6def;
}
@@ -959,6 +968,7 @@ networkDnsmasqConfContents(virNetworkObjPtr network,
virBufferAsprintf(&configbuf, "addn-hosts=%s\n",
dctx->addnhostsfile->path);
+
/* Are we doing RA instead of radvd? */
if (DNSMASQ_RA_SUPPORT(caps)) {
if (ipv6def)
diff --git a/tests/networkxml2xmlin/netboot-network.xml b/tests/networkxml2xmlin/netboot-network.xml
index ed75663..4de8976 100644
--- a/tests/networkxml2xmlin/netboot-network.xml
+++ b/tests/networkxml2xmlin/netboot-network.xml
@@ -9,6 +9,7 @@
<dhcp>
<range start="192.168.122.2" end="192.168.122.254" />
<bootp file="pxeboot.img" />
+ <option number="252" value="\n" />
</dhcp>
</ip>
</network>
diff --git a/tests/networkxml2xmlin/netboot-proxy-network.xml b/tests/networkxml2xmlin/netboot-proxy-network.xml
index ecb6738..4c5c480 100644
--- a/tests/networkxml2xmlin/netboot-proxy-network.xml
+++ b/tests/networkxml2xmlin/netboot-proxy-network.xml
@@ -8,6 +8,7 @@
<dhcp>
<range start="192.168.122.2" end="192.168.122.254" />
<bootp file="pxeboot.img" server="10.20.30.40" />
+ <option number="252" value="\n" />
</dhcp>
</ip>
</network>
diff --git a/tests/networkxml2xmlout/netboot-network.xml b/tests/networkxml2xmlout/netboot-network.xml
index b8a4d99..c3ea95a 100644
--- a/tests/networkxml2xmlout/netboot-network.xml
+++ b/tests/networkxml2xmlout/netboot-network.xml
@@ -9,6 +9,7 @@
<dhcp>
<range start='192.168.122.2' end='192.168.122.254' />
<bootp file='pxeboot.img' />
+ <option number='252' value='\n' />
</dhcp>
</ip>
</network>
diff --git a/tests/networkxml2xmlout/netboot-proxy-network.xml b/tests/networkxml2xmlout/netboot-proxy-network.xml
index e11c50b..f5f2c0d 100644
--- a/tests/networkxml2xmlout/netboot-proxy-network.xml
+++ b/tests/networkxml2xmlout/netboot-proxy-network.xml
@@ -8,6 +8,7 @@
<dhcp>
<range start='192.168.122.2' end='192.168.122.254' />
<bootp file='pxeboot.img' server='10.20.30.40' />
+ <option number='252' value='\n' />
</dhcp>
</ip>
</network>
--
1.7.10.4
11 years, 7 months