[libvirt] [RFC PATCH 0/2] Add some systemtap probes to RPC code

Trying to investigate & debug the keepalive series I decided we needed a better way to trace the RPC protocol than the regular debug messages. Ideally we'd have a wireshark dissector but that seems like it will be an awful lot of work todo. So instead I have added a few systemtap probes to the RPC call which fire everytime an RPC message is queued for dispatch, or a completed RPC message is read off the wire Now I can see all communications using a script like this # cat > watch.stp <<EOF function msginfo(prefix, prog, version, proc, type, status, serial) { if (type == 0) typestr = "call" else if (type == 1) typestr = "reply" else if (type == 2) typestr = "message" else if (type == 3) typestr = "stream" else typestr = "unknown" if (status == 0) statusstr = "ok" else if (status == 1) statusstr = "error" else if (status == 2) statusstr = "continue" else statusstr = "unknown" printf("%s program: %-10d version: %d procedure: %-4d type: %u:%-9s status: %u:%-9s serial: %-4d\n", prefix, prog, version, proc, type, typestr, status, statusstr, serial); } probe libvirt.rpc.server_msg_rx { msginfo(">S", prog, vers, proc, type, status, serial) } probe libvirt.rpc.server_msg_tx { msginfo("<S", prog, vers, proc, type, status, serial) } probe libvirt.rpc.client_msg_rx { msginfo("<C", prog, vers, proc, type, status, serial) } probe libvirt.rpc.client_msg_tx { msginfo(">C", prog, vers, proc, type, status, serial) } EOF # stap watch.stp
C program: 536903814 version: 1 procedure: 66 type: 0:call status: 0:ok serial: 0 S program: 536903814 version: 1 procedure: 66 type: 0:call status: 0:ok serial: 0 <S program: 536903814 version: 1 procedure: 66 type: 1:reply status: 0:ok serial: 0 <C program: 536903814 version: 1 procedure: 66 type: 1:reply status: 0:ok serial: 0 C program: 536903814 version: 1 procedure: 1 type: 0:call status: 0:ok serial: 1 S program: 536903814 version: 1 procedure: 1 type: 0:call status: 0:ok serial: 1 <S program: 536903814 version: 1 procedure: 1 type: 1:reply status: 0:ok serial: 1 <C program: 536903814 version: 1 procedure: 1 type: 1:reply status: 0:ok serial: 1 C program: 536903814 version: 1 procedure: 110 type: 0:call status: 0:ok serial: 2 S program: 536903814 version: 1 procedure: 110 type: 0:call status: 0:ok serial: 2 <S program: 536903814 version: 1 procedure: 110 type: 1:reply status: 0:ok serial: 2 <C program: 536903814 version: 1 procedure: 110 type: 1:reply status: 0:ok serial: 2 C program: 536903814 version: 1 procedure: 23 type: 0:call status: 0:ok serial: 3 S program: 536903814 version: 1 procedure: 23 type: 0:call status: 0:ok serial: 3 <S program: 536903814 version: 1 procedure: 23 type: 1:reply status: 0:ok serial: 3 <C program: 536903814 version: 1 procedure: 23 type: 1:reply status: 0:ok serial: 3 C program: 536903814 version: 1 procedure: 19 type: 0:call status: 0:ok serial: 4 S program: 536903814 version: 1 procedure: 19 type: 0:call status: 0:ok serial: 4 <S program: 536903814 version: 1 procedure: 19 type: 1:reply status: 0:ok serial: 4 <C program: 536903814 version: 1 procedure: 19 type: 1:reply status: 0:ok serial: 4 C program: 536903814 version: 1 procedure: 16 type: 0:call status: 0:ok serial: 5 S program: 536903814 version: 1 procedure: 16 type: 0:call status: 0:ok serial: 5 <S program: 536903814 version: 1 procedure: 16 type: 1:reply status: 0:ok serial: 5 <C program: 536903814 version: 1 procedure: 16 type: 1:reply status: 0:ok serial: 5 C program: 536903814 version: 1 procedure: 151 type: 0:call status: 0:ok serial: 6 S program: 536903814 version: 1 procedure: 151 type: 0:call status: 0:ok serial: 6 <S program: 536903814 version: 1 procedure: 151 type: 1:reply status: 0:ok serial: 6 <C program: 536903814 version: 1 procedure: 151 type: 1:reply status: 0:ok serial: 6 C program: 536903814 version: 1 procedure: 15 type: 0:call status: 0:ok serial: 7 S program: 536903814 version: 1 procedure: 15 type: 0:call status: 0:ok serial: 7 <S program: 536903814 version: 1 procedure: 15 type: 1:reply status: 0:ok serial: 7 <C program: 536903814 version: 1 procedure: 15 type: 1:reply status: 0:ok serial: 7 C program: 536903814 version: 1 procedure: 183 type: 0:call status: 0:ok serial: 8 S program: 536903814 version: 1 procedure: 183 type: 0:call status: 0:ok serial: 8 <S program: 536903814 version: 1 procedure: 183 type: 1:reply status: 0:ok serial: 8 <C program: 536903814 version: 1 procedure: 183 type: 1:reply status: 0:ok serial: 8 C program: 536903814 version: 1 procedure: 122 type: 0:call status: 0:ok serial: 9 S program: 536903814 version: 1 procedure: 122 type: 0:call status: 0:ok serial: 9 <S program: 536903814 version: 1 procedure: 122 type: 1:reply status: 0:ok serial: 9 <C program: 536903814 version: 1 procedure: 122 type: 1:reply status: 0:ok serial: 9 C program: 536903814 version: 1 procedure: 121 type: 0:call status: 0:ok serial: 10 S program: 536903814 version: 1 procedure: 121 type: 0:call status: 0:ok serial: 10 <S program: 536903814 version: 1 procedure: 121 type: 1:reply status: 0:ok serial: 10 <C program: 536903814 version: 1 procedure: 121 type: 1:reply status: 0:ok serial: 10 C program: 536903814 version: 1 procedure: 2 type: 0:call status: 0:ok serial: 11 S program: 536903814 version: 1 procedure: 2 type: 0:call status: 0:ok serial: 11 <S program: 536903814 version: 1 procedure: 2 type: 1:reply status: 0:ok serial: 11 <C program: 536903814 version: 1 procedure: 2 type: 1:reply status: 0:ok serial: 11
Is the trace information resulting from 'virsh dominfo $VM' An RPC call shoudl result in 4 messages, tx by client, rx by server, tx by server and rx by client. An async event will only result in 2 messages, tx by server, rx by client and so on. A further enhancement I want to make is to make the rpc generator script, spit out a systemtap function for converting procedure numbers into function/event names, as well as adding helper functions for converting program type and status numbers into friendly strings

