From b814d3e00185ea46b83ffd51b97ab1e312d7eef6 Mon Sep 17 00:00:00 2001
From: Adam Wujek <adam.wujek@cern.ch>
Date: Wed, 1 Apr 2015 14:24:41 +0200
Subject: [PATCH] userspace/snmpd: add boot count objects to wrsBootStatusGroup

objects added:
--wrsBootCnt (read from /proc/wrs-bootcount)
--wrsRebootCnt (read from /proc/wrs-bootcount)
--wrsRestartReason (read from CPU's register)
--wrsFaultIP (not implemented in kernel)
--wrsFaultLR (not implemented in kernel)

Signed-off-by: Adam Wujek <adam.wujek@cern.ch>
---
 userspace/snmpd/WR-SWITCH-MIB.txt    | 75 ++++++++++++++++++++------
 userspace/snmpd/wrsBootStatusGroup.c | 81 ++++++++++++++++++++++++++++
 userspace/snmpd/wrsBootStatusGroup.h |  2 +
 3 files changed, 143 insertions(+), 15 deletions(-)

diff --git a/userspace/snmpd/WR-SWITCH-MIB.txt b/userspace/snmpd/WR-SWITCH-MIB.txt
index 90847c20c..782114e85 100644
--- a/userspace/snmpd/WR-SWITCH-MIB.txt
+++ b/userspace/snmpd/WR-SWITCH-MIB.txt
@@ -206,21 +206,66 @@ wrsDateTAIString   OBJECT-TYPE
 --wrsBootStatusGroup (.7.1.2)
 wrsBootStatusGroup      OBJECT IDENTIFIER ::= { wrsOperationStatus 2 }
 
---wrsBootCnt      OBJECT-TYPE
---    SYNTAX      Counter32
---    MAX-ACCESS  read-only
---    STATUS      current
---    DESCRIPTION
---        "Number of switch's boots"
---    ::= { wrsBootStatusGroup 1 }
-
---wrsRestartReason  OBJECT-TYPE
---    SYNTAX        Integer32
---    MAX-ACCESS    read-only
---    STATUS        current
---    DESCRIPTION
---        "Reason of last switch restart"
---    ::= { wrsBootStatusGroup 3 }
+wrsBootCnt      OBJECT-TYPE
+    SYNTAX      Counter32
+    MAX-ACCESS  read-only
+    STATUS      current
+    DESCRIPTION
+        "Number of switch's boots since power-on"
+    ::= { wrsBootStatusGroup 1 }
+
+wrsRebootCnt     OBJECT-TYPE
+    SYNTAX       Counter32
+    MAX-ACCESS   read-only
+    STATUS       current
+    DESCRIPTION
+        "The number of soft reboots. This is incremented by the
+        reboot system call. A healthy system should feature one
+        soft-reboot less than total boots."
+    ::= { wrsBootStatusGroup 2 }
+
+wrsRestartReason  OBJECT-TYPE
+    SYNTAX       INTEGER {
+                        na(0),
+                        error(1),
+                        generalReset(2),
+                        wakeUpReset(3),
+                        watchdogReset(4),
+                        softwareReset(5),
+                        userReset(6)
+    }
+    MAX-ACCESS    read-only
+    STATUS        current
+    DESCRIPTION
+      "Reason of last switch restart.
+       error(1) - unable to read restart reason or reset counters
+       generalReset(2) -  Both VDDCORE and VDDBU rising (power-on)
+       wakeUpReset(3) - VDDCORE rising
+       watchdogReset(4) - Watchdog fault occurred
+       softwareReset(5) - Processor reset required by the software (system reboot)
+       userReset(6) -  NRST pin detected low (reset button)"
+    ::= { wrsBootStatusGroup 3 }
+
+wrsFaultIP OBJECT-TYPE
+    SYNTAX         OCTET STRING (SIZE(4))
+    MAX-ACCESS     read-only
+    STATUS         current
+    DESCRIPTION
+        "The fault address of the last panic. This is the instruction
+        pointer normally printed by the stack backtrace. The register
+        is zeroed at first boot and only modified within panic."
+    ::= { wrsBootStatusGroup 4 }
+
+wrsFaultLR OBJECT-TYPE
+    SYNTAX         OCTET STRING (SIZE(4))
+    MAX-ACCESS     read-only
+    STATUS         current
+    DESCRIPTION
+        "The link register register at last panic.
+        This is usually the caller of the function that failed,
+        but it may be a local register if the failing function
+        saved lr to the stack and used it as a scratch register."
+    ::= { wrsBootStatusGroup 5 }
 
 wrsConfigSource  OBJECT-TYPE
     SYNTAX       INTEGER {
diff --git a/userspace/snmpd/wrsBootStatusGroup.c b/userspace/snmpd/wrsBootStatusGroup.c
index 01f343249..2442a9a32 100644
--- a/userspace/snmpd/wrsBootStatusGroup.c
+++ b/userspace/snmpd/wrsBootStatusGroup.c
@@ -1,6 +1,9 @@
 #include "wrsSnmp.h"
+#include "snmp_mmap.h"
 #include "wrsBootStatusGroup.h"
 
+#define BOOTCOUNT_FILE "/proc/wrs-bootcount"
+
 #define DOTCONFIGDIR "/tmp"
 #define DOTCONFIG_PROTO "dot-config_proto"
 #define DOTCONFIG_HOST "dot-config_host"
@@ -10,6 +13,10 @@
  * without new line. Macro expands to something like: "%10[^\n]" */
 #define LINE_READ_LEN_HELPER(x) "%"#x"[^\n]"
 #define LINE_READ_LEN(x) LINE_READ_LEN_HELPER(x)
+#define ARM_RCSR_ADDR 0xFFFFFD04 /* address of CPU's Reset Controller Status
+				  * Register */
+#define ARM_RCSR_RESET_TYPE_MASK 0x00000700 /* reset type mast in CPU's Reset
+					     * Controller Status Register */
 
 static struct pickinfo wrsBootStatus_pickinfo[] = {
 	FIELD(wrsBootStatus_s, ASN_COUNTER, wrsBootCnt),
@@ -24,10 +31,82 @@ static struct pickinfo wrsBootStatus_pickinfo[] = {
 
 struct wrsBootStatus_s wrsBootStatus_s;
 
+struct wrs_bc_item {
+	char *key;
+	uint32_t value;
+};
+
+/* items to be read from BOOTCOUNT_FILE */
+static struct wrs_bc_item boot_info[] = {
+	[0] = {.key = "boot_count:"},
+	[1] = {"reboot_count:"},
+	[2] = {"fault_ip:"},
+	[3] = {"fault_lr:"},
+};
+
+static void get_boot_info(void){
+	static int run_once = 0;
+	FILE *f;
+	char s[80], key[40];
+	uint32_t value;
+	int i;
+	uint32_t *rcsr_map;
+	if (run_once) {
+		/* boot info change only at restart */
+		return;
+	}
+	run_once = 1;
+
+	/* get restart reason */
+	rcsr_map = create_map(ARM_RCSR_ADDR, sizeof(uint32_t));
+	if (!rcsr_map) {
+		snmp_log(LOG_ERR, "SNMP: wrsBootStatusGroup unable to map "
+			 "CPU's Reset Controller Status Register\n");
+		/* pass error to SNMP, assign 1 */
+		wrsBootStatus_s.wrsRestartReason = WRS_RESTART_REASON_ERROR;
+	} else {
+		/* reset reason values are from 0 to 4, SNMP enum is from
+		 * 2 to 6, so "+ 2", 1 is reserved for error */
+		wrsBootStatus_s.wrsRestartReason = 2 +
+				((*rcsr_map & ARM_RCSR_RESET_TYPE_MASK) >> 8);
+	}
+
+	f = fopen(BOOTCOUNT_FILE, "r");
+	if (!f) {
+		snmp_log(LOG_ERR, "SNMP: wrsBootStatusGroup filed to open "
+			 BOOTCOUNT_FILE"\n");
+		/* notify snmp about error in restart reason */
+		wrsBootStatus_s.wrsRestartReason = WRS_RESTART_REASON_ERROR;
+		return;
+	}
+
+	while (fgets(s, sizeof(s), f)) {
+		if (sscanf(s, "%s %i", key, &value) != 2)
+			continue; /* error... */
+		for (i = 0; i < ARRAY_SIZE(boot_info); i++) {
+			if (strncmp(key, boot_info[i].key, 40))
+				continue;
+			boot_info[i].value = value;
+		}
+	}
+	fclose(f);
+
+	wrsBootStatus_s.wrsBootCnt = boot_info[0].value;
+	wrsBootStatus_s.wrsRebootCnt = boot_info[1].value;
+
+	snprintf(wrsBootStatus_s.wrsFaultIP,
+		 sizeof(wrsBootStatus_s.wrsFaultIP), "0x%.8x",
+		 boot_info[2].value);
+	snprintf(wrsBootStatus_s.wrsFaultLR,
+		 sizeof(wrsBootStatus_s.wrsFaultLR), "0x%.8x",
+		 boot_info[3].value);
+}
+
 static void get_dotconfig_source(void)
 {
 	char buff[10];
 	FILE *f;
+
 	/* Check dotconfig source.
 	 * dotconfig source can change in runtime, i.e. from remote to local by
 	 * web-interface */
@@ -97,6 +176,8 @@ time_t wrsBootStatus_data_fill(void)
 	}
 	time_update = time_cur;
 
+	get_boot_info();
+
 	/* get dotconfig source information */
 	get_dotconfig_source();
 
diff --git a/userspace/snmpd/wrsBootStatusGroup.h b/userspace/snmpd/wrsBootStatusGroup.h
index b90c196e7..ed93cc77a 100644
--- a/userspace/snmpd/wrsBootStatusGroup.h
+++ b/userspace/snmpd/wrsBootStatusGroup.h
@@ -4,6 +4,8 @@
 #define WRSBOOTSTATUS_CACHE_TIMEOUT 5
 #define WRSBOOTSTATUS_OID WRS_OID, 7, 1, 2
 
+#define WRS_RESTART_REASON_ERROR 1		/* error */
+
 #define WRS_CONFIG_SOURCE_HOST_LEN 64
 #define WRS_CONFIG_SOURCE_FILENAME_LEN 128
 #define WRS_CONFIG_SOURCE_PROTO_ERROR 1		/* error */
-- 
GitLab