From 68da278bed1f56b7a887cd4f66949a805fdbe08a Mon Sep 17 00:00:00 2001 From: Ken Chiang Date: Mon, 19 Dec 2016 11:23:56 -0800 Subject: [PATCH] Add CpuAllPercentUtilization and CpuAllPercentIdle. --- packages/base/any/onlp-snmpd/APKG.yml | 1 + .../base/any/onlp-snmpd/bin/onl-snmp-mpstat | 33 ++++++ packages/base/any/onlp-snmpd/builds/Makefile | 2 +- .../onlp_snmp/module/src/onlp_snmp_platform.c | 110 +++++++++++++++++- 4 files changed, 144 insertions(+), 2 deletions(-) create mode 100755 packages/base/any/onlp-snmpd/bin/onl-snmp-mpstat diff --git a/packages/base/any/onlp-snmpd/APKG.yml b/packages/base/any/onlp-snmpd/APKG.yml index 76214600..bb37f217 100644 --- a/packages/base/any/onlp-snmpd/APKG.yml +++ b/packages/base/any/onlp-snmpd/APKG.yml @@ -16,6 +16,7 @@ packages: files: builds/$BUILD_DIR/${TOOLCHAIN}/bin/onlp-snmpd: /usr/bin/onlp-snmpd ${ONL}/packages/base/any/onlp-snmpd/bin/onl-snmpwalk : /usr/bin/onl-snmpwalk + ${ONL}/packages/base/any/onlp-snmpd/bin/onl-snmp-mpstat : /usr/bin/onl-snmp-mpstat init: ${ONL}/packages/base/any/onlp-snmpd/onlp-snmpd.init diff --git a/packages/base/any/onlp-snmpd/bin/onl-snmp-mpstat b/packages/base/any/onlp-snmpd/bin/onl-snmp-mpstat new file mode 100755 index 00000000..4b41d1b8 --- /dev/null +++ b/packages/base/any/onlp-snmpd/bin/onl-snmp-mpstat @@ -0,0 +1,33 @@ +#!/usr/bin/python + +# call mpstat and generate json output containing stats for all cpus + +""" +sample output from "mpstat 1 1": +# mpstat 1 1 +Linux 3.8.13-OpenNetworkLinux-e500mc-1.5 (as6700-3) 2016-12-15 _ppc_(4 CPU) + +04:59:31 PM CPU %usr %nice %sys %iowait %irq %soft %steal %guest %idle +04:59:32 PM all 5.17 0.00 2.07 0.00 0.00 0.00 0.00 0.00 92.76 +Average: all 5.17 0.00 2.07 0.00 0.00 0.00 0.00 0.00 92.76 +""" + +import subprocess +import json + +stats = {} + +# 1 second interval, 1 count +out = subprocess.check_output(['mpstat','1','1']) + +for line in out.split('\n'): + if "%idle" in line: + # extract keys from header line, skipping over time and AM/PM + keys = line.split()[2:] + + if "Average" in line: + vals = line.split()[1:] + stats[vals[0]] = { k:int(round(float(v))) \ + for (k,v) in zip(keys[1:],vals[1:]) } + +print json.dumps(stats) diff --git a/packages/base/any/onlp-snmpd/builds/Makefile b/packages/base/any/onlp-snmpd/builds/Makefile index f423035f..c57a98a8 100644 --- a/packages/base/any/onlp-snmpd/builds/Makefile +++ b/packages/base/any/onlp-snmpd/builds/Makefile @@ -3,7 +3,7 @@ include $(ONL)/make/any.mk MODULE := onlp-snmpd include $(BUILDER)/standardinit.mk -DEPENDMODULES := onlp_snmp AIM OS snmp_subagent IOF onlplib +DEPENDMODULES := onlp_snmp AIM OS snmp_subagent IOF onlplib OS cjson cjson_util DEPENDMODULE_HEADERS := onlp include $(BUILDER)/dependmodules.mk diff --git a/packages/base/any/onlp-snmpd/builds/src/onlp_snmp/module/src/onlp_snmp_platform.c b/packages/base/any/onlp-snmpd/builds/src/onlp_snmp/module/src/onlp_snmp_platform.c index 1a6b3e55..f0e83ab6 100644 --- a/packages/base/any/onlp-snmpd/builds/src/onlp_snmp/module/src/onlp_snmp_platform.c +++ b/packages/base/any/onlp-snmpd/builds/src/onlp_snmp/module/src/onlp_snmp_platform.c @@ -25,6 +25,9 @@ #include #include "onlp_snmp_log.h" +#include +#include +#include #include #include #include @@ -54,7 +57,7 @@ platform_string_register(int index, const char* desc, char* value) netsnmp_register_watched_scalar( reg, winfo ); } -void +static void platform_int_register(int index, char* desc, int value) { oid tree[] = { 1, 3, 6, 1, 4, 1, 42623, 1, 1, 1, 1, 1}; @@ -69,6 +72,108 @@ platform_int_register(int index, char* desc, int value) v, NULL); } +static void +resource_int_register(int index, const char* desc, + Netsnmp_Node_Handler *handler) +{ + oid tree[] = { 1, 3, 6, 1, 4, 1, 42623, 1, 3, 1, 1 }; + tree[10] = index; + + netsnmp_handler_registration *reg = + netsnmp_create_handler_registration(desc, handler, + tree, OID_LENGTH(tree), + HANDLER_CAN_RONLY); + if (netsnmp_register_scalar(reg) != MIB_REGISTERED_OK) { + AIM_LOG_ERROR("registering handler for %s failed", desc); + } +} + + +/* resource objects refreshed with this period; units in seconds */ +#define RESOURCE_UPDATE_PERIOD 5 + +/* resource objects */ +typedef struct { + uint32_t utilization_percent; + uint32_t idle_percent; +} resources_t; + +static resources_t resources; +static uint64_t resource_update_time; + +void resource_update(void) +{ + uint64_t now = os_time_monotonic(); + if (now - resource_update_time > RESOURCE_UPDATE_PERIOD * 1000 * 1000) { + resource_update_time = now; + AIM_LOG_INFO("update resource objects"); + + /* invoke mpstat collection script for json output */ + FILE *fp = popen("/usr/bin/onl-snmp-mpstat", "r"); + if (fp == NULL) { + AIM_LOG_ERROR("failed invoking onl-snmp-mpstat"); + return; + } + + /* parse json output */ + char line[1024]; + while (fgets(line, sizeof(line), fp) != NULL) { + cJSON *root = cJSON_Parse(line); + int result; + int rv = cjson_util_lookup_int(root, &result, "all.%%idle"); + if (rv == 0) { + /* save it */ + resources.idle_percent = result; + resources.utilization_percent = 100 - result; + } + cJSON_Delete(root); + } + } +} + +static int +utilization_handler(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + if (MODE_GET == reqinfo->mode) { + resource_update(); + snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, + (u_char *) &resources.utilization_percent, + sizeof(resources.utilization_percent)); + } else { + netsnmp_assert("bad mode in RO handler"); + } + + if (handler->next && handler->next->access_method) { + return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); + } + + return SNMP_ERR_NOERROR; +} + +static int +idle_handler(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + if (MODE_GET == reqinfo->mode) { + resource_update(); + snmp_set_var_typed_value(requests->requestvb, ASN_GAUGE, + (u_char *) &resources.idle_percent, + sizeof(resources.idle_percent)); + } else { + netsnmp_assert("bad mode in RO handler"); + } + + if (handler->next && handler->next->access_method) { + return netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); + } + + return SNMP_ERR_NOERROR; +} void onlp_snmp_platform_init(void) @@ -110,5 +215,8 @@ onlp_snmp_platform_init(void) REGISTER_STR(14, service_tag); REGISTER_STR(15, onie_version); } + + resource_int_register(1, "CpuAllPercentUtilization", utilization_handler); + resource_int_register(2, "CpuAllPercentIdle", idle_handler); }