[libvirt] [PATCH] Add support for systemd init service
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
This patch adds support for a systemd init service for libvirtd
and libvirt-guests. The libvirtd.service is *not* written to use
socket activation, since we want libvirtd to start on boot so it
can do guest auto-start.
The libvirt-guests.service is pretty lame, just exec'ing the
original init script for now. Ideally we would factor out the
functionality, into some shared tool.
Instead of
./configure --with-init-script=redhat
You can now do
./configure --with-init-script=systemd
Or better still:
./configure --with-init-script=systemd+redhat
* configure.ac: Add systemd, and systemd+redhat options to
--with-init-script option
* daemon/Makefile.am: Install systemd services
* daemon/libvirtd.sysconf: Add note about unused env variable
with systemd
* daemon/libvirtd.service.in: libvirtd systemd service unit
* libvirt.spec.in: Add scripts to installing systemd services
and migrating from legacy init scripts
* tools/Makefile.am: Install systemd services
* tools/libvirt-guests.init.sh: Rename to tools/libvirt-guests.init.in
* tools/libvirt-guests.service.in: systemd service unit
---
configure.ac | 32 +++++--
daemon/.gitignore | 1 +
daemon/Makefile.am | 77 ++++++++++++-----
daemon/libvirtd.service.in | 20 ++++
daemon/libvirtd.sysconf | 3 +
libvirt.spec.in | 93 +++++++++++++++++++-
po/POTFILES.in | 2 +-
tools/Makefile.am | 63 +++++++++++---
...bvirt-guests.init.sh => libvirt-guests.init.in} | 0
tools/libvirt-guests.service.in | 13 +++
10 files changed, 257 insertions(+), 47 deletions(-)
create mode 100644 daemon/libvirtd.service.in
rename tools/{libvirt-guests.init.sh => libvirt-guests.init.in} (100%)
create mode 100644 tools/libvirt-guests.service.in
diff --git a/configure.ac b/configure.ac
index 3b7535e..f155666 100644
--- a/configure.ac
+++ b/configure.ac
@@ -329,16 +329,30 @@ dnl init script flavor
dnl
AC_MSG_CHECKING([for init script flavor])
AC_ARG_WITH([init-script],
- [AC_HELP_STRING([--with-init-script=@<:@redhat|auto|none@:>@],
+ [AC_HELP_STRING([--with-init-script=@<:@redhat|systemd|systemd+redhat|upstart|auto|none@:>@],
[Style of init script to install @<:@default=auto@:>@])])
-if test "x$with_init_script" = "x" || test "x$with_init_script" = "xauto"; then
- if test "$cross_compiling" = yes || test ! -f /etc/redhat-release; then
- with_init_script=none
- else
- with_init_script=redhat
- fi
-fi
-AM_CONDITIONAL([LIBVIRT_INIT_SCRIPT_RED_HAT], test x$with_init_script = xredhat)
+init_redhat=no
+init_systemd=no
+case "$with_init_script" in
+ systemd+redhat)
+ init_redhat=yes
+ init_systemd=yes
+ ;;
+ systemd)
+ init_systemd=yes
+ ;;
+ redhat)
+ init_redhat=yes
+ ;;
+ *)
+ if test "$cross_compiling" != yes && test -f /etc/redhat-release; then
+ init_redhat=yes
+ with_init_script=redhat
+ fi
+ ;;
+esac
+AM_CONDITIONAL([LIBVIRT_INIT_SCRIPT_RED_HAT], test "$init_redhat" = "yes")
+AM_CONDITIONAL([LIBVIRT_INIT_SCRIPT_SYSTEMD], test "$init_systemd" = "yes")
AC_MSG_RESULT($with_init_script)
dnl RHEL-5 has a peculiar version of Xen, which requires some special casing
diff --git a/daemon/.gitignore b/daemon/.gitignore
index ab3d093..2873143 100644
--- a/daemon/.gitignore
+++ b/daemon/.gitignore
@@ -7,6 +7,7 @@ Makefile.in
libvirt_qemud
libvirtd
libvirtd.init
+libvirtd.service
libvirtd*.logrotate
libvirtd.8
libvirtd.8.in
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index e8c47ae..92b6b86 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -170,13 +170,14 @@ policyfile = libvirtd.policy-1
endif
endif
-install-data-local: install-init install-data-sasl install-data-polkit \
- install-logrotate
+install-data-local: install-init install-systemd install-data-sasl install-data-polkit \
+ install-logrotate install-sysctl
mkdir -p $(DESTDIR)$(localstatedir)/log/libvirt
mkdir -p $(DESTDIR)$(localstatedir)/run/libvirt
mkdir -p $(DESTDIR)$(localstatedir)/lib/libvirt
-uninstall-local:: uninstall-init uninstall-data-sasl uninstall-data-polkit
+uninstall-local:: uninstall-init uninstall-systemd uninstall-data-sasl uninstall-data-polkit \
+ uninstall-sysctl
rmdir $(DESTDIR)$(localstatedir)/log/libvirt || :
rmdir $(DESTDIR)$(localstatedir)/run/libvirt || :
rmdir $(DESTDIR)$(localstatedir)/lib/libvirt || :
@@ -234,25 +235,56 @@ install-logrotate: $(LOGROTATE_CONFS)
$(INSTALL_DATA) libvirtd.lxc.logrotate $(DESTDIR)$(sysconfdir)/logrotate.d/libvirtd.lxc
$(INSTALL_DATA) libvirtd.uml.logrotate $(DESTDIR)$(sysconfdir)/logrotate.d/libvirtd.uml
-if LIBVIRT_INIT_SCRIPT_RED_HAT
-install-init: libvirtd.init
- mkdir -p $(DESTDIR)$(sysconfdir)/rc.d/init.d \
- $(DESTDIR)$(sysconfdir)/sysconfig \
- $(DESTDIR)$(sysconfdir)/sysctl.d
- $(INSTALL_SCRIPT) libvirtd.init \
- $(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirtd
+install-sysconfig:
+ mkdir -p $(DESTDIR)$(sysconfdir)/sysconfig
$(INSTALL_DATA) $(srcdir)/libvirtd.sysconf \
$(DESTDIR)$(sysconfdir)/sysconfig/libvirtd
+uninstall-sysconfig:
+ rm -f $(DESTDIR)$(sysconfdir)/sysconfig/libvirtd
+
+install-sysctl:
+ mkdir -p $(DESTDIR)$(sysconfdir)/sysctl.d
$(INSTALL_DATA) $(srcdir)/libvirtd.sysctl \
$(DESTDIR)$(sysconfdir)/sysctl.d/libvirtd
-uninstall-init:
- rm -f $(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirtd \
- $(DESTDIR)$(sysconfdir)/sysconfig/libvirtd \
- $(DESTDIR)$(sysconfdir)/sysctl.d/libvirtd
+uninstall-sysctl:
+ rm -f $(DESTDIR)$(sysconfdir)/sysctl.d/libvirtd
+
+if LIBVIRT_INIT_SCRIPT_RED_HAT
BUILT_SOURCES += libvirtd.init
+install-init: install-sysconfig libvirtd.init
+ mkdir -p $(DESTDIR)$(sysconfdir)/rc.d/init.d
+ $(INSTALL_SCRIPT) libvirtd.init \
+ $(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirtd
+
+uninstall-init: uninstall-sysconfig
+ rm -f $(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirtd
+else
+install-init:
+uninstall-init:
+endif # LIBVIRT_INIT_SCRIPT_RED_HAT
+
+
+EXTRA_DIST += libvirtd.service.in
+if LIBVIRT_INIT_SCRIPT_SYSTEMD
+
+SYSTEMD_UNIT_DIR = /lib/systemd/system
+BUILT_SOURCES += libvirtd.service
+
+install-systemd: install-sysconfig libvirtd.service
+ mkdir -p $(DESTDIR)$(SYSTEMD_UNIT_DIR)
+ $(INSTALL_SCRIPT) libvirtd.service \
+ $(DESTDIR)$(SYSTEMD_UNIT_DIR)/libvirtd.service
+
+uninstall-systemd: uninstall-sysconfig
+ rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/libvirtd.service
+else
+install-systemd:
+uninstall-systemd:
+endif # LIBVIRT_INIT_SCRIPT_SYSTEMD
+
libvirtd.init: libvirtd.init.in $(top_builddir)/config.status
$(AM_V_GEN)sed \
-e s!\@localstatedir\@!@localstatedir@!g \
@@ -262,18 +294,21 @@ libvirtd.init: libvirtd.init.in $(top_builddir)/config.status
chmod a+x $@-t && \
mv $@-t $@
+libvirtd.service: libvirtd.service.in $(top_builddir)/config.status
+ $(AM_V_GEN)sed \
+ -e s!\@localstatedir\@!@localstatedir@!g \
+ -e s!\@sbindir\@!@sbindir@!g \
+ -e s!\@sysconfdir\@!@sysconfdir@!g \
+ < $< > $@-t && \
+ chmod a+x $@-t && \
+ mv $@-t $@
+
+
check-local:
$(AM_V_GEN)if test -x '$(AUGPARSE)'; then \
'$(AUGPARSE)' -I $(srcdir) $(srcdir)/test_libvirtd.aug; \
fi
-else
-
-install-init:
-uninstall-init:
-libvirtd.init:
-
-endif # LIBVIRT_INIT_SCRIPT_RED_HAT
# This must be added last, since functions it provides/replaces
# are used by nearly every other library.
diff --git a/daemon/libvirtd.service.in b/daemon/libvirtd.service.in
new file mode 100644
index 0000000..9661428
--- /dev/null
+++ b/daemon/libvirtd.service.in
@@ -0,0 +1,20 @@
+# NB we don't use socket activation. When libvirtd starts it will
+# spawn any virtual machines registered for autostart. We want this
+# to occur on every boot, regardless of whether any client connects
+# to a socket. Thus socket activation doesn't have any benefit
+
+[Unit]
+Description=Virtualization daemon
+After=syslog.target
+After=udev.target
+After=avahi.target
+After=dbus.target
+Before=libvirt-guests.service
+
+[Service]
+EnvironmentFile=-/etc/sysconfig/libvirtd
+ExecStart=@sbindir@/libvirtd $LIBVIRTD_ARGS
+ExecReload=/bin/kill -HUP $MAINPID
+
+[Install]
+WantedBy=multi-user.target
diff --git a/daemon/libvirtd.sysconf b/daemon/libvirtd.sysconf
index b730c5e..ab273c8 100644
--- a/daemon/libvirtd.sysconf
+++ b/daemon/libvirtd.sysconf
@@ -1,4 +1,7 @@
# Override the default config file
+# NOTE: This setting is no longer honoured if using
+# systemd. Set '--config /etc/libvirt/libvirtd.conf'
+# in LIBVIRTD_ARGS instead.
#LIBVIRTD_CONFIG=/etc/libvirt/libvirtd.conf
# Listen for TCP/IP connections
diff --git a/libvirt.spec.in b/libvirt.spec.in
index d4e3e17..0379998 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -78,6 +78,7 @@
%define with_dtrace 0%{!?_without_dtrace:0}
%define with_cgconfig 0%{!?_without_cgconfig:0}
%define with_sanlock 0%{!?_without_sanlock:0}
+%define with_systemd 0%{!?_without_systemd:0}
# Non-server/HV driver defaults which are always enabled
%define with_python 0%{!?_without_python:1}
@@ -111,6 +112,11 @@
%define with_hyperv 0
%endif
+# Although earlier Fedora has systemd, libvirt still used sysvinit
+%if 0%{?fedora} >= 17
+%define with_systemd 1
+%endif
+
# RHEL-5 has restricted QEMU to x86_64 only and is too old for LXC
%if 0%{?rhel} == 5
%ifnarch x86_64
@@ -329,7 +335,9 @@ Requires: libcgroup
# All build-time requirements
BuildRequires: python-devel
-
+%if %{with_systemd}
+BuildRequires: systemd-units
+%endif
%if %{with_xen}
BuildRequires: xen-devel
%endif
@@ -474,6 +482,13 @@ BuildRequires: nfs-utils
# Fedora build root suckage
BuildRequires: gawk
+%if %{with_systemd}
+Requires(post): systemd-units
+Requires(post): systemd-sysv
+Requires(preun): systemd-units
+Requires(postun): systemd-units
+%endif
+
%description
Libvirt is a C toolkit to interact with the virtualization capabilities
of recent versions of Linux (and other OSes). The main package includes
@@ -696,6 +711,13 @@ of recent versions of Linux (and other OSes).
%define with_packager --with-packager="%{who}, %{when}, %{where}"
%define with_packager_version --with-packager-version="%{release}"
+%if %{with_systemd}
+# We use 'systemd+redhat', so if someone installs upstart or
+# legacy init scripts, they can still start libvirtd, etc
+%define init_scripts --with-init_script=systemd+redhat
+%else
+%define init_scripts --with-init_script=redhat
+%endif
%configure %{?_without_xen} \
%{?_without_qemu} \
@@ -736,7 +758,7 @@ of recent versions of Linux (and other OSes).
%{with_packager_version} \
--with-qemu-user=%{qemu_user} \
--with-qemu-group=%{qemu_group} \
- --with-init-script=redhat \
+ %{init_scripts} \
--with-remote-pid-file=%{_localstatedir}/run/libvirtd.pid
make %{?_smp_mflags}
gzip -9 ChangeLog
@@ -744,7 +766,7 @@ gzip -9 ChangeLog
%install
rm -fr %{buildroot}
-%makeinstall
+%makeinstall SYSTEMD_UNIT_DIR=%{?buildroot:%{buildroot}}%{_unitdir}
for i in domain-events/events-c dominfo domsuspend hellolibvirt openauth python xml/nwfilter systemtap
do
(cd examples/$i ; make clean ; rm -rf .deps .libs Makefile Makefile.in)
@@ -893,6 +915,13 @@ do
done
%endif
+%if %{with_systemd}
+if [ $1 -eq 1 ] ; then
+ # Initial installation
+ /bin/systemctl enable libvirtd.service >/dev/null 2>&1 || :
+ /bin/systemctl enable cgconfig.service >/dev/null 2>&1 || :
+fi
+%else
%if %{with_cgconfig}
# Starting with Fedora 16, systemd automounts all cgroups, and cgconfig is
# no longer a necessary service.
@@ -908,25 +937,64 @@ if [ "$1" -ge "1" ]; then
/sbin/service libvirtd condrestart > /dev/null 2>&1
fi
%endif
+%endif
%preun
%if %{with_libvirtd}
+%if %{with_systemd}
+if [ $1 -eq 0 ] ; then
+ # Package removal, not upgrade
+ /bin/systemctl --no-reload disable libvirtd.service > /dev/null 2>&1 || :
+ /bin/systemctl stop libvirtd.service > /dev/null 2>&1 || :
+fi
+%else
if [ $1 = 0 ]; then
/sbin/service libvirtd stop 1>/dev/null 2>&1
/sbin/chkconfig --del libvirtd
fi
%endif
+%endif
+
+%postun
+%if %{with_libvirtd}
+%if %{with_systemd}
+/bin/systemctl daemon-reload >/dev/null 2>&1 || :
+if [ $1 -ge 1 ] ; then
+ # Package upgrade, not uninstall
+ /bin/systemctl try-restart libvirtd.service >/dev/null 2>&1 || :
+fi
+%endif
+%endif
+
+%if %{with_libvirtd}
+%if %{with_systemd}
+%triggerun -- libvirt < 0.9.4
+%{_bindir}/systemd-sysv-convert --save libvirtd >/dev/null 2>&1 ||:
+
+# If the package is allowed to autostart:
+/bin/systemctl --no-reload enable libvirtd.service >/dev/null 2>&1 ||:
+
+# Run these because the SysV package being removed won't do them
+/sbin/chkconfig --del libvirtd >/dev/null 2>&1 || :
+/bin/systemctl try-restart libvirtd.service >/dev/null 2>&1 || :
+%endif
+%endif
%preun client
+%if %{with_systemd}
+%else
if [ $1 = 0 ]; then
/sbin/chkconfig --del libvirt-guests
rm -f /var/lib/libvirt/libvirt-guests
fi
+%endif
%post client
/sbin/ldconfig
+%if %{with_systemd}
+%else
/sbin/chkconfig --add libvirt-guests
if [ $1 -ge 1 ]; then
level=$(/sbin/runlevel | /bin/cut -d ' ' -f 2)
@@ -937,9 +1005,22 @@ if [ $1 -ge 1 ]; then
/sbin/service libvirt-guests start > /dev/null 2>&1 || true
fi
fi
+%endif
%postun client -p /sbin/ldconfig
+%if %{with_systemd}
+%triggerun client -- libvirt < 0.9.4
+%{_bindir}/systemd-sysv-convert --save libvirt-guests >/dev/null 2>&1 ||:
+
+# If the package is allowed to autostart:
+/bin/systemctl --no-reload enable libvirt-guests.service >/dev/null 2>&1 ||:
+
+# Run these because the SysV package being removed won't do them
+/sbin/chkconfig --del libvirt-guests >/dev/null 2>&1 || :
+/bin/systemctl try-restart libvirt-guests.service >/dev/null 2>&1 || :
+%endif
+
%if %{with_libvirtd}
%files
%defattr(-, root, root)
@@ -957,6 +1038,9 @@ fi
%{_sysconfdir}/libvirt/nwfilter/*.xml
%{_sysconfdir}/rc.d/init.d/libvirtd
+%if %{with_systemd}
+%{_unitdir}/libvirtd.service
+%endif
%doc daemon/libvirtd.upstart
%config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
%config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
@@ -1113,6 +1197,9 @@ rm -f $RPM_BUILD_ROOT%{_sysconfdir}/sysctl.d/libvirtd
%{_datadir}/libvirt/cpu_map.xml
%{_sysconfdir}/rc.d/init.d/libvirt-guests
+%if %{with_systemd}
+%{_unitdir}/libvirt-guests.service
+%endif
%config(noreplace) %{_sysconfdir}/sysconfig/libvirt-guests
%dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a3685e8..0fd4442 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -151,5 +151,5 @@ src/xenapi/xenapi_utils.c
src/xenxs/xen_sxpr.c
src/xenxs/xen_xm.c
tools/console.c
-tools/libvirt-guests.init.sh
+tools/libvirt-guests.init.in
tools/virsh.c
diff --git a/tools/Makefile.am b/tools/Makefile.am
index c96c7d9..2e8018e 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -25,7 +25,6 @@ EXTRA_DIST = \
virt-sanlock-cleanup.in \
virt-sanlock-cleanup.8 \
virsh.pod \
- libvirt-guests.init.sh \
libvirt-guests.sysconf
DISTCLEANFILES =
@@ -153,22 +152,33 @@ install-data-local: install-init
uninstall-local: uninstall-init
+install-sysconfig:
+ mkdir -p $(DESTDIR)$(sysconfdir)/sysconfig
+ $(INSTALL_DATA) $(srcdir)/libvirt-guests.sysconf \
+ $(DESTDIR)$(sysconfdir)/sysconfig/libvirt-guests
+
+uninstall-sysconfig:
+ rm -f $(DESTDIR)$(sysconfdir)/sysconfig/libvirt-guests
+
+EXTRA_DIST += libvirt-guests.init.in
+
if LIBVIRT_INIT_SCRIPT_RED_HAT
-install-init: libvirt-guests.init
+install-init: libvirt-guests.init install-sysconfig
mkdir -p $(DESTDIR)$(sysconfdir)/rc.d/init.d
$(INSTALL_SCRIPT) libvirt-guests.init \
$(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirt-guests
- mkdir -p $(DESTDIR)$(sysconfdir)/sysconfig
- $(INSTALL_DATA) $(srcdir)/libvirt-guests.sysconf \
- $(DESTDIR)$(sysconfdir)/sysconfig/libvirt-guests
-uninstall-init:
- rm -f $(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirt-guests \
- $(DESTDIR)$(sysconfdir)/sysconfig/libvirt-guests
+uninstall-init: install-sysconfig
+ rm -f $(DESTDIR)$(sysconfdir)/rc.d/init.d/libvirt-guests
BUILT_SOURCES += libvirt-guests.init
-libvirt-guests.init: libvirt-guests.init.sh $(top_builddir)/config.status
+else
+install-init:
+uninstall-init:
+endif # LIBVIRT_INIT_SCRIPT_RED_HAT
+
+libvirt-guests.init: libvirt-guests.init.in $(top_builddir)/config.status
$(AM_V_GEN)sed \
-e 's!\@PACKAGE\@!$(PACKAGE)!g' \
-e 's!\@bindir\@!$(bindir)!g' \
@@ -179,11 +189,38 @@ libvirt-guests.init: libvirt-guests.init.sh $(top_builddir)/config.status
< $< > $@-t && \
chmod a+x $@-t && \
mv $@-t $@
+
+
+
+EXTRA_DIST += libvirt-guests.service.in
+
+if LIBVIRT_INIT_SCRIPT_SYSTEMD
+install-systemd: libvirt-guests.service install-sysconfig
+ mkdir -p $(DESTDIR)$(sysconfdir)/rc.d/systemd.d
+ $(INSTALL_SCRIPT) libvirt-guests.service \
+ $(DESTDIR)$(sysconfdir)/rc.d/systemd.d/libvirt-guests
+
+uninstall-systemd: install-sysconfig
+ rm -f $(DESTDIR)$(sysconfdir)/rc.d/systemd.d/libvirt-guests
+
+BUILT_SOURCES += libvirt-guests.service
+
else
-install-init:
-uninstall-init:
-libvirt-guests.init:
-endif # LIBVIRT_INIT_SCRIPT_RED_HAT
+install-systemd:
+uninstall-systemd:
+endif # LIBVIRT_INIT_SCRIPT_SYSTEMD
+
+libvirt-guests.service: libvirt-guests.service.in $(top_builddir)/config.status
+ $(AM_V_GEN)sed \
+ -e 's!\@PACKAGE\@!$(PACKAGE)!g' \
+ -e 's!\@bindir\@!$(bindir)!g' \
+ -e 's!\@localedir\@!$(localedir)!g' \
+ -e 's!\@localstatedir\@!$(localstatedir)!g' \
+ -e 's!\@sbindir\@!$(sbindir)!g' \
+ -e 's!\@sysconfdir\@!$(sysconfdir)!g' \
+ < $< > $@-t && \
+ chmod a+x $@-t && \
+ mv $@-t $@
CLEANFILES = $(bin_SCRIPTS)
diff --git a/tools/libvirt-guests.init.sh b/tools/libvirt-guests.init.in
similarity index 100%
rename from tools/libvirt-guests.init.sh
rename to tools/libvirt-guests.init.in
diff --git a/tools/libvirt-guests.service.in b/tools/libvirt-guests.service.in
new file mode 100644
index 0000000..bc63e91
--- /dev/null
+++ b/tools/libvirt-guests.service.in
@@ -0,0 +1,13 @@
+[Unit]
+Description=Suspend Active Libvirt Guests
+After=syslog.target network.target
+
+[Service]
+EnvironmentFile=-/etc/sysconfig/libvirt-guests
+# Hack just call traditional service until we factor
+# out the code
+ExecStart=/etc/init.d/libvirt-guests start
+ExecStop=/etc/init.d/libvirt-guests stop
+
+[Install]
+WantedBy=multi-user.target
--
1.7.6.4
13 years, 6 months
[libvirt] [PATCH 00/33] Refactor all network device handling code
by Daniel P. Berrange
This series is a major re-arrangement and de-duplication of
internal code for dealing with physical network interfaces.
Currently code for physical network interfaces is split
across the following files
- bridge.c: bridge management, TAP device management and
interface IPv4 address management
- network.c: socket address management, network bandwidth
and virtual port profile data management
- interface.c: some generic interface management and
macvtap/macvlan management
- macvtap.c: more macvtap/macvlan management and virtual
port profile interface setup code
- lxc/veth.c: veth device management and generic interface
management
Furthermore across these files
- Argument ordering is inconsistent - sometimes ifname is
the first parameter, sometimes it isn't
- Error handing is terribly inconsistent
1. Return errno values
2. Raise errors
3. Raise errors and return errno values
4. Raise errors, except when a parameter tells
it not to
- API naming is inconsistent. Some APIs have a vir prefix,
others have different prefixes, other don't even follow
a standard prefix, eg virSocketFormatAddr vs virSocketAddrMaks
vs virSocketGetPort
- The bridge.c APIs have an annoying 'brControl *' struct
that must be passed around just to avoid opening & closing
an unbound socket.
- Some APIs are implemented natively, while others call
out to external commands
- Duplication of functionality across APIs
- XML parsing & formatting code is in src/util instead
of src/conf
- Some of the API declarations are hidden behind #ifdefs
forcing yet more #ifdefs in the callers of the APIs
After applying this series, we get to a stage where the source
file split is:
- src/util/virnetdev.c: APIs relating to any type of interface
- src/util/virnetdevbridge.c: APIs relating to bridge interfaces
- src/util/virnetdevmacvlan.c: APIs relating to macvlan/macvtap interfaces
- src/util/virnetdevveth.c: APIs relating to veth interfaces
- src/util/virnetdevbandwidth.c: APIs for network bandwidth controls
- src/util/virnetdevvportprofile.c: APIs for 802.11Qb{g,h} port profiles
- src/util/virsocketaddr.c: the socket address management APIs
- src/conf/netdev_bandwidth_conf.c: Parsing/formatting bandwidth XML
- src/conf/netdev_vport_profile_conf.c: parsing/formatting 801.11Qb{g,h} profile XML
The following style is followed
- All APIs return -1 on error and raise a libvirt error. No exceptions
or flags to turn off errors
- Callers which don't want the raised error call virResetLastError
- All APIs are annotated with ATTRIBUTE_NONNULL and ATTRIBUTE_RETURN_CHECK
where appropriate
- The first parameter of all APIs operating on a network interface is
the interface name
- All APIs have a fixed name prefix which matches the source file. No
exceptions.
- All XML handling code is under src/conf/
- All APIs are unconditionally declared in header files, and stubbed
out with virReportSystemError(ENOSYS...) where unsupported.
- No functionality is duplicated across files
- External commands are avoided except in case of setting IPv4
addresses and network bandwidth controls
The diffstat is a little bit misleading, showing a slight growth in the
number of lines. This is primarily due to the extra GPL copyright header
lines in the new files, being much larger than those removed from old
files. Overall we have a decrease in actual real code, through removal
of duplicated APIs
b/configure.ac | 5
b/daemon/libvirtd.h | 1
b/daemon/remote.c | 1
b/libvirt.spec.in | 2
b/po/POTFILES.in | 12
b/src/Makefile.am | 26
b/src/conf/domain_conf.c | 59 -
b/src/conf/domain_conf.h | 20
b/src/conf/netdev_bandwidth_conf.c | 230 ++++
b/src/conf/netdev_bandwidth_conf.h | 37
b/src/conf/netdev_vport_profile_conf.c | 236 ++++
b/src/conf/netdev_vport_profile_conf.h | 39
b/src/conf/network_conf.c | 101 +-
b/src/conf/network_conf.h | 12
b/src/conf/nwfilter_conf.c | 16
b/src/conf/nwfilter_conf.h | 2
b/src/esx/esx_util.h | 2
b/src/libvirt_private.syms | 71 -
b/src/lxc/lxc_container.c | 9
b/src/lxc/lxc_controller.c | 7
b/src/lxc/lxc_driver.c | 42
b/src/network/bridge_driver.c | 192 +--
b/src/nwfilter/nwfilter_ebiptables_driver.c | 4
b/src/nwfilter/nwfilter_gentech_driver.c | 25
b/src/nwfilter/nwfilter_learnipaddr.c | 32
b/src/openvz/openvz_driver.c | 1
b/src/qemu/qemu_command.c | 86 -
b/src/qemu/qemu_command.h | 4
b/src/qemu/qemu_conf.c | 2
b/src/qemu/qemu_conf.h | 3
b/src/qemu/qemu_driver.c | 16
b/src/qemu/qemu_hotplug.c | 19
b/src/qemu/qemu_migration.c | 29
b/src/qemu/qemu_process.c | 15
b/src/qemu/qemu_process.h | 2
b/src/rpc/virnetsocket.c | 7
b/src/rpc/virnetsocket.h | 2
b/src/uml/uml_conf.c | 41
b/src/uml/uml_conf.h | 2
b/src/uml/uml_driver.c | 22
b/src/util/dnsmasq.c | 4
b/src/util/dnsmasq.h | 2
b/src/util/iptables.c | 20
b/src/util/iptables.h | 2
b/src/util/virnetdev.c | 1083 ++++++++++++++++++++++
b/src/util/virnetdev.h | 102 ++
b/src/util/virnetdevbandwidth.c | 265 +++++
b/src/util/virnetdevbandwidth.h | 53 +
b/src/util/virnetdevbridge.c | 527 ++++++++++
b/src/util/virnetdevbridge.h | 54 +
b/src/util/virnetdevmacvlan.c | 674 +++++++++++++
b/src/util/virnetdevmacvlan.h | 77 +
b/src/util/virnetdevtap.c | 301 ++++++
b/src/util/virnetdevtap.h | 45
b/src/util/virnetdevveth.c | 189 +++
b/src/util/virnetdevveth.h | 35
b/src/util/virnetdevvportprofile.c | 1073 +++++++++++++++++++++
b/src/util/virnetdevvportprofile.h | 95 +
b/src/util/virsocketaddr.c | 687 ++++++++++++++
b/src/util/virsocketaddr.h | 103 ++
b/src/vbox/vbox_tmpl.c | 10
b/tests/qemuxml2argvtest.c | 2
b/tests/qemuxmlnstest.c | 2
b/tests/sockettest.c | 20
b/tests/virnetsockettest.c | 1
b/tests/virnettlscontexttest.c | 6
b/tools/virsh.c | 6
src/lxc/veth.c | 319 ------
src/lxc/veth.h | 33
src/util/bridge.c | 845 -----------------
src/util/bridge.h | 120 --
src/util/interface.c | 1348 ---------------------------
src/util/interface.h | 91 -
src/util/macvtap.c | 1203 ------------------------
src/util/macvtap.h | 93 -
src/util/network.c | 1370 ----------------------------
src/util/network.h | 167 ---
77 files changed, 6302 insertions(+), 6159 deletions(-)
13 years, 6 months
[libvirt] PATCH: Fix build without MACVTAP
by Michael Wood
Hi
Commit c31d23a78715f1144c73862c46ab0436de8b5e85 removed the "conn"
parameter from qemuPhysIfaceConnect(), but it's still used if
WITH_MACVTAP is false. Also, it's still mentioned in the comment
above the function:
/**
* qemuPhysIfaceConnect:
* @def: the definition of the VM (needed by 802.1Qbh and audit)
* @conn: pointer to virConnect object
* @driver: pointer to the qemud_driver
* @net: pointer to he VM's interface description with direct device type
* @qemuCaps: flags for qemu
*
* Returns a filedescriptor on success or -1 in case of error.
*/
int
qemuPhysIfaceConnect(virDomainDefPtr def,
struct qemud_driver *driver,
virDomainNetDefPtr net,
virBitmapPtr qemuCaps,
enum virVMOperationType vmop)
{
int rc;
#if WITH_MACVTAP
[...]
#else
(void)def;
(void)conn;
(void)net;
(void)qemuCaps;
(void)driver;
(void)vmop;
qemuReportError(VIR_ERR_INTERNAL_ERROR,
"%s", _("No support for macvtap device"));
rc = -1;
#endif
return rc;
}
--
Michael Wood <esiotrot(a)gmail.com>
13 years, 6 months
[libvirt] [PATCH 1/8] Add new API virDomain{Set, Get}BlockIoTune
by Lei Li
This patch add new pulic API virDomainSetBlockIoTune and
virDomainGetBlockIoTune.
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
---
include/libvirt/libvirt.h.in | 69 ++++++++++++++++++++
src/driver.h | 18 +++++
src/libvirt.c | 142 ++++++++++++++++++++++++++++++++++++++++++
src/libvirt_public.syms | 2 +
4 files changed, 231 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 2ab89f5..f4988c4 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1671,6 +1671,75 @@ int virDomainBlockPull(virDomainPtr dom, const char *path,
unsigned long bandwidth, unsigned int flags);
+/* Block I/O throttling support */
+
+/**
+ * VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC:
+ *
+ * Macro for the BlockIoTune tunable weight: it represents the total
+ * bytes per second permitted through a block device, as a ullong.
+ */
+
+#define VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC "total_bytes_sec"
+
+/**
+ * VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC:
+ *
+ * Macro for the BlockIoTune tunable weight: it repersents the read
+ * bytes per second permitted through a block device, as a ullong.
+ */
+
+#define VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC "read_bytes_sec"
+
+/**
+ * VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC:
+ *
+ * Macro for the BlockIoTune tunable weight: it repersents the write
+ * bytes per second permitted through a block device, as a ullong.
+ */
+
+#define VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC "write_bytes_sec"
+
+/**
+ * VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC:
+ *
+ * Macro for the BlockIoTune tunable weight: it repersents the total
+ * I/O operations per second permitted through a block device, as a ullong.
+ */
+
+#define VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC "total_iops_sec"
+
+/**
+ * VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC:
+ *
+ * Macro for the BlockIoTune tunable weight: it repersents the read
+ * I/O operations per second permitted through a block device, as a ullong.
+ */
+
+#define VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC "read_iops_sec"
+
+/**
+ * VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC:
+ * Macro for the BlockIoTune tunable weight: it repersents the write
+ * I/O operations per second permitted through a block device, as a ullong.
+ */
+
+#define VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC "write_iops_sec"
+
+int
+virDomainSetBlockIoTune(virDomainPtr dom,
+ const char *disk,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags);
+int
+virDomainGetBlockIoTune(virDomainPtr dom,
+ const char *disk,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags);
+
+
/*
* NUMA support
*/
diff --git a/src/driver.h b/src/driver.h
index 4c14aaa..6ce3efc 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -740,6 +740,24 @@ typedef int
(*virDrvDomainBlockPull)(virDomainPtr dom, const char *path,
unsigned long bandwidth, unsigned int flags);
+/*
+ * Block I/O throttling support
+ */
+
+typedef int
+ (*virDrvDomainSetBlockIoTune)(virDomainPtr dom,
+ const char *disk,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags);
+
+typedef int
+ (*virDrvDomainGetBlockIoTune)(virDomainPtr dom,
+ const char *disk,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags);
+
/**
* _virDriver:
diff --git a/src/libvirt.c b/src/libvirt.c
index 1518ed2..32ad5db 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -17149,3 +17149,145 @@ error:
virDispatchError(dom->conn);
return -1;
}
+
+/**
+ * virDomainSetBlockIoTune:
+ * @dom: pointer to domain object
+ * @disk: Fully-qualified disk name
+ * @params: Pointer to blkio parameter objects
+ * @nparams: Number of blkio parameters (this value can be the same or
+ * less than the number of parameters supported)
+ * @flags: An OR'ed set of virDomainModificationImpact
+ *
+ * Change all or a subset of the per-device block IO tunables.
+ *
+ * The @disk parameter is the name of the block device. Get this
+ * by calling virDomainGetXMLDesc and finding the <target dev='...'>
+ * attribute within //domain/devices/disk. (For example, "xvda").
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int virDomainSetBlockIoTune(virDomainPtr dom,
+ const char *disk,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(dom, "disk=%p, params=%p, nparams=%d, flags=%x",
+ disk, params, nparams, flags);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+
+ if (dom->conn->flags & VIR_CONNECT_RO) {
+ virLibDomainError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+ goto error;
+ }
+
+ if (!disk || (nparams <= 0) || (params == NULL)) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (virTypedParameterValidateSet(dom, params, nparams) < 0)
+ return -1;
+
+ conn = dom->conn;
+
+ if (conn->driver->domainSetBlockIoTune) {
+ int ret;
+ ret = conn->driver->domainSetBlockIoTune(dom, disk, params, nparams, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibDomainError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(dom->conn);
+ return -1;
+}
+
+/**
+ * virDomainGetBlockIoTune:
+ * @dom: pointer to domain object
+ * @disk: Fully-qualified disk name
+ * @params: Pointer to blkio parameter object
+ * (return value, allocated by the caller)
+ * @nparams: Pointer to number of blkio parameters
+ * @flags: An OR'ed set of virDomainModificationImpact
+ *
+ * Get all block IO tunable parameters for a given device. On input,
+ * @nparams gives the size of the @params array; on output, @nparams
+ * gives how many slots were filled with parameter information, which
+ * might be less but will not exceed the input value.
+ *
+ * As a special case, calling with @params as NULL and @nparams as 0 on
+ * input will cause @nparams on output to contain the number of parameters
+ * supported by the hypervisor. The caller should then allocate @params
+ * array, i.e. (sizeof(@virTypedParameter) * @nparams) bytes and call the API
+ * agiain.
+ *
+ * See virDomainGetMemoryParameters() for an equivalent usage example.
+ *
+ * The @disk parameter is the name of the block device. Get this
+ * by calling virDomainGetXMLDesc and finding the <target dev='...'>
+ * attribute within //domain/devices/disk. (For example, "xvda").
+ *
+ * Returns -1 in case of error, 0 in case of success.
+ */
+int virDomainGetBlockIoTune(virDomainPtr dom,
+ const char *disk,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+
+ VIR_DOMAIN_DEBUG(dom, "disk=%p, params=%p, nparams=%d, flags=%x",
+ disk, params, (nparams) ? *nparams : -1, flags);
+
+ virResetLastError();
+
+ if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+ virLibDomainError(VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+
+ if (!disk || (nparams == NULL) || (*nparams < 0) ||
+ (params == NULL && *nparams != 0)) {
+ virLibDomainError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto error;
+ }
+
+ if (VIR_DRV_SUPPORTS_FEATURE(dom->conn->driver, dom->conn,
+ VIR_DRV_FEATURE_TYPED_PARAM_STRING))
+ flags |= VIR_TYPED_PARAM_STRING_OKAY;
+
+ conn = dom->conn;
+
+ if (conn->driver->domainGetBlockIoTune) {
+ int ret;
+ ret = conn->driver->domainGetBlockIoTune(dom, disk, params, nparams, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibDomainError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(dom->conn);
+ return -1;
+
+}
+
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index bcefb10..4808891 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -496,6 +496,8 @@ LIBVIRT_0.9.7 {
virDomainSnapshotGetParent;
virDomainSnapshotListChildrenNames;
virDomainSnapshotNumChildren;
+ virDomainSetBlockIoTune;
+ virDomainGetBlockIoTune;
} LIBVIRT_0.9.5;
# .... define new API here using predicted next version number ....
--
1.7.1
13 years, 6 months
[libvirt] [PATCH 2/8] Add virDomain{Set, Get}BlockIoTune support to the remote driver
by Lei Li
Support Block I/O Throttle setting and query to remote driver.
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
---
daemon/remote.c | 109 ++++++++++++++++++++++++++++++++++++++++++
src/remote/remote_driver.c | 96 +++++++++++++++++++++++++++++++++++++
src/remote/remote_protocol.x | 26 ++++++++++-
src/remote_protocol-structs | 24 +++++++++
4 files changed, 254 insertions(+), 1 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index aa3f768..227d36e 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -1886,6 +1886,115 @@ cleanup:
return rv;
}
+static int
+remoteDispatchDomainSetBlockIoThrottle(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_set_block_io_throttle_args *args)
+{
+ virDomainPtr dom = NULL;
+ int rv = -1;
+ virTypedParameterPtr params = NULL;
+ int nparams;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if ((params = remoteDeserializeTypedParameters(args->params.params_val,
+ args->params.params_len,
+ REMOTE_DOMAIN_BLKIOTHROTTLE_PARAMETERS_MAX,
+ &nparams)) == NULL)
+ goto cleanup;
+
+ rv = virDomainSetBlockIoTune(dom, args->disk, params, nparams, args->flags);
+
+ if (rv < 0)
+ goto cleanup;
+
+cleanup:
+ if (rv < 0)
+ virNetMessageSaveError(rerr);
+ if (dom)
+ virDomainFree(dom);
+ return rv;
+}
+
+static int
+remoteDispatchDomainGetBlockIoThrottle(virNetServerPtr server ATTRIBUTE_UNUSED,
+ virNetServerClientPtr client ATTRIBUTE_UNUSED,
+ virNetMessagePtr hdr ATTRIBUTE_UNUSED,
+ virNetMessageErrorPtr rerr,
+ remote_domain_get_block_io_throttle_args *args,
+ remote_domain_get_block_io_throttle_ret *ret)
+{
+ virDomainPtr dom = NULL;
+ int rv = -1;
+ int i;
+ virTypedParameterPtr params;
+ int nparams = args->nparams;
+ struct daemonClientPrivate *priv =
+ virNetServerClientGetPrivateData(client);
+
+ if (!priv->conn) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+ goto cleanup;
+ }
+
+ if (nparams > REMOTE_DOMAIN_BLKIOTHROTTLE_PARAMETERS_MAX) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("nparams too large"));
+ goto cleanup;
+ }
+
+ if (VIR_ALLOC_N(params, nparams) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+ goto cleanup;
+
+ if (virDomainGetBlockIoTune(dom, args->disk, params, &nparams, args->flags) < 0)
+ goto cleanup;
+
+ /* In this case, we need to send back the number of parameters
+ * supported
+ */
+ if (args->nparams == 0) {
+ ret->nparams = nparams;
+ goto success;
+ }
+
+ /* Serialise the block I/O throttle. */
+ if (remoteSerializeTypedParameters(params, nparams,
+ &ret->params.params_val,
+ &ret->params.params_len,
+ args->flags) < 0)
+ goto cleanup;
+
+success:
+ rv = 0;
+
+cleanup:
+ if (rv < 0) {
+ virNetMessageSaveError(rerr);
+ if (ret->params.params_val) {
+ for (i = 0; i < nparams; i++)
+ VIR_FREE(ret->params.params_val[i].field);
+ VIR_FREE(ret->params.params_val);
+ }
+ }
+ if (dom)
+ virDomainFree(dom);
+ return rv;
+}
/*-------------------------------------------------------------*/
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 94fd3e7..fa2d2c7 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -2178,6 +2178,100 @@ done:
return rv;
}
+static int remoteDomainSetBlockIoTune(virDomainPtr domain,
+ const char *disk,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags)
+{
+ int rv = -1;
+ remote_domain_set_block_io_throttle_args args;
+ struct private_data *priv = domain->conn->privateData;
+
+ remoteDriverLock(priv);
+
+ memset(&args, 0, sizeof(args));
+
+ make_nonnull_domain(&args.dom, domain);
+ args.disk = (char *)disk;
+ args.flags = flags;
+
+ if (remoteSerializeTypedParameters(params, nparams, &args.params.params_val, &args.params.params_len) < 0) {
+ xdr_free((xdrproc_t)xdr_remote_domain_set_block_io_throttle_args, (char *)&args);
+ goto done;
+ }
+
+ if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_SET_BLOCK_IO_THROTTLE,
+ (xdrproc_t) xdr_remote_domain_set_block_io_throttle_args,
+ (char *) &args,
+ (xdrproc_t) xdr_void,
+ (char *) NULL) == -1) {
+ goto done;
+ }
+ rv = 0;
+
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
+static int remoteDomainGetBlockIoTune(virDomainPtr domain,
+ const char *disk,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ int rv = -1;
+ remote_domain_get_block_io_throttle_args args;
+ remote_domain_get_block_io_throttle_ret ret;
+ struct private_data *priv = domain->conn->privateData;
+
+ remoteDriverLock(priv);
+
+ make_nonnull_domain(&args.dom, domain);
+ args.disk = (char *)disk;
+ args.nparams = *nparams;
+ args.flags = flags;
+
+ memset(&ret, 0, sizeof(ret));
+
+
+ if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_BLOCK_IO_THROTTLE,
+ (xdrproc_t) xdr_remote_domain_get_block_io_throttle_args,
+ (char *) &args,
+ (xdrproc_t) xdr_remote_domain_get_block_io_throttle_ret,
+ (char *) &ret) == -1) {
+ goto done;
+ }
+
+ /* Handle the case when the caller does not know the number of parameters
+ * and is asking for the number of parameters supported
+ */
+ if (*nparams == 0) {
+ *nparams = ret.nparams;
+ rv = 0;
+ goto cleanup;
+ }
+
+ if (remoteDeserializeTypedParameters(ret.params.params_val,
+ ret.params.params_len,
+ REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX,
+ params,
+ nparams) < 0)
+ goto cleanup;
+
+ rv = 0;
+
+cleanup:
+ xdr_free ((xdrproc_t) xdr_remote_domain_get_block_io_throttle_ret,
+ (char *) &ret);
+ rv = 0;
+
+done:
+ remoteDriverUnlock(priv);
+ return rv;
+}
+
/*----------------------------------------------------------------------*/
static virDrvOpenStatus ATTRIBUTE_NONNULL (1)
@@ -4550,6 +4644,8 @@ static virDriver remote_driver = {
.domainGetBlockJobInfo = remoteDomainGetBlockJobInfo, /* 0.9.4 */
.domainBlockJobSetSpeed = remoteDomainBlockJobSetSpeed, /* 0.9.4 */
.domainBlockPull = remoteDomainBlockPull, /* 0.9.4 */
+ .domainSetBlockIoTune = remoteDomainSetBlockIoTune, /* 0.9.8 */
+ .domainGetBlockIoTune = remoteDomainGetBlockIoTune, /* 0.9.8 */
};
static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 5ea1114..9969990 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -125,6 +125,9 @@ const REMOTE_DOMAIN_BLKIO_PARAMETERS_MAX = 16;
/* Upper limit on list of memory parameters. */
const REMOTE_DOMAIN_MEMORY_PARAMETERS_MAX = 16;
+/* Upper limit on list of blockio throttle parameters. */
+const REMOTE_DOMAIN_BLKIOTHROTTLE_PARAMETERS_MAX = 16;
+
/* Upper limit on list of node cpu stats. */
const REMOTE_NODE_CPU_STATS_MAX = 16;
@@ -1075,6 +1078,25 @@ struct remote_domain_block_pull_args {
unsigned int flags;
};
+struct remote_domain_set_block_io_throttle_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string disk;
+ remote_typed_param params<REMOTE_DOMAIN_BLKIOTHROTTLE_PARAMETERS_MAX>;
+ unsigned int flags;
+};
+
+struct remote_domain_get_block_io_throttle_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string disk;
+ int nparams;
+ unsigned int flags;
+};
+
+struct remote_domain_get_block_io_throttle_ret {
+ remote_typed_param params<REMOTE_DOMAIN_BLKIOTHROTTLE_PARAMETERS_MAX>;
+ int nparams;
+};
+
/* Network calls: */
struct remote_num_of_networks_ret {
@@ -2564,7 +2586,9 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_SNAPSHOT_NUM_CHILDREN = 246, /* autogen autogen priority:high */
REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES = 247, /* autogen autogen priority:high */
REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE = 248, /* skipgen skipgen */
- REMOTE_PROC_DOMAIN_OPEN_GRAPHICS = 249 /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_OPEN_GRAPHICS = 249, /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_SET_BLOCK_IO_THROTTLE = 250, /* skipgen skipgen */
+ REMOTE_PROC_DOMAIN_GET_BLOCK_IO_THROTTLE = 251 /* skipgen skipgen */
/*
* Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index b460b77..eabf5e5 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -759,6 +759,28 @@ struct remote_domain_block_pull_args {
uint64_t bandwidth;
u_int flags;
};
+struct remote_domain_set_block_io_throttle_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string disk;
+ struct {
+ u_int params_len;
+ remote_typed_param * params_val;
+ } params;
+ u_int flags;
+};
+struct remote_domain_get_block_io_throttle_args {
+ remote_nonnull_domain dom;
+ remote_nonnull_string disk;
+ int nparams;
+ u_int flags;
+};
+struct remote_domain_get_block_io_throttle_ret {
+ struct {
+ u_int params_len;
+ remote_typed_param * params_val;
+ } params;
+ int nparams;
+};
struct remote_num_of_networks_ret {
int num;
};
@@ -2007,4 +2029,6 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_SNAPSHOT_LIST_CHILDREN_NAMES = 247,
REMOTE_PROC_DOMAIN_EVENT_DISK_CHANGE = 248,
REMOTE_PROC_DOMAIN_OPEN_GRAPHICS = 249,
+ REMOTE_PROC_DOMAIN_SET_BLOCK_IO_THROTTLE = 250,
+ REMOTE_PROC_DOMAIN_GET_BLOCK_IO_THROTTLE = 251,
};
--
1.7.1
13 years, 6 months
[libvirt] [PATCH 8/8] Add tests for blkdeviotune
by Lei Li
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
---
.../qemuxml2argv-blkdeviotune.args | 5 +++
.../qemuxml2argvdata/qemuxml2argv-blkdeviotune.xml | 37 ++++++++++++++++++++
tests/qemuxml2argvtest.c | 1 +
tests/qemuxml2xmltest.c | 1 +
4 files changed, 44 insertions(+), 0 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.xml
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.args b/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.args
new file mode 100644
index 0000000..9db8aff
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.args
@@ -0,0 +1,5 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
+pc -m 214 -smp 1 -name QEMUGuest1 -nographic -monitor unix:/tmp/test-monitor, \
+server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -net none -serial \
+none -parallel none -usb
+
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.xml b/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.xml
new file mode 100644
index 0000000..0cabb90
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-blkdeviotune.xml
@@ -0,0 +1,37 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219100</memory>
+ <currentMemory>219100</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk' snapshot='internal'>
+ <driver name='qemu' type='qcow2' cache='none'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <iotune>
+ <total_bytes_sec>5000</total_bytes_sec>
+ <total_iops_sec>6000</total_iops_sec>
+ <address type='drive' controller='0' bus='0' unit='0'/>
+ </disk>
+ <disk type='block' device='cdrom' snapshot='no'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/HostVG/QEMUGuest2'/>
+ <target dev='hdc' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <controller type='ide' index='0'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
+
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index d9a6e8d..1ebb950 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -585,6 +585,7 @@ mymain(void)
DO_TEST("blkiotune", false, QEMU_CAPS_NAME);
DO_TEST("cputune", false, QEMU_CAPS_NAME);
DO_TEST("numatune-memory", false, NONE);
+ DO_TEST("blkdeviotune", false, QEMU_CAPS_NAME);
DO_TEST("multifunction-pci-device", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG,
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 3f37520..2e6b5c7 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -191,6 +191,7 @@ mymain(void)
DO_TEST("event_idx");
DO_TEST("usb-redir");
+ DO_TEST("blkdeviotune");
/* These tests generate different XML */
DO_TEST_DIFFERENT("balloon-device-auto");
--
1.7.1
13 years, 6 months
[libvirt] [PATCH 7/8] Support virDomain{Set, Get}BlockIoThrottle in the python API
by Lei Li
Python support for both setting and getting block I/O throttle.
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
---
python/generator.py | 2 +
python/libvirt-override-api.xml | 16 ++++
python/libvirt-override.c | 178 +++++++++++++++++++++++++++++++++++++++
3 files changed, 196 insertions(+), 0 deletions(-)
diff --git a/python/generator.py b/python/generator.py
index 71afdb7..88c52b9 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -414,6 +414,8 @@ skip_impl = (
'virDomainGetBlockJobInfo',
'virDomainMigrateGetMaxSpeed',
'virDomainBlockStatsFlags',
+ 'virDomainSetBlockIoTune',
+ 'virDomainGetBlockIoTune',
)
qemu_skip_impl = (
diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml
index ef02f34..a05da3c 100644
--- a/python/libvirt-override-api.xml
+++ b/python/libvirt-override-api.xml
@@ -375,5 +375,21 @@
<arg name='flags' type='unsigned int' info='flags, currently unused, pass 0.'/>
<return type='unsigned long' info='current max migration speed, or None in case of error'/>
</function>
+ <function name='virDomainSetBlockIoTune' file='python'>
+ <info>Change the I/O throttle for a block device</info>
+ <arg name='dom' type='virDomainPtr' info='pointer to the domain'/>
+ <arg name='disk' type='const char *' info='disk name'/>
+ <arg name='params' type='virTypedParameterPtr' info='Pointer to blkio throttle params object'/>
+ <arg name='flags' type='unsigned int' info='an OR'ed set of virDomainModificationImpact'/>
+ <return type='int' info='0 in case of success, -1 in case of failure'/>
+ </function>
+ <function name='virDomainGetBlockIoTune' file='python'>
+ <info>Get the I/O throttle a block device</info>
+ <arg name='dom' type='virDomainPtr' info='pointer to the domain'/>
+ <arg name='disk' type='const char *' info='disk name'/>
+ <arg name='params' type='virTypedParameterPtr' info='Pointer to blkio throttle params object'/>
+ <arg name='flags' type='unsigned int' info='an OR'ed set of virDomainModificationImpact'/>
+ <return type='int' info='0 in case of success, -1 in case of failure'/>
+ </function>
</symbols>
</api>
diff --git a/python/libvirt-override.c b/python/libvirt-override.c
index 1759bae..be76d87 100644
--- a/python/libvirt-override.c
+++ b/python/libvirt-override.c
@@ -3195,6 +3195,182 @@ LIBVIRT_END_ALLOW_THREADS;
return ret;
}
+static PyObject *
+libvirt_virDomainSetBlockIoTune(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args)
+{
+ virDomainPtr domain;
+ PyObject *pyobj_domain, *pyinfo;
+ const char *disk;
+ unsigned int flags;
+ virTypedParameterPtr params;
+ int nparams = 0, i;
+ int c_ret;
+
+ if (!PyArg_ParseTuple(args, (char *)"Ozi:virDomainSetBlockIoTune",
+ &pyobj_domain, &disk, &pyinfo, &flags))
+ return(NULL);
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ c_ret = virDomainGetBlockIoTune(domain, disk, NULL, &nparams, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (c_ret < 0)
+ return VIR_PY_INT_FAIL;
+
+ if ((params = malloc(sizeof(*params)*nparams)) == NULL)
+ return VIR_PY_INT_FAIL;
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ c_ret = virDomainGetBlockIoTune(domain, disk, params, &nparams, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (c_ret < 0) {
+ free(params);
+ return VIR_PY_INT_FAIL;
+ }
+
+ /* convert to a Python tuple of long objects */
+ for (i = 0; i < nparams; i++) {
+ PyObject *key, *val;
+ key = libvirt_constcharPtrWrap(params[i].field);
+ val = PyDict_GetItem(pyinfo, key);
+ Py_DECREF(key);
+
+ if (val == NULL)
+ continue;
+
+ switch (params[i].type) {
+ case VIR_TYPED_PARAM_INT:
+ params[i].value.i = (int)PyInt_AS_LONG(val);
+ break;
+
+ case VIR_TYPED_PARAM_UINT:
+ params[i].value.ui = (unsigned int)PyInt_AS_LONG(val);
+ break;
+
+ case VIR_TYPED_PARAM_LLONG:
+ params[i].value.l = (long long)PyLong_AsLongLong(val);
+ break;
+
+ case VIR_TYPED_PARAM_ULLONG:
+ params[i].value.ul = (unsigned long long)PyLong_AsLongLong(val);
+ break;
+
+ case VIR_TYPED_PARAM_DOUBLE:
+ params[i].value.d = (double)PyFloat_AsDouble(val);
+ break;
+
+ case VIR_TYPED_PARAM_BOOLEAN:
+ {
+ PyObject *hacktrue = PyBool_FromLong(1);
+ params[i].value.b = hacktrue == val ? 1: 0;
+ Py_DECREF(hacktrue);
+ }
+ break;
+
+ default:
+ free(params);
+ return VIR_PY_INT_FAIL;
+ }
+ }
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ c_ret = virDomainSetMemoryParameters(domain, params, nparams, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (c_ret < 0) {
+ free(params);
+ return VIR_PY_INT_FAIL;
+ }
+
+ free(params);
+ return VIR_PY_INT_SUCCESS;
+}
+
+static PyObject *
+libvirt_virDomainGetBlockIoTune(PyObject *self ATTRIBUTE_UNUSED,
+ PyObject *args)
+{
+ virDomainPtr domain;
+ PyObject *pyobj_domain, *pyreply;
+ const char *disk;
+ int nparams = 0, i;
+ unsigned int flags;
+ virTypedParameterPtr params;
+ int c_ret;
+
+ if (!PyArg_ParseTuple(args, (char *)"Oi:virDomainGetBlockIoTune",
+ &pyobj_domain, &disk, &flags))
+ return(NULL);
+ domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain);
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ c_ret = virDomainGetBlockIoTune(domain, disk, NULL, &nparams, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (c_ret < 0)
+ return VIR_PY_NONE;
+
+ if ((params = malloc(sizeof(*params)*nparams)) == NULL)
+ return VIR_PY_NONE;
+
+ LIBVIRT_BEGIN_ALLOW_THREADS;
+ c_ret = virDomainGetBlockIoTune(domain, disk, params, &nparams, flags);
+ LIBVIRT_END_ALLOW_THREADS;
+
+ if (c_ret < 0) {
+ free(params);
+ return VIR_PY_NONE;
+ }
+
+ /* convert to a Python tuple of long objects */
+ if ((pyreply = PyDict_New()) == NULL) {
+ free(params);
+ return VIR_PY_NONE;
+ }
+ for (i = 0 ; i < nparams ; i++) {
+ PyObject *key, *val;
+
+ switch (params[i].type) {
+ case VIR_TYPED_PARAM_INT:
+ val = PyInt_FromLong((long)params[i].value.i);
+ break;
+
+ case VIR_TYPED_PARAM_UINT:
+ val = PyInt_FromLong((long)params[i].value.ui);
+ break;
+
+ case VIR_TYPED_PARAM_LLONG:
+ val = PyLong_FromLongLong((long long)params[i].value.l);
+ break;
+
+ case VIR_TYPED_PARAM_ULLONG:
+ val = PyLong_FromLongLong((unsigned long long)params[i].value.ul);
+ break;
+
+ case VIR_TYPED_PARAM_DOUBLE:
+ val = PyFloat_FromDouble((double)params[i].value.d);
+ break;
+
+ case VIR_TYPED_PARAM_BOOLEAN:
+ val = PyBool_FromLong((long)params[i].value.b);
+ break;
+
+ default:
+ free(params);
+ Py_DECREF(pyreply);
+ return VIR_PY_NONE;
+ }
+
+ key = libvirt_constcharPtrWrap(params[i].field);
+ PyDict_SetItem(pyreply, key, val);
+ }
+ free(params);
+ return(pyreply);
+}
+
/*******************************************
* Helper functions to avoid importing modules
* for every callback
@@ -4837,6 +5013,8 @@ static PyMethodDef libvirtMethods[] = {
{(char *) "virDomainSnapshotListNames", libvirt_virDomainSnapshotListNames, METH_VARARGS, NULL},
{(char *) "virDomainRevertToSnapshot", libvirt_virDomainRevertToSnapshot, METH_VARARGS, NULL},
{(char *) "virDomainGetBlockJobInfo", libvirt_virDomainGetBlockJobInfo, METH_VARARGS, NULL},
+ {(char *) "virDomainSetBlockIoTune", libvirt_virDomainSetBlockIoTune, METH_VARARGS, NULL},
+ {(char *) "virDomainGetBlockIoTune", libvirt_virDomainGetBlockIoTune, METH_VARARGS, NULL},
{(char *) "virDomainSendKey", libvirt_virDomainSendKey, METH_VARARGS, NULL},
{(char *) "virDomainMigrateGetMaxSpeed", libvirt_virDomainMigrateGetMaxSpeed, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
--
1.7.1
13 years, 6 months
[libvirt] [PATCH 6/8] Doc: Add description and validation for blkdeviotune
by Lei Li
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
---
docs/formatdomain.html.in | 31 +++++++++++++++++++++++++++++++
docs/schemas/domaincommon.rng | 24 ++++++++++++++++++++++++
2 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index cbad196..733062d 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -893,6 +893,14 @@
<driver name="tap" type="aio" cache="default"/>
<source file='/var/lib/xen/images/fv0'/ startupPolicy='optional'>
<target dev='hda' bus='ide'/>
+ <iotune>
+ <total_bytes_sec>n</total_bytes_sec>
+ <read_bytes_sec>n</read_bytes_sec>
+ <write_bytes_sec>n</write_bytes_sec>
+ <total_iops_sec>n</total_iops_sec>
+ <read_bytes_sec>n</read_bytes_sec>
+ <write_bytes_sec>n</write_bytes_sec>
+ </iotune>
<boot order='2'/>
<encryption type='...'>
...
@@ -1010,6 +1018,29 @@
<span class="since">Since 0.0.3; <code>bus</code> attribute since 0.4.3;
"usb" attribute value since after 0.4.4; "sata" attribute value since
0.9.7</span></dd>
+ <dt><code>iotune</code></dt>
+ <dd>The optional <code>iotune</code> element provides the ability
+ to set or get block I/O throttling for the device. Block I/O
+ throtting be implemented by qemu, is specified per-disk and can
+ vary across multiple disks.</dd>
+ <dt><code>total_bytes_sec</code></dt>
+ <dd>The optinal <code>total_bytes_sec</code> element is the total throughput
+ limit in bytes per second.</dd>
+ <dt><code>read_bytes_sec</code></dt>
+ <dd>The optinal <code>read_bytes_sec</code> element is the read throughput
+ limit in bytes per second.</dd>
+ <dt><code>write_bytes_sec</code</dt>
+ <dd>The optinal <code>write_bytes_sec</code> element is the write throughput
+ limit in bytes per second.</dd>
+ <dt><code>total_iops_sec</code></dt>
+ <dd>The optional <code>total_iops_sec</code> element is the total I/O operations
+ per second.</dd>
+ <dt><code>read_iops_sec</code></dt>
+ <dd>The optional <code>read_iops_sec</code> element is the read I/O operations
+ per second.</dd>
+ <dt><code>write_iops_sec</code></dt>
+ <dd>The optional <code>write_iops_sec</code> element is the write I/O operations
+ per second.</dd>
<dt><code>driver</code></dt>
<dd>
The optional driver element allows specifying further details
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index b6f858e..c6873a0 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -698,6 +698,30 @@
<optional>
<ref name="snapshot"/>
</optional>
+ <optional>
+ <element name="iotune">
+ <choice>
+ <element name="total_bytes_sec">
+ <ref name="unsignedLongLong">
+ </element>
+ <element name="read_bytes_sec">
+ <ref name="unsignedLongLong">
+ </element>
+ <element name="write_bytes_sec">
+ <ref name="unsignedLongLong">
+ </element>
+ <element name="total_iops_sec">
+ <ref name="unsignedLongLong">
+ </element>
+ <element name="read_iops_sec">
+ <ref name="unsignedLongLong">
+ </element>
+ <element name="write_iopw_sec">
+ <ref name="unsignedLongLong">
+ </emement>
+ </choice>
+ </element>
+ </optional>
<choice>
<group>
<attribute name="type">
--
1.7.1
13 years, 6 months
[libvirt] [PATCH 5/8] Enable the blkdeviotune command in virsh
by Lei Li
Support virsh command blkdeviotune. Can set or query a block disk
I/O throttle setting.
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
---
tools/virsh.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
tools/virsh.pod | 23 +++++
2 files changed, 263 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 83dc3c7..9eec68e 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -6074,6 +6074,245 @@ cmdNetworkAutostart(vshControl *ctl, const vshCmd *cmd)
}
/*
+ * "blkdeviotune" command
+ */
+static const vshCmdInfo info_blkdeviotune[] = {
+ {"help", N_("Set or query a block disk I/O throttle setting.")},
+ {"desc", N_("Set or query a block disk I/O throttle setting.\n" \
+ " To query the block disk I/O throttle setting use the following" \
+ " command: \n\n" \
+ " virsh # blkdeviotune <domain> <device>")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_blkdeviotune[] = {
+ {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")},
+ {"device", VSH_OT_DATA, VSH_OFLAG_REQ, N_("block device")},
+ {"total_bytes_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("total throughput limit in bytes per second")},
+ {"read_bytes_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("read throughput limit in bytes per second")},
+ {"write_bytes_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("write throughput limit in bytes per second")},
+ {"total_iops_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("total I/O operations limit per second")},
+ {"read_iops_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("read I/O operations limit per second")},
+ {"write_iops_sec", VSH_OT_INT, VSH_OFLAG_NONE, N_("write I/O operations limit per second")},
+ {"config", VSH_OT_BOOL, 0, N_("affect next boot")},
+ {"live", VSH_OT_BOOL, 0, N_("affect running domain")},
+ {"current", VSH_OT_BOOL, 0, N_("affect current domain")},
+ {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdBlkdeviotune(vshControl *ctl, const vshCmd *cmd)
+{
+ virDomainPtr dom = NULL;
+ const char *name, *disk;
+ unsigned long long total_bytes_sec = 0, read_bytes_sec = 0, write_bytes_sec = 0;
+ unsigned long long total_iops_sec = 0, read_iops_sec = 0, write_iops_sec = 0;
+ int nparams = 0;
+ virTypedParameterPtr params = NULL, temp = NULL;
+ unsigned int flags = 0, i = 0;
+ int rv = 0;
+ int current = vshCommandOptBool(cmd, "current");
+ int config = vshCommandOptBool(cmd, "config");
+ int live = vshCommandOptBool(cmd, "live");
+
+ if (current) {
+ if (live || config) {
+ vshError(ctl, "%s", _("--current must be specified exclusively"));
+ return false;
+ }
+ flags = VIR_DOMAIN_AFFECT_CURRENT;
+ } else {
+ if (config)
+ flags |= VIR_DOMAIN_AFFECT_CONFIG;
+ if (live)
+ flags |= VIR_DOMAIN_AFFECT_LIVE;
+ }
+
+ if (!vshConnectionUsability(ctl, ctl->conn))
+ goto out;
+
+ if (!(dom = vshCommandOptDomain(ctl, cmd, &name)))
+ goto out;
+
+ if (vshCommandOptString(cmd, "device", &disk) < 0)
+ goto out;
+
+ if ((rv = vshCommandOptULongLong(cmd, "total_bytes_sec", &total_bytes_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ nparams++;
+ }
+
+ if ((rv = vshCommandOptULongLong(cmd, "read_bytes_sec", &read_bytes_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ nparams++;
+ }
+
+ if ((rv = vshCommandOptULongLong(cmd, "write_bytes_sec", &write_bytes_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ nparams++;
+ }
+
+ if ((rv = vshCommandOptULongLong(cmd, "total_iops_sec", &total_iops_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ nparams++;
+ }
+
+ if ((rv = vshCommandOptULongLong(cmd, "read_iops_sec", &read_iops_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ nparams++;
+ }
+
+ if ((rv = vshCommandOptULongLong(cmd, "write_iops_sec", &write_iops_sec)) < 0) {
+ vshError(ctl, "%s",
+ _("Unable to parse integer parameter"));
+ goto out;
+ } else if (rv > 0) {
+ nparams++;
+ }
+
+ if (nparams == 0) {
+
+ if ((virDomainGetBlockIoTune(dom, disk, NULL, &nparams, flags)) != 0) {
+ vshError(ctl, "%s",
+ _("Unable to get number of block I/O throttle parameters"));
+ goto out;
+ }
+
+ if (nparams == 0) {
+ virDomainFree(dom);
+ return true;
+ }
+
+ params = vshCalloc(ctl, nparams, sizeof(*params));
+
+ if ((virDomainGetBlockIoTune(dom, disk, params, &nparams, flags)) != 0) {
+ vshError(ctl, "%s",
+ _("Unable to get block I/O throttle parameters"));
+ goto out;
+ }
+
+ for (i = 0; i < nparams; i++) {
+ switch(params[i].type) {
+ case VIR_TYPED_PARAM_INT:
+ vshPrint(ctl, "%-15s: %d\n", params[i].field,
+ params[i].value.i);
+ break;
+ case VIR_TYPED_PARAM_UINT:
+ vshPrint(ctl, "%-15s: %u\n", params[i].field,
+ params[i].value.ui);
+ break;
+ case VIR_TYPED_PARAM_LLONG:
+ vshPrint(ctl, "%-15s: %lld\n", params[i].field,
+ params[i].value.l);
+ break;
+ case VIR_TYPED_PARAM_ULLONG:
+ vshPrint(ctl, "%-15s: %llu\n", params[i].field,
+ params[i].value.ul);
+ break;
+ case VIR_TYPED_PARAM_DOUBLE:
+ vshPrint(ctl, "%-15s: %f\n", params[i].field,
+ params[i].value.d);
+ break;
+ case VIR_TYPED_PARAM_BOOLEAN:
+ vshPrint(ctl, "%-15s: %d\n", params[i].field,
+ params[i].value.b);
+ break;
+ default:
+ vshPrint(ctl, "unimplemented block I/O throttle parameter type\n");
+ }
+ }
+
+ virDomainFree(dom);
+ return true;
+ } else {
+ /* Set the block I/O throttle, match by opt since parameters can be 0 */
+ params = vshCalloc(ctl, nparams, sizeof(*params));
+ i = 0;
+
+ if ((i < nparams) && (vshCommandOptBool(cmd, "total_bytes_sec"))) {
+ temp = ¶ms[i];
+ temp->type = VIR_TYPED_PARAM_ULLONG;
+ strncpy(temp->field, VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
+ sizeof(temp->field));
+ temp->value.ul = total_bytes_sec;
+ i++;
+ }
+
+ if ((i < nparams) && (vshCommandOptBool(cmd, "read_bytes_sec"))) {
+ temp = ¶ms[i];
+ temp->type = VIR_TYPED_PARAM_ULLONG;
+ strncpy(temp->field, VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
+ sizeof(temp->field));
+ temp->value.ul = read_bytes_sec;
+ i++;
+ }
+
+ if ((i < nparams) && (vshCommandOptBool(cmd, "write_bytes_sec"))) {
+ temp = ¶ms[i];
+ temp->type = VIR_TYPED_PARAM_ULLONG;
+ strncpy(temp->field, VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
+ sizeof(temp->field));
+ temp->value.ul = write_bytes_sec;
+ i++;
+ }
+
+ if ((i < nparams) && (vshCommandOptBool(cmd, "total_iops_sec"))) {
+ temp = ¶ms[i];
+ temp->type = VIR_TYPED_PARAM_ULLONG;
+ strncpy(temp->field, VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
+ sizeof(temp->field));
+ temp->value.ul = total_iops_sec;
+ i++;
+ }
+
+ if ((i < nparams) && (vshCommandOptBool(cmd, "read_iops_sec"))) {
+ temp = ¶ms[i];
+ temp->type = VIR_TYPED_PARAM_ULLONG;
+ strncpy(temp->field, VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
+ sizeof(temp->field));
+ temp->value.ul = read_iops_sec;
+ i++;
+ }
+
+ if ((i < nparams) && (vshCommandOptBool(cmd, "write_iops_sec"))) {
+ temp = ¶ms[i];
+ temp->type = VIR_TYPED_PARAM_ULLONG;
+ strncpy(temp->field, VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
+ sizeof(temp->field));
+ temp->value.ul = write_iops_sec;
+ }
+
+ if ((virDomainSetBlockIoTune(dom, disk, params, nparams, flags)) != 0) {
+ vshError(ctl, "%s",
+ _("Unable to change block I/O throttle"));
+ goto out;
+ } else {
+ virDomainFree(dom);
+ return true;
+ }
+ }
+
+out:
+ virDomainFree(dom);
+ return false;
+}
+
+/*
* "net-create" command
*/
static const vshCmdInfo info_network_create[] = {
@@ -14023,6 +14262,7 @@ static const vshCmdDef domManagementCmds[] = {
{"blkiotune", cmdBlkiotune, opts_blkiotune, info_blkiotune, 0},
{"blockpull", cmdBlockPull, opts_block_pull, info_block_pull, 0},
{"blockjob", cmdBlockJob, opts_block_job, info_block_job, 0},
+ {"blkdeviotune", cmdBlkdeviotune, opts_blkdeviotune, info_blkdeviotune, 0},
#ifndef WIN32
{"console", cmdConsole, opts_console, info_console, 0},
#endif
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 775d302..fedb8b1 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -572,6 +572,29 @@ operation can be checked with B<blockjob>.
I<path> specifies fully-qualified path of the disk.
I<bandwidth> specifies copying bandwidth limit in Mbps.
+=item B<blkdeviotune> I<domain> I<device> [[I<--total_bytes_sec> B<total_bytes_sec>]
+| [[I<--read_bytes_sec> B<read_bytes_sec>] [I<--write_bytes_sec> B<write_bytes_sec>]]
+[[I<--total_iops_sec> B<total_iops_sec>] | [[I<--read_iops_sec> B<read_iops_sec>]
+[I<--write_iops_sec> B<write_iops_sec>]] [[I<--config>] [I<--live>] | [I<--current>]]
+
+Set or query the block disk io limits settting.
+I<path> specifies block disk name.
+I<--total_bytes_sec> specifies total throughput limit in bytes per second.
+I<--read_bytes_sec> specifies read throughput limit in bytes per second.
+I<--write_bytes_sec> specifies write throughput limit in bytes per second.
+I<--total_iops_sec> specifies total I/O operations limit per second.
+I<--read_iops_sec> specifies read I/O operations limit per second.
+I<--write_iops_sec> specifies write I/O operations limit per second.
+
+If I<--live> is specified, affect a running guest.
+If I<--config> is specified, affect the next boot of a persistent guest.
+If I<--current> is specified, affect the current guest state.
+Both I<--live> and I<--current> flags may be given, but I<--current> is
+exclusive. If no flag is specified, behavior is different depending
+on hypervisor.
+
+If no limit is specified, it will query current I/O limits setting.
+
=item B<blockjob> I<domain> I<path> [I<--abort>] [I<--info>] [I<bandwidth>]
Manage active block operations.
--
1.7.1
13 years, 6 months
[libvirt] [PATCH 4/8] Support block I/O throtte in XML
by Lei Li
Enable block I/O throttle for per-disk in XML.
Signed-off-by: Lei Li <lilei(a)linux.vnet.ibm.com>
Signed-off-by: Zhi Yong Wu <wuzhy(a)linux.vnet.ibm.com>
---
src/conf/domain_conf.c | 101 +++++++++++++++++++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 12 ++++++
src/qemu/qemu_command.c | 33 +++++++++++++++
src/util/xml.h | 2 +
4 files changed, 145 insertions(+), 3 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 58f4d0f..a157b80 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2318,7 +2318,8 @@ static virDomainDiskDefPtr
virDomainDiskDefParseXML(virCapsPtr caps,
xmlNodePtr node,
virBitmapPtr bootMap,
- unsigned int flags)
+ unsigned int flags,
+ xmlXPathContextPtr ctxt)
{
virDomainDiskDefPtr def;
xmlNodePtr cur, child;
@@ -2517,6 +2518,62 @@ virDomainDiskDefParseXML(virCapsPtr caps,
}
child = child->next;
}
+ } else if (xmlStrEqual(cur->name, BAD_CAST "iotune")) {
+ if (virXPathULongLong("string(./devices/disk/iotune/total_bytes_sec)",
+ ctxt, &def->blkdeviotune.total_bytes_sec) < 0) {
+ def->blkdeviotune.total_bytes_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if (virXPathULongLong("string(./devices/disk/iotune/read_bytes_sec)",
+ ctxt, &def->blkdeviotune.read_bytes_sec) < 0) {
+ def->blkdeviotune.read_bytes_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if (virXPathULongLong("string(./devices/disk/iotune/write_bytes_sec)",
+ ctxt, &def->blkdeviotune.write_bytes_sec) < 0) {
+ def->blkdeviotune.write_bytes_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if (virXPathULongLong("string(./devices/disk/iotune/total_iops_sec)",
+ ctxt, &def->blkdeviotune.total_iops_sec) < 0) {
+ def->blkdeviotune.total_iops_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if (virXPathULongLong("string(./devices/disk/iotune/read_iops_sec)",
+ ctxt, &def->blkdeviotune.read_iops_sec) < 0) {
+ def->blkdeviotune.read_iops_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if (virXPathULongLong("string(./devices/disk/iotune/write_iops_sec)",
+ ctxt, &def->blkdeviotune.write_iops_sec) < 0) {
+ def->blkdeviotune.write_iops_sec = 0;
+ } else {
+ def->blkdeviotune.mark = 1;
+ }
+
+ if ((def->blkdeviotune.total_bytes_sec && def->blkdeviotune.read_bytes_sec)
+ || (def->blkdeviotune.total_bytes_sec && def->blkdeviotune.write_bytes_sec)) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("total and read/write bytes_sec cannot be set at the same time"));
+ goto error;
+ }
+
+ if ((def->blkdeviotune.total_iops_sec && def->blkdeviotune.read_iops_sec)
+ || (def->blkdeviotune.total_iops_sec && def->blkdeviotune.write_iops_sec)) {
+ virDomainReportError(VIR_ERR_XML_ERROR,
+ _("total and read/write iops_sec cannot be set at the same time"));
+ goto error;
+ }
} else if (xmlStrEqual(cur->name, BAD_CAST "readonly")) {
def->readonly = 1;
} else if (xmlStrEqual(cur->name, BAD_CAST "shareable")) {
@@ -6003,7 +6060,7 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
if (xmlStrEqual(node->name, BAD_CAST "disk")) {
dev->type = VIR_DOMAIN_DEVICE_DISK;
if (!(dev->data.disk = virDomainDiskDefParseXML(caps, node,
- NULL, flags)))
+ NULL, flags, NULL)))
goto error;
} else if (xmlStrEqual(node->name, BAD_CAST "lease")) {
dev->type = VIR_DOMAIN_DEVICE_LEASE;
@@ -7076,7 +7133,8 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
virDomainDiskDefPtr disk = virDomainDiskDefParseXML(caps,
nodes[i],
bootMap,
- flags);
+ flags,
+ ctxt);
if (!disk)
goto error;
@@ -9511,6 +9569,43 @@ virDomainDiskDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " <target dev='%s' bus='%s'/>\n",
def->dst, bus);
+ /*disk I/O throttling*/
+ if (def->blkdeviotune.mark) {
+ virBufferAddLit(buf, " <iotune>\n");
+ if (def->blkdeviotune.total_bytes_sec) {
+ virBufferAsprintf(buf, " <total_bytes_sec>%llu</total_bytes_sec>\n",
+ def->blkdeviotune.total_bytes_sec);
+ }
+
+ if (def->blkdeviotune.read_bytes_sec) {
+ virBufferAsprintf(buf, " <read_bytes_sec>%llu</read_bytes_sec>\n",
+ def->blkdeviotune.read_bytes_sec);
+
+ }
+
+ if (def->blkdeviotune.write_bytes_sec) {
+ virBufferAsprintf(buf, " <write_bytes_sec>%llu</write_bytes_sec>\n",
+ def->blkdeviotune.write_bytes_sec);
+ }
+
+ if (def->blkdeviotune.total_iops_sec) {
+ virBufferAsprintf(buf, " <total_iops_sec>%llu</total_iops_sec>\n",
+ def->blkdeviotune.total_iops_sec);
+ }
+
+ if (def->blkdeviotune.read_iops_sec) {
+ virBufferAsprintf(buf, " <read_iops_sec>%llu</read_iops_sec>",
+ def->blkdeviotune.read_iops_sec);
+ }
+
+ if (def->blkdeviotune.write_iops_sec) {
+ virBufferAsprintf(buf, " <write_iops_sec>%llu</write_iops_sec>",
+ def->blkdeviotune.write_iops_sec);
+ }
+
+ virBufferAddLit(buf, " </iotune>\n");
+ }
+
if (def->bootIndex)
virBufferAsprintf(buf, " <boot order='%d'/>\n", def->bootIndex);
if (def->readonly)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a3cb834..d95e239 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -333,6 +333,18 @@ struct _virDomainDiskDef {
} auth;
char *driverName;
char *driverType;
+
+ /*disk I/O throttling*/
+ struct {
+ unsigned long long total_bytes_sec;
+ unsigned long long read_bytes_sec;
+ unsigned long long write_bytes_sec;
+ unsigned long long total_iops_sec;
+ unsigned long long read_iops_sec;
+ unsigned long long write_iops_sec;
+ unsigned int mark;
+ } blkdeviotune;
+
char *serial;
int cachemode;
int error_policy; /* enum virDomainDiskErrorPolicy */
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 2fbf691..91c6508 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1690,6 +1690,39 @@ qemuBuildDriveStr(virConnectPtr conn ATTRIBUTE_UNUSED,
}
}
+ /*block I/O throttling*/
+ if (disk->blkdeviotune.mark) {
+ if (disk->blkdeviotune.total_bytes_sec) {
+ virBufferAsprintf(&opt, ",bps=%llu",
+ disk->blkdeviotune.total_bytes_sec);
+ }
+
+ if (disk->blkdeviotune.read_bytes_sec) {
+ virBufferAsprintf(&opt, ",bps_rd=%llu",
+ disk->blkdeviotune.read_bytes_sec);
+ }
+
+ if (disk->blkdeviotune.write_bytes_sec) {
+ virBufferAsprintf(&opt, ",bps_wr=%llu",
+ disk->blkdeviotune.write_bytes_sec);
+ }
+
+ if (disk->blkdeviotune.total_iops_sec) {
+ virBufferAsprintf(&opt, ",iops=%llu",
+ disk->blkdeviotune.total_iops_sec);
+ }
+
+ if (disk->blkdeviotune.read_iops_sec) {
+ virBufferAsprintf(&opt, ",iops_rd=%llu",
+ disk->blkdeviotune.read_iops_sec);
+ }
+
+ if (disk->blkdeviotune.write_iops_sec) {
+ virBufferAsprintf(&opt, ",iops_wr=%llu",
+ disk->blkdeviotune.write_iops_sec);
+ }
+ }
+
if (virBufferError(&opt)) {
virReportOOMError();
goto error;
diff --git a/src/util/xml.h b/src/util/xml.h
index c492063..5742f19 100644
--- a/src/util/xml.h
+++ b/src/util/xml.h
@@ -50,6 +50,8 @@ xmlNodePtr virXPathNode(const char *xpath,
int virXPathNodeSet(const char *xpath,
xmlXPathContextPtr ctxt,
xmlNodePtr **list);
+int virXMLStringToULongLong (const char *stringval,
+ unsigned long long *value);
char * virXMLPropString(xmlNodePtr node,
const char *name);
--
1.7.1
13 years, 6 months