dpdkstats: Added errors and filter_result types.
[collectd.git] / src / dpdkstat.c
index e37c4ba..3e0ea04 100644 (file)
@@ -85,6 +85,7 @@ struct dpdk_config_s {
   cdtime_t interval;
   uint32_t eal_initialized;
   uint32_t enabled_port_mask;
+  char port_name[RTE_MAX_ETHPORTS][DATA_MAX_NAME_LEN];
   uint32_t eal_argc;
   /* Helper info */
   int   collectd_reinit_shm;
@@ -113,7 +114,7 @@ static int dpdk_config(oconfig_item_t *ci);
 static int dpdk_helper_init_eal(void);
 static int dpdk_helper_run(void);
 static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action);
-static int dpdk_init (void);
+static int dpdk_init(void);
 static int dpdk_read(user_data_t *ud);
 static int dpdk_shm_cleanup(void);
 static int dpdk_shm_init(size_t size);
@@ -124,7 +125,8 @@ static void dpdk_config_init_default(void)
     g_configuration->interval = plugin_get_interval();
     WARNING("dpdkstat: No time interval was configured, default value %lu ms is set\n",
              CDTIME_T_TO_MS(g_configuration->interval));
-    g_configuration->enabled_port_mask = 0;
+    /* Default is all ports enabled */
+    g_configuration->enabled_port_mask = ~0;
     g_configuration->eal_argc = 2;
     g_configuration->eal_initialized = 0;
     ssnprintf(g_configuration->coremask, DATA_MAX_NAME_LEN, "%s", "0xf");
@@ -132,11 +134,14 @@ static void dpdk_config_init_default(void)
     ssnprintf(g_configuration->process_type, DATA_MAX_NAME_LEN, "%s", "secondary");
     ssnprintf(g_configuration->file_prefix, DATA_MAX_NAME_LEN, "%s",
              "/var/run/.rte_config");
+
+    for (int i = 0; i < RTE_MAX_ETHPORTS; i++)
+      g_configuration->port_name[i][0] = 0;
 }
 
 static int dpdk_config(oconfig_item_t *ci)
 {
-  int i = 0;
+  int port_counter = 0;
 
   /* Initialize a POSIX SHared Memory (SHM) object. */
   int err = dpdk_shm_init(sizeof(dpdk_config_t));
@@ -148,7 +153,7 @@ static int dpdk_config(oconfig_item_t *ci)
   /* Set defaults for config, overwritten by loop if config item exists */
   dpdk_config_init_default();
 
-  for (i = 0; i < ci->children_num; i++) {
+  for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp("Interval", child->key) == 0) {
@@ -183,11 +188,20 @@ static int dpdk_config(oconfig_item_t *ci)
       if (strcasecmp(g_configuration->file_prefix, "/var/run/.rte_config") != 0) {
         g_configuration->eal_argc+=1;
       }
+    } else if (strcasecmp("EnabledPortMask", child->key) == 0) {
+      g_configuration->enabled_port_mask = (uint32_t)child->values[0].value.number;
+      DEBUG("dpdkstat: Enabled Port Mask %u\n", g_configuration->enabled_port_mask);
+    } else if (strcasecmp("PortName", child->key) == 0) {
+      ssnprintf(g_configuration->port_name[port_counter], DATA_MAX_NAME_LEN, "%s",
+               child->values[0].value.string);
+      DEBUG("dpdkstat: Port %d Name: %s \n", port_counter,
+               g_configuration->port_name[port_counter]);
+      port_counter++;
     } else {
       WARNING ("dpdkstat: The config option \"%s\" is unknown.",
                child->key);
     }
-  } /* End for (i = 0; i < ci->children_num; i++)*/
+  } /* End for (int i = 0; i < ci->children_num; i++)*/
   g_configured = 1; /* Bypass configuration in dpdk_shm_init(). */
 
   return 0;
