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)
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])
--- /dev/null
+#
+# 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
+])
AM_CFLAGS = -I $(top_srcdir)/include
+BUILT_SOURCES =
sbin_PROGRAMS = lldpd
dist_man_MANS = lldpd.8
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 = \
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
*/
#include "lldpd.h"
+#include "trace.h"
static int
client_handle_none(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
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);
*/
#include "lldpd.h"
+#include "trace.h"
#include <unistd.h>
#include <signal.h>
/* libevent loop */
do {
+ TRACE(LLDPD_EVENT_LOOP());
if (event_base_got_break(cfg->g_base) ||
event_base_got_exit(cfg->g_base))
break;
/* 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) {
}
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;
*/
#include "lldpd.h"
+#include "trace.h"
#include <stddef.h>
#include <unistd.h>
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,
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);
*/
#include "lldpd.h"
+#include "trace.h"
#include <stdio.h>
#include <unistd.h>
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
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);
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;
/* 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) {
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);
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);
* 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,
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);
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 *,
* case, error can be non fatal. */
#include "lldpd.h"
+#include "trace.h"
#include <stdio.h>
#include <unistd.h>
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);
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));
}
--- /dev/null
+/* -*- 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);
+};
--- /dev/null
+#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