#include "common.h"
#include "plugin.h"
#include "utils_complain.h"
+#include "utils_ignorelist.h"
#include <asm/types.h>
#include <errno.h>
#define MYPROTO NETLINK_ROUTE
+#define LINK_STATE_DOWN 0
+#define LINK_STATE_UP 1
+#define LINK_STATE_UNKNOWN 2
+
#define CONNECTIVITY_DOMAIN_FIELD "domain"
#define CONNECTIVITY_DOMAIN_VALUE "stateChange"
#define CONNECTIVITY_EVENT_ID_FIELD "eventId"
/*
* Private data types
*/
-struct interfacelist_s {
+struct interface_list_s {
char *interface;
uint32_t status;
uint32_t sent;
long long unsigned int timestamp;
- struct interfacelist_s *next;
+ struct interface_list_s *next;
};
-typedef struct interfacelist_s interfacelist_t;
+typedef struct interface_list_s interface_list_t;
/*
* Private variables
*/
-static interfacelist_t *interfacelist_head = NULL;
+static ignorelist_t *ignorelist = NULL;
+
+static interface_list_t *interface_list_head = NULL;
+static int monitor_all_interfaces = 0;
static int connectivity_thread_loop = 0;
static int connectivity_thread_error = 0;
long long unsigned int timestamp, char **buf) {
const unsigned char *buf2;
yajl_gen g;
+ char json_str[DATA_MAX_NAME_LEN];
#if !defined(HAVE_YAJL_V2)
yajl_gen_config conf = {};
event_id = event_id + 1;
int event_id_len = sizeof(char) * sizeof(int) * 4 + 1;
- char *event_id_str = malloc(event_id_len);
- snprintf(event_id_str, event_id_len, "%d", event_id);
+ memset(json_str, '\0', DATA_MAX_NAME_LEN);
+ snprintf(json_str, event_id_len, "%d", event_id);
- if (yajl_gen_number(g, event_id_str, strlen(event_id_str)) !=
- yajl_gen_status_ok) {
- sfree(event_id_str);
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
goto err;
}
- sfree(event_id_str);
-
// eventName
if (yajl_gen_string(g, (u_char *)CONNECTIVITY_EVENT_NAME_FIELD,
strlen(CONNECTIVITY_EVENT_NAME_FIELD)) !=
event_name_len = event_name_len + (state == 0 ? 4 : 2); // "down" or "up"
event_name_len =
event_name_len + 12; // "interface", 2 spaces and null-terminator
- char *event_name_str = malloc(event_name_len);
- memset(event_name_str, '\0', event_name_len);
- snprintf(event_name_str, event_name_len, "interface %s %s", interface,
+ memset(json_str, '\0', DATA_MAX_NAME_LEN);
+ snprintf(json_str, event_name_len, "interface %s %s", interface,
(state == 0 ? CONNECTIVITY_EVENT_NAME_DOWN_VALUE
: CONNECTIVITY_EVENT_NAME_UP_VALUE));
- if (yajl_gen_string(g, (u_char *)event_name_str, strlen(event_name_str)) !=
+ if (yajl_gen_string(g, (u_char *)json_str, strlen(json_str)) !=
yajl_gen_status_ok) {
- sfree(event_name_str);
goto err;
}
- sfree(event_name_str);
-
// lastEpochMicrosec
if (yajl_gen_string(g, (u_char *)CONNECTIVITY_LAST_EPOCH_MICROSEC_FIELD,
strlen(CONNECTIVITY_LAST_EPOCH_MICROSEC_FIELD)) !=
int last_epoch_microsec_len =
sizeof(char) * sizeof(long long unsigned int) * 4 + 1;
- char *last_epoch_microsec_str = malloc(last_epoch_microsec_len);
- snprintf(last_epoch_microsec_str, last_epoch_microsec_len, "%llu",
+ memset(json_str, '\0', DATA_MAX_NAME_LEN);
+ snprintf(json_str, last_epoch_microsec_len, "%llu",
(long long unsigned int)CDTIME_T_TO_US(cdtime()));
- if (yajl_gen_number(g, last_epoch_microsec_str,
- strlen(last_epoch_microsec_str)) != yajl_gen_status_ok) {
- sfree(last_epoch_microsec_str);
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
goto err;
}
- sfree(last_epoch_microsec_str);
-
// priority
if (yajl_gen_string(g, (u_char *)CONNECTIVITY_PRIORITY_FIELD,
strlen(CONNECTIVITY_PRIORITY_FIELD)) !=
int start_epoch_microsec_len =
sizeof(char) * sizeof(long long unsigned int) * 4 + 1;
- char *start_epoch_microsec_str = malloc(start_epoch_microsec_len);
- snprintf(start_epoch_microsec_str, start_epoch_microsec_len, "%llu",
+ memset(json_str, '\0', DATA_MAX_NAME_LEN);
+ snprintf(json_str, start_epoch_microsec_len, "%llu",
(long long unsigned int)timestamp);
- if (yajl_gen_number(g, start_epoch_microsec_str,
- strlen(start_epoch_microsec_str)) != yajl_gen_status_ok) {
- sfree(start_epoch_microsec_str);
+ if (yajl_gen_number(g, json_str, strlen(json_str)) != yajl_gen_status_ok) {
goto err;
}
- sfree(start_epoch_microsec_str);
-
// version
if (yajl_gen_string(g, (u_char *)CONNECTIVITY_VERSION_FIELD,
strlen(CONNECTIVITY_VERSION_FIELD)) != yajl_gen_status_ok)
*buf = malloc(strlen((char *)buf2) + 1);
+ if (*buf == NULL) {
+ char errbuf[1024];
+ ERROR("connectivity plugin: malloc failed during gen_message_payload: %s",
+ sstrerror(errno, errbuf, sizeof(errbuf)));
+ goto err;
+ }
+
sstrncpy(*buf, (char *)buf2, strlen((char *)buf2) + 1);
yajl_gen_free(g);
return -1;
}
+static interface_list_t *add_interface(const char *interface, int status,
+ int prev_status) {
+ interface_list_t *il;
+ char *interface2;
+
+ il = malloc(sizeof(*il));
+ if (il == NULL) {
+ char errbuf[1024];
+ ERROR("connectivity plugin: malloc failed during add_interface: %s",
+ sstrerror(errno, errbuf, sizeof(errbuf)));
+ return NULL;
+ }
+
+ interface2 = strdup(interface);
+ if (interface2 == NULL) {
+ char errbuf[1024];
+ sfree(il);
+ ERROR("connectivity plugin: strdup failed during add_interface: %s",
+ sstrerror(errno, errbuf, sizeof(errbuf)));
+ return NULL;
+ }
+
+ il->interface = interface2;
+ il->status = status;
+ il->prev_status = prev_status;
+ il->timestamp = (long long unsigned int)CDTIME_T_TO_US(cdtime());
+ il->sent = 0;
+ il->next = interface_list_head;
+ interface_list_head = il;
+
+ DEBUG("connectivity plugin: added interface %s", interface2);
+
+ return il;
+}
+
static int connectivity_link_state(struct nlmsghdr *msg) {
int retval = 0;
struct ifinfomsg *ifi = mnl_nlmsg_get_payload(msg);
pthread_mutex_lock(&connectivity_lock);
- interfacelist_t *il;
+ interface_list_t *il = NULL;
/* Scan attribute list for device name. */
mnl_attr_for_each(attr, msg, sizeof(*ifi)) {
dev = mnl_attr_get_str(attr);
- for (il = interfacelist_head; il != NULL; il = il->next)
- if (strcmp(dev, il->interface) == 0)
- break;
-
- if (il == NULL) {
+ // Check the list of interfaces we should monitor, if we've chosen
+ // a subset. If we don't care about this one, abort.
+ if (ignorelist_match(ignorelist, dev) != 0) {
DEBUG("connectivity plugin: Ignoring link state change for unmonitored "
"interface: %s",
dev);
- } else {
- uint32_t prev_status;
+ break;
+ }
+
+ for (il = interface_list_head; il != NULL; il = il->next)
+ if (strcmp(dev, il->interface) == 0)
+ break;
- prev_status = il->status;
- il->status = ((ifi->ifi_flags & IFF_RUNNING) ? 1 : 0);
- il->timestamp = (long long unsigned int)CDTIME_T_TO_US(cdtime());
+ uint32_t prev_status;
- // If the new status is different than the previous status,
- // store the previous status and set sent to zero
- if (il->status != prev_status) {
- il->prev_status = prev_status;
- il->sent = 0;
+ if (il == NULL) {
+ // We haven't encountered this interface yet, so add it to the linked list
+ il = add_interface(dev, LINK_STATE_UNKNOWN, LINK_STATE_UNKNOWN);
+
+ if (il == NULL) {
+ ERROR("connectivity plugin: unable to add interface %s during "
+ "connectivity_link_state",
+ dev);
+ return MNL_CB_ERROR;
}
+ }
+
+ prev_status = il->status;
+ il->status =
+ ((ifi->ifi_flags & IFF_RUNNING) ? LINK_STATE_UP : LINK_STATE_DOWN);
+ il->timestamp = (long long unsigned int)CDTIME_T_TO_US(cdtime());
- DEBUG("connectivity plugin (%llu): Interface %s status is now %s",
- il->timestamp, dev,
- ((ifi->ifi_flags & IFF_RUNNING) ? "UP" : "DOWN"));
+ // If the new status is different than the previous status,
+ // store the previous status and set sent to zero
+ if (il->status != prev_status) {
+ il->prev_status = prev_status;
+ il->sent = 0;
}
+ DEBUG("connectivity plugin (%llu): Interface %s status is now %s",
+ il->timestamp, dev, ((ifi->ifi_flags & IFF_RUNNING) ? "UP" : "DOWN"));
+
// no need to loop again, we found the interface name attr
// (otherwise the first if-statement in the loop would
// have moved us on with 'continue')
static int msg_handler(struct nlmsghdr *msg) {
switch (msg->nlmsg_type) {
case RTM_NEWADDR:
- break;
case RTM_DELADDR:
- break;
case RTM_NEWROUTE:
- break;
case RTM_DELROUTE:
+ case RTM_DELLINK:
+ // Not of interest in current version
break;
case RTM_NEWLINK:
connectivity_link_state(msg);
break;
- case RTM_DELLINK:
- break;
default:
ERROR("connectivity plugin: msg_handler: Unknown netlink nlmsg_type %d\n",
msg->nlmsg_type);
static int connectivity_init(void) /* {{{ */
{
- if (interfacelist_head == NULL) {
- NOTICE("connectivity plugin: No interfaces have been configured.");
- return (-1);
+ if (interface_list_head == NULL) {
+ NOTICE("connectivity plugin: No interfaces have been selected, so all will "
+ "be monitored");
+ monitor_all_interfaces = 1;
}
return (start_thread());
static int connectivity_config(const char *key, const char *value) /* {{{ */
{
- if (strcasecmp(key, "Interface") == 0) {
- interfacelist_t *il;
- char *interface;
-
- il = malloc(sizeof(*il));
- if (il == NULL) {
- char errbuf[1024];
- ERROR("connectivity plugin: malloc failed during connectivity_config: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
- return (1);
- }
-
- interface = strdup(value);
- if (interface == NULL) {
- char errbuf[1024];
- sfree(il);
- ERROR("connectivity plugin: strdup failed connectivity_config: %s",
- sstrerror(errno, errbuf, sizeof(errbuf)));
- return (1);
- }
-
- il->interface = interface;
- il->status = 2; // "unknown"
- il->prev_status = 2;
- il->timestamp = (long long unsigned int)CDTIME_T_TO_US(cdtime());
- il->sent = 0;
- il->next = interfacelist_head;
- interfacelist_head = il;
+ if (ignorelist == NULL)
+ ignorelist = ignorelist_create(/* invert = */ 1);
+ if (strcasecmp(key, "Interface") == 0) {
+ ignorelist_add(ignorelist, value);
} else {
return (-1);
}
notification_t n = {
NOTIF_FAILURE, cdtime(), "", "", "connectivity", "", "", "", NULL};
- if (value == 1)
+ if (value == LINK_STATE_UP)
n.severity = NOTIF_OKAY;
- char hostname[1024];
- gethostname(hostname, sizeof(hostname));
-
- sstrncpy(n.host, hostname, sizeof(n.host));
+ sstrncpy(n.host, hostname_g, sizeof(n.host));
sstrncpy(n.plugin_instance, interface, sizeof(n.plugin_instance));
sstrncpy(n.type, "gauge", sizeof(n.type));
sstrncpy(n.type_instance, "interface_status", sizeof(n.type_instance));
stop_thread(0);
- for (interfacelist_t *il = interfacelist_head; il != NULL; il = il->next) {
- il->status = 2; // signifies "unknown"
- il->prev_status = 2;
+ for (interface_list_t *il = interface_list_head; il != NULL;
+ il = il->next) {
+ il->status = LINK_STATE_UNKNOWN;
+ il->prev_status = LINK_STATE_UNKNOWN;
il->sent = 0;
}
return (-1);
} /* if (connectivity_thread_error != 0) */
- for (interfacelist_t *il = interfacelist_head; il != NULL;
+ for (interface_list_t *il = interface_list_head; il != NULL;
il = il->next) /* {{{ */
{
uint32_t status;
}
pthread_mutex_unlock(&connectivity_lock);
- } /* }}} for (il = interfacelist_head; il != NULL; il = il->next) */
+ } /* }}} for (il = interface_list_head; il != NULL; il = il->next) */
return (0);
} /* }}} int connectivity_read */
static int connectivity_shutdown(void) /* {{{ */
{
- interfacelist_t *il;
+ interface_list_t *il;
DEBUG("connectivity plugin: Shutting down thread.");
if (stop_thread(1) < 0)
return (-1);
- il = interfacelist_head;
+ il = interface_list_head;
while (il != NULL) {
- interfacelist_t *il_next;
+ interface_list_t *il_next;
il_next = il->next;
il = il_next;
}
+ ignorelist_free(ignorelist);
+
return (0);
} /* }}} int connectivity_shutdown */