From: Vincent Bernat Date: Sat, 28 Sep 2013 10:26:03 +0000 (+0200) Subject: dtrace: add systemtap/DTrace support X-Git-Tag: 0.7.7~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bdfe419389075af3cdfeadc78008a157afc2d5d7;p=thirdparty%2Flldpd.git dtrace: add systemtap/DTrace support Let's dive into what is hot today. The support was mostly just tested with systemtap but should works just fine with dtrace as well. We should provide a tapset to help use all this. --- diff --git a/NEWS b/NEWS index 8c48eebb..7e599264 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ lldpd (0.7.7) instead of null MAC address for bond devices on Linux. This is configurable through `lldpcli`. + Add support for "team" driver (alternative to bond devices). + + Preliminary support for DTrace/systemtap. * Fixes: + Various bugs related to fixed point number handling (for coordinates in LLDP-MED) diff --git a/configure.ac b/configure.ac index 470f42c3..dab40293 100644 --- a/configure.ac +++ b/configure.ac @@ -192,6 +192,9 @@ AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) AM_CONDITIONAL(HAVE_SYSTEMDSYSTEMUNITDIR, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ]) +# Systemtap/DTrace +lldp_SYSTEMTAP + # Privsep settings lldp_ARG_WITH([privsep-user], [Which user to use for privilege separation], [_lldpd]) lldp_ARG_WITH([privsep-group], [Which group to use for privilege separation], [_lldpd]) diff --git a/m4/systemtap.m4 b/m4/systemtap.m4 new file mode 100644 index 00000000..daa6c34b --- /dev/null +++ b/m4/systemtap.m4 @@ -0,0 +1,16 @@ +# +# lldp_SYSTEMTAP +# +# Check for DTrace/Systemtap support + +AC_DEFUN([lldp_SYSTEMTAP], [ + lldp_ARG_ENABLE([dtrace], [systemtap/DTrace trace support], [no]) + AM_CONDITIONAL([ENABLE_SYSTEMTAP], [test x"$enable_dtrace" = x"yes"]) + if test x"$enable_dtrace" = x"yes"; then + AC_CHECK_PROGS(DTRACE, dtrace) + if test -z "$DTRACE"; then + AC_MSG_ERROR([*** dtrace command not found]) + fi + AC_CHECK_HEADER([sys/sdt.h],,[AC_MSG_ERROR([*** no sys/sdt.h header found])]) + fi +]) diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am index dbf38068..80fa5e7e 100644 --- a/src/daemon/Makefile.am +++ b/src/daemon/Makefile.am @@ -1,4 +1,5 @@ AM_CFLAGS = -I $(top_srcdir)/include +BUILT_SOURCES = sbin_PROGRAMS = lldpd dist_man_MANS = lldpd.8 @@ -15,7 +16,8 @@ liblldpd_la_SOURCES = \ client.c \ priv.c privsep_io.c \ interfaces.c \ - event.c lldpd.c + event.c lldpd.c \ + probes.d trace.h liblldpd_la_CFLAGS = $(AM_CFLAGS) @LIBEVENT_CFLAGS@ liblldpd_la_CPPFLAGS = -DSYSCONFDIR='"$(sysconfdir)"' -DLLDPCLI_PATH='"$(sbindir)/lldpcli"' liblldpd_la_LIBADD = \ @@ -93,6 +95,18 @@ endif lldpd_SOURCES = main.c lldpd_LDADD = liblldpd.la @LIBEVENT_LDFLAGS@ +## Systemtap/DTrace +if ENABLE_SYSTEMTAP +BUILT_SOURCES += probes.h +probes.h: probes.d + $(AM_V_GEN) + $(AM_V_at)$(DTRACE) -C -h -s $< -o $@ +probes.o: probes.d + $(AM_V_GEN) + $(AM_V_at)$(DTRACE) -C -G -s $< -o $@ +lldpd_LDADD += probes.o +endif + ## libevent if LIBEVENT_EMBEDDED event.c: $(top_builddir)/libevent/libevent.la diff --git a/src/daemon/client.c b/src/daemon/client.c index bbccf9e6..0322199d 100644 --- a/src/daemon/client.c +++ b/src/daemon/client.c @@ -16,6 +16,7 @@ */ #include "lldpd.h" +#include "trace.h" static int client_handle_none(struct lldpd *cfg, enum hmsg_type *type, @@ -335,18 +336,19 @@ client_handle_subscribe(struct lldpd *cfg, enum hmsg_type *type, struct client_handle { enum hmsg_type type; + const char *name; int (*handle)(struct lldpd*, enum hmsg_type *, void *, int, void **, int *); }; static struct client_handle client_handles[] = { - { NONE, client_handle_none }, - { GET_CONFIG, client_handle_get_configuration }, - { SET_CONFIG, client_handle_set_configuration }, - { GET_INTERFACES, client_handle_get_interfaces }, - { GET_INTERFACE, client_handle_get_interface }, - { SET_PORT, client_handle_set_port }, - { SUBSCRIBE, client_handle_subscribe }, + { NONE, "None", client_handle_none }, + { GET_CONFIG, "Get configuration", client_handle_get_configuration }, + { SET_CONFIG, "Set configuration", client_handle_set_configuration }, + { GET_INTERFACES, "Get interfaces", client_handle_get_interfaces }, + { GET_INTERFACE, "Get interface", client_handle_get_interface }, + { SET_PORT, "Set port", client_handle_set_port }, + { SUBSCRIBE, "Subscribe", client_handle_subscribe }, { 0, NULL } }; int @@ -362,6 +364,7 @@ client_handle_client(struct lldpd *cfg, log_debug("rpc", "handle client request"); for (ch = client_handles; ch->handle != NULL; ch++) { if (ch->type == type) { + TRACE(LLDPD_CLIENT_REQUEST(ch->name)); answer = NULL; len = ch->handle(cfg, &type, buffer, n, &answer, subscribed); diff --git a/src/daemon/event.c b/src/daemon/event.c index 192047f3..fd7cf832 100644 --- a/src/daemon/event.c +++ b/src/daemon/event.c @@ -16,6 +16,7 @@ */ #include "lldpd.h" +#include "trace.h" #include #include @@ -491,6 +492,7 @@ levent_loop(struct lldpd *cfg) /* libevent loop */ do { + TRACE(LLDPD_EVENT_LOOP()); if (event_base_got_break(cfg->g_base) || event_base_got_exit(cfg->g_base)) break; @@ -618,6 +620,7 @@ levent_iface_recv(evutil_socket_t fd, short what, void *arg) /* Schedule local port update. We don't run it right away because we may * receive a batch of events like this. */ struct timeval one_sec = {1, 0}; + TRACE(LLDPD_INTERFACES_NOTIFICATION()); log_debug("event", "received notification change, schedule an update of all interfaces in one second"); if (cfg->g_iface_timer_event == NULL) { diff --git a/src/daemon/interfaces-linux.c b/src/daemon/interfaces-linux.c index dcf482dc..e4a7ddae 100644 --- a/src/daemon/interfaces-linux.c +++ b/src/daemon/interfaces-linux.c @@ -565,7 +565,7 @@ iflinux_handle_bond(struct lldpd *cfg, struct interfaces_device_list *interfaces } hardware->h_ops = &bond_ops; hardware->h_mangle = 1; - TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries); + interfaces_helper_add_hardware(cfg, hardware); } else { if (hardware->h_flags) continue; /* Already seen this time */ bmaster = hardware->h_data; diff --git a/src/daemon/interfaces.c b/src/daemon/interfaces.c index 0d8d6d27..2af06331 100644 --- a/src/daemon/interfaces.c +++ b/src/daemon/interfaces.c @@ -16,6 +16,7 @@ */ #include "lldpd.h" +#include "trace.h" #include #include @@ -495,6 +496,14 @@ interfaces_helper_port_name_desc(struct lldpd_hardware *hardware, port->p_descr = strdup(iface->alias); } +void +interfaces_helper_add_hardware(struct lldpd *cfg, + struct lldpd_hardware *hardware) +{ + TRACE(LLDPD_INTERFACES_NEW(hardware->h_ifname)); + TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries); +} + void interfaces_helper_physical(struct lldpd *cfg, struct interfaces_device_list *interfaces, @@ -531,7 +540,7 @@ interfaces_helper_physical(struct lldpd *cfg, hardware->h_ops = ops; hardware->h_mangle = (iface->upper && iface->upper->type & IFACE_BOND_T); - TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries); + interfaces_helper_add_hardware(cfg, hardware); } else { if (hardware->h_flags) continue; /* Already seen this time */ lldpd_port_cleanup(&hardware->h_lport, 0); diff --git a/src/daemon/lldpd.c b/src/daemon/lldpd.c index 5a111022..b4860be3 100644 --- a/src/daemon/lldpd.c +++ b/src/daemon/lldpd.c @@ -16,6 +16,7 @@ */ #include "lldpd.h" +#include "trace.h" #include #include @@ -275,6 +276,9 @@ static void notify_clients_deletion(struct lldpd_hardware *hardware, struct lldpd_port *rport) { + TRACE(LLDPD_NEIGHBOR_DELETE(hardware->h_ifname, + rport->p_chassis->c_name, + rport->p_descr)); levent_ctl_notify(hardware->h_ifname, NEIGHBOR_CHANGE_DELETED, rport); #ifdef USE_SNMP @@ -334,6 +338,7 @@ lldpd_cleanup(struct lldpd *cfg) hardware = hardware_next) { hardware_next = TAILQ_NEXT(hardware, h_entries); if (!hardware->h_flags) { + TRACE(LLDPD_INTERFACES_DELETE(hardware->h_ifname)); TAILQ_REMOVE(&cfg->g_hardware, hardware, h_entries); lldpd_remote_cleanup(hardware, notify_clients_deletion, 1); lldpd_hardware_cleanup(cfg, hardware); @@ -482,6 +487,11 @@ lldpd_decode(struct lldpd *cfg, char *frame, int s, hardware->h_ifname); return; } + TRACE(LLDPD_FRAME_DECODED( + hardware->h_ifname, + cfg->g_protocols[i].name, + chassis->c_name, + port->p_descr)); /* Do we already have the same MSAP somewhere? */ int count = 0; @@ -577,11 +587,25 @@ lldpd_decode(struct lldpd *cfg, char *frame, int s, /* Notify */ log_debug("decode", "send notifications for changes on %s", hardware->h_ifname); - i = oport?NEIGHBOR_CHANGE_UPDATED:NEIGHBOR_CHANGE_ADDED; - levent_ctl_notify(hardware->h_ifname, i, port); + if (oport) { + TRACE(LLDPD_NEIGHBOR_UPDATE(hardware->h_ifname, + chassis->c_name, + port->p_descr, + i)); + levent_ctl_notify(hardware->h_ifname, NEIGHBOR_CHANGE_UPDATED, port); #ifdef USE_SNMP - agent_notify(hardware, i, port); + agent_notify(hardware, NEIGHBOR_CHANGE_UPDATED, port); #endif + } else { + TRACE(LLDPD_NEIGHBOR_NEW(hardware->h_ifname, + chassis->c_name, + port->p_descr, + i)); + levent_ctl_notify(hardware->h_ifname, NEIGHBOR_CHANGE_ADDED, port); +#ifdef USE_SNMP + agent_notify(hardware, NEIGHBOR_CHANGE_ADDED, port); +#endif + } #ifdef ENABLE_LLDPMED if (!oport && port->p_chassis->c_med_type) { @@ -851,6 +875,7 @@ lldpd_recv(struct lldpd *cfg, struct lldpd_hardware *hardware, int fd) hardware->h_rx_cnt++; log_debug("receive", "decode received frame on %s", hardware->h_ifname); + TRACE(LLDPD_FRAME_RECEIVED(hardware->h_ifname, buffer, (size_t)n)); lldpd_decode(cfg, buffer, n, hardware); lldpd_hide_all(cfg); /* Immediatly hide */ lldpd_count_neighbors(cfg); @@ -887,6 +912,8 @@ lldpd_send(struct lldpd_hardware *hardware) continue; if (port->p_protocol == cfg->g_protocols[i].mode) { + TRACE(LLDPD_FRAME_SEND(hardware->h_ifname, + cfg->g_protocols[i].name)); log_debug("send", "send PDU on %s with protocol %s", hardware->h_ifname, cfg->g_protocols[i].name); @@ -903,6 +930,8 @@ lldpd_send(struct lldpd_hardware *hardware) * available protocol. */ for (i = 0; cfg->g_protocols[i].mode != 0; i++) { if (!cfg->g_protocols[i].enabled) continue; + TRACE(LLDPD_FRAME_SEND(hardware->h_ifname, + cfg->g_protocols[i].name)); log_debug("send", "fallback to protocol %s for %s", cfg->g_protocols[i].name, hardware->h_ifname); cfg->g_protocols[i].send(cfg, @@ -1025,6 +1054,7 @@ lldpd_update_localports(struct lldpd *cfg) TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) hardware->h_flags = 0; + TRACE(LLDPD_INTERFACES_UPDATE()); interfaces_update(cfg); lldpd_cleanup(cfg); lldpd_reset_timer(cfg); diff --git a/src/daemon/lldpd.h b/src/daemon/lldpd.h index 659e3e60..a568b380 100644 --- a/src/daemon/lldpd.h +++ b/src/daemon/lldpd.h @@ -352,6 +352,8 @@ void interfaces_helper_whitelist(struct lldpd *, struct interfaces_device_list *); void interfaces_helper_chassis(struct lldpd *, struct interfaces_device_list *); +void interfaces_helper_add_hardware(struct lldpd *, + struct lldpd_hardware *); void interfaces_helper_physical(struct lldpd *, struct interfaces_device_list *, struct lldpd_ops *, diff --git a/src/daemon/priv.c b/src/daemon/priv.c index c5e630ae..c8e262d9 100644 --- a/src/daemon/priv.c +++ b/src/daemon/priv.c @@ -21,6 +21,7 @@ * case, error can be non fatal. */ #include "lldpd.h" +#include "trace.h" #include #include @@ -217,6 +218,7 @@ asroot_iface_init() must_read(&name, sizeof(name)); name[sizeof(name) - 1] = '\0'; + TRACE(LLDPD_PRIV_INTERFACE_INIT(name)); rc = asroot_iface_init_os(ifindex, name, &fd); must_write(&rc, sizeof(rc)); if (rc == 0 && fd >=0) send_fd(fd); @@ -276,6 +278,7 @@ asroot_iface_description() must_read(description, len); description[len] = 0; + TRACE(LLDPD_PRIV_INTERFACE_DESCRIPTION(name, description)); rc = asroot_iface_description_os(name, description); must_write(&rc, sizeof(rc)); } diff --git a/src/daemon/probes.d b/src/daemon/probes.d new file mode 100644 index 00000000..7528f962 --- /dev/null +++ b/src/daemon/probes.d @@ -0,0 +1,116 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * Copyright (c) 2013 Vincent Bernat + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +provider lldpd { + + /** + * Fired when a frame is received, before it is decoded. + * @param ifname the name of the interface + * @param frame the received frame + * @param len the len of the received frame + */ + probe frame_received(const char *ifname, void *frame, size_t len); + + /** + * Fired when a frame is decoded. + * @param ifname the name of the interface + * @param protocol the name of the protocol + * @param chassis_name the name of chassis (may be NULL) + * @param port_descr the description of the port (may be NULL) + */ + probe frame_decoded(const char *ifname, const char *protocol, + const char *chassis_name, const char *port_descr); + + /** + * Fired when a frame is sent. + * @param ifname the name of the interface + * @param protocol the name of the protocol + */ + probe frame_send(const char *ifname, const char *protocol); + + /** + * Fired when a neighbor is added. + * @param ifname the name of the interface where the neighbor appeared + * @param chassis_name the name of chassis (may be NULL) + * @param port_descr the description of the port (may be NULL) + * @param count the total number of neighbors known + */ + probe neighbor_new(const char *ifname, const char *chassis_name, const char *port_descr, int count); + + /** + * Fired when a neighbor is updated. + * @param ifname the name of the interface where the neighbor updated + * @param chassis_name the name of chassis (may be NULL) + * @param port_descr the description of the port (may be NULL) + * @param count the total number of neighbors known + */ + probe neighbor_update(const char *ifname, const char *chassis_name, const char *port_descr, int count); + + /** + * Fired when a neighbor is deleted. + * @param ifname the name of the interface where the neighbor deleted + * @param chassis_name the name of chassis (may be NULL) + * @param port_descr the description of the port (may be NULL) + * @param count the total number of neighbors known + */ + probe neighbor_delete(const char *ifname, const char *chassis_name, const char *port_descr); + + /** + * Fired before handling a client request. + * @param name the name of the request + */ + probe client_request(const char *name); + + /** + * Fired for each iteration of the event loop. + */ + probe event_loop(); + + /** + * Fired when initializing a new interface in privileged mode. + * @param name the name of the interface + */ + probe priv_interface_init(const char *name); + + /** + * Fired when setting description of an interface. + * @param name the name of the interface + * @param desc the description of the interface + */ + probe priv_interface_description(const char *name, const char *description); + + /** + * Fired when doing an interface updates. + */ + probe interfaces_update(); + + /** + * Fired when receiving an interface update notification. + */ + probe interfaces_notification(); + + /** + * Fired when an interface is removed. + * @param name the name of the interface + */ + probe interfaces_delete(const char *name); + + /** + * Fired when an interface is added. + * @param name the name of the interface + */ + probe interfaces_new(const char *name); +}; diff --git a/src/daemon/trace.h b/src/daemon/trace.h new file mode 100644 index 00000000..d4b48464 --- /dev/null +++ b/src/daemon/trace.h @@ -0,0 +1,8 @@ +#ifdef ENABLE_DTRACE +# include "probes.h" +# define TRACE(probe) probe +# define TRACE_ENABLED(probe) probe ## _ENABLED() +#else +# define TRACE(probe) +# define TRACE_ENABLED(probe) (0) +#endif