Merge branch 'master' into connectivity
[collectd.git] / src / connectivity.c
index 8cacf3b..e39bce1 100644 (file)
@@ -30,6 +30,7 @@
 #include "common.h"
 #include "plugin.h"
 #include "utils_complain.h"
+#include "utils_ignorelist.h"
 
 #include <asm/types.h>
 #include <errno.h>
@@ -108,7 +109,10 @@ typedef struct interface_list_s interface_list_t;
 /*
  * Private variables
  */
+static ignorelist_t *ignorelist = NULL;
+
 static interface_list_t *interface_list_head = NULL;
+static int monitor_all_interfaces = 1;
 
 static int connectivity_thread_loop = 0;
 static int connectivity_thread_error = 0;
@@ -361,6 +365,13 @@ static int gen_message_payload(int state, int old_state, const char *interface,
 
   *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);
@@ -373,6 +384,41 @@ err:
   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);
@@ -381,7 +427,7 @@ static int connectivity_link_state(struct nlmsghdr *msg) {
 
   pthread_mutex_lock(&connectivity_lock);
 
-  interface_list_t *il;
+  interface_list_t *il = NULL;
 
   /* Scan attribute list for device name. */
   mnl_attr_for_each(attr, msg, sizeof(*ifi)) {
@@ -398,34 +444,48 @@ static int connectivity_link_state(struct nlmsghdr *msg) {
 
     dev = mnl_attr_get_str(attr);
 
+    // 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);
+      break;
+    }
+
     for (il = interface_list_head; il != NULL; il = il->next)
       if (strcmp(dev, il->interface) == 0)
         break;
 
+    uint32_t prev_status;
+
     if (il == NULL) {
-      DEBUG("connectivity plugin: Ignoring link state change for unmonitored "
-            "interface: %s",
-            dev);
-    } else {
-      uint32_t prev_status;
-
-      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());
-
-      // 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;
+      // 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')
@@ -645,9 +705,9 @@ static int stop_thread(int shutdown) /* {{{ */
 
 static int connectivity_init(void) /* {{{ */
 {
-  if (interface_list_head == NULL) {
-    NOTICE("connectivity plugin: No interfaces have been configured.");
-    return (-1);
+  if (monitor_all_interfaces) {
+    NOTICE("connectivity plugin: No interfaces have been selected, so all will "
+           "be monitored");
   }
 
   return (start_thread());
@@ -655,35 +715,13 @@ static int connectivity_init(void) /* {{{ */
 
 static int connectivity_config(const char *key, const char *value) /* {{{ */
 {
-  if (strcasecmp(key, "Interface") == 0) {
-    interface_list_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 = LINK_STATE_UNKNOWN;
-    il->prev_status = LINK_STATE_UNKNOWN;
-    il->timestamp = (long long unsigned int)CDTIME_T_TO_US(cdtime());
-    il->sent = 0;
-    il->next = interface_list_head;
-    interface_list_head = il;
+  if (ignorelist == NULL) {
+    ignorelist = ignorelist_create(/* invert = */ 1);
+  }
 
+  if (strcasecmp(key, "Interface") == 0) {
+    ignorelist_add(ignorelist, value);
+    monitor_all_interfaces = 0;
   } else {
     return (-1);
   }
@@ -701,10 +739,7 @@ static void connectivity_dispatch_notification(
   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));
@@ -805,6 +840,8 @@ static int connectivity_shutdown(void) /* {{{ */
     il = il_next;
   }
 
+  ignorelist_free(ignorelist);
+
   return (0);
 } /* }}} int connectivity_shutdown */