]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
dtrace: add systemtap/DTrace support
authorVincent Bernat <bernat@luffy.cx>
Sat, 28 Sep 2013 10:26:03 +0000 (12:26 +0200)
committerVincent Bernat <bernat@luffy.cx>
Sat, 28 Sep 2013 10:26:03 +0000 (12:26 +0200)
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.

13 files changed:
NEWS
configure.ac
m4/systemtap.m4 [new file with mode: 0644]
src/daemon/Makefile.am
src/daemon/client.c
src/daemon/event.c
src/daemon/interfaces-linux.c
src/daemon/interfaces.c
src/daemon/lldpd.c
src/daemon/lldpd.h
src/daemon/priv.c
src/daemon/probes.d [new file with mode: 0644]
src/daemon/trace.h [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 8c48eebbd4cfa739a4b92d04ae34a24239ac6a79..7e599264c09069600d86cc4f131c1ffbca4755d7 100644 (file)
--- 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)
index 470f42c3dff690db0a2caea75756e01e1d368ad4..dab40293c67786a033a846f104b706831abe9a39 100644 (file)
@@ -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 (file)
index 0000000..daa6c34
--- /dev/null
@@ -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
+])
index dbf380688aafc0a48da6749202cdd557f02396a4..80fa5e7e3f9c6ce3f84789156a52829f459a6226 100644 (file)
@@ -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
index bbccf9e6e8be89d6b0e33f9c4edcce26b8fed3c6..0322199d0de66ed6929533ae9ea64f27d7be3290 100644 (file)
@@ -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);
index 192047f38b1693dea905a45fc4b3bca880cf8b62..fd7cf832ec20dc0c97c5ca8b0574cc64b9ddadc1 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "lldpd.h"
+#include "trace.h"
 
 #include <unistd.h>
 #include <signal.h>
@@ -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) {
index dcf482dca1e49ea026eef0a86c24e1b872a655b6..e4a7ddaecdf4d8652319b1e2cab9a9e2459ecd30 100644 (file)
@@ -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;
index 0d8d6d279ffe4f1bb4a9066a144e560836c95237..2af06331c3cb2407920dcda7d4ae4b68311f698c 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "lldpd.h"
+#include "trace.h"
 
 #include <stddef.h>
 #include <unistd.h>
@@ -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);
index 5a11102265ad609ecb128432110b0efe7c652fbe..b4860be33bf4789413733bfe7fa6b94088eebb9c 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "lldpd.h"
+#include "trace.h"
 
 #include <stdio.h>
 #include <unistd.h>
@@ -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);
index 659e3e60a30619430b56305e2fea902ee370d5a4..a568b38019602577f57ae6985c2a98d8fb9ca08e 100644 (file)
@@ -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 *,
index c5e630aea7cd9fc412a2a89e5c39837f31ed8d96..c8e262d9b15236d8b0f99d246319689c2ef72294 100644 (file)
@@ -21,6 +21,7 @@
  * case, error can be non fatal. */
 
 #include "lldpd.h"
+#include "trace.h"
 
 #include <stdio.h>
 #include <unistd.h>
@@ -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 (file)
index 0000000..7528f96
--- /dev/null
@@ -0,0 +1,116 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2013 Vincent Bernat <bernat@luffy.cx>
+ *
+ * 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 (file)
index 0000000..d4b4846
--- /dev/null
@@ -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