From: "Daniel P. Berrange" <berrange@redhat.com> To avoid static linking libvirtd to the RPC server code, which then prevents sane introduction of DTrace probes, put it all in the libvirt.so, and export it * daemon/Makefile.am: Don't link to RPC libraries * src/Makefile.am: Link all RPC libraries to libvirt.so * src/libvirt_private.syms: Export all RPC functions --- daemon/Makefile.am | 2 - src/Makefile.am | 2 +- src/libvirt_private.syms | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 690bf85..046bff3 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -110,8 +110,6 @@ libvirtd_LDADD = \ $(POLKIT_LIBS) libvirtd_LDADD += \ - ../src/libvirt-net-rpc-server.la \ - ../src/libvirt-net-rpc.la \ ../src/libvirt-qemu.la if ! WITH_DRIVER_MODULES diff --git a/src/Makefile.am b/src/Makefile.am index d983d28..7281802 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -612,7 +612,7 @@ libvirt_driver_remote_la_CFLAGS = \ -I@top_srcdir@/src/rpc \ $(AM_CFLAGS) libvirt_driver_remote_la_LDFLAGS = $(AM_LDFLAGS) -libvirt_driver_remote_la_LIBADD = $(GNUTLS_LIBS) libvirt-net-rpc-client.la libvirt-net-rpc.la +libvirt_driver_remote_la_LIBADD = $(GNUTLS_LIBS) libvirt-net-rpc-client.la libvirt-net-rpc-server.la libvirt-net-rpc.la if WITH_DRIVER_MODULES libvirt_driver_remote_la_LIBADD += ../gnulib/lib/libgnu.la libvirt_driver_remote_la_LDFLAGS += -module -avoid-version diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c2a3fab..e086253 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1162,6 +1162,82 @@ virFileDirectFdNew; virFileFclose; virFileFdopen; +# rpc +virNetMessageClear; +virNetMessageEncodeHeader; +virNetMessageEncodePayload; +virNetMessageFree; +virNetMessageNew; +virNetMessageQueuePush; +virNetMessageQueueServe; +virNetMessageSaveError; +virNetSASLContextCheckIdentity; +virNetSASLContextNewServer; +virNetSASLSessionExtKeySize; +virNetSASLSessionFree; +virNetSASLSessionGetIdentity; +virNetSASLSessionGetKeySize; +virNetSASLSessionListMechanisms; +virNetSASLSessionNewServer; +virNetSASLSessionSecProps; +virNetSASLSessionServerStart; +virNetSASLSessionServerStep; +virNetServerAddProgram; +virNetServerAddService; +virNetServerAddSignalHandler; +virNetServerAutoShutdown; +virNetServerClientAddFilter; +virNetServerClientClose; +virNetServerClientDelayedClose; +virNetServerClientFree; +virNetServerClientGetAuth; +virNetServerClientGetFD; +virNetServerClientGetLocalIdentity; +virNetServerClientGetPrivateData; +virNetServerClientGetReadonly; +virNetServerClientGetTLSKeySize; +virNetServerClientHasTLSSession; +virNetServerClientImmediateClose; +virNetServerClientIsSecure; +virNetServerClientLocalAddrString; +virNetServerClientRef; +virNetServerClientRemoteAddrString; +virNetServerClientRemoveFilter; +virNetServerClientSendMessage; +virNetServerClientSetCloseHook; +virNetServerClientSetIdentity; +virNetServerClientSetPrivateData; +virNetServerClientSetSASLSession; +virNetServerClose; +virNetServerFree; +virNetServerIsPrivileged; +virNetServerNew; +virNetServerProgramFree; +virNetServerProgramGetID; +virNetServerProgramGetVersion; +virNetServerProgramMatches; +virNetServerProgramNew; +virNetServerProgramRef; +virNetServerProgramSendReplyError; +virNetServerProgramSendStreamData; +virNetServerProgramSendStreamError; +virNetServerQuit; +virNetServerRef; +virNetServerRun; +virNetServerServiceFree; +virNetServerServiceNewTCP; +virNetServerServiceNewUNIX; +virNetServerUpdateServices; +virNetSocketDupFD; +virNetSocketFree; +virNetSocketGetFD; +virNetSocketListen; +virNetSocketNewConnectTCP; +virNetSocketNewListenUNIX; +virNetTLSContextFree; +virNetTLSContextNewServer; +virNetTLSContextNewServerPath; + # virpidfile.h virPidFileAcquire; -- 1.7.6.2