@@ -304,17 +318,17 @@ static int dpdk_init (void)
 static int dpdk_helper_exit(int reset)
 {
   g_configuration->helper_status = DPDK_HELPER_GRACEFUL_QUIT;
-  if(reset) {
+  if (reset) {
     g_configuration->eal_initialized = 0;
     g_configuration->num_ports = 0;
     memset(&g_configuration->xstats, 0, g_configuration->num_xstats* sizeof(struct rte_eth_xstats));
     g_configuration->num_xstats = 0;
-    for(int i = 0; i < RTE_MAX_ETHPORTS; i++)
+    for (int i = 0; i < RTE_MAX_ETHPORTS; i++)
       g_configuration->num_stats_in_port[i] = 0;
   }
   close(g_configuration->helper_pipes[1]);
   int err = kill(g_configuration->helper_pid, SIGKILL);
-  if(err) {
+  if (err) {
     ERROR("dpdkstat: error sending kill to helper: %s\n", strerror(errno));
   }
 
@@ -329,7 +343,7 @@ static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action)
    * Create a pipe for helper stdout back to collectd. This is necessary for
    * logging EAL failures, as rte_eal_init() calls rte_panic().
    */
-  if(g_configuration->helper_pipes[1]) {
+  if (g_configuration->helper_pipes[1]) {
     DEBUG("dpdkstat: collectd closing helper pipe %d\n",
           g_configuration->helper_pipes[1]);
   } else {
@@ -341,11 +355,16 @@ static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action)
     return -1;
   }
 
-  int pipe0_flags = fcntl(g_configuration->helper_pipes[1], F_GETFL, 0);
-  int pipe1_flags = fcntl(g_configuration->helper_pipes[0], F_GETFL, 0);
-  int p1err = fcntl(g_configuration->helper_pipes[1], F_SETFL, pipe1_flags | O_NONBLOCK);
-  int p2err = fcntl(g_configuration->helper_pipes[0], F_SETFL, pipe0_flags | O_NONBLOCK);
-  if (pipe0_flags == -1 || pipe1_flags == -1 || p1err == -1 || p2err == -1) {
+  int pipe0_flags = fcntl(g_configuration->helper_pipes[0], F_GETFL, 0);
+  int pipe1_flags = fcntl(g_configuration->helper_pipes[1], F_GETFL, 0);
+  if (pipe0_flags == -1 || pipe1_flags == -1) {
+    ERROR("dpdkstat: error setting up pipe flags: %s\n", strerror(errno));
+  }
+  int  pipe0_err = fcntl(g_configuration->helper_pipes[0], F_SETFL, pipe1_flags
+                         | O_NONBLOCK);
+  int  pipe1_err = fcntl(g_configuration->helper_pipes[1], F_SETFL, pipe0_flags
+                         | O_NONBLOCK);
+  if (pipe0_err == -1 || pipe1_err == -1) {
     ERROR("dpdkstat: error setting up pipes: %s\n", strerror(errno));
   }
 
@@ -380,24 +399,24 @@ static int dpdk_helper_init_eal(void)
   int i = 0;
 
   argp[i++] = "collectd-dpdk";
-  if(strcasecmp(g_configuration->coremask, "") != 0) {
+  if (strcasecmp(g_configuration->coremask, "") != 0) {
     argp[i++] = "-c";
     argp[i++] = g_configuration->coremask;
   }
-  if(strcasecmp(g_configuration->memory_channels, "") != 0) {
+  if (strcasecmp(g_configuration->memory_channels, "") != 0) {
     argp[i++] = "-n";
     argp[i++] = g_configuration->memory_channels;
   }
-  if(strcasecmp(g_configuration->socket_memory, "") != 0) {
+  if (strcasecmp(g_configuration->socket_memory, "") != 0) {
     argp[i++] = "--socket-mem";
     argp[i++] = g_configuration->socket_memory;
   }
-  if(strcasecmp(g_configuration->file_prefix, "") != 0 &&
+  if (strcasecmp(g_configuration->file_prefix, "") != 0 &&
      strcasecmp(g_configuration->file_prefix, "/var/run/.rte_config") != 0) {
     argp[i++] = "--file-prefix";
     argp[i++] = g_configuration->file_prefix;
   }
-  if(strcasecmp(g_configuration->process_type, "") != 0) {
+  if (strcasecmp(g_configuration->process_type, "") != 0) {
     argp[i++] = "--proc-type";
     argp[i++] = g_configuration->process_type;
   }
@@ -409,11 +428,11 @@ static int dpdk_helper_init_eal(void)
     g_configuration->eal_initialized = 0;
     printf("dpdkstat: ERROR initializing EAL ret = %d\n", ret);
     printf("dpdkstat: EAL arguments: ");
-    for (i=0; i< g_configuration->eal_argc; i++) {
+    for (i = 0; i < g_configuration->eal_argc; i++) {
       printf("%s ", argp[i]);
     }
     printf("\n");
-    return -1;
+    return ret;
   }
   return 0;
 }
@@ -423,7 +442,7 @@ static int dpdk_helper_run (void)
   pid_t ppid = getppid();
   g_configuration->helper_status = DPDK_HELPER_WAITING_ON_PRIMARY;
 
-   while(1) {
+   while (1) {
     /* sem_timedwait() to avoid blocking forever */
     struct timespec ts;
     cdtime_t now = cdtime();
@@ -431,12 +450,11 @@ static int dpdk_helper_run (void)
     CDTIME_T_TO_TIMESPEC(now + half_sec + g_configuration->interval *2, &ts);
     int ret = sem_timedwait(&g_configuration->sema_helper_get_stats, &ts);
 
-    if(ret == -1 && errno == ETIMEDOUT) {
+    if (ret == -1 && errno == ETIMEDOUT) {
       ERROR("dpdkstat-helper: sem timedwait()"
              " timeout, did collectd terminate?\n");
       dpdk_helper_exit(RESET);
     }
-
     /* Parent PID change means collectd died so quit the helper process. */
     if (ppid != getppid()) {
       WARNING("dpdkstat-helper: parent PID changed, quitting.\n");
@@ -455,11 +473,13 @@ static int dpdk_helper_run (void)
       continue;
     }
 
-    if(!g_configuration->eal_initialized) {
+    if (!g_configuration->eal_initialized) {
       /* Initialize EAL. */
       int ret = dpdk_helper_init_eal();
-      if(ret != 0)
+      if(ret != 0) {
+        WARNING("ERROR INITIALIZING EAL\n");
         dpdk_helper_exit(RESET);
+      }
     }
 
     g_configuration->helper_status = DPDK_HELPER_ALIVE_SENDING_STATS;
@@ -473,12 +493,9 @@ static int dpdk_helper_run (void)
 
     if (nb_ports > RTE_MAX_ETHPORTS)
       nb_ports = RTE_MAX_ETHPORTS;
-    /* If no port mask was specified enable all ports*/
-    if (g_configuration->enabled_port_mask == 0)
-      g_configuration->enabled_port_mask = 0xffff;
 
     int len = 0, enabled_port_count = 0, num_xstats = 0;
-    for (int i = 0; i < nb_ports; i++) {
+    for (uint8_t i = 0; i < nb_ports; i++) {
       if (g_configuration->enabled_port_mask & (1 << i)) {
         if(g_configuration->helper_action == DPDK_HELPER_ACTION_COUNT_STATS) {
           len = rte_eth_xstats_get(i, NULL, 0);
@@ -506,7 +523,7 @@ static int dpdk_helper_run (void)
       } /* if (enabled_port_mask) */
     } /* for (nb_ports) */
 
-    if(g_configuration->helper_action == DPDK_HELPER_ACTION_COUNT_STATS) {
+    if (g_configuration->helper_action == DPDK_HELPER_ACTION_COUNT_STATS) {
       g_configuration->num_ports  = enabled_port_count;
       g_configuration->num_xstats = num_xstats;
       DEBUG("dpdkstat-helper ports: %d, num stats: %d\n",
@@ -532,7 +549,7 @@ static int dpdk_read (user_data_t *ud)
    * Check if SHM flag is set to be re-initialized. AKA DPDK ports have been
    * counted, so re-init SHM to be large enough to fit all the statistics.
    */
-  if(g_configuration->collectd_reinit_shm) {
+  if (g_configuration->collectd_reinit_shm) {
     DEBUG("dpdkstat: read() now reinit SHM then launching send-thread\n");
     dpdk_re_init_shm();
   }
@@ -542,14 +559,14 @@ static int dpdk_read (user_data_t *ud)
    * must be done in dpdk_read(), because the DPDK primary process may not be
    * alive at dpdk_init() time.
    */
-  if(g_configuration->helper_status == DPDK_HELPER_NOT_INITIALIZED ||
+  if (g_configuration->helper_status == DPDK_HELPER_NOT_INITIALIZED ||
      g_configuration->helper_status == DPDK_HELPER_GRACEFUL_QUIT) {
       int action = DPDK_HELPER_ACTION_SEND_STATS;
       if(g_configuration->num_xstats == 0)
         action = DPDK_HELPER_ACTION_COUNT_STATS;
       /* Spawn the helper thread to count stats or to read stats. */
       int err = dpdk_helper_spawn(action);
-      if(err) {
+      if (err) {
         ERROR("dpdkstat: error spawning helper %s\n", strerror(errno));
         return -1;
       }
@@ -562,7 +579,7 @@ static int dpdk_read (user_data_t *ud)
    *  waitpid() fails, helper process died (or quit), so respawn
    */
   int respawn_helper = 0;
-  if(ws != 0) {
+  if (ws != 0) {
     respawn_helper = 1;
   }
 
@@ -574,15 +591,15 @@ static int dpdk_read (user_data_t *ud)
   fds.fd = g_configuration->helper_pipes[0];
   fds.events = POLLIN;
   int data_avail = poll(&fds, 1, 0);
-  while(data_avail) {
+  while (data_avail) {
     int nbytes = read(g_configuration->helper_pipes[0], buf, sizeof(buf));
-    if(nbytes <= 0)
+    if (nbytes <= 0)
       break;
     ssnprintf( out, nbytes, "%s", buf);
     DEBUG("dpdkstat: helper-proc: %s\n", out);
   }
 
-  if(respawn_helper) {
+  if (respawn_helper) {
     if (g_configuration->helper_pid)
       dpdk_helper_exit(RESET);
     dpdk_helper_spawn(DPDK_HELPER_ACTION_COUNT_STATS);
@@ -597,26 +614,34 @@ static int dpdk_read (user_data_t *ud)
   cdtime_t now = cdtime();
   CDTIME_T_TO_TIMESPEC(now + g_configuration->interval, &ts);
   ret = sem_timedwait(&g_configuration->sema_stats_in_shm, &ts);
-  if(ret == -1 && errno == ETIMEDOUT) {
+  if (ret == -1 && errno == ETIMEDOUT) {
     DEBUG("dpdkstat: timeout in collectd thread: is a DPDK Primary running? \n");
     return 0;
   }
 
   /* Dispatch the stats.*/
-  int count = 0;
+  int count = 0, port_num = 0;
 
-  for (int i = 0; i < g_configuration->num_ports; i++) {
+  for (uint32_t i = 0; i < g_configuration->num_ports; i++) {
     cdtime_t time = g_configuration->port_read_time[i];
     char dev_name[64];
     int len = g_configuration->num_stats_in_port[i];
-    ssnprintf(dev_name, sizeof(dev_name), "port.%d", i);
+
+    while(!(g_configuration->enabled_port_mask & (1 << port_num)))
+      port_num++;
+
+    if (g_configuration->port_name[i][0] != 0)
+      ssnprintf(dev_name, sizeof(dev_name), "%s", g_configuration->port_name[i]);
+    else
+      ssnprintf(dev_name, sizeof(dev_name), "port.%d", port_num);
     struct rte_eth_xstats *xstats = (&g_configuration->xstats);
     xstats += count; /* pointer arithmetic to jump to each stats struct */
     for (int j = 0; j < len; j++) {
       value_t dpdkstat_values[1];
       value_list_t dpdkstat_vl = VALUE_LIST_INIT;
+      char *type_end;
 
-      dpdkstat_values[0].counter = xstats[j].value;
+      dpdkstat_values[0].derive = (derive_t) xstats[j].value;
       dpdkstat_vl.values = dpdkstat_values;
       dpdkstat_vl.values_len = 1; /* Submit stats one at a time */
       dpdkstat_vl.time = time;
@@ -624,13 +649,86 @@ static int dpdk_read (user_data_t *ud)
       sstrncpy (dpdkstat_vl.plugin, "dpdkstat", sizeof (dpdkstat_vl.plugin));
       sstrncpy (dpdkstat_vl.plugin_instance, dev_name,
                 sizeof (dpdkstat_vl.plugin_instance));
-      sstrncpy (dpdkstat_vl.type, "counter",
-                sizeof (dpdkstat_vl.type));
+
+      type_end = strrchr(xstats[j].name, '_');
+
+      if ((type_end != NULL) &&
+                (strncmp(xstats[j].name, "rx_", strlen("rx_")) == 0)) {
+        if (strncmp(type_end, "_errors", strlen("_errors")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "if_rx_errors",
+                  sizeof(dpdkstat_vl.type));
+        } else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "if_rx_dropped",
+                  sizeof(dpdkstat_vl.type));
+        } else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "if_rx_octets",
+                  sizeof(dpdkstat_vl.type));
+        } else if (strncmp(type_end, "_packets", strlen("_packets")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "if_rx_packets",
+                  sizeof(dpdkstat_vl.type));
+        } else if (strncmp(type_end, "_placement", strlen("_placement")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "if_rx_errors",
+                  sizeof(dpdkstat_vl.type));
+        } else if (strncmp(type_end, "_buff", strlen("_buff")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "if_rx_errors",
+                  sizeof(dpdkstat_vl.type));
+        } else {
+          /* Does not fit obvious type: use a more generic one */
+          sstrncpy (dpdkstat_vl.type, "derive",
+                  sizeof(dpdkstat_vl.type));
+        }
+
+      } else if ((type_end != NULL) &&
+                (strncmp(xstats[j].name, "tx_", strlen("tx_"))) == 0) {
+        if (strncmp(type_end, "_errors", strlen("_errors")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "if_tx_errors",
+                  sizeof(dpdkstat_vl.type));
+        } else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "if_tx_dropped",
+                  sizeof(dpdkstat_vl.type));
+        } else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "if_tx_octets",
+                  sizeof(dpdkstat_vl.type));
+        } else if (strncmp(type_end, "_packets", strlen("_packets")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "if_tx_packets",
+                  sizeof(dpdkstat_vl.type));
+        } else {
+          /* Does not fit obvious type: use a more generic one */
+          sstrncpy (dpdkstat_vl.type, "derive",
+                  sizeof(dpdkstat_vl.type));
+        }
+      } else if ((type_end != NULL) &&
+                (strncmp(xstats[j].name, "flow_", strlen("flow_"))) == 0) {
+
+        if (strncmp(type_end, "_filters", strlen("_filters")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "operations",
+                  sizeof(dpdkstat_vl.type));
+        } else if (strncmp(type_end, "_errors", strlen("_errors")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "errors",
+                  sizeof(dpdkstat_vl.type));
+        } else if (strncmp(type_end, "_filters", strlen("_filters")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "filter_result",
+                  sizeof(dpdkstat_vl.type));
+        }
+      } else if ((type_end != NULL) &&
+                (strncmp(xstats[j].name, "mac_", strlen("mac_"))) == 0) {
+        if (strncmp(type_end, "_errors", strlen("_errors")) == 0) {
+          sstrncpy (dpdkstat_vl.type, "errors",
+                  sizeof(dpdkstat_vl.type));
+        }
+      } else {
+        /* Does not fit obvious type, or strrchr error:
+         *   use a more generic type */
+        sstrncpy (dpdkstat_vl.type, "derive",
+                sizeof(dpdkstat_vl.type));
+      }
+
       sstrncpy (dpdkstat_vl.type_instance, xstats[j].name,
                 sizeof (dpdkstat_vl.type_instance));
       plugin_dispatch_values (&dpdkstat_vl);
     }
     count += len;
+    port_num++;
   } /* for each port */
   return 0;
 }
@@ -639,12 +737,12 @@ static int dpdk_shm_cleanup(void)
 {
   int ret = munmap(g_configuration, sizeof(dpdk_config_t));
   g_configuration = 0;
-  if(ret) {
+  if (ret) {
     WARNING("dpdkstat: munmap returned %d\n", ret);
     return ret;
   }
   ret = shm_unlink(DPDK_SHM_NAME);
-  if(ret) {
+  if (ret) {
     WARNING("dpdkstat: shm_unlink returned %d\n", ret);
     return ret;
   }