[libvirt] [PATCH 0/2] Add support for DTrace probes in libvirtd

This is an update of the earlier DTrace patch. Primarily it is just a rebase, but the second patch adds support for including the socket address in the CLIENT_CONNECT probe event. This is dependant on the big virSocket API series. Support for probing public API functions in libvirt.so is still under investigation.

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 | 17 +++++++++++ daemon/libvirtd.stp | 63 ++++++++++++++++++++++++++++++++++++++++ daemon/probes.d | 12 +++++++ daemon/remote.c | 24 +++++++++++++++ examples/systemtap/Makefile.am | 2 + examples/systemtap/client.stp | 28 +++++++++++++++++ libvirt.spec.in | 16 +++++++++- mingw32-libvirt.spec.in | 1 + 14 files changed, 222 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 844ce53..4eda788 100755 --- a/autobuild.sh +++ b/autobuild.sh @@ -86,6 +86,7 @@ if [ -x /usr/bin/i686-pc-mingw32-gcc ]; then --without-phyp \ --without-netcf \ --without-audit \ + --without-dtrace \ --without-libvirtd make diff --git a/configure.ac b/configure.ac index d8c4d0d..dd19598 100644 --- a/configure.ac +++ b/configure.ac @@ -1107,6 +1107,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], @@ -2230,6 +2253,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([]) @@ -2396,6 +2420,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 987133c..0e254d4 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) @@ -161,6 +164,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 @@ -317,5 +339,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 88e85ec..7235439 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -1240,12 +1240,15 @@ remoteCheckCertificate(struct qemud_client *client) } } + PROBE(CLIENT_TLS_ALLOW, "fd=%d, name=%s", client->fd, name); return 0; authdeny: + PROBE(CLIENT_TLS_DENY, "fd=%d, name=%s", client->fd, name); return -1; authfail: + PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd); return -1; } @@ -1327,6 +1330,8 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket return -1; } + PROBE(CLIENT_CONNECT, "fd=%d, readonly=%d", fd, sock->readonly); + if (server->nclients >= max_clients) { VIR_ERROR(_("Too many active clients (%d), dropping connection"), max_clients); goto error; @@ -1445,6 +1450,7 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket if (qemudRegisterClientEvent (server, client) < 0) goto error; } else { + PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd); VIR_ERROR(_("TLS handshake failed: %s"), gnutls_strerror (ret)); goto error; @@ -1476,6 +1482,7 @@ error: VIR_FREE(client); } close (fd); + PROBE(CLIENT_DISCONNECT, "fd=%d", fd); return -1; } @@ -1519,6 +1526,7 @@ void qemudDispatchClientFailure(struct qemud_client *client) { client->tlssession = NULL; } if (client->fd != -1) { + PROBE(CLIENT_DISCONNECT, "fd=%d", client->fd); close(client->fd); client->fd = -1; } @@ -2079,6 +2087,7 @@ qemudDispatchClientHandshake(struct qemud_client *client) { direction has changed */ qemudUpdateClientEvent (client); } else { + PROBE(CLIENT_TLS_FAIL, "fd=%d", 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..94de5e1 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -49,6 +49,23 @@ # 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, FMT, ...) \ + VIR_DEBUG_INT("trace." __FILE__ , __func__, __LINE__, \ + #NAME ": " FMT, __VA_ARGS__); \ + if (LIBVIRTD_ ## NAME ## _ENABLED()) { \ + LIBVIRTD_ ## NAME(__VA_ARGS__); \ + } +# else +# define PROBE(NAME, FMT, ...) \ + VIR_DEBUG_INT("trace." __FILE__, __func__, __LINE__, \ + #NAME ": " FMT, __VA_ARGS__); +# 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 37dffe3..c98e633 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -3791,6 +3791,7 @@ remoteDispatchAuthSaslInit (struct qemud_server *server, authfail: remoteDispatchAuthError(rerr); error: + PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL); virMutexUnlock(&client->lock); return -1; } @@ -3977,6 +3978,8 @@ remoteDispatchAuthSaslStart (struct qemud_server *server, } REMOTE_DEBUG("Authentication successful %d", client->fd); + PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s", + client->fd, REMOTE_AUTH_SASL, client->saslUsername); ret->complete = 1; client->auth = REMOTE_AUTH_NONE; } @@ -3985,10 +3988,13 @@ remoteDispatchAuthSaslStart (struct qemud_server *server, return 0; authfail: + PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL); remoteDispatchAuthError(rerr); goto error; authdeny: + PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s", + client->fd, REMOTE_AUTH_SASL, client->saslUsername); goto error; error: @@ -4073,6 +4079,8 @@ remoteDispatchAuthSaslStep (struct qemud_server *server, } REMOTE_DEBUG("Authentication successful %d", client->fd); + PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s", + client->fd, REMOTE_AUTH_SASL, client->saslUsername); ret->complete = 1; client->auth = REMOTE_AUTH_NONE; } @@ -4081,10 +4089,13 @@ remoteDispatchAuthSaslStep (struct qemud_server *server, return 0; authfail: + PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL); remoteDispatchAuthError(rerr); goto error; authdeny: + PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s", + client->fd, REMOTE_AUTH_SASL, client->saslUsername); goto error; error: @@ -4104,6 +4115,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, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL); remoteDispatchAuthError(rerr); return -1; } @@ -4118,6 +4130,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, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL); remoteDispatchAuthError(rerr); return -1; } @@ -4132,6 +4145,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, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_SASL); remoteDispatchAuthError(rerr); return -1; } @@ -4208,6 +4222,8 @@ remoteDispatchAuthPolkit (struct qemud_server *server, action, callerPid, callerUid, status); goto authdeny; } + PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s", + client->fd, REMOTE_AUTH_POLKIT, ident); VIR_INFO(_("Policy allowed action %s from pid %d, uid %d"), action, callerPid, callerUid); ret->complete = 1; @@ -4217,9 +4233,12 @@ remoteDispatchAuthPolkit (struct qemud_server *server, return 0; authfail: + PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_POLKIT); goto error; authdeny: + PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s", + client->fd, REMOTE_AUTH_POLKIT, ident); goto error; error: @@ -4333,6 +4352,8 @@ remoteDispatchAuthPolkit (struct qemud_server *server, polkit_result_to_string_representation(pkresult)); goto authdeny; } + PROBE(CLIENT_AUTH_ALLOW, "fd=%d, auth=%d, username=%s", + 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)); @@ -4343,9 +4364,12 @@ remoteDispatchAuthPolkit (struct qemud_server *server, return 0; authfail: + PROBE(CLIENT_AUTH_FAIL, "fd=%d, auth=%d", client->fd, REMOTE_AUTH_POLKIT); goto error; authdeny: + PROBE(CLIENT_AUTH_DENY, "fd=%d, auth=%d, username=%s", + 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 93386fb..bc6ed6f 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -67,6 +67,7 @@ %define with_macvtap 0%{!?_without_macvtap:0} %define with_libnl 0%{!?_without_libnl:0} %define with_audit 0%{!?_without_audit:0} +%define with_dtrace 0%{!?_without_dtrace:0} # Non-server/HV driver defaults which are always enabled %define with_python 0%{!?_without_python:1} @@ -170,6 +171,10 @@ %define with_audit 0%{!?_without_audit: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 @@ -564,6 +569,10 @@ of recent versions of Linux (and other OSes). %define _without_audit --without-audit %endif +%if ! %{with_dtrace} +%define _without_dtrace --without-dtrace +%endif + %configure %{?_without_xen} \ %{?_without_qemu} \ %{?_without_openvz} \ @@ -596,6 +605,7 @@ of recent versions of Linux (and other OSes). %{?_without_libpcap} \ %{?_without_macvtap} \ %{?_without_audit} \ + %{?_without_dtrace} \ --with-qemu-user=%{qemu_user} \ --with-qemu-group=%{qemu_group} \ --with-init-script=redhat \ @@ -607,7 +617,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 @@ -763,6 +773,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/ @@ -909,6 +922,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 e762c77..0841dc0 100644 --- a/mingw32-libvirt.spec.in +++ b/mingw32-libvirt.spec.in @@ -58,6 +58,7 @@ MinGW Windows libvirt virtualization library. --without-phyp \ --without-netcf \ --without-audit \ + --without-dtrace \ --without-libvirtd make -- 1.7.2.3

On Thu, Oct 21, 2010 at 07:19:32PM +0100, Daniel P. Berrange wrote:
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.
Wasn't that problem found ? I though so ...
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
Patch looks very similar to the first version. Dunno if you want to push the set early or wait for a more complete support check, ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, Oct 21, 2010 at 09:59:55PM +0200, Daniel Veillard wrote:
On Thu, Oct 21, 2010 at 07:19:32PM +0100, Daniel P. Berrange wrote:
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.
Wasn't that problem found ? I though so ...
Yes it is partially solved, I'll remove this comment since it isn't really relevant to the changeset. Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

It is useful to know where the client is connecting from, so include the socket address in probe data. * daemon/libvirtd.h: Use virSocketAddr for storing client address and keep printable address handy for logging * daemon/libvirtd.c: Include socket address in client connect/disconnect probes * daemon/probes.d: Add socket address to probes * examples/systemtap/client.stp: Print socket address * src/util/network.h: Add sockaddr_un to virSocketAddr union --- configure.ac | 2 +- daemon/libvirtd.c | 82 +++++++++++++++++++++------------------- daemon/libvirtd.h | 15 +++++-- daemon/libvirtd.stp | 2 + daemon/probes.d | 2 +- daemon/remote.c | 2 +- examples/systemtap/client.stp | 4 +- src/util/network.h | 6 +++ 8 files changed, 66 insertions(+), 49 deletions(-) diff --git a/configure.ac b/configure.ac index dd19598..e41f2b5 100644 --- a/configure.ac +++ b/configure.ac @@ -108,7 +108,7 @@ AC_CHECK_FUNCS([pthread_sigmask pthread_mutexattr_init]) LIBS=$old_libs dnl Availability of various common headers (non-fatal if missing). -AC_CHECK_HEADERS([pwd.h paths.h regex.h sys/syslimits.h \ +AC_CHECK_HEADERS([pwd.h paths.h regex.h sys/syslimits.h sys/un.h \ sys/poll.h syslog.h mntent.h net/ethernet.h linux/magic.h]) AC_CHECK_LIB([intl],[gettext],[]) diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 7235439..8e88d05 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -541,7 +541,6 @@ static int qemudWritePidFile(const char *pidFile) { static int qemudListenUnix(struct qemud_server *server, char *path, int readonly, int auth) { struct qemud_socket *sock; - struct sockaddr_un addr; mode_t oldmask; gid_t oldgrp; char ebuf[1024]; @@ -552,10 +551,15 @@ static int qemudListenUnix(struct qemud_server *server, } sock->readonly = readonly; - sock->port = -1; sock->type = QEMUD_SOCK_TYPE_UNIX; sock->auth = auth; sock->path = path; + sock->addr.len = sizeof(sock->addr.data.un); + if (!(sock->addrstr = strdup(path))) { + VIR_ERROR(_("Failed to copy socket address: %s"), + virStrerror(errno, ebuf, sizeof ebuf)); + goto cleanup; + } if ((sock->fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { VIR_ERROR(_("Failed to create socket: %s"), @@ -567,14 +571,13 @@ static int qemudListenUnix(struct qemud_server *server, virSetNonBlock(sock->fd) < 0) goto cleanup; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - if (virStrcpyStatic(addr.sun_path, path) == NULL) { + sock->addr.data.un.sun_family = AF_UNIX; + if (virStrcpyStatic(sock->addr.data.un.sun_path, path) == NULL) { VIR_ERROR(_("Path %s too long for unix socket"), path); goto cleanup; } - if (addr.sun_path[0] == '@') - addr.sun_path[0] = '\0'; + if (sock->addr.data.un.sun_path[0] == '@') + sock->addr.data.un.sun_path[0] = '\0'; oldgrp = getgid(); oldmask = umask(readonly ? ~unix_sock_ro_mask : ~unix_sock_rw_mask); @@ -583,7 +586,7 @@ static int qemudListenUnix(struct qemud_server *server, goto cleanup; } - if (bind(sock->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + if (bind(sock->fd, &sock->addr.data.sa, sock->addr.len) < 0) { VIR_ERROR(_("Failed to bind socket to '%s': %s"), path, virStrerror(errno, ebuf, sizeof ebuf)); goto cleanup; @@ -692,16 +695,7 @@ remoteListenTCP (struct qemud_server *server, return -1; for (i = 0; i < nfds; ++i) { - union { - struct sockaddr_storage sa_stor; - struct sockaddr sa; - struct sockaddr_in sa_in; -#ifdef AF_INET6 - struct sockaddr_in6 sa_in6; -#endif - } s; char ebuf[1024]; - socklen_t salen = sizeof(s); if (VIR_ALLOC(sock) < 0) { VIR_ERROR(_("remoteListenTCP: calloc: %s"), @@ -709,6 +703,7 @@ remoteListenTCP (struct qemud_server *server, goto cleanup; } + sock->addr.len = sizeof(sock->addr.data.stor); sock->readonly = 0; sock->next = server->sockets; server->sockets = sock; @@ -718,17 +713,11 @@ remoteListenTCP (struct qemud_server *server, sock->type = type; sock->auth = auth; - if (getsockname(sock->fd, &s.sa, &salen) < 0) + if (getsockname(sock->fd, &sock->addr.data.sa, &sock->addr.len) < 0) goto cleanup; - if (s.sa.sa_family == AF_INET) { - sock->port = htons(s.sa_in.sin_port); -#ifdef AF_INET6 - } else if (s.sa.sa_family == AF_INET6) - sock->port = htons(s.sa_in6.sin6_port); -#endif - else - sock->port = -1; + if (!(sock->addrstr = virSocketFormatAddrFull(&sock->addr, true, ";"))) + goto cleanup; if (virSetCloseExec(sock->fd) < 0 || virSetNonBlock(sock->fd) < 0) @@ -1043,8 +1032,9 @@ static int qemudNetworkInit(struct qemud_server *server) { */ sock = server->sockets; while (sock) { - if (sock->port != -1 && sock->type == QEMUD_SOCK_TYPE_TLS) { - port = sock->port; + if (virSocketGetPort(&sock->addr) != -1 && + sock->type == QEMUD_SOCK_TYPE_TLS) { + port = virSocketGetPort(&sock->addr); break; } sock = sock->next; @@ -1315,13 +1305,14 @@ int qemudGetSocketIdentity(int fd, uid_t *uid, pid_t *pid) { static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket *sock) { int fd; - struct sockaddr_storage addr; - socklen_t addrlen = (socklen_t) (sizeof addr); + virSocketAddr addr; + char *addrstr = NULL; struct qemud_client *client = NULL; int no_slow_start = 1; int i; - if ((fd = accept(sock->fd, (struct sockaddr *)&addr, &addrlen)) < 0) { + addr.len = sizeof(addr.data.stor); + if ((fd = accept(sock->fd, &addr.data.sa, &addr.len)) < 0) { char ebuf[1024]; if (errno == EAGAIN) return 0; @@ -1329,11 +1320,17 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket virStrerror(errno, ebuf, sizeof ebuf)); return -1; } + if (!(addrstr = virSocketFormatAddrFull(&addr, true, ";"))) { + VIR_ERROR0(_("Failed to format addresss: out of memory")); + goto error; + } - PROBE(CLIENT_CONNECT, "fd=%d, readonly=%d", fd, sock->readonly); + PROBE(CLIENT_CONNECT, "fd=%d, readonly=%d localAddr=%s remoteAddr=%s", + fd, sock->readonly, sock->addrstr, addrstr); if (server->nclients >= max_clients) { - VIR_ERROR(_("Too many active clients (%d), dropping connection"), max_clients); + VIR_ERROR(_("Too many active clients (%d), dropping connection from %s"), + max_clients, addrstr); goto error; } @@ -1384,8 +1381,9 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket client->readonly = sock->readonly; client->type = sock->type; client->auth = sock->auth; - memcpy (&client->addr, &addr, sizeof addr); - client->addrlen = addrlen; + client->addr = addr; + client->addrstr = addrstr; + addrstr = NULL; for (i = 0 ; i < VIR_DOMAIN_EVENT_ID_LAST ; i++) { client->domainEventCallbackID[i] = -1; @@ -1411,7 +1409,8 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket /* Client is running as root, so disable auth */ if (uid == 0) { - VIR_INFO(_("Turn off polkit auth for privileged client %d"), pid); + VIR_INFO(_("Turn off polkit auth for privileged client pid %d from %s"), + pid, addrstr); client->auth = REMOTE_AUTH_NONE; } } @@ -1451,8 +1450,8 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket goto error; } else { PROBE(CLIENT_TLS_FAIL, "fd=%d", client->fd); - VIR_ERROR(_("TLS handshake failed: %s"), - gnutls_strerror (ret)); + VIR_ERROR(_("TLS handshake failed for client %s: %s"), + addrstr, gnutls_strerror (ret)); goto error; } } @@ -1477,10 +1476,13 @@ static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket error: if (client) { if (client->tlssession) gnutls_deinit (client->tlssession); - if (client) + if (client) { + VIR_FREE(client->addrstr); VIR_FREE(client->rx); + } VIR_FREE(client); } + VIR_FREE(addrstr); close (fd); PROBE(CLIENT_DISCONNECT, "fd=%d", fd); return -1; @@ -1530,6 +1532,7 @@ void qemudDispatchClientFailure(struct qemud_client *client) { close(client->fd); client->fd = -1; } + VIR_FREE(client->addrstr); } @@ -2448,6 +2451,7 @@ static void qemudCleanup(struct qemud_server *server) { sock->path[0] != '@') unlink(sock->path); VIR_FREE(sock->path); + VIR_FREE(sock->addrstr); VIR_FREE(sock); sock = next; diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index 94de5e1..785ac07 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -48,6 +48,7 @@ # include "qemu_protocol.h" # include "logging.h" # include "threads.h" +# include "network.h" # if WITH_DTRACE # ifndef LIBVIRTD_PROBES_H @@ -61,8 +62,8 @@ LIBVIRTD_ ## NAME(__VA_ARGS__); \ } # else -# define PROBE(NAME, FMT, ...) \ - VIR_DEBUG_INT("trace." __FILE__, __func__, __LINE__, \ +# define PROBE(NAME, FMT, ...) \ + VIR_DEBUG_INT("trace." __FILE__, __func__, __LINE__, \ #NAME ": " FMT, __VA_ARGS__); # endif @@ -197,8 +198,8 @@ struct qemud_client { unsigned int closing :1; int domainEventCallbackID[VIR_DOMAIN_EVENT_ID_LAST]; - struct sockaddr_storage addr; - socklen_t addrlen; + virSocketAddr addr; + const char *addrstr; int type; /* qemud_sock_type */ gnutls_session_t tlssession; @@ -252,12 +253,16 @@ struct qemud_client { struct qemud_socket { char *path; + + virSocketAddr addr; + const char *addrstr; + int fd; int watch; int readonly; int type; /* qemud_sock_type */ int auth; - int port; + struct qemud_socket *next; }; diff --git a/daemon/libvirtd.stp b/daemon/libvirtd.stp index 6e8b929..7406eeb 100644 --- a/daemon/libvirtd.stp +++ b/daemon/libvirtd.stp @@ -2,6 +2,8 @@ probe libvirt.daemon.client.connect = process("libvirtd").mark("client_connect") { fd = $arg1; readonly = $arg2; + localAddr = user_string($arg3); + remoteAddr = user_string($arg4); } probe libvirt.daemon.client.disconnect = process("libvirtd").mark("client_disconnect") diff --git a/daemon/probes.d b/daemon/probes.d index d8cc77c..d1050c0 100644 --- a/daemon/probes.d +++ b/daemon/probes.d @@ -1,5 +1,5 @@ provider libvirtd { - probe client_connect(int fd, int readonly); + probe client_connect(int fd, int readonly, const char *localAddr, const char *remoteAddr); probe client_disconnect(int fd); probe client_auth_allow(int fd, int authtype, const char *identity); diff --git a/daemon/remote.c b/daemon/remote.c index c98e633..3b72f98 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -3687,7 +3687,7 @@ remoteDispatchAuthSaslInit (struct qemud_server *server, VIR_FREE(localAddr); goto error; } - if ((localAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL) { + if ((remoteAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL) { VIR_FREE(localAddr); remoteDispatchConnError(rerr, conn); goto error; diff --git a/examples/systemtap/client.stp b/examples/systemtap/client.stp index 00df15a..bf32402 100644 --- a/examples/systemtap/client.stp +++ b/examples/systemtap/client.stp @@ -1,10 +1,10 @@ #!/usr/bin/stap probe libvirt.daemon.client.connect { - printf("Client fd=%d connected readonly=%d\n", fd, readonly); + printf("Client fd=%d connected readonly=%d addr=%s\n", fd, readonly, addr); } probe libvirt.daemon.client.disconnect { - printf("Client fd=%d disconnected\n", fd); + printf("Client fd=%d disconnected addr=%s\n", fd, addr); } probe libvirt.daemon.client.tls_allow { diff --git a/src/util/network.h b/src/util/network.h index 5147ea5..9f9a340 100644 --- a/src/util/network.h +++ b/src/util/network.h @@ -15,6 +15,9 @@ # include <sys/types.h> # include <sys/socket.h> +# ifdef HAVE_SYS_UN_H +# include <sys/un.h> +# endif # include <netdb.h> # include <stdbool.h> @@ -24,6 +27,9 @@ typedef struct { struct sockaddr_storage stor; struct sockaddr_in inet4; struct sockaddr_in6 inet6; +# ifdef HAVE_SYS_UN_H + struct sockaddr_un un; +# endif } data; socklen_t len; } virSocketAddr; -- 1.7.2.3

On Thu, Oct 21, 2010 at 07:19:33PM +0100, Daniel P. Berrange wrote:
It is useful to know where the client is connecting from, so include the socket address in probe data.
* daemon/libvirtd.h: Use virSocketAddr for storing client address and keep printable address handy for logging
Ah ... that's the reason of the big socket revamp :-)
* daemon/libvirtd.c: Include socket address in client connect/disconnect probes * daemon/probes.d: Add socket address to probes * examples/systemtap/client.stp: Print socket address * src/util/network.h: Add sockaddr_un to virSocketAddr union --- configure.ac | 2 +- daemon/libvirtd.c | 82 +++++++++++++++++++++------------------- daemon/libvirtd.h | 15 +++++-- daemon/libvirtd.stp | 2 + daemon/probes.d | 2 +- daemon/remote.c | 2 +- examples/systemtap/client.stp | 4 +- src/util/network.h | 6 +++ 8 files changed, 66 insertions(+), 49 deletions(-) [...] static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket *sock) { int fd; - struct sockaddr_storage addr; - socklen_t addrlen = (socklen_t) (sizeof addr); + virSocketAddr addr; + char *addrstr = NULL;
Patch looks fine, there is actually quite a bit of cleanup too ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Thu, Oct 21, 2010 at 10:05:42PM +0200, Daniel Veillard wrote:
On Thu, Oct 21, 2010 at 07:19:33PM +0100, Daniel P. Berrange wrote:
It is useful to know where the client is connecting from, so include the socket address in probe data.
* daemon/libvirtd.h: Use virSocketAddr for storing client address and keep printable address handy for logging
Ah ... that's the reason of the big socket revamp :-)
* daemon/libvirtd.c: Include socket address in client connect/disconnect probes * daemon/probes.d: Add socket address to probes * examples/systemtap/client.stp: Print socket address * src/util/network.h: Add sockaddr_un to virSocketAddr union --- configure.ac | 2 +- daemon/libvirtd.c | 82 +++++++++++++++++++++------------------- daemon/libvirtd.h | 15 +++++-- daemon/libvirtd.stp | 2 + daemon/probes.d | 2 +- daemon/remote.c | 2 +- examples/systemtap/client.stp | 4 +- src/util/network.h | 6 +++ 8 files changed, 66 insertions(+), 49 deletions(-) [...] static int qemudDispatchServer(struct qemud_server *server, struct qemud_socket *sock) { int fd; - struct sockaddr_storage addr; - socklen_t addrlen = (socklen_t) (sizeof addr); + virSocketAddr addr; + char *addrstr = NULL;
Patch looks fine, there is actually quite a bit of cleanup too
ACK,
Ok, pushed this and the other dtrace patch Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|
participants (2)
-
Daniel P. Berrange
-
Daniel Veillard