On 09/30/2011 07:54 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange"<berrange@redhat.com>
To avoid static linking libvirtd to the RPC server code, which then prevents sane introduction of DTrace probes, put it all in the libvirt.so, and export it
* daemon/Makefile.am: Don't link to RPC libraries * src/Makefile.am: Link all RPC libraries to libvirt.so * src/libvirt_private.syms: Export all RPC functions --- daemon/Makefile.am | 2 - src/Makefile.am | 2 +- src/libvirt_private.syms | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-)
+++ b/src/Makefile.am @@ -612,7 +612,7 @@ libvirt_driver_remote_la_CFLAGS = \ -I@top_srcdir@/src/rpc \ $(AM_CFLAGS) libvirt_driver_remote_la_LDFLAGS = $(AM_LDFLAGS) -libvirt_driver_remote_la_LIBADD = $(GNUTLS_LIBS) libvirt-net-rpc-client.la libvirt-net-rpc.la +libvirt_driver_remote_la_LIBADD = $(GNUTLS_LIBS) libvirt-net-rpc-client.la libvirt-net-rpc-server.la libvirt-net-rpc.la
Use \-newline wrapping to make this not be quite so long.
if WITH_DRIVER_MODULES libvirt_driver_remote_la_LIBADD += ../gnulib/lib/libgnu.la libvirt_driver_remote_la_LDFLAGS += -module -avoid-version diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c2a3fab..e086253 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1162,6 +1162,82 @@ virFileDirectFdNew; virFileFclose; virFileFdopen;
+# rpc
Hmm, that's not really the .h where they are declared, although it is the right directory. As is, sticking 'rpc' between 'virfile.h' and 'virpidfile.h' doesn't sort very well. It shouldn't be too much more effort to break this into multiple sections, one for each relevant .h... virnetmessage.h:
+virNetMessageClear; +virNetMessageEncodeHeader; +virNetMessageEncodePayload; +virNetMessageFree; +virNetMessageNew; +virNetMessageQueuePush; +virNetMessageQueueServe; +virNetMessageSaveError;
virnetsaslcontext.h
+virNetSASLContextCheckIdentity; +virNetSASLContextNewServer; +virNetSASLSessionExtKeySize; +virNetSASLSessionFree; +virNetSASLSessionGetIdentity; +virNetSASLSessionGetKeySize; +virNetSASLSessionListMechanisms; +virNetSASLSessionNewServer; +virNetSASLSessionSecProps; +virNetSASLSessionServerStart; +virNetSASLSessionServerStep;
virnetserver.h
+virNetServerAddProgram; +virNetServerAddService; +virNetServerAddSignalHandler; +virNetServerAutoShutdown;
virnetserverclient.h
+virNetServerClientAddFilter; +virNetServerClientClose; +virNetServerClientDelayedClose; +virNetServerClientFree; +virNetServerClientGetAuth; +virNetServerClientGetFD; +virNetServerClientGetLocalIdentity; +virNetServerClientGetPrivateData; +virNetServerClientGetReadonly; +virNetServerClientGetTLSKeySize; +virNetServerClientHasTLSSession; +virNetServerClientImmediateClose; +virNetServerClientIsSecure; +virNetServerClientLocalAddrString; +virNetServerClientRef; +virNetServerClientRemoteAddrString; +virNetServerClientRemoveFilter; +virNetServerClientSendMessage; +virNetServerClientSetCloseHook; +virNetServerClientSetIdentity; +virNetServerClientSetPrivateData; +virNetServerClientSetSASLSession;
move these to be with the rest of virnetserver.h
+virNetServerClose; +virNetServerFree; +virNetServerIsPrivileged; +virNetServerNew;
virnetserverprogram.h
+virNetServerProgramFree; +virNetServerProgramGetID; +virNetServerProgramGetVersion; +virNetServerProgramMatches; +virNetServerProgramNew; +virNetServerProgramRef; +virNetServerProgramSendReplyError; +virNetServerProgramSendStreamData; +virNetServerProgramSendStreamError; +virNetServerQuit; +virNetServerRef; +virNetServerRun;
virnetserverservice.h
+virNetServerServiceFree; +virNetServerServiceNewTCP; +virNetServerServiceNewUNIX; +virNetServerUpdateServices;
virnetsocket.h
+virNetSocketDupFD; +virNetSocketFree; +virNetSocketGetFD; +virNetSocketListen; +virNetSocketNewConnectTCP; +virNetSocketNewListenUNIX;
virnettlscontext.h
+virNetTLSContextFree; +virNetTLSContextNewServer; +virNetTLSContextNewServerPath; +
# virpidfile.h virPidFileAcquire;
But all of those are just layout nits, not technical objections, so I'm okay giving: ACK with changes -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

