Commit 23781a79 authored by Adam Wujek's avatar Adam Wujek 💬

Merge branch 'adam-snmp'

Improvement of snmp
Signed-off-by: Adam Wujek's avatarAdam Wujek <adam.wujek@cern.ch>
parents 41061669 cb78bf7e
......@@ -107,15 +107,11 @@ struct hal_temp_sensors {
int pll; /* IC18 */
int psl; /* IC20 Power Supply Left (PSL) */
int psr; /* IC17 Power Supply Right (PSR) */
int fpga_thold; /* Threshold value for FPGA temperature */
int pll_thold; /* Threshold value for PLL temperature */
int psl_thold; /* Threshold value for PSL temperature */
int psr_thold; /* Threshold value for PSR temperature */
};
/* This is the overall structure stored in shared memory */
#define HAL_SHMEM_VERSION 6 /* Version 6 because of new structure
* hal_temp_sensors in hal_shmem_header */
#define HAL_SHMEM_VERSION 7 /* Version 7 because of moving of reading
* temperature treshold values to snmpd */
struct hal_shmem_header {
int nports;
struct hal_port_state *ports;
......
ppsi @ b8ebe5fe
Subproject commit 782773077690f2b2d53af0395e3b94e8fcc89a9d
Subproject commit b8ebe5fee29e094175bb7d349483fdc651de146e
......@@ -32,12 +32,17 @@ SOURCES = \
wrsScalar.c \
wrsGeneralStatusGroup.c \
wrsOSStatusGroup.c \
wrsTimingStatusGroup.c \
wrsNetworkingStatusGroup.c \
wrsVersionGroup.c \
wrsCurrentTimeGroup.c \
wrsBootStatusGroup.c \
wrsTemperatureGroup.c \
wrsMemoryGroup.c \
wrsCpuLoadGroup.c \
wrsDiskTable.c \
wrsStartCntGroup.c \
wrsSpllVersionGroup.c \
wrsSpllStatusGroup.c \
wrsPstatsTable.c \
wrsPtpDataTable.c \
......
This diff is collapsed.
......@@ -11,12 +11,17 @@
#include "libwr/config.h"
#include "wrsGeneralStatusGroup.h"
#include "wrsOSStatusGroup.h"
#include "wrsTimingStatusGroup.h"
#include "wrsNetworkingStatusGroup.h"
#include "wrsVersionGroup.h"
#include "wrsCurrentTimeGroup.h"
#include "wrsBootStatusGroup.h"
#include "wrsTemperatureGroup.h"
#include "wrsMemoryGroup.h"
#include "wrsCpuLoadGroup.h"
#include "wrsDiskTable.h"
#include "wrsStartCntGroup.h"
#include "wrsSpllVersionGroup.h"
#include "wrsSpllStatusGroup.h"
#include "wrsPstatsTable.h"
#include "wrsPtpDataTable.h"
......@@ -38,14 +43,24 @@ void init_wrsSnmp(void)
init_wrsScalar();
init_wrsGeneralStatusGroup();
init_wrsOSStatusGroup();
init_wrsTimingStatusGroup();
init_wrsNetworkingStatusGroup();
init_wrsVersionGroup();
init_wrsCurrentTimeGroup();
init_wrsBootStatusGroup();
init_wrsTemperatureGroup();
init_wrsMemoryGroup();
init_wrsCpuLoadGroup();
init_wrsDiskTable();
init_wrsStartCntGroup();
init_wrsSpllVersionGroup();
init_wrsSpllStatusGroup();
init_wrsPstatsTable();
init_wrsPtpDataTable();
init_wrsPortStatusTable();
/* perform first reads, needed to calculate deltas later */
wrsTimingStatus_data_fill();
wrsNetworkingStatus_data_fill();
}
......@@ -11,6 +11,8 @@ int hal_nports_local;
struct wrs_shm_head *ppsi_head;
static struct pp_globals *ppg;
struct wr_servo_state *ppsi_servo;
struct pp_instance *ppsi_ppi;
int *ppsi_ppi_nlinks;
/* RTUd */
struct wrs_shm_head *rtud_head;
......@@ -74,6 +76,13 @@ static void init_shm_ppsi(void)
exit(-1);
}
ppsi_ppi = wrs_shm_follow(ppsi_head, ppg->pp_instances);
if (!ppsi_ppi) {
snmp_log(LOG_ERR, "Cannot follow ppsi_ppi in shmem.\n");
exit(-1);
}
/* use pointer instead of copying */
ppsi_ppi_nlinks = &(ppg->nlinks);
}
static void init_shm_rtud(void)
......
......@@ -16,6 +16,8 @@ extern int hal_nports_local;
/* PPSI */
extern struct wrs_shm_head *ppsi_head;
extern struct wr_servo_state *ppsi_servo;
extern struct pp_instance *ppsi_ppi;
extern int *ppsi_ppi_nlinks;
/* RTUd */
struct wrs_shm_head *rtud_head;
......
......@@ -129,7 +129,10 @@ int spll_get_dac(int out_channel);
void check_vco_frequencies();
#define SPLL_STATS_VER 2
/* info reported through .stat section */
/* due to endiannes problem strings has to be 4 bytes alligned */
struct spll_stats {
int magic; /* 0x5b1157a7 = SPLLSTAT ?;)*/
int ver; /* version of the structure */
......@@ -142,6 +145,10 @@ struct spll_stats {
int M_lock;
int H_y, M_y;
int del_cnt;
int start_cnt;
char commit_id[32];
char build_date[16];
char build_time[16];
};
/* This only exists in wr-switch, but we should use it always */
......
......@@ -8,7 +8,7 @@
#define DOTCONFIG_PROTO "dot-config_proto"
#define DOTCONFIG_HOST "dot-config_host"
#define DOTCONFIG_FILENAME "dot-config_filename"
#define DOTCONFIG_DOWNLOAD "dot-config_status"
#define DOTCONFIG_STATUS "dot-config_status"
#define HWINFO_FILE "/tmp/hwinfo_read_status"
#define LOAD_FPGA_STATUS_FILE "/tmp/load_fpga_status"
......@@ -63,19 +63,27 @@ static struct wrs_km_item kernel_modules[] = {
/* user space deamon list item */
struct wrs_usd_item {
char *key;
char *key; /* process name */
int32_t exp; /* expected number of processes */
uint32_t cnt; /* number of processes found */
};
/* user space deamon list */
static struct wrs_km_item userspace_deamons[] = {
[0] = {.key = "/usr/sbin/dropbear"},
[1] = {"/wr/bin/wrsw_hal"}, /* two wrsw_hal instances */
[2] = {"/wr/bin/wrsw_hal"}, /* two wrsw_hal instances */
[3] = {"/wr/bin/wrsw_rtud"},
[4] = {"/wr/bin/ppsi"},
[5] = {"/usr/sbin/lighttpd"},
[6] = {"/usr/bin/monit"},
[7] = {"snmpd"},
/* - key contain process name reported by ps command
* - positive exp describe exact number of expected processes
* - negative exp describe minimum number of expected processes. Usefull for
* processes that is hard to predict number of their instances. For example
* new dropbear process is spawned at ssh login.
*/
static struct wrs_usd_item userspace_deamons[] = {
[0] = {.key = "/usr/sbin/dropbear", .exp = -1}, /* expect at least one
* dropbear process */
[1] = {"/wr/bin/wrsw_hal", 2}, /* two wrsw_hal instances */
[2] = {"/wr/bin/wrsw_rtud", 1},
[3] = {"/wr/bin/ppsi", 1},
[4] = {"/usr/sbin/lighttpd", 1},
[5] = {"/usr/bin/monit", 1},
[6] = {"/usr/sbin/snmpd", 1},
};
struct wrs_bc_item {
......@@ -185,32 +193,38 @@ static void get_dotconfig_source(void)
WRS_CONFIG_SOURCE_PROTO_ERROR_MINOR;
}
/* read host used to get dotconfig */
f = fopen(DOTCONFIGDIR "/" DOTCONFIG_HOST, "r");
if (f) {
/* readline without newline */
fscanf(f, LINE_READ_LEN(WRS_CONFIG_SOURCE_HOST_LEN),
wrsBootStatus_s.wrsConfigSourceHost);
fclose(f);
} else {
/* host file not found, put "error" into wrsConfigSourceHost */
strcpy(wrsBootStatus_s.wrsConfigSourceHost, "error");
}
/* read hostname and file name only when config is not local */
if (wrsBootStatus_s.wrsConfigSource != WRS_CONFIG_SOURCE_PROTO_LOCAL) {
/* read host used to get dotconfig */
f = fopen(DOTCONFIGDIR "/" DOTCONFIG_HOST, "r");
if (f) {
/* readline without newline */
fscanf(f, LINE_READ_LEN(WRS_CONFIG_SOURCE_HOST_LEN),
wrsBootStatus_s.wrsConfigSourceHost);
fclose(f);
} else {
/* host file not found, put "error" into
* wrsConfigSourceHost */
strcpy(wrsBootStatus_s.wrsConfigSourceHost, "error");
}
/* read filename used to get dotconfig */
f = fopen(DOTCONFIGDIR "/" DOTCONFIG_FILENAME, "r");
if (f) {
/* readline without newline */
fscanf(f, LINE_READ_LEN(WRS_CONFIG_SOURCE_FILENAME_LEN),
wrsBootStatus_s.wrsConfigSourceFilename);
fclose(f);
} else {
/* host file not found, put "error" into
* wrsConfigSourceFilename */
strcpy(wrsBootStatus_s.wrsConfigSourceFilename, "error");
/* read filename used to get dotconfig */
f = fopen(DOTCONFIGDIR "/" DOTCONFIG_FILENAME, "r");
if (f) {
/* readline without newline */
fscanf(f,
LINE_READ_LEN(WRS_CONFIG_SOURCE_FILENAME_LEN),
wrsBootStatus_s.wrsConfigSourceFilename);
fclose(f);
} else {
/* host file not found, put "error" into
* wrsConfigSourceFilename */
strcpy(wrsBootStatus_s.wrsConfigSourceFilename,
"error");
}
}
f = fopen(DOTCONFIGDIR "/" DOTCONFIG_DOWNLOAD, "r");
f = fopen(DOTCONFIGDIR "/" DOTCONFIG_STATUS, "r");
if (f) {
/* readline without newline */
fscanf(f, LINE_READ_LEN(20), buff);
......@@ -322,10 +336,10 @@ static void get_loaded_kernel_modules_status(void)
{
FILE *f;
char key[41]; /* 1 for null char */
int modules_found;
int ret;
int modules_found = 0;
int ret = 0;
int i;
int guess_index;
int guess_index = 0;
int modules_missing;
f = fopen(MODULES_FILE, "r");
......@@ -372,23 +386,36 @@ static void get_deamons_status(void)
{
FILE *f;
char key[41]; /* 1 for null char */
int ret;
int ret = 0;
int i;
int processes_found;
int processes_missing;
int processes_wrong = 0; /* number of too many or too few processes */
/* clear user space deamon counters */
for (i = 0; i < ARRAY_SIZE(userspace_deamons); i++) {
userspace_deamons[i].cnt = 0;
}
/* use ps command to get process list, more portable, less error prone
/* Use ps command to get process list, more portable, less error prone
* but probably slower than manually parsing /proc/ */
f = popen(PROCESS_COMMAND, "r");
if (!f) {
snmp_log(LOG_ERR, "SNMP: wrsBootStatusGroup failed to execute "
PROCESS_COMMAND"\n");
/* notify snmp about error in processes list */
wrsBootStatus_s.wrsBootUserspaceDaemonsMissing =
ARRAY_SIZE(userspace_deamons);
wrsBootStatus_s.wrsBootUserspaceDaemonsMissing = 0;
/* Notify snmp about error in processes list */
/* Count number of expected processes */
for (i = 0; i < ARRAY_SIZE(userspace_deamons); i++) {
/* when exp < 0 then expect at least number of
* -exp processes */
wrsBootStatus_s.wrsBootUserspaceDaemonsMissing +=
abs(userspace_deamons[i].exp);
}
return;
}
/* count processes */
while (ret != EOF) {
/* read first word from line (process name) ignore rest of
* the line */
......@@ -399,22 +426,32 @@ static void get_deamons_status(void)
for (i = 0; i < ARRAY_SIZE(userspace_deamons); i++) {
if (strncmp(key, userspace_deamons[i].key, 40))
continue;
processes_found++;
userspace_deamons[i].cnt++;
break;
}
}
processes_missing = ARRAY_SIZE(userspace_deamons) - processes_found;
for (i = 0; i < ARRAY_SIZE(userspace_deamons); i++) {
if (userspace_deamons[i].exp < 0) {
/* if exp < 0 then expect at least -exp processes,
* useful in situation when we cannot predict exact
* number of processes.
* NOTE: exp in this case is negative number */
/* saturate cnt */
if (userspace_deamons[i].cnt > (-userspace_deamons[i].exp)) {
userspace_deamons[i].cnt =
(-userspace_deamons[i].exp);
}
}
/* Calculate delta between expected and counted number
* of processes. Neither too much or too few are ok.
* NOTE: abs "exp" too */
processes_wrong += abs(abs(userspace_deamons[i].exp)
- userspace_deamons[i].cnt);
}
/* save number of processes missing */
if (processes_missing < 0) {
/* probably something wrong with multiple process' instances */
wrsBootStatus_s.wrsBootUserspaceDaemonsMissing =
ARRAY_SIZE(userspace_deamons);
} else {
wrsBootStatus_s.wrsBootUserspaceDaemonsMissing =
processes_missing;
}
wrsBootStatus_s.wrsBootUserspaceDaemonsMissing = processes_wrong;
pclose(f);
}
......
#include "wrsSnmp.h"
#include "wrsCpuLoadGroup.h"
#include <sys/sysinfo.h> /* sysinfo */
static struct pickinfo wrsCpuLoad_pickinfo[] = {
FIELD(wrsCpuLoad_s, ASN_INTEGER, wrsCPULoadAvg1min),
FIELD(wrsCpuLoad_s, ASN_INTEGER, wrsCPULoadAvg5min),
FIELD(wrsCpuLoad_s, ASN_INTEGER, wrsCPULoadAvg15min),
};
struct wrsCpuLoad_s wrsCpuLoad_s;
time_t wrsCpuLoad_data_fill(void)
{
static time_t time_update;
time_t time_cur;
struct sysinfo info;
time_cur = time(NULL);
if (time_update
&& time_cur - time_update < WRSCPULOAD_CACHE_TIMEOUT) {
/* cache not updated, return last update time */
return time_update;
}
time_update = time_cur;
memset(&wrsCpuLoad_s, 0, sizeof(wrsCpuLoad_s));
if (sysinfo(&info) != 0) {
snmp_log(LOG_ERR, "SNMP: wrsMemoryGroup error while reading "
"system statistics with function sysinfo\n");
}
wrsCpuLoad_s.wrsCPULoadAvg1min =
(info.loads[0] * 100)/(1 << SI_LOAD_SHIFT);
wrsCpuLoad_s.wrsCPULoadAvg5min =
(info.loads[1] * 100)/(1 << SI_LOAD_SHIFT);
wrsCpuLoad_s.wrsCPULoadAvg15min =
(info.loads[2] * 100)/(1 << SI_LOAD_SHIFT);
/* there was an update, return current time */
return time_update;
}
#define GT_OID WRSCPULOAD_OID
#define GT_PICKINFO wrsCpuLoad_pickinfo
#define GT_DATA_FILL_FUNC wrsCpuLoad_data_fill
#define GT_DATA_STRUCT wrsCpuLoad_s
#define GT_GROUP_NAME "wrsCpuLoadGroup"
#define GT_INIT_FUNC init_wrsCpuLoadGroup
#include "wrsGroupTemplate.h"
#ifndef WRS_CPU_LOAD_GROUP_H
#define WRS_CPU_LOAD_GROUP_H
#define WRSCPULOAD_CACHE_TIMEOUT 5
#define WRSCPULOAD_OID WRS_OID, 7, 1, 5
struct wrsCpuLoad_s {
int wrsCPULoadAvg1min;
int wrsCPULoadAvg5min;
int wrsCPULoadAvg15min;
};
extern struct wrsCpuLoad_s wrsCpuLoad_s;
time_t wrsCpuLoad_data_fill(void);
void init_wrsCpuLoadGroup(void);
#endif /* WRS_CPU_LOAD_GROUP_H */
#include "wrsSnmp.h"
#include "snmp_shmem.h"
#include "wrsDiskTable.h"
#define DISKUSAGE_COMMAND "/bin/df -P"
struct wrsDiskTable_s wrsDiskTable_array[WRS_MAX_N_DISKS];
static struct pickinfo wrsDiskTable_pickinfo[] = {
/* Warning: strings are a special case for snmp format */
FIELD(wrsDiskTable_s, ASN_UNSIGNED, wrsDiskIndex), /* not reported */
FIELD(wrsDiskTable_s, ASN_OCTET_STR, wrsDiskMountPath),
FIELD(wrsDiskTable_s, ASN_INTEGER, wrsDiskSize),
FIELD(wrsDiskTable_s, ASN_INTEGER, wrsDiskUsed),
FIELD(wrsDiskTable_s, ASN_INTEGER, wrsDiskFree),
FIELD(wrsDiskTable_s, ASN_INTEGER, wrsDiskUseRate),
FIELD(wrsDiskTable_s, ASN_OCTET_STR, wrsDiskFilesystem),
};
static int32_t int_saturate(int64_t value)
{
if (value >= INT32_MAX)
return INT32_MAX;
else if (value <= INT32_MIN)
return INT32_MIN;
return value;
}
time_t wrsDiskTable_data_fill(unsigned int *ret_n_rows)
{
static time_t time_update;
time_t time_cur;
FILE *f;
char filesystem[64];
uint64_t disk_size;
uint64_t disk_used;
uint64_t disk_available;
char mount_path[32];
char s[80];
static int n_rows;
/* number of rows depends on numbef or mounted disks */
if (ret_n_rows)
*ret_n_rows = n_rows;
time_cur = time(NULL);
if (time_update
&& time_cur - time_update < WRSDISKTABLE_CACHE_TIMEOUT) {
/* cache not updated, return last update time */
return time_update;
}
time_update = time_cur;
memset(&wrsDiskTable_array, 0, sizeof(wrsDiskTable_array));
f = popen(DISKUSAGE_COMMAND, "r");
if (!f) {
snmp_log(LOG_ERR, "SNMP: wrsDiskTable filed to execute "
DISKUSAGE_COMMAND"\n");
return time_cur;
}
/* skip first line with columns' descriptions */
fgets(s, sizeof(s), f);
n_rows = 0;
while (fgets(s, sizeof(s), f)) {
if (n_rows > WRS_MAX_N_DISKS) {
n_rows = WRS_MAX_N_DISKS;
break;
}
if (5 != sscanf(s, "%s %llu %llu %llu %*s %s %*[^\n]",
filesystem, &disk_size, &disk_used,
&disk_available, mount_path))
continue; /* error while reading df's output */
strncpy(wrsDiskTable_array[n_rows].wrsDiskFilesystem,
filesystem, 64);
wrsDiskTable_array[n_rows].wrsDiskSize =
int_saturate(disk_size);
wrsDiskTable_array[n_rows].wrsDiskUsed =
int_saturate(disk_used);
wrsDiskTable_array[n_rows].wrsDiskFree =
int_saturate(disk_available);
wrsDiskTable_array[n_rows].wrsDiskUseRate =
(wrsDiskTable_array[n_rows].wrsDiskUsed * 100)
/wrsDiskTable_array[n_rows].wrsDiskSize;
strncpy(wrsDiskTable_array[n_rows].wrsDiskMountPath,
mount_path, 32);
n_rows++;
}
pclose(f);
if (ret_n_rows)
*ret_n_rows = n_rows;
/* there was an update, return current time */
return time_update;
}
#define TT_OID WRSDISKTABLE_OID
#define TT_PICKINFO wrsDiskTable_pickinfo
#define TT_DATA_FILL_FUNC wrsDiskTable_data_fill
#define TT_DATA_ARRAY wrsDiskTable_array
#define TT_GROUP_NAME "wrsDiskTable"
#define TT_INIT_FUNC init_wrsDiskTable
#define TT_CACHE_TIMEOUT WRSDISKTABLE_CACHE_TIMEOUT
#include "wrsTableTemplate.h"
#ifndef WRS_DISK_TABLE_H
#define WRS_DISK_TABLE_H
#define WRSDISKTABLE_CACHE_TIMEOUT 5
#define WRSDISKTABLE_OID WRS_OID, 7, 1, 6
#define WRS_MAX_N_DISKS 10
struct wrsDiskTable_s {
uint32_t wrsDiskIndex; /* not reported, index fields has to be marked
* as not-accessible in MIB */
char wrsDiskMountPath[32];
uint32_t wrsDiskSize;
uint32_t wrsDiskUsed;
uint32_t wrsDiskFree;
uint32_t wrsDiskUseRate;
char wrsDiskFilesystem[64];
};
extern struct wrsDiskTable_s wrsDiskTable_array[WRS_MAX_N_DISKS];
time_t wrsDiskTable_data_fill(unsigned int *rows);
void init_wrsDiskTable(void);
#endif /* WRS_DISK_TABLE_H */
#include "wrsSnmp.h"
#include "wrsOSStatusGroup.h"
#include "wrsTimingStatusGroup.h"
#include "wrsNetworkingStatusGroup.h"
#include "wrsGeneralStatusGroup.h"
......@@ -16,16 +17,21 @@ time_t wrsGeneralStatus_data_fill(void)
{
static time_t time_update; /* time of last update */
time_t time_osstatus; /* time when wrsOSStatus data was updated */
time_t time_timing_status; /* time when wrsTimingStatus data was
* updated */
time_t time_networking_status; /* time when wrsNetworkingStatus data
* was updated */
struct wrsOSStatus_s *o;
struct wrsTimingStatus_s *t;
struct wrsNetworkingStatus_s *n;
struct wrsGeneralStatus_s *g;
time_osstatus = wrsOSStatus_data_fill();
time_timing_status = wrsTimingStatus_data_fill();
time_networking_status = wrsNetworkingStatus_data_fill();
if (time_osstatus <= time_update
&& time_timing_status <= time_update
&& time_networking_status <= time_update) {
/* cache not updated, return last update time */
snmp_log(LOG_ERR,
......@@ -41,6 +47,9 @@ time_t wrsGeneralStatus_data_fill(void)
o = &wrsOSStatus_s;
if ( /* check if error */
o->wrsBootSuccessful == WRS_BOOT_SUCCESSFUL_ERROR
|| o->wrsMemoryFreeLow == WRS_MEMORY_FREE_LOW_ERROR
|| o->wrsCpuLoadHigh == WRS_CPU_LOAD_HIGH_ERROR
|| o->wrsDiskSpaceLow == WRS_DISK_SPACE_LOW_ERROR
) {
wrsGeneralStatus_s.wrsOSStatus = WRS_OS_STATUS_ERROR;
......@@ -48,6 +57,9 @@ time_t wrsGeneralStatus_data_fill(void)
o->wrsBootSuccessful == WRS_BOOT_SUCCESSFUL_WARNING
|| o->wrsTemperatureWarning == WRS_TEMPERATURE_WARNING_THOLD_NOT_SET
|| o->wrsTemperatureWarning == WRS_TEMPERATURE_WARNING_TOO_HIGH
|| o->wrsMemoryFreeLow == WRS_MEMORY_FREE_LOW_WARNING
|| o->wrsCpuLoadHigh == WRS_CPU_LOAD_HIGH_WARNING
|| o->wrsDiskSpaceLow == WRS_DISK_SPACE_LOW_WARNING
) { /* warning */
wrsGeneralStatus_s.wrsOSStatus = WRS_OS_STATUS_WARNING;
......@@ -55,12 +67,20 @@ time_t wrsGeneralStatus_data_fill(void)
o->wrsBootSuccessful == WRS_BOOT_SUCCESSFUL_WARNING_NA
|| o->wrsBootSuccessful == 0
|| o->wrsTemperatureWarning == 0
|| o->wrsMemoryFreeLow == WRS_MEMORY_FREE_LOW_WARNING_NA
|| o->wrsMemoryFreeLow == 0
|| o->wrsCpuLoadHigh == 0
|| o->wrsDiskSpaceLow == WRS_DISK_SPACE_LOW_WARNING_NA
|| o->wrsDiskSpaceLow == 0
) { /* warning NA */
wrsGeneralStatus_s.wrsOSStatus = WRS_OS_STATUS_WARNING_NA;
} else if ( /* check if OK */
o->wrsBootSuccessful == WRS_BOOT_SUCCESSFUL_OK
&& o->wrsTemperatureWarning == WRS_TEMPERATURE_WARNING_OK
&& o->wrsMemoryFreeLow == WRS_MEMORY_FREE_LOW_OK
&& o->wrsCpuLoadHigh == WRS_CPU_LOAD_HIGH_OK
&& o->wrsDiskSpaceLow == WRS_DISK_SPACE_LOW_OK
) { /* OK */
wrsGeneralStatus_s.wrsOSStatus = WRS_OS_STATUS_OK;
......@@ -73,8 +93,50 @@ time_t wrsGeneralStatus_data_fill(void)
|************************** wrsTimingStatus **************************|
\*********************************************************************/
/* not implemented, always return OK */
wrsGeneralStatus_s.wrsTimingStatus = WRS_TIMING_STATUS_OK;
t = &wrsTimingStatus_s;
if ( /* check if error */
t->wrsPTPStatus == WRS_PTP_STATUS_ERROR
|| t->wrsSoftPLLStatus == WRS_SOFTPLL_STATUS_ERROR
|| t->wrsSlaveLinksStatus == WRS_SLAVE_LINK_STATUS_ERROR
|| t->wrsPTPFramesFlowing == WRS_PTP_FRAMES_FLOWING_ERROR
) {
wrsGeneralStatus_s.wrsTimingStatus =
WRS_TIMING_STATUS_ERROR;
} else if ( /* check if warning */
t->wrsSoftPLLStatus == WRS_SOFTPLL_STATUS_WARNING
) { /* warning */
wrsGeneralStatus_s.wrsTimingStatus =
WRS_TIMING_STATUS_WARNING;
} else if ( /* check if any of fields equal to 0 or WARNING_NA */
t->wrsPTPStatus == 0
|| t->wrsSoftPLLStatus == WRS_SOFTPLL_STATUS_WARNING_NA
|| t->wrsSoftPLLStatus == 0
|| t->wrsSlaveLinksStatus == 0
|| t->wrsSlaveLinksStatus == WRS_SLAVE_LINK_STATUS_WARNING_NA
|| t->wrsPTPFramesFlowing == 0
|| t->wrsPTPFramesFlowing == WRS_PTP_FRAMES_FLOWING_WARNING_NA
) { /* warning NA */
wrsGeneralStatus_s.wrsTimingStatus =
WRS_TIMING_STATUS_WARNING_NA;
} else if ( /* check if OK, FR (first read) is also ok */
(t->wrsPTPStatus == WRS_PTP_STATUS_OK
|| t->wrsPTPStatus == WRS_PTP_STATUS_FR) /* FR*/
&& t->wrsSoftPLLStatus == WRS_SOFTPLL_STATUS_OK
&& t->wrsSlaveLinksStatus == WRS_SLAVE_LINK_STATUS_OK
&& (t->wrsPTPFramesFlowing == WRS_PTP_FRAMES_FLOWING_OK
|| t->wrsPTPFramesFlowing == WRS_PTP_FRAMES_FLOWING_FR) /* FR */
) { /* OK */
wrsGeneralStatus_s.wrsTimingStatus =
WRS_TIMING_STATUS_OK;
} else { /* probably bug in previous conditions,
* this should never happen */
wrsGeneralStatus_s.wrsTimingStatus =
WRS_TIMING_STATUS_BUG;
}
/*********************************************************************\
|************************ wrsNetworkingStatus ************************|
......
#include "wrsSnmp.h"
#include "wrsMemoryGroup.h"
#define MEMINFO_FILE "/proc/meminfo"
#define MEMINFO_ENTRIES 4 /* How many meminfo are interesting for us, used to
* speed up reading meminfo file */
static struct pickinfo wrsMemory_pickinfo[] = {
FIELD(wrsMemory_s, ASN_INTEGER, wrsMemoryTotal),
FIELD(wrsMemory_s, ASN_INTEGER, wrsMemoryUsed),
FIELD(wrsMemory_s, ASN_INTEGER, wrsMemoryUsedPerc),
FIELD(wrsMemory_s, ASN_INTEGER, wrsMemoryFree),
};
struct wrsMemory_s wrsMemory_s;
time_t wrsMemory_data_fill(void)
{
static time_t time_update;
time_t time_cur;
unsigned long value;
unsigned long mem_total = 0;
unsigned long mem_free = 0;
unsigned long mem_cached = 0;
unsigned long mem_buffers = 0;
int found = 0;
FILE *f;
int ret = 0;
char key[41]; /* 1 for null char */
time_cur = time(NULL);
if (time_update
&& time_cur - time_update < WRSMEMORY_CACHE_TIMEOUT) {
/* cache not updated, return last update time */
return time_update;
}
time_update = time_cur;
memset(&wrsMemory_s, 0, sizeof(wrsMemory_s));
f = fopen(MEMINFO_FILE, "r");
if (!f) {
snmp_log(LOG_ERR, "SNMP: wrsMemoryGroup filed to open "
MEMINFO_FILE"\n");
/* notify snmp about error in kernel modules */
return time_update;
}
while (ret != EOF && found < MEMINFO_ENTRIES) {
/* read first word from line (module name) ignore rest of
* the line */
ret = fscanf(f, "%40s %lu %*[^\n]", key, &value);
if (ret != 2)
continue; /* error... or EOF */
if (!strcmp(key, "MemTotal:")) {
mem_total = value;
found++;
} else if (!strcmp(key, "MemFree:")) {
mem_free = value;
found++;
} else if (!strcmp(key, "Buffers:")) {
mem_buffers = value;
found++;
} else if (!strcmp(key, "Cached:")) {
mem_cached = value;
found++;
}
}
if (found == MEMINFO_ENTRIES && mem_total > 0) { /* avoid div 0 */
wrsMemory_s.wrsMemoryTotal = (int) mem_total;
wrsMemory_s.wrsMemoryUsed = (int) (mem_total - mem_free
- mem_buffers - mem_cached);
wrsMemory_s.wrsMemoryUsedPerc = (int) ((mem_total - mem_free
- mem_buffers - mem_cached)
* 100 / mem_total);
wrsMemory_s.wrsMemoryFree = (int) (mem_free + mem_buffers
+ mem_cached);
} else { /* if not enough entries found */
snmp_log(LOG_ERR, "SNMP: wrsMemoryGroup error while reading "
"values from "MEMINFO_FILE"\n");
}
/* there was an update, return current time */
return time_update;
}
#define GT_OID WRSMEMORY_OID
#define GT_PICKINFO wrsMemory_pickinfo
#define GT_DATA_FILL_FUNC wrsMemory_data_fill
#define GT_DATA_STRUCT wrsMemory_s
#define GT_GROUP_NAME "wrsMemoryGroup"
#define GT_INIT_FUNC init_wrsMemoryGroup
#include "wrsGroupTemplate.h"
#ifndef WRS_MEMORY_GROUP_H
#define WRS_MEMORY_GROUP_H
#define WRSMEMORY_CACHE_TIMEOUT 5
#define WRSMEMORY_OID WRS_OID, 7, 1, 4
struct wrsMemory_s {
int wrsMemoryTotal;
int wrsMemoryUsed;
int wrsMemoryUsedPerc;
int wrsMemoryFree;
};
extern struct wrsMemory_s wrsMemory_s;
time_t wrsMemory_data_fill(void);
void init_wrsMemoryGroup(void);
#endif /* WRS_MEMORY_GROUP_H */
......@@ -13,17 +13,17 @@
* normal operation */
#define WRS_SFPS_STATUS_BUG 5 /* warning */
#define WRS_ENDPOINT_STATUS_FR 1 /* ok, first read */
#define WRS_ENDPOINT_STATUS_OK 2 /* ok */
#define WRS_ENDPOINT_STATUS_ERROR 3 /* error */
#define WRS_ENDPOINT_STATUS_OK 1 /* ok */
#define WRS_ENDPOINT_STATUS_ERROR 2 /* error */
#define WRS_ENDPOINT_STATUS_FR 6 /* ok, first read */
#define WRS_SWCORE_STATUS_FR 1 /* ok, first read */
#define WRS_SWCORE_STATUS_OK 2 /* ok */
#define WRS_SWCORE_STATUS_ERROR 3 /* error */
#define WRS_SWCORE_STATUS_OK 1 /* ok */
#define WRS_SWCORE_STATUS_ERROR 2 /* error */
#define WRS_SWCORE_STATUS_FR 6 /* ok, first read */
#define WRS_RTU_STATUS_FR 1 /* ok, first read */
#define WRS_RTU_STATUS_OK 2 /* ok */
#define WRS_RTU_STATUS_ERROR 3 /* error */
#define WRS_RTU_STATUS_OK 1 /* ok */
#define WRS_RTU_STATUS_ERROR 2 /* error */
#define WRS_RTU_STATUS_FR 6 /* ok, first read */
struct wrsNetworkingStatus_s {
int wrsSFPsStatus;
......
#include "wrsSnmp.h"
#include "wrsBootStatusGroup.h"
#include "wrsTemperatureGroup.h"
#include "wrsMemoryGroup.h"
#include "wrsCpuLoadGroup.h"
#include "wrsDiskTable.h"
#include "wrsOSStatusGroup.h"
#define WRSMEMORYFREELOW_TRESHOLD_ERROR 80
#define WRSMEMORYFREELOW_TRESHOLD_WARNING 50
/* To avoid float values for cpu load, they are multiplied by 100 */
#define WRSCPULOAD_1MIN_WARNING 200
#define WRSCPULOAD_5MIN_WARNING 150
#define WRSCPULOAD_15MIN_WARNING 100
#define WRSCPULOAD_1MIN_ERROR 300
#define WRSCPULOAD_5MIN_ERROR 200
#define WRSCPULOAD_15MIN_ERROR 150
#define WRSDISKSPACELOW_TRESHOLD_ERROR 90
#define WRSDISKSPACELOW_TRESHOLD_WARNING 80
static struct pickinfo wrsOSStatus_pickinfo[] = {
FIELD(wrsOSStatus_s, ASN_INTEGER, wrsBootSuccessful),
FIELD(wrsOSStatus_s, ASN_INTEGER, wrsTemperatureWarning),
FIELD(wrsOSStatus_s, ASN_INTEGER, wrsMemoryFreeLow),
FIELD(wrsOSStatus_s, ASN_INTEGER, wrsCpuLoadHigh),
FIELD(wrsOSStatus_s, ASN_INTEGER, wrsDiskSpaceLow),
};
struct wrsOSStatus_s wrsOSStatus_s;
......@@ -15,13 +35,28 @@ time_t wrsOSStatus_data_fill(void)
static time_t time_update; /* time of last update */
time_t time_temp; /* time when temperature data was updated */
time_t time_boot; /* time when boot data was updated */
time_t time_free_mem; /* time when free memory data was updated */
time_t time_cpu_load; /* time when cpu load data was updated */
time_t time_disk_space; /* time when disk space data was updated */
unsigned int n_rows_disk_space; /* number of rows in wrsDiskTable_array
*/
unsigned int i;
struct wrsBootStatus_s *b;
struct wrsMemory_s *f;
struct wrsCpuLoad_s *c;
struct wrsDiskTable_s *d;
time_boot = wrsBootStatus_data_fill();
time_temp = wrsTemperature_data_fill();
time_free_mem = wrsMemory_data_fill();
time_cpu_load = wrsCpuLoad_data_fill();
time_disk_space = wrsDiskTable_data_fill(&n_rows_disk_space);
if (time_boot <= time_update
&& time_temp <= time_update) {
&& time_temp <= time_update
&& time_free_mem <= time_update
&& time_cpu_load <= time_update
&& time_disk_space <= time_update) {
/* cache not updated, return last update time */
return time_update;
}
......@@ -127,6 +162,76 @@ time_t wrsOSStatus_data_fill(void)
|| (wrsTemperature_s.temp_psr > wrsTemperature_s.temp_psr_thold));
}
/*********************************************************************\
|************************* wrsMemoryFreeLow *************************|
\*********************************************************************/
/* Check memory usage */
f = &wrsMemory_s;
if (f->wrsMemoryUsedPerc > WRSMEMORYFREELOW_TRESHOLD_ERROR) {
/* Memory usage above error threshold level */
wrsOSStatus_s.wrsMemoryFreeLow = WRS_MEMORY_FREE_LOW_ERROR;
} else if (f->wrsMemoryUsedPerc > WRSMEMORYFREELOW_TRESHOLD_WARNING) {
/* Memory usage above warning threshold level */
wrsOSStatus_s.wrsMemoryFreeLow = WRS_MEMORY_FREE_LOW_WARNING;
} else if (f->wrsMemoryTotal == 0) {
/* Problem with read memory size */
wrsOSStatus_s.wrsMemoryFreeLow =
WRS_MEMORY_FREE_LOW_WARNING_NA;
} else {
/* Memory usage below threshold levels */
wrsOSStatus_s.wrsMemoryFreeLow = WRS_MEMORY_FREE_LOW_OK;
}
/*********************************************************************\
|************************** wrsCpuLoadHigh **************************|
\*********************************************************************/
/* Check CPU load */
c = &wrsCpuLoad_s;
if (c->wrsCPULoadAvg1min > WRSCPULOAD_1MIN_ERROR
|| c->wrsCPULoadAvg5min > WRSCPULOAD_5MIN_ERROR
|| c->wrsCPULoadAvg15min > WRSCPULOAD_15MIN_ERROR) {
/* CPU load above error threshold level */
wrsOSStatus_s.wrsCpuLoadHigh = WRS_CPU_LOAD_HIGH_ERROR;
} else if (c->wrsCPULoadAvg1min > WRSCPULOAD_1MIN_WARNING
|| c->wrsCPULoadAvg5min > WRSCPULOAD_5MIN_WARNING
|| c->wrsCPULoadAvg15min > WRSCPULOAD_15MIN_WARNING) {
/* CPU load above warning threshold level */
wrsOSStatus_s.wrsCpuLoadHigh = WRS_CPU_LOAD_HIGH_WARNING;
} else {
/* CPU load below threshold levels */
wrsOSStatus_s.wrsCpuLoadHigh = WRS_CPU_LOAD_HIGH_OK;
}
/*********************************************************************\
|************************** wrsDiskSpaceLow **************************|
\*********************************************************************/
/* Check disk usage */
d = wrsDiskTable_array;
wrsOSStatus_s.wrsDiskSpaceLow = WRS_DISK_SPACE_LOW_OK;
for (i = 0; i < n_rows_disk_space; i++) {
if (d[i].wrsDiskUseRate > WRSDISKSPACELOW_TRESHOLD_ERROR) {
/* Disk usage above error threshold level */
wrsOSStatus_s.wrsDiskSpaceLow =
WRS_DISK_SPACE_LOW_ERROR;
snmp_log(LOG_ERR, "SNMP: wrsDiskSpaceLow error for "
"disk %s\n", d[i].wrsDiskMountPath);
/* error, can't be worst so break */
break;
} else if (d[i].wrsDiskUseRate > WRSDISKSPACELOW_TRESHOLD_WARNING) {
/* Disk usage above warning threshold level */
wrsOSStatus_s.wrsDiskSpaceLow =
WRS_DISK_SPACE_LOW_WARNING;
snmp_log(LOG_ERR, "SNMP: wrsDiskSpaceLow warning for "
"disk %s\n", d[i].wrsDiskMountPath);
} else if (d[i].wrsDiskSize == 0
&& wrsOSStatus_s.wrsDiskSpaceLow == WRS_DISK_SPACE_LOW_OK) {
/* disk size is 0, propably error while reading size,
* but don't overwrite regular warning */
wrsOSStatus_s.wrsDiskSpaceLow =
WRS_DISK_SPACE_LOW_WARNING_NA;
}
}
/* there was an update, return current time */
return time_update;
}
......
......@@ -15,9 +15,30 @@
#define WRS_TEMPERATURE_WARNING_OK 2 /* ok */
#define WRS_TEMPERATURE_WARNING_TOO_HIGH 3 /* warning */
#define WRS_MEMORY_FREE_LOW_OK 1 /* ok */
#define WRS_MEMORY_FREE_LOW_ERROR 2 /* error */
#define WRS_MEMORY_FREE_LOW_WARNING 3 /* warning */
#define WRS_MEMORY_FREE_LOW_WARNING_NA 4 /* warning, at least one field is
* equal to 0 (NA),shouldn't happen in
* normal operation */
#define WRS_CPU_LOAD_HIGH_OK 1 /* ok */
#define WRS_CPU_LOAD_HIGH_ERROR 2 /* error */
#define WRS_CPU_LOAD_HIGH_WARNING 3 /* warning */
#define WRS_DISK_SPACE_LOW_OK 1 /* ok */
#define WRS_DISK_SPACE_LOW_ERROR 2 /* error */
#define WRS_DISK_SPACE_LOW_WARNING 3 /* warning */
#define WRS_DISK_SPACE_LOW_WARNING_NA 4 /* warning, at least one field is
* equal to 0 (NA),shouldn't happen in
* normal operation */
struct wrsOSStatus_s {
int wrsBootSuccessful;
int wrsTemperatureWarning;
int wrsMemoryFreeLow;
int wrsCpuLoadHigh;
int wrsDiskSpaceLow;
};
extern struct wrsOSStatus_s wrsOSStatus_s;
......
......@@ -18,15 +18,18 @@ static struct pickinfo wrsPortStatusTable_pickinfo[] = {
FIELD(wrsPortStatusTable_s, ASN_INTEGER, sfp_in_db),
FIELD(wrsPortStatusTable_s, ASN_INTEGER, sfp_GbE),
FIELD(wrsPortStatusTable_s, ASN_INTEGER, sfp_error),
FIELD(wrsPortStatusTable_s, ASN_COUNTER, ptp_tx_count),
FIELD(wrsPortStatusTable_s, ASN_COUNTER, ptp_rx_count),
};
time_t wrsPortStatusTable_data_fill(unsigned int *n_rows)
{
unsigned ii, i;
unsigned ii, i, ppi_i;
unsigned retries = 0;
static time_t time_update;
time_t time_cur;
char *ppsi_iface_name;
/* number of rows does not change for wrsPortStatusTable */
if (n_rows)
......@@ -55,9 +58,13 @@ time_t wrsPortStatusTable_data_fill(unsigned int *n_rows)
wrsPortStatusTable_array[i].port_name);
/* No need to copy all ports structures, only what
* we're interested in.
* Keep value 0 for Not available */
* Keep value 0 for Not available
* values defined as WRS_PORT_STATUS_LINK_*
*/
wrsPortStatusTable_array[i].link_up =
1 + state_up(port_state->state);
/* values defined as
* WRS_PORT_STATUS_CONFIGURED_MODE_* */
wrsPortStatusTable_array[i].port_mode =
port_state->mode;
if (port_state->state == HAL_PORT_STATE_DISABLED) {
......@@ -116,6 +123,49 @@ time_t wrsPortStatusTable_data_fill(unsigned int *n_rows)
usleep(1000);
}
retries = 0;
/* fill ptp_tx_count and ptp_tx_count
* ptp_tx_count and ptp_tx_count statistics in PPSI are collected per
* ppi instance. Since there can be more than one instance per physical
* port, proper counters has to be added. */
while (1) {
ii = wrs_shm_seqbegin(ppsi_head);
/* Match port name with interface name of ppsi instance.
* More than one ppsi_iface_name can match to
* wrsPortStatusTable_array[i].port_name, but only one can
* match way round */
for (ppi_i = 0; ppi_i < *ppsi_ppi_nlinks; ppi_i++) {
/* (ppsi_ppi + ppi_i)->iface_name is a pointer in
* shmem, so we have to follow it
* NOTE: ppi->cfg.port_name cannot be used instead,
* because it is not used when ppsi is configured from
* cmdline */
ppsi_iface_name = (char *) wrs_shm_follow(ppsi_head,
(ppsi_ppi + ppi_i)->iface_name);
for (i = 0; i < hal_nports_local; ++i) {
if (!strncmp(wrsPortStatusTable_array[i].port_name,
ppsi_iface_name, 12)) {
wrsPortStatusTable_array[i].ptp_tx_count +=
(ppsi_ppi + ppi_i)->ptp_tx_count;
wrsPortStatusTable_array[i].ptp_rx_count +=
(ppsi_ppi + ppi_i)->ptp_rx_count;
/* speed up a little, break here */
break;
}
}
}
retries++;
if (retries > 100) {
snmp_log(LOG_ERR, "%s: too many retries to read PPSI "
"shmem\n", __func__);
retries = 0;
break;
}
if (!wrs_shm_seqretry(ppsi_head, ii))
break; /* consistent read */
usleep(1000);
}
/* there was an update, return current time */
return time_cur;
}
......
......@@ -8,6 +8,15 @@
#define WRS_PORT_STATUS_SFP_ERROR_SFP_ERROR 2 /* error */
#define WRS_PORT_STATUS_SFP_ERROR_PORT_DOWN 3 /* ok */
#define WRS_PORT_STATUS_LINK_DOWN 1
#define WRS_PORT_STATUS_LINK_UP 2
#define WRS_PORT_STATUS_CONFIGURED_MODE_MASTER 1
#define WRS_PORT_STATUS_CONFIGURED_MODE_SLAVE 2
#define WRS_PORT_STATUS_CONFIGURED_MODE_NON_WR 3
#define WRS_PORT_STATUS_CONFIGURED_MODE_AUTO 4
struct wrsPortStatusTable_s {
uint32_t index; /* not reported, index fields has to be marked
* as not-accessible in MIB */
......@@ -23,6 +32,8 @@ struct wrsPortStatusTable_s {
int sfp_in_db;
int sfp_GbE;
int sfp_error;
unsigned long ptp_tx_count;
unsigned long ptp_rx_count;
};
......
......@@ -25,6 +25,10 @@ static struct pickinfo wrsPtpDataTable_pickinfo[] = {
FIELD(wrsPtpDataTable_s, ASN_INTEGER, delta_rx_m),
FIELD(wrsPtpDataTable_s, ASN_INTEGER, delta_tx_s),
FIELD(wrsPtpDataTable_s, ASN_INTEGER, delta_rx_s),
FIELD(wrsPtpDataTable_s, ASN_COUNTER, n_err_state),
FIELD(wrsPtpDataTable_s, ASN_COUNTER, n_err_offset),
FIELD(wrsPtpDataTable_s, ASN_COUNTER, n_err_delta_rtt),
FIELD(wrsPtpDataTable_s, ASN_COUNTER, n_err_rxtx_deltas),
};
static int32_t int_saturate(int64_t value)
......@@ -90,6 +94,10 @@ time_t wrsPtpDataTable_data_fill(unsigned int *n_rows)
wrsPtpDataTable_array[0].delta_rx_m = ppsi_servo->delta_rx_m;
wrsPtpDataTable_array[0].delta_tx_s = ppsi_servo->delta_tx_s;
wrsPtpDataTable_array[0].delta_rx_s = ppsi_servo->delta_rx_s;
wrsPtpDataTable_array[0].n_err_state = ppsi_servo->n_err_state;
wrsPtpDataTable_array[0].n_err_offset = ppsi_servo->n_err_offset;
wrsPtpDataTable_array[0].n_err_delta_rtt = ppsi_servo->n_err_delta_rtt;
wrsPtpDataTable_array[0].n_err_rxtx_deltas = ppsi_servo->n_err_rxtx_deltas;
retries++;
if (retries > 100) {
snmp_log(LOG_ERR, "%s: too many retries to read PPSI\n",
......
......@@ -30,8 +30,13 @@ struct wrsPtpDataTable_s {
int32_t delta_rx_m;
int32_t delta_tx_s;
int32_t delta_rx_s;
uint32_t n_err_state;
uint32_t n_err_offset;
uint32_t n_err_delta_rtt;
uint32_t n_err_rxtx_deltas;
};
extern struct wrsPtpDataTable_s wrsPtpDataTable_array[WRS_MAX_N_SERVO_INSTANCES];
time_t wrsPtpDataTable_data_fill(unsigned int *rows);
void init_wrsPtpDataTable(void);
......
......@@ -51,8 +51,8 @@ time_t wrsSpllStatus_data_fill(void)
"wrsSpllStatusGroup Wrong SPLL magic number\n");
return time_update;
}
/* check version of SPLL's stat structure */
if (spll_stats_p->ver == 1) {
/* check version of SPLL's stat structure, versions 1 and 2 are ok */
if ((spll_stats_p->ver == 1) || (spll_stats_p->ver == 2)) {
wrsSpllStatus_s.wrsSpllMode = spll_stats_p->mode;
wrsSpllStatus_s.wrsSpllIrqCnt = spll_stats_p->irq_cnt;
wrsSpllStatus_s.wrsSpllSeqState = spll_stats_p->seq_state;
......
......@@ -4,6 +4,34 @@
#define WRSSPLLSTATUS_CACHE_TIMEOUT 5
#define WRSSPLLSTATUS_OID WRS_OID, 7, 3, 2
/* values taken from softpll_ng.h */
#define WRS_SPLL_MODE_GRAND_MASTER 1
#define WRS_SPLL_MODE_MASTER 2 /* free running master */
#define WRS_SPLL_MODE_SLAVE 3
/* values taken from file spll_external.c in wrpc-sw repo */
#define WRS_SPLL_ALIGN_STATE_EXT_OFF 0
#define WRS_SPLL_ALIGN_STATE_START 1
#define WRS_SPLL_ALIGN_STATE_INIT_CSYNC 2
#define WRS_SPLL_ALIGN_STATE_WAIT_CSYNC 3
#define WRS_SPLL_ALIGN_STATE_START_ALIGNMENT 7
#define WRS_SPLL_ALIGN_STATE_WAIT_SAMPLE 4
#define WRS_SPLL_ALIGN_STATE_COMPENSATE_DELAY 5
#define WRS_SPLL_ALIGN_STATE_LOCKED 6
#define WRS_SPLL_ALIGN_STATE_START_MAIN 8
/* values taken from file softpll_ng.c in wrpc-sw repo */
#define WRS_SPLL_SEQ_STATE_START_EXT 1
#define WRS_SPLL_SEQ_STATE_WAIT_EXT 2
#define WRS_SPLL_SEQ_STATE_START_HELPER 3
#define WRS_SPLL_SEQ_STATE_WAIT_HELPER 4
#define WRS_SPLL_SEQ_STATE_START_MAIN 5
#define WRS_SPLL_SEQ_STATE_WAIT_MAIN 6
#define WRS_SPLL_SEQ_STATE_DISABLED 7
#define WRS_SPLL_SEQ_STATE_READY 8
#define WRS_SPLL_SEQ_STATE_CLEAR_DACS 9
#define WRS_SPLL_SEQ_STATE_WAIT_CLEAR_DACS 10
struct wrsSpllStatus_s {
int32_t wrsSpllMode;
int32_t wrsSpllIrqCnt;
......
#include "wrsSnmp.h"
#include "wrsSpllVersionGroup.h"
#include "softpll_ng.h"
#include "snmp_mmap.h"
#define FPGA_SPLL_STAT 0x10006800
#define SPLL_MAGIC 0x5b1157a7
static struct spll_stats *spll_stats_p;
static struct pickinfo wrsSpllVersion_pickinfo[] = {
FIELD(wrsSpllVersion_s, ASN_OCTET_STR, commit_id),
FIELD(wrsSpllVersion_s, ASN_OCTET_STR, build_date),
};
struct wrsSpllVersion_s wrsSpllVersion_s;
/* change endianess of the string */
static void strncpy_e(char *d, char *s, int len)
{
int i;
int len_4;
uint32_t *s_i, *d_i;
s_i = (uint32_t *)s;
d_i = (uint32_t *)d;
len_4 = (len+3)/4; /* ceil len to word lenth (4) */
for (i = 0; i < len_4; i++)
d_i[i] = ntohl(s_i[i]);
}
time_t wrsSpllVersion_data_fill(void)
{
static time_t time_update;
time_t time_cur;
time_cur = time(NULL);
if (time_update
&& time_cur - time_update < WRSSPLLVERSION_CACHE_TIMEOUT) {
/* cache not updated, return last update time */
return time_update;
}
time_update = time_cur;
memset(&wrsSpllVersion_s, 0, sizeof(wrsSpllVersion_s));
if (!spll_stats_p) /* first time, map the fpga space */
spll_stats_p = create_map(FPGA_SPLL_STAT,
sizeof(*spll_stats_p));
if (!spll_stats_p) {
/* unable to mmap */
return time_update;
}
/* check magic number in SPLL stat memory */
if (spll_stats_p->magic != SPLL_MAGIC) {
/* wrong magic */
snmp_log(LOG_ERR,
"wrsSpllVersionGroup Wrong SPLL magic number\n");
return time_update;
}
/* check version of SPLL's stat structure, version fields are from
* version 2 */
if (spll_stats_p->ver == 2) {
int len;
strncpy_e(wrsSpllVersion_s.commit_id, spll_stats_p->commit_id, 32);
/* concatenate date and time */
strncpy_e(wrsSpllVersion_s.build_date, spll_stats_p->build_date, 16);
len = strnlen(wrsSpllVersion_s.build_date, 32);
wrsSpllVersion_s.build_date[len] = ' '; /* put space instead of null */
/* add time after added space at the end of string */
strncpy_e(&wrsSpllVersion_s.build_date[len + 1], spll_stats_p->build_time, 16 - 1);
}
/* there was an update, return current time */
return time_update;
}
#define GT_OID WRSSPLLVERSION_OID
#define GT_PICKINFO wrsSpllVersion_pickinfo
#define GT_DATA_FILL_FUNC wrsSpllVersion_data_fill
#define GT_DATA_STRUCT wrsSpllVersion_s
#define GT_GROUP_NAME "wrsSpllVersionGroup"
#define GT_INIT_FUNC init_wrsSpllVersionGroup
#include "wrsGroupTemplate.h"
#ifndef WRS_SPLL_VERSION_GROUP_H
#define WRS_SPLL_VERSION_GROUP_H
#define WRSSPLLVERSION_CACHE_TIMEOUT 5
#define WRSSPLLVERSION_OID WRS_OID, 7, 3, 1
struct wrsSpllVersion_s {
char commit_id[32];
char build_date[32];
};
extern struct wrsSpllVersion_s wrsSpllVersion_s;
time_t wrsSpllVersion_data_fill(void);
void init_wrsSpllVersionGroup(void);
#endif /* WRS_SPLL_VERSION_GROUP_H */
#include "wrsSnmp.h"
#include "snmp_shmem.h"
#include "wrsTemperatureGroup.h"
#include <libwr/config.h>
static struct pickinfo wrsTemperature_pickinfo[] = {
FIELD(wrsTemperature_s, ASN_INTEGER, temp_fpga),
......@@ -15,12 +16,31 @@ static struct pickinfo wrsTemperature_pickinfo[] = {
struct wrsTemperature_s wrsTemperature_s;
static void get_thresholds(void)
{
char *config_item;
/* check wether config fields exist, atoi has to have valid string */
config_item = libwr_cfg_get("SNMP_TEMP_THOLD_FPGA");
if (config_item)
wrsTemperature_s.temp_fpga_thold = atoi(config_item);
config_item = libwr_cfg_get("SNMP_TEMP_THOLD_PLL");
if (config_item)
wrsTemperature_s.temp_pll_thold = atoi(config_item);
config_item = libwr_cfg_get("SNMP_TEMP_THOLD_PSL");
if (config_item)
wrsTemperature_s.temp_psl_thold = atoi(config_item);
config_item = libwr_cfg_get("SNMP_TEMP_THOLD_PSR");
if (config_item)
wrsTemperature_s.temp_psr_thold = atoi(config_item);
}
time_t wrsTemperature_data_fill(void)
{
unsigned ii;
unsigned retries = 0;
static time_t time_update;
time_t time_cur;
static int first_run = 1;
time_cur = time(NULL);
if (time_update
......@@ -30,7 +50,12 @@ time_t wrsTemperature_data_fill(void)
}
time_update = time_cur;
memset(&wrsTemperature_s, 0, sizeof(wrsTemperature_s));
if (first_run) {
/* load thresholds only once */
get_thresholds();
first_run = 0;
}
while (1) {
ii = wrs_shm_seqbegin(hal_head);
......@@ -38,10 +63,6 @@ time_t wrsTemperature_data_fill(void)
wrsTemperature_s.temp_pll = hal_shmem->temp.pll >> 8;
wrsTemperature_s.temp_psl = hal_shmem->temp.psl >> 8;
wrsTemperature_s.temp_psr = hal_shmem->temp.psr >> 8;
wrsTemperature_s.temp_fpga_thold = hal_shmem->temp.fpga_thold;
wrsTemperature_s.temp_pll_thold = hal_shmem->temp.pll_thold;
wrsTemperature_s.temp_psl_thold = hal_shmem->temp.psl_thold;
wrsTemperature_s.temp_psr_thold = hal_shmem->temp.psr_thold;
retries++;
if (retries > 100) {
......
#include "wrsSnmp.h"
#include "wrsPtpDataTable.h"
#include "wrsSpllStatusGroup.h"
#include "wrsPortStatusTable.h"
#include "wrsTimingStatusGroup.h"
static struct pickinfo wrsTimingStatus_pickinfo[] = {
FIELD(wrsTimingStatus_s, ASN_INTEGER, wrsPTPStatus),
FIELD(wrsTimingStatus_s, ASN_INTEGER, wrsSoftPLLStatus),
FIELD(wrsTimingStatus_s, ASN_INTEGER, wrsSlaveLinksStatus),
FIELD(wrsTimingStatus_s, ASN_INTEGER, wrsPTPFramesFlowing),
};
struct wrsTimingStatus_s wrsTimingStatus_s;
/* store old values of ptp servo error counters and number of updates */
static uint32_t servo_updates_prev[WRS_MAX_N_SERVO_INSTANCES];
static uint32_t n_err_state_prev[WRS_MAX_N_SERVO_INSTANCES];
static uint32_t n_err_offset_prev[WRS_MAX_N_SERVO_INSTANCES];
static uint32_t n_err_delta_rtt_prev[WRS_MAX_N_SERVO_INSTANCES];
static uint32_t n_err_rxtx_deltas_prev[WRS_MAX_N_SERVO_INSTANCES];
/* store old values of TX and RX PTP counters to calculate delta */
static unsigned long ptp_tx_count_prev[WRS_N_PORTS];
static unsigned long ptp_rx_count_prev[WRS_N_PORTS];
time_t wrsTimingStatus_data_fill(void)
{
static time_t time_update; /* time of last update */
static int first_run = 1;
time_t time_ptp_data; /* time when wrsPtpDataTable was updated */
time_t time_spll; /* time when softPLL data was updated */
time_t time_port_status; /* time when port status table was updated */
unsigned int ptp_data_nrows; /* number of rows in wrsPtpDataTable */
unsigned int port_status_nrows; /* number of rows in PortStatusTable */
int i;
struct wrsPtpDataTable_s *pd_a;
struct wrsSpllStatus_s *s;
struct wrsPortStatusTable_s *p_a;
time_ptp_data = wrsPtpDataTable_data_fill(&ptp_data_nrows);
time_spll = wrsSpllStatus_data_fill();
time_port_status = wrsPortStatusTable_data_fill(&port_status_nrows);
if (ptp_data_nrows > WRS_MAX_N_SERVO_INSTANCES) {
snmp_log(LOG_ERR, "SNMP: wrsTimingStatusGroup too many PTP "
"instances(%d), only %d supported!\n",
WRS_MAX_N_SERVO_INSTANCES, ptp_data_nrows);
ptp_data_nrows = WRS_MAX_N_SERVO_INSTANCES;
}
if (port_status_nrows > WRS_N_PORTS) {
snmp_log(LOG_ERR, "SNMP: wrsTimingStatusGroup too many ports"
"(%d), only %d supported!\n",
WRS_N_PORTS, port_status_nrows);
port_status_nrows = WRS_N_PORTS;
}
if (time_ptp_data <= time_update
&& time_spll <= time_update
&& time_port_status <= time_update) {
/* cache not updated, return last update time */
return time_update;
}
time_update = time(NULL);
memset(&wrsTimingStatus_s, 0, sizeof(wrsTimingStatus_s));
/*********************************************************************\
|*************************** wrsPTPStatus ***************************|
\*********************************************************************/
/*
* Error when SPLL is in slave mode and at least one error counter in
* PTP increased or no PTP servo updates
*/
s = &wrsSpllStatus_s;
pd_a = wrsPtpDataTable_array;
wrsTimingStatus_s.wrsPTPStatus = WRS_PTP_STATUS_OK;
/* NOTE: only one PTP instance is used right now. When switchover is
* implemented it will change */
for (i = 0; i < ptp_data_nrows; i++) {
if (first_run == 1) {
/* don't report errors during first run */
wrsTimingStatus_s.wrsPTPStatus = WRS_PTP_STATUS_FR;
/* check if error */
} else if ((s->wrsSpllMode == WRS_SPLL_MODE_SLAVE)
&& ((pd_a[i].servo_updates == servo_updates_prev[i])
|| (pd_a[i].n_err_state != n_err_state_prev[i])
|| (pd_a[i].n_err_offset != n_err_offset_prev[i])
|| (pd_a[i].n_err_delta_rtt != n_err_delta_rtt_prev[i])
|| (pd_a[i].n_err_rxtx_deltas != n_err_rxtx_deltas_prev[i]))) {
wrsTimingStatus_s.wrsPTPStatus = WRS_PTP_STATUS_ERROR;
snmp_log(LOG_ERR, "SNMP: wrsPTPStatus "
"failed for instance %d\n", i);
/* don't break! Check all other PTP instances,
* to update all prev values */
}
/* update old values */
servo_updates_prev[i] = pd_a[i].servo_updates;
n_err_state_prev[i] = pd_a[i].n_err_state;
n_err_offset_prev[i] = pd_a[i].n_err_offset;
n_err_delta_rtt_prev[i] = pd_a[i].n_err_delta_rtt;
n_err_rxtx_deltas_prev[i] = pd_a[i].n_err_rxtx_deltas;
}
/*********************************************************************\
|************************* wrsSoftPLLStatus *************************|
\*********************************************************************/
/*
* DelCnt - warning if > 0
* seqstate has to be 8 (ready)
* mode = 1 (grand master) aligin state must be 6 (LOCKED)
* mode = 2 (free running master)
* mode = 3 (slave)
*/
s = &wrsSpllStatus_s;
if ( /* check if error */
s->wrsSpllSeqState != WRS_SPLL_SEQ_STATE_READY
|| (s->wrsSpllMode == WRS_SPLL_MODE_GRAND_MASTER && s->wrsSpllAlignState != WRS_SPLL_ALIGN_STATE_LOCKED)
|| ((s->wrsSpllMode != WRS_SPLL_MODE_GRAND_MASTER)
&& (s->wrsSpllMode != WRS_SPLL_MODE_MASTER)
&& (s->wrsSpllMode != WRS_SPLL_MODE_SLAVE))
) {
wrsTimingStatus_s.wrsSoftPLLStatus =
WRS_SOFTPLL_STATUS_ERROR;
} else if ( /* check if warning */
s->wrsSpllDelCnt > 0
) { /* warning */
wrsTimingStatus_s.wrsSoftPLLStatus =
WRS_SOFTPLL_STATUS_WARNING;
} else if ( /* check if any of fields equal to 0 or WARNING_NA */
s->wrsSpllMode == 0
) { /* warning NA */
wrsTimingStatus_s.wrsSoftPLLStatus =
WRS_SOFTPLL_STATUS_WARNING_NA;
} else if ( /* check if OK */
s->wrsSpllDelCnt == 0
&& s->wrsSpllSeqState == WRS_SPLL_SEQ_STATE_READY
&& ((s->wrsSpllMode == WRS_SPLL_MODE_GRAND_MASTER && s->wrsSpllAlignState == WRS_SPLL_ALIGN_STATE_LOCKED)
|| (s->wrsSpllMode == WRS_SPLL_MODE_MASTER)
|| (s->wrsSpllMode == WRS_SPLL_MODE_SLAVE))
) { /* OK */
wrsTimingStatus_s.wrsSoftPLLStatus =
WRS_SOFTPLL_STATUS_OK;
} else { /* probably bug in previous conditions,
* this should never happen */
wrsTimingStatus_s.wrsSoftPLLStatus =
WRS_SOFTPLL_STATUS_BUG;
}
/*********************************************************************\
|************************ wrsSlaveLinksStatus ************************|
\*********************************************************************/
/*
* ok when every slave port is up when switch is in slave mode
* and when every slave port is down when switch in master/grandmaster
* mode. Don't care about non-wr and auto ports.
*/
p_a = wrsPortStatusTable_array;
wrsTimingStatus_s.wrsSlaveLinksStatus = WRS_SLAVE_LINK_STATUS_OK;
for (i = 0; i < port_status_nrows; i++) {
/* warning N/A */
if (s->wrsSpllMode == 0
|| p_a[i].port_mode == 0
|| p_a[i].link_up == 0){
wrsTimingStatus_s.wrsSlaveLinksStatus =
WRS_SLAVE_LINK_STATUS_WARNING_NA;
}
/* error when slave port is down when switch is in slave mode
*/
if (s->wrsSpllMode == WRS_SPLL_MODE_SLAVE
&& (p_a[i].port_mode == WRS_PORT_STATUS_CONFIGURED_MODE_SLAVE)
&& (p_a[i].link_up == WRS_PORT_STATUS_LINK_DOWN)) {
wrsTimingStatus_s.wrsSlaveLinksStatus =
WRS_SLAVE_LINK_STATUS_ERROR;
snmp_log(LOG_ERR, "SNMP: wrsSlaveLinksStatus (slave) "
"failed for port %d\n", i);
}
/* error when slave port is up when switch is in master or
* grandmaster mode */
if (((s->wrsSpllMode == WRS_SPLL_MODE_GRAND_MASTER) || (s->wrsSpllMode == WRS_SPLL_MODE_MASTER))
&& (p_a[i].port_mode == WRS_PORT_STATUS_CONFIGURED_MODE_SLAVE)
&& (p_a[i].link_up == WRS_PORT_STATUS_LINK_UP)) {
wrsTimingStatus_s.wrsSlaveLinksStatus =
WRS_SLAVE_LINK_STATUS_ERROR;
snmp_log(LOG_ERR, "SNMP: wrsSlaveLinksStatus (master) "
"failed for port %d\n", i);
}
}
/*********************************************************************\
|************************ wrsPTPFramesFlowing ************************|
\*********************************************************************/
/*
* Check if PTP frames are flowing. Check only on ports that are
* non-wr and up.
*/
p_a = wrsPortStatusTable_array;
wrsTimingStatus_s.wrsPTPFramesFlowing = WRS_PTP_FRAMES_FLOWING_OK;
for (i = 0; i < port_status_nrows; i++) {
if (first_run == 1) {
/* don't report errors during first run */
wrsTimingStatus_s.wrsPTPFramesFlowing =
WRS_PTP_FRAMES_FLOWING_FR;
/* Error when there is no increase in TX/RX PTP counters.
Check only when port is non-wr and port is down */
} else if ((p_a[i].port_mode != WRS_PORT_STATUS_CONFIGURED_MODE_NON_WR)
&& (p_a[i].link_up == WRS_PORT_STATUS_LINK_UP)
&& ((ptp_tx_count_prev[i] == p_a[i].ptp_tx_count)
|| (ptp_rx_count_prev[i] == p_a[i].ptp_rx_count))) {
wrsTimingStatus_s.wrsPTPFramesFlowing =
WRS_PTP_FRAMES_FLOWING_ERROR;
snmp_log(LOG_ERR, "SNMP: wrsPTPFramesFlowing "
"failed for port %d\n", i);
/* warning N/A */
} else if (p_a[i].port_mode == 0
|| p_a[i].link_up == 0){
wrsTimingStatus_s.wrsPTPFramesFlowing =
WRS_PTP_FRAMES_FLOWING_WARNING_NA;
}
/* save current values */
ptp_tx_count_prev[i] = p_a[i].ptp_tx_count;
ptp_rx_count_prev[i] = p_a[i].ptp_rx_count;
}
first_run = 0;
/* there was an update, return current time */
return time_update;
}
#define GT_OID WRSTIMINGSTATUS_OID
#define GT_PICKINFO wrsTimingStatus_pickinfo
#define GT_DATA_FILL_FUNC wrsTimingStatus_data_fill
#define GT_DATA_STRUCT wrsTimingStatus_s
#define GT_GROUP_NAME "wrsTimingStatusGroup"
#define GT_INIT_FUNC init_wrsTimingStatusGroup
#include "wrsGroupTemplate.h"
#ifndef WRS_TIMING_STATUS_GROUP_H
#define WRS_TIMING_STATUS_GROUP_H
#define WRSTIMINGSTATUS_OID WRS_OID, 6, 2, 2
#define WRS_PTP_STATUS_OK 1 /* ok */
#define WRS_PTP_STATUS_ERROR 2 /* error */
#define WRS_PTP_STATUS_FR 6 /* first read, ok */
#define WRS_SOFTPLL_STATUS_OK 1 /* ok */
#define WRS_SOFTPLL_STATUS_ERROR 2 /* error */
#define WRS_SOFTPLL_STATUS_WARNING 3 /* warning */
#define WRS_SOFTPLL_STATUS_WARNING_NA 4 /* warning, at least one field is
* equal to 0 (NA),shouldn't happen in
* normal operation */
#define WRS_SOFTPLL_STATUS_BUG 5 /* warning */
#define WRS_SLAVE_LINK_STATUS_OK 1 /* ok */
#define WRS_SLAVE_LINK_STATUS_ERROR 2 /* error */
#define WRS_SLAVE_LINK_STATUS_WARNING_NA 4 /* warning, at least one field is
* equal to 0 (NA),shouldn't happen in
* normal operation */
#define WRS_PTP_FRAMES_FLOWING_OK 1 /* ok */
#define WRS_PTP_FRAMES_FLOWING_ERROR 2 /* error */
#define WRS_PTP_FRAMES_FLOWING_WARNING_NA 4 /* warning, at least one field is
* equal to 0 (NA),shouldn't happen in
* normal operation */
#define WRS_PTP_FRAMES_FLOWING_FR 6 /* ok, first run */
struct wrsTimingStatus_s {
int wrsPTPStatus;
int wrsSoftPLLStatus;
int wrsSlaveLinksStatus;
int wrsPTPFramesFlowing;
};
extern struct wrsTimingStatus_s wrsTimingStatus_s;
time_t wrsTimingStatus_data_fill(void);
void init_wrsTimingStatusGroup(void);
#endif /* WRS_TIMING_STATUS_GROUP_H */
......@@ -412,21 +412,6 @@ void show_temperatures(void)
term_cprintf(C_GREY, "PSR: ");
term_cprintf(C_WHITE, "%2.2f\n",
temp_sensors_local.psr/256.0);
term_cprintf(C_BLUE, "Temperature thresholds:\n");
term_cprintf(C_GREY, "FPGA: ");
term_cprintf(C_WHITE, "%5d ",
temp_sensors_local.fpga_thold);
term_cprintf(C_GREY, "PLL: ");
term_cprintf(C_WHITE, "%5d ",
temp_sensors_local.pll_thold);
term_cprintf(C_GREY, "PSL: ");
term_cprintf(C_WHITE, "%5d ",
temp_sensors_local.psl_thold);
term_cprintf(C_GREY, "PSR: ");
term_cprintf(C_WHITE, "%5d\n",
temp_sensors_local.psr_thold);
}
}
......
......@@ -240,10 +240,6 @@ struct dump_info hal_shmem_info [] = {
DUMP_FIELD(sensor_temp, temp.pll),
DUMP_FIELD(sensor_temp, temp.psl),
DUMP_FIELD(sensor_temp, temp.psr),
DUMP_FIELD(int, temp.fpga_thold),
DUMP_FIELD(int, temp.pll_thold),
DUMP_FIELD(int, temp.psl_thold),
DUMP_FIELD(int, temp.psr_thold),
};
/* map for fields of hal_port_state (hal_shmem.h) */
......@@ -505,6 +501,10 @@ struct dump_info servo_state_info [] = {
DUMP_FIELD_SIZE(char, servo_state_name, 32),
DUMP_FIELD(Integer64, skew),
DUMP_FIELD(Integer64, offset),
DUMP_FIELD(UInteger32, n_err_state),
DUMP_FIELD(UInteger32, n_err_offset),
DUMP_FIELD(UInteger32, n_err_delta_rtt),
DUMP_FIELD(UInteger32, n_err_rxtx_deltas),
};
#undef DUMP_STRUCT
......@@ -571,6 +571,8 @@ struct dump_info ppi_info [] = {
DUMP_FIELD_SIZE(char, cfg.port_name, 16),
DUMP_FIELD_SIZE(char, cfg.iface_name, 16),
DUMP_FIELD(int, cfg.ext),
DUMP_FIELD(UInteger32, ptp_tx_count),
DUMP_FIELD(UInteger32, ptp_rx_count),
};
int dump_ppsi_mem(struct wrs_shm_head *head)
......
......@@ -185,7 +185,6 @@ int hal_port_init_all()
{
int index;
struct wrs_shm_head *hal_shmem_hdr;
char *config_item;
pr_info("Initializing switch ports...\n");
......@@ -231,19 +230,6 @@ int hal_port_init_all()
/* We are done, mark things as valid */
hal_shmem->nports = hal_port_nports;
hal_shmem_hdr->version = HAL_SHMEM_VERSION;
/* check wether config fields exist, atoi has to have valid string */
config_item = libwr_cfg_get("SNMP_TEMP_THOLD_FPGA");
if (config_item)
hal_shmem->temp.fpga_thold = atoi(config_item);
config_item = libwr_cfg_get("SNMP_TEMP_THOLD_PLL");
if (config_item)
hal_shmem->temp.pll_thold = atoi(config_item);
config_item = libwr_cfg_get("SNMP_TEMP_THOLD_PSL");
if (config_item)
hal_shmem->temp.psl_thold = atoi(config_item);
config_item = libwr_cfg_get("SNMP_TEMP_THOLD_PSR");
if (config_item)
hal_shmem->temp.psr_thold = atoi(config_item);
/* Release processes waiting for HAL's to fill shm with correct data
When shm is opened successfully data in shm is still not populated!
Read data with wrs_shm_seqbegin and wrs_shm_seqend!
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment