Adds initial support for dtrace static probes in libvirtd
daemon, assuming use of systemtap dtrace compat shim on
Linux. The probes are inserted for network client connect,
disconnect, TLS handshake states and authentication protocol
states.
This can be tested by running the xample program and then
attempting to connect with any libvirt client (virsh,
virt-manager, etc).
# stap examples/systemtap/client.stp
Client fd=44 connected readonly=0
Client fd=44 auth polkit deny pid:24997,uid:500
Client fd=44 disconnected
Client fd=46 connected readonly=1
Client fd=46 auth sasl allow test
Client fd=46 disconnected
For unknown reasons, libvirtd must be restarted after
the stap script is launched, otherwise the probes are
not enabled. This bug needs to be fixed, probably in
systemtap itself, to allow probing an existing running
daemon.
The connect/disconnect events need to be augmented to
include the socket address data.
The libvirtd.stp file should also really not be required,
since it is duplicated info that is already available in
the main probes.d definition file. A script to autogenerate
the .stp file is needed, either in libvirtd tree, or better
as part of systemtap itself.
* Makefile.am: Add examples/systemtap subdir
* autobuild.sh: Disable dtrace for mingw32
* configure.ac: Add check for dtrace
* daemon/.gitignore: Ignore generated dtrace probe file
* daemon/Makefile.am: Build dtrace probe header & object
files
* daemon/libvirtd.stp: SystemTAP convenience probeset
* daemon/libvirtd.c: Add connect/disconnect & TLS probes
* daemon/remote.c: Add SASL and PolicyKit auth probes
* daemon/probes.d: Master probe definition
* daemon/libvirtd.h: Add convenience macro for probes
so that compilation is a no-op when dtrace is not available
* examples/systemtap/Makefile.am, examples/systemtap/client.stp
Example systemtap script using dtrace probe markers
* libvirt.spec.in: Enable dtrace on F13/RHEL6
* mingw32-libvirt.spec.in: Force disable dtrace
---
Makefile.am | 2 +-
autobuild.sh | 1 +
configure.ac | 25 ++++++++++++++++
daemon/.gitignore | 1 +
daemon/Makefile.am | 24 ++++++++++++++-
daemon/libvirtd.c | 9 ++++++
daemon/libvirtd.h | 13 ++++++++
daemon/libvirtd.stp | 63 ++++++++++++++++++++++++++++++++++++++++
daemon/probes.d | 12 +++++++
daemon/remote.c | 16 ++++++++++
examples/systemtap/Makefile.am | 2 +
examples/systemtap/client.stp | 28 +++++++++++++++++
libvirt.spec.in | 15 +++++++++-
mingw32-libvirt.spec.in | 1 +
14 files changed, 209 insertions(+), 3 deletions(-)
create mode 100644 daemon/libvirtd.stp
create mode 100644 daemon/probes.d
create mode 100644 examples/systemtap/Makefile.am
create mode 100644 examples/systemtap/client.stp
diff --git a/Makefile.am b/Makefile.am
index c5d278b..b51bd2b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,7 +6,7 @@ GENHTML = genhtml
SUBDIRS = gnulib/lib include src daemon tools proxy docs gnulib/tests \
python tests po examples/domain-events/events-c examples/hellolibvirt \
examples/dominfo examples/domsuspend examples/python examples/apparmor \
- examples/xml/nwfilter examples/openauth
+ examples/xml/nwfilter examples/openauth examples/systemtap
ACLOCAL_AMFLAGS = -I m4 -I gnulib/m4
diff --git a/autobuild.sh b/autobuild.sh
index c527479..02a5037 100755
--- a/autobuild.sh
+++ b/autobuild.sh
@@ -85,6 +85,7 @@ if [ -x /usr/bin/i686-pc-mingw32-gcc ]; then
--without-one \
--without-phyp \
--without-netcf \
+ --without-dtrace \
--without-libvirtd
make
diff --git a/configure.ac b/configure.ac
index ecaf9cb..9076fce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1057,6 +1057,29 @@ fi
AM_CONDITIONAL([WITH_SECDRIVER_APPARMOR], [test "$with_secdriver_apparmor" !=
"no"])
+dnl DTrace static probes
+AC_ARG_WITH([dtrace],
+ AC_HELP_STRING([--with-dtrace], [use dtrace for static probing
@<:@default=check@:>@]),
+ [],
+ [with_dtrace=check])
+
+if test "$with_dtrace" != "no" ; then
+ AC_PATH_PROG([DTRACE], [dtrace], [], [/bin:/usr/bin])
+ if test -z "$DTRACE" ; then
+ if test "$with_dtrace" = "check"; then
+ with_dtrace=no
+ else
+ AC_MSG_ERROR([You must install the 'dtrace' binary to enable libvirt static
probes])
+ fi
+ else
+ with_dtrace=yes
+ fi
+ if test "$with_dtrace" = "yes"; then
+ AC_DEFINE_UNQUOTED([WITH_DTRACE], 1, [whether DTrace static probes are available])
+ fi
+fi
+AM_CONDITIONAL([WITH_DTRACE], [test "$with_dtrace" != "no"])
+
dnl NUMA lib
AC_ARG_WITH([numactl],
@@ -2147,6 +2170,7 @@ AC_OUTPUT(Makefile src/Makefile include/Makefile docs/Makefile \
examples/openauth/Makefile \
examples/python/Makefile \
examples/hellolibvirt/Makefile \
+ examples/systemtap/Makefile \
examples/xml/nwfilter/Makefile)
AC_MSG_NOTICE([])
@@ -2308,6 +2332,7 @@ AC_MSG_NOTICE([ Debug: $enable_debug])
AC_MSG_NOTICE([ Warnings: $enable_compile_warnings])
AC_MSG_NOTICE([ Readline: $lv_use_readline])
AC_MSG_NOTICE([ Python: $with_python])
+AC_MSG_NOTICE([ DTrace: $with_dtrace])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Privileges])
AC_MSG_NOTICE([])
diff --git a/daemon/.gitignore b/daemon/.gitignore
index 8ed7784..840ddd8 100644
--- a/daemon/.gitignore
+++ b/daemon/.gitignore
@@ -10,3 +10,4 @@ libvirtd.init
libvirtd*.logrotate
libvirtd.pod
libvirtd.8
+probes.h
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index b020b77..c51b4a9 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -1,5 +1,7 @@
## Process this file with automake to produce Makefile.in
+CLEANFILES =
+
DAEMON_SOURCES = \
event.c event.h \
libvirtd.c libvirtd.h \
@@ -36,6 +38,7 @@ EXTRA_DIST = \
test_libvirtd.aug \
THREADING.txt \
libvirtd.pod.in \
+ libvirtd.stp \
$(AVAHI_SOURCES) \
$(DAEMON_SOURCES)
@@ -163,6 +166,25 @@ libvirtd_CFLAGS += $(AVAHI_CFLAGS)
libvirtd_LDADD += $(AVAHI_LIBS)
endif
+EXTRA_DIST += probes.d libvirtd.stp
+
+if WITH_DTRACE
+libvirtd_LDADD += probes.o
+libvirtd_SOURCES += probes.h
+
+BUILT_SOURCES += probes.h
+
+tapsetdir = $(datadir)/systemtap/tapsets
+tapset_DATA = libvirtd.stp
+
+probes.h: probes.d
+ $(AM_V_GEN)$(DTRACE) -o $@ -h -s $<
+
+probes.o: probes.d
+ $(AM_V_GEN)$(DTRACE) -o $@ -G -s $<
+
+CLEANFILES += probes.h probes.o
+endif
install-data-local: install-init install-data-sasl install-data-polkit \
install-logrotate
@@ -319,5 +341,5 @@ uninstall-data-sasl:
endif
-CLEANFILES = $(BUILT_SOURCES) $(man_MANS) libvirtd.pod
+CLEANFILES += $(BUILT_SOURCES) $(man_MANS) libvirtd.pod
CLEANFILES += *.cov *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda
diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 5e18077..884aaff 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -1234,12 +1234,15 @@ remoteCheckCertificate(struct qemud_client *client)
}
}
+ PROBE(CLIENT_TLS_ALLOW, client->fd, name);
return 0;
authdeny:
+ PROBE(CLIENT_TLS_DENY, client->fd, name);
return -1;
authfail:
+ PROBE(CLIENT_TLS_FAIL, client->fd);
return -1;
}
@@ -1321,6 +1324,8 @@ static int qemudDispatchServer(struct qemud_server *server, struct
qemud_socket
return -1;
}
+ PROBE(CLIENT_CONNECT, fd, sock->readonly);
+
if (server->nclients >= max_clients) {
VIR_ERROR(_("Too many active clients (%d), dropping connection"),
max_clients);
goto error;
@@ -1439,6 +1444,7 @@ static int qemudDispatchServer(struct qemud_server *server, struct
qemud_socket
if (qemudRegisterClientEvent (server, client) < 0)
goto error;
} else {
+ PROBE(CLIENT_TLS_FAIL, client->fd);
VIR_ERROR(_("TLS handshake failed: %s"),
gnutls_strerror (ret));
goto error;
@@ -1470,6 +1476,7 @@ error:
VIR_FREE(client);
}
close (fd);
+ PROBE(CLIENT_DISCONNECT, fd);
return -1;
}
@@ -1513,6 +1520,7 @@ void qemudDispatchClientFailure(struct qemud_client *client) {
client->tlssession = NULL;
}
if (client->fd != -1) {
+ PROBE(CLIENT_DISCONNECT, client->fd);
close(client->fd);
client->fd = -1;
}
@@ -2073,6 +2081,7 @@ qemudDispatchClientHandshake(struct qemud_client *client) {
direction has changed */
qemudUpdateClientEvent (client);
} else {
+ PROBE(CLIENT_TLS_FAIL, client->fd);
/* Fatal error in handshake */
VIR_ERROR(_("TLS handshake failed: %s"),
gnutls_strerror (ret));
diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h
index 3f13fb1..1d06886 100644
--- a/daemon/libvirtd.h
+++ b/daemon/libvirtd.h
@@ -49,6 +49,19 @@
# include "logging.h"
# include "threads.h"
+# if WITH_DTRACE
+# ifndef LIBVIRTD_PROBES_H
+# define LIBVIRTD_PROBES_H
+# include "probes.h"
+# endif /* LIBVIRTD_PROBES_H */
+# define PROBE(NAME, ...) \
+ if (LIBVIRTD_ ## NAME ## _ENABLED()) { \
+ LIBVIRTD_ ## NAME(__VA_ARGS__); \
+ }
+# else
+# define PROBE(NAME, ...)
+# endif
+
# ifdef __GNUC__
# ifdef HAVE_ANSIDECL_H
# include <ansidecl.h>
diff --git a/daemon/libvirtd.stp b/daemon/libvirtd.stp
new file mode 100644
index 0000000..6e8b929
--- /dev/null
+++ b/daemon/libvirtd.stp
@@ -0,0 +1,63 @@
+probe libvirt.daemon.client.connect =
process("libvirtd").mark("client_connect")
+{
+ fd = $arg1;
+ readonly = $arg2;
+}
+
+probe libvirt.daemon.client.disconnect =
process("libvirtd").mark("client_disconnect")
+{
+ fd = $arg1;
+}
+
+
+probe libvirt.daemon.client.tls_allow =
process("libvirtd").mark("client_tls_allow")
+{
+ fd = $arg1;
+ x509dname = user_string($arg2);
+}
+
+probe libvirt.daemon.client.tls_deny =
process("libvirtd").mark("client_tls_deny")
+{
+ fd = $arg1;
+ x509dname = user_string($arg2);
+}
+
+probe libvirt.daemon.client.tls_fail =
process("libvirtd").mark("client_tls_fail")
+{
+ fd = $arg1;
+}
+
+
+function authtype_to_string(authtype) {
+ if (authtype == 0)
+ return "none"
+ if (authtype == 1)
+ return "sasl"
+ if (authtype == 2)
+ return "polkit"
+ return "unknown"
+}
+
+
+probe libvirt.daemon.client.auth_allow =
process("libvirtd").mark("client_auth_allow")
+{
+ fd = $arg1;
+ authtype = $arg2;
+ authname = authtype_to_string($arg2);
+ identity = user_string($arg3);
+}
+
+probe libvirt.daemon.client.auth_deny =
process("libvirtd").mark("client_auth_deny")
+{
+ fd = $arg1;
+ authtype = $arg2;
+ authname = authtype_to_string($arg2);
+ identity = user_string($arg3);
+}
+
+probe libvirt.daemon.client.auth_fail =
process("libvirtd").mark("client_auth_fail")
+{
+ fd = $arg1;
+ authtype = $arg2;
+ authname = authtype_to_string($arg2);
+}
diff --git a/daemon/probes.d b/daemon/probes.d
new file mode 100644
index 0000000..d8cc77c
--- /dev/null
+++ b/daemon/probes.d
@@ -0,0 +1,12 @@
+provider libvirtd {
+ probe client_connect(int fd, int readonly);
+ probe client_disconnect(int fd);
+
+ probe client_auth_allow(int fd, int authtype, const char *identity);
+ probe client_auth_deny(int fd, int authtype, const char *identity);
+ probe client_auth_fail(int fd, int authtype);
+
+ probe client_tls_allow(int fd, const char *x509dname);
+ probe client_tls_deny(int fd, const char *x509dname);
+ probe client_tls_fail(int fd);
+};
diff --git a/daemon/remote.c b/daemon/remote.c
index 6b67678..26f9ed4 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -3462,6 +3462,7 @@ remoteDispatchAuthSaslInit (struct qemud_server *server,
authfail:
remoteDispatchAuthError(rerr);
error:
+ PROBE(CLIENT_AUTH_FAIL, client->fd, REMOTE_AUTH_SASL);
virMutexUnlock(&client->lock);
return -1;
}
@@ -3648,6 +3649,7 @@ remoteDispatchAuthSaslStart (struct qemud_server *server,
}
REMOTE_DEBUG("Authentication successful %d", client->fd);
+ PROBE(CLIENT_AUTH_ALLOW, client->fd, REMOTE_AUTH_SASL,
client->saslUsername);
ret->complete = 1;
client->auth = REMOTE_AUTH_NONE;
}
@@ -3656,10 +3658,12 @@ remoteDispatchAuthSaslStart (struct qemud_server *server,
return 0;
authfail:
+ PROBE(CLIENT_AUTH_FAIL, client->fd, REMOTE_AUTH_SASL);
remoteDispatchAuthError(rerr);
goto error;
authdeny:
+ PROBE(CLIENT_AUTH_DENY, client->fd, REMOTE_AUTH_SASL, client->saslUsername);
goto error;
error:
@@ -3744,6 +3748,7 @@ remoteDispatchAuthSaslStep (struct qemud_server *server,
}
REMOTE_DEBUG("Authentication successful %d", client->fd);
+ PROBE(CLIENT_AUTH_ALLOW, client->fd, REMOTE_AUTH_SASL,
client->saslUsername);
ret->complete = 1;
client->auth = REMOTE_AUTH_NONE;
}
@@ -3752,10 +3757,12 @@ remoteDispatchAuthSaslStep (struct qemud_server *server,
return 0;
authfail:
+ PROBE(CLIENT_AUTH_FAIL, client->fd, REMOTE_AUTH_SASL);
remoteDispatchAuthError(rerr);
goto error;
authdeny:
+ PROBE(CLIENT_AUTH_DENY, client->fd, REMOTE_AUTH_SASL, client->saslUsername);
goto error;
error:
@@ -3775,6 +3782,7 @@ remoteDispatchAuthSaslInit (struct qemud_server *server
ATTRIBUTE_UNUSED,
remote_auth_sasl_init_ret *ret ATTRIBUTE_UNUSED)
{
VIR_ERROR0(_("client tried unsupported SASL init request"));
+ PROBE(CLIENT_AUTH_FAIL, client->fd, REMOTE_AUTH_SASL);
remoteDispatchAuthError(rerr);
return -1;
}
@@ -3789,6 +3797,7 @@ remoteDispatchAuthSaslStart (struct qemud_server *server
ATTRIBUTE_UNUSED,
remote_auth_sasl_start_ret *ret ATTRIBUTE_UNUSED)
{
VIR_ERROR0(_("client tried unsupported SASL start request"));
+ PROBE(CLIENT_AUTH_FAIL, client->fd, REMOTE_AUTH_SASL);
remoteDispatchAuthError(rerr);
return -1;
}
@@ -3803,6 +3812,7 @@ remoteDispatchAuthSaslStep (struct qemud_server *server
ATTRIBUTE_UNUSED,
remote_auth_sasl_step_ret *ret ATTRIBUTE_UNUSED)
{
VIR_ERROR0(_("client tried unsupported SASL step request"));
+ PROBE(CLIENT_AUTH_FAIL, client->fd, REMOTE_AUTH_SASL);
remoteDispatchAuthError(rerr);
return -1;
}
@@ -3879,6 +3889,7 @@ remoteDispatchAuthPolkit (struct qemud_server *server,
action, callerPid, callerUid, status);
goto authdeny;
}
+ PROBE(CLIENT_AUTH_ALLOW, client->fd, REMOTE_AUTH_POLKIT, ident);
VIR_INFO(_("Policy allowed action %s from pid %d, uid %d"),
action, callerPid, callerUid);
ret->complete = 1;
@@ -3888,9 +3899,11 @@ remoteDispatchAuthPolkit (struct qemud_server *server,
return 0;
authfail:
+ PROBE(CLIENT_AUTH_FAIL, client->fd, REMOTE_AUTH_POLKIT);
goto error;
authdeny:
+ PROBE(CLIENT_AUTH_DENY, client->fd, REMOTE_AUTH_POLKIT, ident);
goto error;
error:
@@ -4004,6 +4017,7 @@ remoteDispatchAuthPolkit (struct qemud_server *server,
polkit_result_to_string_representation(pkresult));
goto authdeny;
}
+ PROBE(CLIENT_AUTH_ALLOW, client->fd, REMOTE_AUTH_POLKIT, ident);
VIR_INFO(_("Policy allowed action %s from pid %d, uid %d, result %s"),
action, callerPid, callerUid,
polkit_result_to_string_representation(pkresult));
@@ -4014,9 +4028,11 @@ remoteDispatchAuthPolkit (struct qemud_server *server,
return 0;
authfail:
+ PROBE(CLIENT_AUTH_FAIL, client->fd, REMOTE_AUTH_POLKIT);
goto error;
authdeny:
+ PROBE(CLIENT_AUTH_DENY, client->fd, REMOTE_AUTH_POLKIT, ident);
goto error;
error:
diff --git a/examples/systemtap/Makefile.am b/examples/systemtap/Makefile.am
new file mode 100644
index 0000000..084081e
--- /dev/null
+++ b/examples/systemtap/Makefile.am
@@ -0,0 +1,2 @@
+
+EXTRA_DIST = client.stp
diff --git a/examples/systemtap/client.stp b/examples/systemtap/client.stp
new file mode 100644
index 0000000..00df15a
--- /dev/null
+++ b/examples/systemtap/client.stp
@@ -0,0 +1,28 @@
+#!/usr/bin/stap
+
+probe libvirt.daemon.client.connect {
+ printf("Client fd=%d connected readonly=%d\n", fd, readonly);
+}
+probe libvirt.daemon.client.disconnect {
+ printf("Client fd=%d disconnected\n", fd);
+}
+
+probe libvirt.daemon.client.tls_allow {
+ printf("Client fd=%d tls allow %s\n", fd, x509dname);
+}
+probe libvirt.daemon.client.tls_deny {
+ printf("Client fd=%d tls deny %s\n", fd, x509dname);
+}
+probe libvirt.daemon.client.tls_fail {
+ printf("Client fd=%d tls fail\n", fd);
+}
+
+probe libvirt.daemon.client.auth_allow {
+ printf("Client fd=%d auth %s allow %s\n", fd, authname, identity);
+}
+probe libvirt.daemon.client.auth_deny {
+ printf("Client fd=%d auth %s deny %s\n", fd, authname, identity);
+}
+probe libvirt.daemon.client.auth_fail {
+ printf("Client fd=%d auth %s fail\n", fd, authname);
+}
diff --git a/libvirt.spec.in b/libvirt.spec.in
index a58be54..f03a474 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -65,6 +65,7 @@
%define with_libpcap 0%{!?_without_libpcap:0}
%define with_macvtap 0%{!?_without_macvtap:0}
%define with_libnl 0%{!?_without_libnl:0}
+%define with_dtrace 0%{!?_without_dtrace:0}
# Non-server/HV driver defaults which are always enabled
%define with_python 0%{!?_without_python:1}
@@ -162,6 +163,10 @@
%define with_libnl 1
%endif
+%if 0%{?fedora} >= 13 || 0%{?rhel} >= 6
+%define with_dtrace 1
+%endif
+
# Force QEMU to run as non-root
%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
%define qemu_user qemu
@@ -545,6 +550,10 @@ of recent versions of Linux (and other OSes).
%define _without_macvtap --without-macvtap
%endif
+%if ! %{with_dtrace}
+%define _without_dtrace --without-dtrace
+%endif
+
%configure %{?_without_xen} \
%{?_without_qemu} \
%{?_without_openvz} \
@@ -586,7 +595,7 @@ gzip -9 ChangeLog
rm -fr %{buildroot}
%makeinstall
-for i in domain-events/events-c dominfo domsuspend hellolibvirt openauth python
xml/nwfilter
+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)
done
@@ -742,6 +751,9 @@ fi
%{_sysconfdir}/rc.d/init.d/libvirtd
%config(noreplace) %{_sysconfdir}/sysconfig/libvirtd
%config(noreplace) %{_sysconfdir}/libvirt/libvirtd.conf
+%if %{with_dtrace}
+%{_datadir}/systemtap/tapsets/libvirtd.stp
+%endif
%dir %attr(0700, root, root) %{_localstatedir}/log/libvirt/qemu/
%dir %attr(0700, root, root) %{_localstatedir}/log/libvirt/lxc/
%dir %attr(0700, root, root) %{_localstatedir}/log/libvirt/uml/
@@ -888,6 +900,7 @@ fi
%doc examples/domsuspend
%doc examples/openauth
%doc examples/xml
+%doc examples/systemtap
%if %{with_python}
%files python
diff --git a/mingw32-libvirt.spec.in b/mingw32-libvirt.spec.in
index 4bbbc3b..0e0bef6 100644
--- a/mingw32-libvirt.spec.in
+++ b/mingw32-libvirt.spec.in
@@ -57,6 +57,7 @@ MinGW Windows libvirt virtualization library.
--without-one \
--without-phyp \
--without-netcf \
+ --without-dtrace \
--without-libvirtd
make
--
1.7.2.2