From: "Daniel P. Berrange" <berrange@redhat.com> --- daemon/libvirtd.h | 28 +--------------- src/Makefile.am | 28 +++++++++++++++-- src/internal.h | 70 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt.stp | 35 +++++++++++++++++++++ src/probes.d | 7 ++++ src/rpc/virnetclient.c | 13 +++++-- src/rpc/virnetserverclient.c | 9 +++++ 7 files changed, 157 insertions(+), 33 deletions(-) create mode 100644 src/libvirt.stp create mode 100644 src/probes.d diff --git a/daemon/libvirtd.h b/daemon/libvirtd.h index 6d6460e..43f5921 100644 --- a/daemon/libvirtd.h +++ b/daemon/libvirtd.h @@ -45,32 +45,8 @@ # include "probes.h" # endif /* LIBVIRTD_PROBES_H */ -/* Systemtap 1.2 headers have a bug where they cannot handle a - * variable declared with array type. Work around this by casting all - * arguments. This is some gross use of the preprocessor because - * PROBE is a var-arg macro, but it is better than the alternative of - * making all callers to PROBE have to be aware of the issues. And - * hopefully, if we ever add a call to PROBE with other than 2 or 3 - * end arguments, you can figure out the pattern to extend this hack. - */ -# define VIR_COUNT_ARGS(...) VIR_ARG5(__VA_ARGS__, 4, 3, 2, 1) -# define VIR_ARG5(_1, _2, _3, _4, _5, ...) _5 -# define VIR_ADD_CAST_EXPAND(a, b, ...) VIR_ADD_CAST_PASTE(a, b, __VA_ARGS__) -# define VIR_ADD_CAST_PASTE(a, b, ...) a##b(__VA_ARGS__) - -/* The double cast is necessary to silence gcc warnings; any pointer - * can safely go to intptr_t and back to void *, which collapses - * arrays into pointers; while any integer can be widened to intptr_t - * then cast to void *. */ -# define VIR_ADD_CAST(a) ((void *)(intptr_t)(a)) -# define VIR_ADD_CAST2(a, b) \ - VIR_ADD_CAST(a), VIR_ADD_CAST(b) -# define VIR_ADD_CAST3(a, b, c) \ - VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c) - -# define VIR_ADD_CASTS(...) \ - VIR_ADD_CAST_EXPAND(VIR_ADD_CAST, VIR_COUNT_ARGS(__VA_ARGS__), \ - __VA_ARGS__) +# undef PROBE_EXPAND +# undef PROBE # define PROBE_EXPAND(NAME, ARGS) NAME(ARGS) # define PROBE(NAME, FMT, ...) \ diff --git a/src/Makefile.am b/src/Makefile.am index 7281802..d974904 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,6 +25,9 @@ AM_LDFLAGS = $(COVERAGE_LDFLAGS) EXTRA_DIST = $(conf_DATA) util/keymaps.csv BUILT_SOURCES = +CLEANFILES = +DISTCLEANFILES = +MAINTAINERCLEANFILES = if WITH_NETWORK UUID=$(shell uuidgen 2>/dev/null) @@ -1248,6 +1251,25 @@ libvirt_la_CFLAGS = -DIN_LIBVIRT $(AM_CFLAGS) # picked out for us. libvirt_la_DEPENDENCIES = $(libvirt_la_BUILT_LIBADD) $(LIBVIRT_SYMBOL_FILE) +if WITH_DTRACE +libvirt_la_LIBADD += probes.o +nodist_libvirt_la_SOURCES = probes.h + +BUILT_SOURCES += probes.h + +tapsetdir = $(datadir)/systemtap/tapset +tapset_DATA = libvirt.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 + + # Create an automake "convenience library" version of libvirt_la, # just for testing, since the test harness requires access to internal # bits and pieces that we don't want to make publicly accessible. @@ -1549,6 +1571,6 @@ if WITH_NETWORK endif rmdir "$(DESTDIR)$(localstatedir)/lib/libvirt" ||: -CLEANFILES = *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda *.i *.s -DISTCLEANFILES = $(GENERATED_SYM_FILES) -MAINTAINERCLEANFILES = $(REMOTE_DRIVER_GENERATED) $(VIR_NET_RPC_GENERATED) $(ESX_DRIVER_GENERATED) +CLEANFILES += *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda *.i *.s +DISTCLEANFILES += $(GENERATED_SYM_FILES) +MAINTAINERCLEANFILES += $(REMOTE_DRIVER_GENERATED) $(VIR_NET_RPC_GENERATED) $(ESX_DRIVER_GENERATED) diff --git a/src/internal.h b/src/internal.h index 1997031..18867fd 100644 --- a/src/internal.h +++ b/src/internal.h @@ -242,4 +242,74 @@ /* divide value by size, rounding up */ # define VIR_DIV_UP(value, size) (((value) + (size) - 1) / (size)) + +# if WITH_DTRACE +# ifndef LIBVIRT_PROBES_H +# define LIBVIRT_PROBES_H +# include "probes.h" +# endif /* LIBVIRT_PROBES_H */ + +/* Systemtap 1.2 headers have a bug where they cannot handle a + * variable declared with array type. Work around this by casting all + * arguments. This is some gross use of the preprocessor because + * PROBE is a var-arg macro, but it is better than the alternative of + * making all callers to PROBE have to be aware of the issues. And + * hopefully, if we ever add a call to PROBE with other than 2 or 3 + * end arguments, you can figure out the pattern to extend this hack. + */ +# define VIR_COUNT_ARGS(...) VIR_ARG9(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1) +# define VIR_ARG9(_1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9 +# define VIR_ADD_CAST_EXPAND(a, b, ...) VIR_ADD_CAST_PASTE(a, b, __VA_ARGS__) +# define VIR_ADD_CAST_PASTE(a, b, ...) a##b(__VA_ARGS__) + +/* The double cast is necessary to silence gcc warnings; any pointer + * can safely go to intptr_t and back to void *, which collapses + * arrays into pointers; while any integer can be widened to intptr_t + * then cast to void *. */ +# define VIR_ADD_CAST(a) ((void *)(intptr_t)(a)) +# define VIR_ADD_CAST2(a, b) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b) +# define VIR_ADD_CAST3(a, b, c) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c) +# define VIR_ADD_CAST4(a, b, c, d) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d) +# define VIR_ADD_CAST5(a, b, c, d, e) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d), VIR_ADD_CAST(e) +# define VIR_ADD_CAST6(a, b, c, d, e, f) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f) +# define VIR_ADD_CAST7(a, b, c, d, e, f, g) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f), \ + VIR_ADD_CAST(g) +# define VIR_ADD_CAST8(a, b, c, d, e, f, g, h) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f), \ + VIR_ADD_CAST(g), VIR_ADD_CAST(h) +# define VIR_ADD_CAST9(a, b, c, d, e, f, g, h, i) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f), \ + VIR_ADD_CAST(g), VIR_ADD_CAST(h), VIR_ADD_CAST(i) + +# define VIR_ADD_CASTS(...) \ + VIR_ADD_CAST_EXPAND(VIR_ADD_CAST, VIR_COUNT_ARGS(__VA_ARGS__), \ + __VA_ARGS__) + +# define PROBE_EXPAND(NAME, ARGS) NAME(ARGS) +# define PROBE(NAME, FMT, ...) \ + VIR_DEBUG_INT("trace." __FILE__ , __func__, __LINE__, \ + #NAME ": " FMT, __VA_ARGS__); \ + if (LIBVIRT_ ## NAME ## _ENABLED()) { \ + PROBE_EXPAND(LIBVIRT_ ## NAME, \ + VIR_ADD_CASTS(__VA_ARGS__)); \ + } +# else +# define PROBE(NAME, FMT, ...) \ + VIR_DEBUG_INT("trace." __FILE__, __func__, __LINE__, \ + #NAME ": " FMT, __VA_ARGS__); +# endif + + #endif /* __VIR_INTERNAL_H__ */ diff --git a/src/libvirt.stp b/src/libvirt.stp new file mode 100644 index 0000000..0b8ad14 --- /dev/null +++ b/src/libvirt.stp @@ -0,0 +1,35 @@ +probe libvirt.rpc.server_msg_tx = process("libvirt.so").mark("rpc_server_msg_tx") { + prog = $arg1; + vers = $arg2; + proc = $arg3; + type = $arg4; + status = $arg5; + serial = $arg6; +} + +probe libvirt.rpc.server_msg_rx = process("libvirt.so").mark("rpc_server_msg_rx") { + prog = $arg1; + vers = $arg2; + proc = $arg3; + type = $arg4; + status = $arg5; + serial = $arg6; +} + +probe libvirt.rpc.client_msg_tx = process("libvirt.so").mark("rpc_client_msg_tx") { + prog = $arg1; + vers = $arg2; + proc = $arg3; + type = $arg4; + status = $arg5; + serial = $arg6; +} + +probe libvirt.rpc.client_msg_rx = process("libvirt.so").mark("rpc_client_msg_rx") { + prog = $arg1; + vers = $arg2; + proc = $arg3; + type = $arg4; + status = $arg5; + serial = $arg6; +} diff --git a/src/probes.d b/src/probes.d new file mode 100644 index 0000000..e1f4212 --- /dev/null +++ b/src/probes.d @@ -0,0 +1,7 @@ +provider libvirt { + probe rpc_server_msg_tx(int prog, int vers, int proc, int type, int status, int serial); + probe rpc_server_msg_rx(int prog, int vers, int proc, int type, int status, int serial); + + probe rpc_client_msg_tx(int prog, int vers, int proc, int type, int status, int serial); + probe rpc_client_msg_rx(int prog, int vers, int proc, int type, int status, int serial); +}; diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c index 64f1075..3d81f3c 100644 --- a/src/rpc/virnetclient.c +++ b/src/rpc/virnetclient.c @@ -834,10 +834,10 @@ virNetClientCallDispatch(virNetClientPtr client) if (virNetMessageDecodeHeader(&client->msg) < 0) return -1; - VIR_DEBUG("Incoming message prog %d vers %d proc %d type %d status %d serial %d", - client->msg.header.prog, client->msg.header.vers, - client->msg.header.proc, client->msg.header.type, - client->msg.header.status, client->msg.header.serial); + PROBE(RPC_CLIENT_MSG_RX, + "prog=%u vers=%u proc=%u type=%u status=%u serial=%u", + client->msg.header.prog, client->msg.header.vers, client->msg.header.proc, + client->msg.header.type, client->msg.header.status, client->msg.header.serial); if (virKeepAliveCheckMessage(client->keepalive, &client->msg)) return 0; @@ -1406,6 +1406,11 @@ virNetClientSendInternal(virNetClientPtr client, virNetClientCallPtr call; int ret = -1; + PROBE(RPC_CLIENT_MSG_TX, + "prog=%u vers=%u proc=%u type=%u status=%u serial=%u", + msg->header.prog, msg->header.vers, msg->header.proc, + msg->header.type, msg->header.status, msg->header.serial); + if (expectReply && (msg->bufferLength != 0) && (msg->header.status == VIR_NET_CONTINUE || dontBlock)) { diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c index 9bd8914..7474ea3 100644 --- a/src/rpc/virnetserverclient.c +++ b/src/rpc/virnetserverclient.c @@ -807,6 +807,11 @@ readmore: return; } + PROBE(RPC_SERVER_MSG_RX, + "prog=%u vers=%u proc=%u type=%u status=%u serial=%u", + msg->header.prog, msg->header.vers, msg->header.proc, + msg->header.type, msg->header.status, msg->header.serial); + /* Maybe send off for queue against a filter */ filter = client->filters; while (filter) { @@ -1015,6 +1020,10 @@ int virNetServerClientSendMessage(virNetServerClientPtr client, virNetServerClientLock(client); if (client->sock && !client->wantClose) { + PROBE(RPC_SERVER_MSG_TX, + "prog=%u vers=%u proc=%u type=%u status=%u serial=%u", + msg->header.prog, msg->header.vers, msg->header.proc, + msg->header.type, msg->header.status, msg->header.serial); virNetMessageQueuePush(&client->tx, msg); virNetServerClientUpdateEvent(client); -- 1.7.6.2

