Commit 5aa17763 authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'snmp-for-wrs'

parents 4c9d7912 956159be
#
# Automatically generated make config: don't edit
#
CONFIG_BR2_CONFIGFILE="wrs_release_br2_config"
# CONFIG_PTP_NOPOSIX is not set
CONFIG_PPSI=y
......@@ -2,5 +2,22 @@
# Automatically generated make config: don't edit
#
CONFIG_BR2_CONFIGFILE="wrs_release_br2_config"
# CONFIG_PTP_NOPOSIX is not ser
# CONFIG_PTP_NOPOSIX is not set
CONFIG_PPSI=y
#
# Local configuration
#
CONFIG_NTP_SERVER=""
CONFIG_DNS_SERVER=""
CONFIG_DNS_DOMAIN=""
CONFIG_REMOTE_SYSLOG_SERVER=""
CONFIG_REMOTE_SYSLOG_UDP=y
CONFIG_SNMP_TRAPSINK_ADDRESS=""
CONFIG_SNMP_TRAP2SINK_ADDRESS=""
CONFIG_SNMP_RO_COMMUNITY="public"
CONFIG_SNMP_RW_COMMUNITY="private"
CONFIG_WRS_LOG_HAL="daemon.info"
CONFIG_WRS_LOG_RTU="daemon.info"
CONFIG_WRS_LOG_PTP="daemon.info"
# CONFIG_KEEP_ROOTFS is not set
......@@ -35,7 +35,7 @@
@setchapternewpage off
@set update-month June 2014
@set update-month July 2014
@c the release name below is substituted at build time
@set release __RELEASE_GIT_ID__
......@@ -402,7 +402,7 @@ switches pre-configured for your network, we suggest you rebuild
the @i{firmware} archive after running @t{make menuconfig} to select
your own values
FIXME FIXME FIXME: Store kconfig and build info in the archive itself
@c FIXME FIXME FIXME: Store kconfig and build info in the archive itself
@c --------------------------------------------------------------------------
@node Rebuilding Parts
......@@ -1372,11 +1372,16 @@ The most important tools in @file{userspace/tools} are the following:
exists and includes a line of the form @t{ntpserver 192.168.16.1}.
@item shw_ver
Print informations about the SW & HW version of the WRS.
Print information about the SW & HW version of the WRS.
See also @ref{DIP Switch HW version}.
@item wrs_vlans
The tool allows to configure and unconfigure the VLAN settings
for each port and for the RTU daemon. The @t{--help} option
lists all configuration items of the tool.
@c FIXME: document lm32-vuart rtu_stat spll_dbg_proxy wr_management
@c FIXME: document wrsw_pstats wrsw_vlans
@c FIXME: document wrsw_pstats
@end table
Please note that to compile the applications and tools outside of the build
......@@ -1564,6 +1569,138 @@ For further details on the update procedure, please see
@t{/etc/init.d/wrs-boot-procedure} (in the source archive it is
distributed in @t{userspace/rootfs_override/}.
@c ##########################################################################
@node SNMP Support
@appendix SNMP Support
The White Rabbit Switch supports SNMP, although some more work is needed
in this respect. The default read-only ``community'' name is @t{private},
but you can change it from the @t{Kconfig} interface before building.
The default read-write community is @t{private}.
The switch supports all the standard information throught the @i{net-snmp}
installation. We'll remove some of the items in a later release, because
nobody wants to check running processes or disk space usage.
The additional, switch-specific information are in the
``enterprise.96.100 subtree, where @t{96} is CERN and @t{100} is White
Rabbit. The associatd MIB is in the directory @t{userspace/snmpd},
where related source files live as well.
@c ==========================================================================
@node The WRS MIB
@section The WRS MIB
This a summary of the available tables and scalars:
@table @code
@item 96.100.1
This is a simple scalar as a test. It is an integer value
that is incremented each time you access it. It can be used to
test basic functionality.
@item 96.100.2
Port statistics, as an SNMP table. The first column is the
name of each counter, and further columns represent interfaces
@t{wr0} through @t{wr17}. Each counters is shown in a table line,
as the number and names of the counters may change in the future.
@item 96.100.3
White Rabbit specific information. Subid @t{.1} is the global
items, and subid @t{.2} is a table with per-port items.
@item 96.100.4
Hardware, gateware and software versions. It currently
returns fake data, we'll complete it soon.
@end table
@b{Note:} due to a buglet of mine, there is an extra item at
the end of each table (@t{96.100.2} and @t{96.100.3.2}. It makes no
harm, so its removal is not high priority.
@c @b{Note:} due to a bug in management of 64-bit values in @i{net-snmp},
@c we are using a bad work-around in the code, that may cause wrong values
@c to be returned by other versions of the agent, where this bug is fixed.
the easiest way to retrieve the values is using @i{snmpwalk}, telling
it to access our MIB file in order to use symbolic names. Assuming
@t{wrs} is the DNS name for your White Rabbit Switch and @t{WR_SWITCH_SW}
is an environment variable pointing to this package:
@smallexample
snmpwalk -c public -v 2c wrs \
-m +${WR_SWITCH_SW})/userspace/snmpd/WR-SWITCH-MIB.txt \
1.3.6.1.4.1.96.100
@end smallexample
Using SNMP version 1 instead of 2c is fine as well, but you won't receive
the 64-bit values for slave/tracking information.
The output you will get back is something like the following:
@smallexample
WR-SWITCH-MIB::wrsScalar.0 = INTEGER: 2
WR-SWITCH-MIB::pstatsDescr.1 = STRING: TX Underrun
WR-SWITCH-MIB::pstatsDescr.2 = STRING: RX Overrun
WR-SWITCH-MIB::pstatsDescr.3 = STRING: RX Invalid Code
[...]
WR-SWITCH-MIB::pstatsDescr.38 = STRING: Forwarded
WR-SWITCH-MIB::pstatsDescr.39 = STRING: TRU Resp Valid
WR-SWITCH-MIB::pstatsWR0.1 = Counter32: 0
[...]
WR-SWITCH-MIB::pstatsWR17.38 = Counter32: 50819
WR-SWITCH-MIB::pstatsWR17.39 = Counter32: 0
WR-SWITCH-MIB::pstatsEntry.20 = Counter32: 0
WR-SWITCH-MIB::ppsiGrandmaterID.0 = Hex-STRING: 00 00 00 00 00 00 00 00
WR-SWITCH-MIB::ppsiOwnID.0 = Hex-STRING: 00 00 00 00 00 00 00 00
WR-SWITCH-MIB::ppsiMode.0 = INTEGER: unknown(0)
WR-SWITCH-MIB::ppsiServoState.0 = STRING:
WR-SWITCH-MIB::ppsiPhaseTracking.0 = INTEGER: not-tracking(0)
[...]
WR-SWITCH-MIB::portLink.14 = INTEGER: down(0)
WR-SWITCH-MIB::portLink.15 = INTEGER: up(1)
WR-SWITCH-MIB::portLink.16 = INTEGER: down(0)
[...]
WR-SWITCH-MIB::portPeer.18 = Hex-STRING: FF FF FF FF FF FF FF FF
WR-SWITCH-MIB::ppsiPort.5 = Hex-STRING: FF FF FF FF FF FF FF FF
WR-SWITCH-MIB::wrsVersionSw.0 = STRING: fake-v4.0-rc1
WR-SWITCH-MIB::wrsVersionGw1.0 = STRING: fake-7cce708
WR-SWITCH-MIB::wrsVersionGw2.0 = STRING: fake-5118070
WR-SWITCH-MIB::wrsVersionGw3.0 = STRING: fake-7efeb16
WR-SWITCH-MIB::wrsVersionHw1.0 = STRING: fake-3.30
WR-SWITCH-MIB::wrsVersionHw2.0 = STRING: fake-LX240T
@end smallexample
@c ==========================================================================
@node show-pstats
@section show-pstats
To visualize all port statistics in a single window, this package
includes the simple tool @t{userspace/snmpd/show-pstats}. It is
a Tk script, so you need to install @t{tk8.5} or any other version.
The script receives one or more host names (or IP addresses) on the command
line. They must refer to a switch (or switches) or the program fails like this:
@smallexample
laptopo% ./show-pstats morgana
Error in snmpwalk for host morgana
No log handling enabled - using stderr logging
.1.3.6.1.4.1.96.100.2.1.: Unknown Object Identifier (Sub-id not found: enterprises -> )
@end smallexample
If everything goes well, you'll get a window like the following one:
@center @image{show-pstats, 10cm,, show-pstats}
@c ##########################################################################
@node Schematics are Available
@appendix Schematics are Available
......
......@@ -12,7 +12,7 @@ WR_INSTALL_ROOT ?= $(WRS_OUTPUT_DIR)/images/wr
WRDEV_DIR ?= $(WRS_BASE_DIR)/..
# subdirectories we want to compile
SUBDIRS = libptpnetif mini-rpc libswitchhw wrsw_hal wrsw_rtud tools
SUBDIRS = libptpnetif mini-rpc libswitchhw wrsw_hal wrsw_rtud tools snmpd
# all variables are exported
export
......
#!/bin/sh
# Log to syslog at daemon level. Amd log source address (-a)
snmpd -Lsd -p /var/run/snmpd.pid -a -c /wr/etc/snmpd.conf
\ No newline at end of file
snmpd -Lsd -p /var/run/snmpd.pid -a -c /wr/etc/snmpd.conf
......@@ -16,3 +16,6 @@ authtrapenable 1
#rocommunity CONFIG_SNMP_RO_COMMUNITY
#rwcommunity CONFIG_SNMP_RW_COMMUNITY
# This is picked from /usr/lib, and the first argument is said to be the
# "init function", but it is not, because the daemon adds a leading "init_"
dlmod wrsSnmp /wr/lib/wrsSnmp.so
SNMP_BUILD := $(wildcard $(WRS_OUTPUT_DIR)/build/buildroot-2*)
SNMP_BUILD := $(wildcard $(SNMP_BUILD)/output/build/netsnmp-*)
NET_SNMP_CONFIG ?= $(SNMP_BUILD)/net-snmp-config
CC = $(CROSS_COMPILE)gcc
LD = $(CROSS_COMPILE)ld
# defer running "net-snmp-config --cflags" so it is visible in make output
CFLAGS += -fPIC -Wall $$($(NET_SNMP_CONFIG) --cflags | sed s,-I/usr/include,,)
LDFLAGS = -shared $$($(NET_SNMP_CONFIG) --ldflags)
CFLAGS += -Iinclude -I../ppsi/include -I../ppsi/arch-wrs/include -I../mini-rpc
CFLAGS += -DWRS_WITH_SNMP_HACKISH_LOG=0
SHLIB = wrsSnmp.so
SOURCES = init.c wrsScalar.c wrsPstats.c wrsPpsi.c wrsVersion.c
OBJECTS = $(SOURCES:.c=.o)
all: $(SHLIB)
$(SHLIB): $(OBJECTS)
$(CC) $(LDFLAGS) $^ -o $@
clean:
rm -f $(SHLIB) $(OBJECTS)
install:
install -d $(WR_INSTALL_ROOT)/lib
install *.so $(WR_INSTALL_ROOT)/lib
The initial version of wrsScalar.c and wrsScalar.h is generated by running
export BUILD_DIR="$WRS_OUTPUT_DIR/build/buildroot-2011.11/output/build"
export MIBDIRS=$BUILD_DIR/netsnmp-5.6.1.1/mibs
And then this "intuitive" command:
export MIBS=./WR-SWITCH-MIB.txt
$BUILD_DIR/netsnmp-5.6.1.1/local/mib2c \
-I $BUILD_DIR/netsnmp-5.6.1.1/local \
-c mib2c.scalar.conf \
wrsScalar
Clearly, if you rename the item, the code must be completely rewritten
(and I already did it once).
Pstats code, on the other hand, is based on what ifTable does in the
real snmpd. i.e., no autogeneration was used.
This is one option I tried, but the result was too complex:
export MIBS=./WR-SWITCH-MIB.txt
$BUILD_DIR/netsnmp-5.6.1.1/local/mib2c \
-I $BUILD_DIR/netsnmp-5.6.1.1/local \
-I $BUILD_DIR/netsnmp-5.6.1.1/local/mib2c-conf.d \
-c mib2c.mfd.conf \
pstatsTable
This one spits out a single file, but again too complex for me:
export MIBS=./WR-SWITCH-MIB.txt
$BUILD_DIR/netsnmp-5.6.1.1/local/mib2c \
-I $BUILD_DIR/netsnmp-5.6.1.1/local \
-I $BUILD_DIR/netsnmp-5.6.1.1/local/mib2c-conf.d \
-c mib2c.raw-table.conf \
pstatsTable
Using "mib2c.create-dataset.conf" is even worse, becahse the dataset
is static and hidden in some obscure place, I can't change it after
creation.
With the current code base, I properly get the counters:
tornado% snmpwalk -c public -v 2c wrs SNMPv2-SMI::enterprises.96.100 | wc -l
743
The numeric OID for WRS is:
.1.3.6.1.4.1.96.100
The OID for counters is:
.1.3.6.1.4.1.96.100.2.1
Then, column 1 is the counter names, and colomn N+2 is the counters for
port wrN (0..17). Column M+1 is for port M as written on the device (1..18).
Example: get counter 18 (line 19):
snmpwalk -On -c public -v 2c wrs SNMPv2-SMI::enterprises.96.100.2.1 | \
grep '2\.1\..*\.19 ='
.1.3.6.1.4.1.96.100.2.1.1.19 = STRING: "TX Frames"
.1.3.6.1.4.1.96.100.2.1.2.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.3.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.4.19 = Counter32: 0
.1.3.6.1.4.1.96.100.2.1.5.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.6.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.7.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.8.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.9.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.10.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.11.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.12.19 = Counter32: 1057
.1.3.6.1.4.1.96.100.2.1.13.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.14.19 = Counter32: 0
.1.3.6.1.4.1.96.100.2.1.15.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.16.19 = Counter32: 1025
.1.3.6.1.4.1.96.100.2.1.17.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.18.19 = Counter32: 38
.1.3.6.1.4.1.96.100.2.1.19.19 = Counter32: 38
You can get a symbolic readout by forcing the tool to access the
local WR-SWITCH-MIB.txt. So we can get all counters for port WR14 like
this:
snmpwalk -m $WR_SWITCH_SW/userspace/snmpd/WR-SWITCH-MIB.txt \
-c public -v 2c wrs 1.3.6.1.4.1.96.100.2 | \
grep WR14
This diff is collapsed.
/*
* A global (library-wide) init function to register several things
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
/* The sub-init functions */
#include "wrsSnmp.h"
FILE *wrs_logf; /* for the local-hack messages */
void init_wrsSnmp(void)
{
init_wrsScalar();
init_wrsPstats();
init_wrsPpsi();
init_wrsVersion();
}
/* open a file or a pipe, so I test with files, and run with pipes */
FILE *wrs_fpopen(char *file_or_pipe, char *mode)
{
if (file_or_pipe[0] == '|')
return popen(file_or_pipe + 1, mode);
else
return fopen(file_or_pipe, mode);
}
void wrs_fpclose(FILE *f, char *file_or_pipe)
{
if (file_or_pipe[0] == '|')
pclose(f);
else
fclose(f);
}
#!/usr/bin/wish
# Allow user override
if [catch "set cmd \"\$env(SHOWPS_CMD)\""] {
set cmd "snmpwalk -c public -v 2c -On -Oq HOST .1.3.6.1.4.1.96.100.2.1"
}
if ![llength $argv] {
puts stderr "$argv0: Pass IP number of names of switch(es) as arguments"
exit 1
}
# A procedure to update the window's content
proc updatew {wname} {
global w
set new [expr ![llength [winfo children $wname]]]
if $new {
grid [label $wname.name -text "CTR NAME" -fg blue] -row 0 -column 1
for {set i 0; set c 2} {$i < 18} {incr i; incr c} {
grid [label $wname.wr$i -text "WR$i" -fg blue] -row 0 -column $c
}
}
# open a file according to the command given
set F [open "| $w($wname:cmd)" r]
while {[gets $F str] > 0} {
foreach {oid value} $str {
# remove the leading part
regsub ".1.3.6.1.4.1.96.100.2.1." $oid "" oid
# extract column and row
foreach {col row} [split $oid .] {
if ![string length $row] break
set name $wname.${col}_${row}
if $new {
label $name
}
set width "-width 8"
if {$col == 1} {set width ""}
eval $name config -text \"$value\" $width
grid $name -row $row -column $col
}
}
}
if [catch "close $F" message] {
puts stderr "Error in snmpwalk for host $w($wname:host)"
puts stderr $message
exit 1
}
# our cache is 5 seconds: make sure it changed
after 6000 "updatew $wname"
}
foreach host $argv {
# turn "10.0.0.1" into "10_0_0_1"
regsub -all "\\\." $host "_" win
wm withdraw .
toplevel .$win
# create the command name. Use "w" array, in case we need more info later
regsub "HOST" $cmd $host w(.$win:cmd)
set w(.$win:host) $host
# get the first batch of items and schedule the next
updatew .$win
wm deiconify .$win
}
This diff is collapsed.
/*
* White Rabbit Switch pstats table
* Using the netsnmp iterator, like in tcpTable
* Alessandro Rubini for CERN, 2014
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/agent/auto_nlist.h>
#include "wrsSnmp.h"
#define PSTATS_CACHE_TIMEOUT 5 /* seconds */
/* Our structure for caching data */
#define PSTATS_N_COUNTERS 39
#define PSTATS_N_PORTS 18 /* this hardwired in the mib too */
struct pstats_per_port {
uint32_t val[PSTATS_N_COUNTERS];
};
static struct pstats_global_data {
struct pstats_per_port port[PSTATS_N_PORTS];
char *pname[PSTATS_N_PORTS];
} pstats_global_data;
static char *pstats_names[] = {
[0] = "TX Underrun",
[1] = "RX Overrun",
[2] = "RX Invalid Code",
[3] = "RX Sync Lost",
[4] = "RX Pause Frames",
[5] = "RX Pfilter Dropped",
[6] = "RX PCS Errors",
[7] = "RX Giant Frames",
[8] = "RX Runt Frames",
[9] = "RX CRC Errors",
[10] = "RX Pclass 0",
[11] = "RX Pclass 1",
[12] = "RX Pclass 2",
[13] = "RX Pclass 3",
[14] = "RX Pclass 4",
[15] = "RX Pclass 5",
[16] = "RX Pclass 6",
[17] = "RX Pclass 7",
[18] = "TX Frames",
[19] = "RX Frames",
[20] = "RX Drop RTU Full",
[21] = "RX PRIO 0",
[22] = "RX PRIO 1",
[23] = "RX PRIO 2",
[24] = "RX PRIO 3",
[25] = "RX PRIO 4",
[26] = "RX PRIO 5",
[27] = "RX PRIO 6",
[28] = "RX PRIO 7",
[29] = "RTU Valid",
[30] = "RTU Responses",
[31] = "RTU Dropped",
[32] = "FastMatch: Priority",
[33] = "FastMatch: FastForward",
[34] = "FastMatch: NonForward",
[35] = "FastMatch: Resp Valid",
[36] = "FullMatch: Resp Valid",
[37] = "Forwarded",
[38] = "TRU Resp Valid"
};
/* FIXME: build error if ARRAY_SIZE(pstats_names) != PSTATS_N_COUNTERS */
static int
wrsPstats_handler(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
netsnmp_request_info *request;
netsnmp_variable_list *requestvb;
netsnmp_table_request_info *table_info;
struct pstats_global_data *data = &pstats_global_data; /* a shorter name */
int counter;
int wrport;
uint32_t *c;
logmsg("%s: %i\n", __func__, __LINE__);
switch (reqinfo->mode) {
case MODE_GET:
for (request=requests; request; request=request->next) {
requestvb = request->requestvb;
logmsg("%s: %i\n", __func__, __LINE__);
/* our "context" is the counter number; "subid" the column i.e. the port */
counter = (intptr_t)netsnmp_extract_iterator_context(request);
table_info = netsnmp_extract_table_info(request);
wrport = table_info->colnum - 2; /* port is 0-based and position 1 is the string */
logmsg("counter %i, port %i\n", counter, wrport);
if (wrport < 0) {
char *s = pstats_names[counter];
snmp_set_var_typed_value(requestvb, ASN_OCTET_STR, s, strlen(s));
continue;
}
/* While most tables do "switch(subid)" we'd better just index */
c = &data->port[wrport].val[counter];
snmp_set_var_typed_value(requestvb, ASN_COUNTER,
(u_char *)c, sizeof(*c));
}
break;
case MODE_GETNEXT:
case MODE_GETBULK:
case MODE_SET_RESERVE1:
case MODE_SET_RESERVE2:
case MODE_SET_ACTION:
case MODE_SET_COMMIT:
case MODE_SET_FREE:
case MODE_SET_UNDO:
/* unsupported mode */
break;
default:
/* unknown mode */
break;
}
return SNMP_ERR_NOERROR;
}
static netsnmp_variable_list *
wrsPstats_next_entry( void **loop_context,
void **data_context,
netsnmp_variable_list *index,
netsnmp_iterator_info *data)
{
intptr_t i;
/* create the line ID from counter number */
i = (intptr_t)*loop_context;
//logmsg("%s: %i (i = %i)\n", __func__, __LINE__, i);
if (i >= PSTATS_N_COUNTERS)
return NULL; /* no more */
i++;
/* Create the row OID: only the counter index */
snmp_set_var_value(index, (u_char*)&i, sizeof(i));
/* Set the data context (1..39 -> 0..38) */
*data_context = (void *)(intptr_t)(i - 1);
/* and set the loop context for the next iteration */
*loop_context = (void *)i;
return index;
}
static netsnmp_variable_list *
wrsPstats_first_entry(void **loop_context,
void **data_context,
netsnmp_variable_list *index,
netsnmp_iterator_info *data)
{
logmsg("%s: %i\n", __func__, __LINE__);
/* reset internal position, so "next" is "first" */
*loop_context = (void*)0; /* first counter */
return wrsPstats_next_entry(loop_context, data_context, index, data);
}
static int
wrsPstats_load(netsnmp_cache *cache, void *vmagic)
{
FILE *f;
char fname[32];
int wrport, counter;
struct pstats_per_port *stat;
for (wrport = 0; wrport < PSTATS_N_PORTS; wrport++) {
sprintf(fname, "/proc/sys/pstats/port%i", wrport);
stat = pstats_global_data.port + wrport;
f = fopen(fname, "r");
if (!f) {
memset(stat, 0x7f, sizeof(*stat));
continue;
}
for (counter = 0; counter < PSTATS_N_COUNTERS; counter++) {
if (fscanf(f, "%u", stat->val + counter) != 1)
stat->val[counter] = 0xffffff;
}
fclose(f);
}
//dumpstruct(logf, "global data", &pstats_global_data, sizeof(pstats_global_data));
return 0;
}
void
init_wrsPstats(void)
{
const oid wrsPstats_oid[] = { WRS_OID, 2 };
netsnmp_table_registration_info *table_info;
netsnmp_iterator_info *iinfo;
netsnmp_handler_registration *reginfo;
table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
if (!table_info)
return;
/* Add indexes: we only use one integer OID member as line identifier */
netsnmp_table_helper_add_indexes(table_info, ASN_INTEGER, 0);
table_info->min_column = 1;
table_info->max_column = 1 + PSTATS_N_PORTS;
/* Iterator info */
iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
if (!iinfo)
return; /* free table_info? */
iinfo->get_first_data_point = wrsPstats_first_entry;
iinfo->get_next_data_point = wrsPstats_next_entry;
iinfo->table_reginfo = table_info;
/* register the table */
reginfo = netsnmp_create_handler_registration("wrsPstats",
wrsPstats_handler,
wrsPstats_oid, OID_LENGTH(wrsPstats_oid),
HANDLER_CAN_RONLY);
netsnmp_register_table_iterator(reginfo, iinfo);
/* and create a local cache */
netsnmp_inject_handler(reginfo,
netsnmp_get_cache_handler(PSTATS_CACHE_TIMEOUT,
wrsPstats_load, NULL,
wrsPstats_oid, OID_LENGTH(wrsPstats_oid)));
}
/*
* Note: this file originally auto-generated by mib2c using
* : mib2c.scalar.conf 17798 2009-10-27 06:44:54Z magfr $
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "wrsSnmp.h"
#include <stdint.h>
static uint32_t fakeStatValue;
static int
handle_wrsScalarOne(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
int ret;
/*
* We are never called for a GETNEXT if it's registered as a
* "instance", as it's "magically" handled for us.
*/
/*
* a instance handler also only hands us one request at a time, so
* we don't need to loop over a list of requests; we'll only get one.
*/
switch (reqinfo->mode) {
case MODE_GET:
fakeStatValue++;
snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
&fakeStatValue,
sizeof(fakeStatValue));
break;
/*
* SET REQUEST
*
* multiple states in the transaction. See:
* http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
*/
case MODE_SET_RESERVE1:
/*
* or you could use netsnmp_check_vb_type_and_size instead
*/
ret = netsnmp_check_vb_type(requests->requestvb, ASN_INTEGER);
if (ret != SNMP_ERR_NOERROR) {
netsnmp_set_request_error(reqinfo, requests, ret);
}
break;
case MODE_SET_RESERVE2:
case MODE_SET_FREE:
break;
case MODE_SET_ACTION:
/* FIXME: set... */
break;
case MODE_SET_COMMIT:
/* FIXME: commit */
break;
case MODE_SET_UNDO:
/* FIXME: undo */
break;
default:
/*
* we should never get here, so this is a really bad error
*/
snmp_log(LOG_ERR, "unknown mode (%d) in handle_wrsScalarOne\n",
reqinfo->mode);
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
/** Initializes the wrsScalar module */
void
init_wrsScalar(void)
{
const oid wrsScalarOne_oid[] = { WRS_OID, 1 };
DEBUGMSGTL(("wrsScalar", "Initializing\n"));
netsnmp_register_scalar(netsnmp_create_handler_registration
("wrsScalarOne", handle_wrsScalarOne,
wrsScalarOne_oid,
OID_LENGTH(wrsScalarOne_oid),
HANDLER_CAN_RWRITE));
}
#ifndef WRS_SNMP_H
#define WRS_SNMP_H
/*
* local hack: besides the file pointer, that is there anyways,
* everything else is not actually built if WRS_WITH_SNMP_HACKISH_LOG
* is set 0 at build time (currently the default)
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
extern FILE *wrs_logf;
static inline int logmsg(const char *fmt, ...)
{
va_list args;
int ret;
if (WRS_WITH_SNMP_HACKISH_LOG) {
if (!wrs_logf) {
char *fname = getenv("WRS_SNMP_LOGFILE");
if (!fname)
fname = "/dev/console";
wrs_logf = fopen(fname, "w");
}
if (!wrs_logf)
return 0;
va_start(args, fmt);
ret = vfprintf(wrs_logf, fmt, args);
va_end(args);
return ret;
} else {
return 0;
}
}
static inline int dumpstruct(FILE *dest, char *name, void *ptr, int size)
{
int ret = 0, i;
unsigned char *p = ptr;
if (WRS_WITH_SNMP_HACKISH_LOG) {
ret = fprintf(dest, "dump %s at %p (size 0x%x)\n",
name, ptr, size);
for (i = 0; i < size; ) {
ret += fprintf(dest, "%02x", p[i]);
i++;
ret += fprintf(dest, i & 3 ? " " : i & 0xf ? " " : "\n");
}
if (i & 0xf)
ret += fprintf(dest, "\n");
}
return ret;
}
/* end local hack */
/* be safe, in case some other header had them slightly differntly */
#undef container_of
#undef offsetof
#undef ARRAY_SIZE
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define WRS_N_PORTS 18
/* Scalar is just a stupid thing, but let's keep it */
extern void init_wrsScalar(void);
/* Real stuff follows */
extern void init_wrsPstats(void);
extern void init_wrsPpsi(void);
extern void init_wrsVersion(void);
#define WRS_OID 1, 3, 6, 1, 4, 1, 96, 100
/* Open a file or a pipe according to name[0] (e.g. "|wr_mon", "/tmp/log") */
extern FILE *wrs_fpopen(char *file_or_pipe, char *mode);
extern void wrs_fpclose(FILE *f, char *file_or_pipe);
#endif /* WRS_SNMP_H */
/*
* White Rabbit Switch versions. This is a series of scalars,
* so I used the approach of disman/expr/expScalars.c
*
* Alessandro Rubini for CERN, 2014
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include <net-snmp/agent/auto_nlist.h>
#include "wrsSnmp.h"
/* Our structure for caching data */
#define VERSION_N_STRINGS 6 /* sw, 3 gw, 2 hw */
static struct wrs_version {
char *value[VERSION_N_STRINGS];
} wrs_version;
static int version_group(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
oid obj; /* actually, an integer, i.e. the final index */
char *s;
switch (reqinfo->mode) {
case MODE_GET:
/* "- 2" because last is 0 for all scalars, I suppose */
obj = requests->requestvb->name[
requests->requestvb->name_length - 2
];
s = wrs_version.value[obj - 1];
snmp_set_var_typed_value(requests->requestvb,
ASN_OCTET_STR, s, strlen(s));
break;
default:
snmp_log(LOG_ERR, "unknown mode (%d) in wrs version group\n",
reqinfo->mode);
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
void
init_wrsVersion(void)
{
const oid wrsVersion_oid[] = { WRS_OID, 4 };
netsnmp_handler_registration *hreg;
/* FIXME.... */
wrs_version.value[0] = "fake-v4.0-rc1";
wrs_version.value[1] = "fake-7cce708";
wrs_version.value[2] = "fake-5118070";
wrs_version.value[3] = "fake-7efeb16";
wrs_version.value[4] = "fake-3.30";
wrs_version.value[5] = "fake-LX240T";
/* do the registration */
hreg = netsnmp_create_handler_registration(
"wrsVersion", version_group,
wrsVersion_oid, OID_LENGTH(wrsVersion_oid),
HANDLER_CAN_RONLY);
netsnmp_register_scalar_group(
hreg, 1 /* min */, VERSION_N_STRINGS /* max */);
}
......@@ -11,8 +11,12 @@
#include "hal_client.h"
#define SHOW_GUI 0
#define SHOW_STATS 1
#define SHOW_GUI 0
#define SHOW_STATS 1
#define SHOW_SNMP_PORTS 2
#define SHOW_SNMP_GLOBALS 3
int mode = SHOW_GUI;
hexp_port_list_t port_list;
......@@ -36,7 +40,7 @@ void init(int usecolor)
halexp_query_ports(&port_list);
}
void show_ports(int mode)
void show_ports(void)
{
int i, j;
time_t t;
......@@ -55,12 +59,12 @@ void show_ports(int mode)
hexp_port_state_t state;
snprintf(if_name, 10, "wr%d", i);
for(j=0;j<port_list.num_ports;j++)
if(!strcmp(port_list.port_names[j], if_name)) { found = 1; break; }
if(!found) continue;
halexp_get_port_state(&state, if_name);
term_cprintf(C_WHITE, " %-5s: ", if_name);
......@@ -101,9 +105,9 @@ void show_ports(int mode)
snprintf(if_name, 10, "wr%d", i);
for(j=0;j<port_list.num_ports;j++)
if(!strcmp(port_list.port_names[j], if_name)) { found = 1; break; }
if(!found) continue;
halexp_get_port_state(&state, if_name);
printf("port:%s ", if_name);
printf("lnk:%d ", state.up ? 1:0);
......@@ -112,9 +116,29 @@ void show_ports(int mode)
}
printf("\n");
}
else if (mode == SHOW_SNMP_PORTS) {
for(i=0; i<18; ++i) {
char if_name[10], found = 0;
hexp_port_state_t state;
printf("PORT %i\n", i);
snprintf(if_name, 10, "wr%d", i);
for(j=0;j<port_list.num_ports;j++)
if(!strcmp(port_list.port_names[j], if_name)) { found = 1; break; }
if(!found) continue;
halexp_get_port_state(&state, if_name);
printf("linkup: %d\n", state.up ? 1:0);
printf("mode: %d\n", state.mode==HEXP_PORT_MODE_WR_SLAVE
? 0 : 1);
printf("locked: %d\n", state.is_locked ? 1:0);
printf("peer_id: ff:ff:ff:ff:ff:ff:ff:ff\n"); /* FIXME */
}
}
}
void show_servo(int mode)
void show_servo(void)
{
ptpdexp_sync_state_t ss;
......@@ -196,44 +220,63 @@ void show_servo(int mode)
printf("setp:%lld ", ss.cur_setpoint);
printf("ucnt:%llu ", ss.update_count);
printf("\n");
} else if (mode == SHOW_SNMP_GLOBALS) {
if(!ss.valid)
return;
/* This is oh so similar to the above, but by lines */
printf("gm_id: f0:f0:f0:f0:f0:f0:f0:f0\n"); /* FIXME */
printf("clock_id: f1:f1:f1:f1:f1:f1:f1:f1\n"); /* FIXME */
printf("mode: 9999\n"); /* FIXME */
printf("servo_state: %s\n", ss.slave_servo_state);
printf("tracking: %i\n", ss.tracking_enabled ? 1 : 0);
printf("source: %s\n", ss.sync_source);
printf("ck_offset: %lli\n", ss.cur_offset);
printf("skew: %li\n", (long)ss.cur_skew);
printf("rtt: %lli\n", ss.mu);
printf("llength: %li\n", (long)(ss.delay_ms/1e12 * 300e6 / 1.55));
printf("servo_upd: %lli\n", ss.update_count);
}
}
int track_onoff = 1;
void show_screen()
void show_all()
{
term_clear();
term_pcprintf(1, 1, C_BLUE, "WR Switch Sync Monitor v 1.0 [q = quit]");
show_ports(SHOW_GUI);
show_servo(SHOW_GUI);
fflush(stdout);
}
void show_stats()
{
show_ports(SHOW_STATS);
show_servo(SHOW_STATS);
if (mode == SHOW_GUI) {
term_clear();
term_pcprintf(1, 1, C_BLUE,
"WR Switch Sync Monitor v 1.0 [q = quit]");
}
show_ports();
show_servo();
fflush(stdout);
}
int main(int argc, char *argv[])
{
int opt;
int stats = 0;
int usecolor = 1;
while((opt=getopt(argc, argv, "sb")) != -1)
while((opt=getopt(argc, argv, "sbgp")) != -1)
{
switch(opt)
{
case 's':
stats = 1;
mode = SHOW_STATS;
break;
case 'b':
usecolor = 0;
break;
case 'g':
mode = SHOW_SNMP_GLOBALS;
init(0);
show_all();
exit(0);
case 'p':
mode = SHOW_SNMP_PORTS;
init(0);
show_all();
exit(0);
default:
fprintf(stderr, "Unrecognized option.\n");
break;
......@@ -260,8 +303,10 @@ int main(int argc, char *argv[])
track_onoff);
}
}
if(stats) show_stats();
else show_screen();
show_all();
/* If we got broken pipe or anything, exit */
if (ferror(stdout))
exit(1);
}
term_restore();
setlinebuf(stdout);
......
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