Merge branch 'collectd-5.8'
[collectd.git] / src / ovs_stats.c
index 31af77c..f513e72 100644 (file)
@@ -3,14 +3,17 @@
  *
  * Copyright(c) 2016 Intel Corporation. All rights reserved.
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of
  * this software and associated documentation files (the "Software"), to deal in
  * the Software without restriction, including without limitation the rights to
  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
+ * of the Software, and to permit persons to whom the Software is furnished to
+ * do
  * so, subject to the following conditions:
  *
- * The above copyright notice and this permission notice shall be included in all
+ * The above copyright notice and this permission notice shall be included in
+ * all
  * copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
@@ -241,6 +244,9 @@ static port_list_t *ovs_stats_get_port_by_name(const char *name) {
 /* Create or get port by port uuid */
 static port_list_t *ovs_stats_new_port(bridge_list_t *bridge,
                                        const char *uuid) {
+  if (uuid == NULL)
+    return NULL;
+
   port_list_t *port = ovs_stats_get_port(uuid);
 
   if (port == NULL) {
@@ -327,9 +333,10 @@ static int ovs_stats_update_bridge(yajl_val bridge) {
         br = ovs_stats_get_bridge(g_bridge_list_head, YAJL_GET_STRING(br_name));
         pthread_mutex_lock(&g_stats_lock);
         if (br == NULL) {
-          br = (bridge_list_t *)calloc(1, sizeof(bridge_list_t));
+          br = calloc(1, sizeof(*br));
           if (!br) {
-            ERROR("%s: Error allocating memory for bridge", plugin_name);
+            pthread_mutex_unlock(&g_stats_lock);
+            ERROR("%s: calloc(%zu) failed.", plugin_name, sizeof(*br));
             return -1;
           }
           char *tmp = YAJL_GET_STRING(br_name);
@@ -339,6 +346,7 @@ static int ovs_stats_update_bridge(yajl_val bridge) {
           if (br->name == NULL) {
             sfree(br);
             pthread_mutex_unlock(&g_stats_lock);
+            ERROR("%s: strdup failed.", plugin_name);
             return -1;
           }
           br->next = g_bridge_list_head;
@@ -352,21 +360,33 @@ static int ovs_stats_update_bridge(yajl_val bridge) {
           yajl_val *array = YAJL_GET_ARRAY(br_ports)->values;
           size_t array_len = YAJL_GET_ARRAY(br_ports)->len;
           if (array != NULL && array_len > 0 && YAJL_IS_ARRAY(array[1])) {
-            yajl_val *ports_arr = YAJL_GET_ARRAY(array[1])->values;
-            size_t ports_num = YAJL_GET_ARRAY(array[1])->len;
-            for (size_t i = 0; i < ports_num && ports_arr != NULL; i++)
-              ovs_stats_new_port(
-                  br, YAJL_GET_STRING(ports_arr[i]->u.array.values[1]));
+            if (YAJL_GET_ARRAY(array[1]) == NULL)
+              goto failure;
+            else {
+              yajl_val *ports_arr = YAJL_GET_ARRAY(array[1])->values;
+              size_t ports_num = YAJL_GET_ARRAY(array[1])->len;
+              for (size_t i = 0; i < ports_num && ports_arr != NULL; i++) {
+                tmp = YAJL_GET_STRING(ports_arr[i]->u.array.values[1]);
+                if (tmp != NULL)
+                  ovs_stats_new_port(br, tmp);
+                else
+                  goto failure;
+              }
+            }
           }
         } else
           ovs_stats_new_port(br, YAJL_GET_STRING(br_ports->u.array.values[1]));
       }
     }
   } else {
-    ERROR("Incorrect JSON Bridge data");
-    return -1;
+    goto failure;
   }
+
   return 0;
+
+failure:
+  ERROR("Incorrect JSON Bridge data");
+  return -1;
 }
 
 /* Handle JSON with Bridge Table change event */
@@ -578,56 +598,62 @@ static int ovs_stats_update_iface_ext_ids(port_list_t *port, yajl_val ext_ids) {
 
 /* Get interface statistic and external_ids */
 static int ovs_stats_update_iface(yajl_val iface) {
-  yajl_val row;
-  port_list_t *port = NULL;
-  if (iface && YAJL_IS_OBJECT(iface)) {
-    row = ovs_utils_get_value_by_key(iface, "new");
-    if (row && YAJL_IS_OBJECT(row)) {
-      yajl_val iface_name = ovs_utils_get_value_by_key(row, "name");
-      yajl_val iface_stats = ovs_utils_get_value_by_key(row, "statistics");
-      yajl_val iface_ext_ids = ovs_utils_get_value_by_key(row, "external_ids");
-      yajl_val iface_uuid = ovs_utils_get_value_by_key(row, "_uuid");
-      if (iface_name && YAJL_IS_STRING(iface_name)) {
-        port = ovs_stats_get_port_by_name(YAJL_GET_STRING(iface_name));
-        if (port == NULL)
-          return 0;
-      }
-      /*
-       * {
-            "statistics": [
-              "map",
-              [
-                [
-                  "collisions",
-                  0
-                ],
-                . . .
-                [
-                  "tx_packets",
-                  0
-                ]
-              ]
+  if (!iface || !YAJL_IS_OBJECT(iface)) {
+    ERROR("ovs_stats plugin: incorrect JSON port data");
+    return -1;
+  }
+
+  yajl_val row = ovs_utils_get_value_by_key(iface, "new");
+  if (!row || !YAJL_IS_OBJECT(row))
+    return 0;
+
+  yajl_val iface_name = ovs_utils_get_value_by_key(row, "name");
+  if (!iface_name || !YAJL_IS_STRING(iface_name))
+    return 0;
+
+  port_list_t *port = ovs_stats_get_port_by_name(YAJL_GET_STRING(iface_name));
+  if (port == NULL)
+    return 0;
+
+  yajl_val iface_stats = ovs_utils_get_value_by_key(row, "statistics");
+  yajl_val iface_ext_ids = ovs_utils_get_value_by_key(row, "external_ids");
+  yajl_val iface_uuid = ovs_utils_get_value_by_key(row, "_uuid");
+  /*
+   * {
+        "statistics": [
+          "map",
+          [
+            [
+              "collisions",
+              0
+            ],
+            . . .
+            [
+              "tx_packets",
+              0
             ]
-          }
-       Check that statistics is an array with 2 elements
-       */
-      if (iface_stats && YAJL_IS_ARRAY(iface_stats) &&
-          YAJL_GET_ARRAY(iface_stats)->len == 2)
-        ovs_stats_update_iface_stats(port,
-                                     YAJL_GET_ARRAY(iface_stats)->values[1]);
-      if (iface_ext_ids && YAJL_IS_ARRAY(iface_ext_ids))
-        ovs_stats_update_iface_ext_ids(
-            port, YAJL_GET_ARRAY(iface_ext_ids)->values[1]);
-      if (iface_uuid && YAJL_IS_ARRAY(iface_uuid) &&
-          YAJL_GET_ARRAY(iface_uuid)->len == 2)
-        sstrncpy(port->iface_uuid,
-                 YAJL_GET_STRING(YAJL_GET_ARRAY(iface_uuid)->values[1]),
-                 sizeof(port->iface_uuid));
-    }
-  } else {
-    ERROR("Incorrect JSON Port data");
+          ]
+        ]
+      }
+   Check that statistics is an array with 2 elements
+   */
+  if (iface_stats && YAJL_IS_ARRAY(iface_stats) &&
+      YAJL_GET_ARRAY(iface_stats)->len == 2)
+    ovs_stats_update_iface_stats(port, YAJL_GET_ARRAY(iface_stats)->values[1]);
+  if (iface_ext_ids && YAJL_IS_ARRAY(iface_ext_ids))
+    ovs_stats_update_iface_ext_ids(port,
+                                   YAJL_GET_ARRAY(iface_ext_ids)->values[1]);
+  if (iface_uuid && YAJL_IS_ARRAY(iface_uuid) &&
+      YAJL_GET_ARRAY(iface_uuid)->len == 2 &&
+      YAJL_GET_STRING(YAJL_GET_ARRAY(iface_uuid)->values[1]) != NULL)
+    sstrncpy(port->iface_uuid,
+             YAJL_GET_STRING(YAJL_GET_ARRAY(iface_uuid)->values[1]),
+             sizeof(port->iface_uuid));
+  else {
+    ERROR("ovs_stats plugin: incorrect JSON interface data");
     return -1;
   }
+
   return 0;
 }
 
@@ -711,33 +737,30 @@ static void ovs_stats_initialize(ovs_db_t *pdb) {
                                      "external_ids", NULL};
 
   /* subscribe to a tables */
-  ovs_db_table_cb_register(pdb, "Bridge", bridge_columns,
-                           ovs_stats_bridge_table_change_cb,
+  ovs_db_table_cb_register(
+      pdb, "Bridge", bridge_columns, ovs_stats_bridge_table_change_cb,
       ovs_stats_bridge_table_result_cb,
-                           OVS_DB_TABLE_CB_FLAG_INITIAL |
-                           OVS_DB_TABLE_CB_FLAG_INSERT |
+      OVS_DB_TABLE_CB_FLAG_INITIAL | OVS_DB_TABLE_CB_FLAG_INSERT |
           OVS_DB_TABLE_CB_FLAG_MODIFY);
 
   ovs_db_table_cb_register(pdb, "Bridge", bridge_columns,
                            ovs_stats_bridge_table_delete_cb, NULL,
                            OVS_DB_TABLE_CB_FLAG_DELETE);
 
-  ovs_db_table_cb_register(pdb, "Port", port_columns,
-                           ovs_stats_port_table_change_cb,
+  ovs_db_table_cb_register(
+      pdb, "Port", port_columns, ovs_stats_port_table_change_cb,
       ovs_stats_port_table_result_cb,
-                           OVS_DB_TABLE_CB_FLAG_INITIAL |
-                           OVS_DB_TABLE_CB_FLAG_INSERT |
+      OVS_DB_TABLE_CB_FLAG_INITIAL | OVS_DB_TABLE_CB_FLAG_INSERT |
           OVS_DB_TABLE_CB_FLAG_MODIFY);
 
   ovs_db_table_cb_register(pdb, "Port", port_columns,
                            ovs_stats_port_table_delete_cb, NULL,
                            OVS_DB_TABLE_CB_FLAG_DELETE);
 
-  ovs_db_table_cb_register(pdb, "Interface", interface_columns,
-                           ovs_stats_interface_table_change_cb,
+  ovs_db_table_cb_register(
+      pdb, "Interface", interface_columns, ovs_stats_interface_table_change_cb,
       ovs_stats_interface_table_result_cb,
-                           OVS_DB_TABLE_CB_FLAG_INITIAL |
-                           OVS_DB_TABLE_CB_FLAG_INSERT |
+      OVS_DB_TABLE_CB_FLAG_INITIAL | OVS_DB_TABLE_CB_FLAG_INSERT |
           OVS_DB_TABLE_CB_FLAG_MODIFY);
 }
 
@@ -789,7 +812,6 @@ static void ovs_stats_conn_terminate() {
  */
 static int ovs_stats_plugin_config(oconfig_item_t *ci) {
   bridge_list_t *bridge;
-  char *br_name;
 
   for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *child = ci->children + i;
@@ -821,19 +843,23 @@ static int ovs_stats_plugin_config(oconfig_item_t *ci) {
           goto cleanup_fail;
         }
         /* get value */
-        if ((br_name = strdup(child->values[j].value.string)) == NULL) {
-          ERROR("%s: strdup() copy bridge name fail", plugin_name);
-          goto cleanup_fail;
-        }
+        char const *br_name = child->values[j].value.string;
         if ((bridge = ovs_stats_get_bridge(g_monitored_bridge_list_head,
                                            br_name)) == NULL) {
           if ((bridge = calloc(1, sizeof(bridge_list_t))) == NULL) {
             ERROR("%s: Error allocating memory for bridge", plugin_name);
             goto cleanup_fail;
           } else {
+            char *br_name_dup = strdup(br_name);
+            if (br_name_dup == NULL) {
+              ERROR("%s: strdup() copy bridge name fail", plugin_name);
+              sfree(bridge);
+              goto cleanup_fail;
+            }
+
             pthread_mutex_lock(&g_stats_lock);
             /* store bridge name */
-            bridge->name = br_name;
+            bridge->name = br_name_dup;
             bridge->next = g_monitored_bridge_list_head;
             g_monitored_bridge_list_head = bridge;
             pthread_mutex_unlock(&g_stats_lock);
@@ -862,8 +888,8 @@ static int ovs_stats_plugin_init(void) {
        plugin_name, ovs_stats_cfg.ovs_db_node, ovs_stats_cfg.ovs_db_serv,
        ovs_stats_cfg.ovs_db_unix);
   /* connect to OvS DB */
-  if ((g_ovs_db = ovs_db_init (ovs_stats_cfg.ovs_db_node,
-                             ovs_stats_cfg.ovs_db_serv,
+  if ((g_ovs_db =
+           ovs_db_init(ovs_stats_cfg.ovs_db_node, ovs_stats_cfg.ovs_db_serv,
                        ovs_stats_cfg.ovs_db_unix, &cb)) == NULL) {
     ERROR("%s: plugin: failed to connect to OvS DB server", plugin_name);
     return -1;
@@ -969,9 +995,9 @@ static int ovs_stats_plugin_read(__attribute__((unused)) user_data_t *ud) {
 
 /* Shutdown OvS Stats plugin */
 static int ovs_stats_plugin_shutdown(void) {
-  pthread_mutex_lock(&g_stats_lock);
   DEBUG("OvS Statistics plugin shutting down");
   ovs_db_destroy(g_ovs_db);
+  pthread_mutex_lock(&g_stats_lock);
   ovs_stats_free_bridge_list(g_bridge_list_head);
   ovs_stats_free_bridge_list(g_monitored_bridge_list_head);
   ovs_stats_free_port_list(g_port_list_head);