On 09/30/2011 07:54 AM, Daniel P. Berrange wrote:
From: "Daniel P. Berrange"<berrange@redhat.com>
Not much of a commit comment. Even mentioning that half of the patch is code motion rather than new content might be useful.
+ +/* Systemtap 1.2 headers have a bug where they cannot handle a + * variable declared with array type. Work around this by casting all + * arguments. This is some gross use of the preprocessor because + * PROBE is a var-arg macro, but it is better than the alternative of + * making all callers to PROBE have to be aware of the issues. And + * hopefully, if we ever add a call to PROBE with other than 2 or 3
s/other than 2 or 3/more than 7/
+ * end arguments, you can figure out the pattern to extend this hack. + */ +# define VIR_COUNT_ARGS(...) VIR_ARG9(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1) +# define VIR_ARG9(_1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9 +# define VIR_ADD_CAST_EXPAND(a, b, ...) VIR_ADD_CAST_PASTE(a, b, __VA_ARGS__) +# define VIR_ADD_CAST_PASTE(a, b, ...) a##b(__VA_ARGS__) + +/* The double cast is necessary to silence gcc warnings; any pointer + * can safely go to intptr_t and back to void *, which collapses + * arrays into pointers; while any integer can be widened to intptr_t + * then cast to void *. */ +# define VIR_ADD_CAST(a) ((void *)(intptr_t)(a))
Now that you've expanded the list, it looks awkward not having VIR_ADD_CAST1(a) VIR_ADD_CAST(a)
+# define VIR_ADD_CAST2(a, b) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b) +# define VIR_ADD_CAST3(a, b, c) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c) +# define VIR_ADD_CAST4(a, b, c, d) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d) +# define VIR_ADD_CAST5(a, b, c, d, e) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d), VIR_ADD_CAST(e) +# define VIR_ADD_CAST6(a, b, c, d, e, f) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f) +# define VIR_ADD_CAST7(a, b, c, d, e, f, g) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f), \ + VIR_ADD_CAST(g)
Up to here is reachable...
+# define VIR_ADD_CAST8(a, b, c, d, e, f, g, h) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f), \ + VIR_ADD_CAST(g), VIR_ADD_CAST(h) +# define VIR_ADD_CAST9(a, b, c, d, e, f, g, h, i) \ + VIR_ADD_CAST(a), VIR_ADD_CAST(b), VIR_ADD_CAST(c), \ + VIR_ADD_CAST(d), VIR_ADD_CAST(e), VIR_ADD_CAST(f), \ + VIR_ADD_CAST(g), VIR_ADD_CAST(h), VIR_ADD_CAST(i)
but these two are impossible given your definition of VIR_COUNT_ARGS. To really support 9 arguments, VIR_COUNT_ARGS needs to call VIR_ARG11(__VA_ARGS__, 10, 9, ...). ACK with that fixed. Everything else looks like a lot of stap black magic, but the end result is indeed a setup that can be easily traced to track traffic. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org
participants (2)
-
Daniel P. Berrange
-
Eric Blake