|
NetBurner 3.5.8
PDF Version |
Example Path: examples/snmp/TableRead
This example demonstrates a read-only SNMP table MIB on a NetBurner device. Eight simulated sensors are registered with the SNMP agent at startup, and a background task in UserMain writes fresh readings into the per-row data structs every few seconds. SNMP GET / GET-NEXT / walk requests pick up the latest values automatically; nothing about the SNMP tree is ever re-registered after startup.
Use this pattern when you have repeating measured data (one row per sensor, per RS-485 board, per port) that an external manager only ever needs to read. Read-only access is enforced simply by what we never register: the code uses AddSnmpEntry to expose each column for reading, and never calls AddSnmpWriteEntry.
The CustomMIB example shows how to wire up individual scalars with SNMPREADFUNC(name, "oid.literal", type, fn, mask). That macro is fine for true singletons – read community, write community, trap destination – but it does not scale:
For a device polling, say, 12 RS-485 boards x 12 parameters each (~150 OIDs), the macro form forces 150+ hand-written functions and macro lines – repetitive and impossible to drive from data.
The SNMP table is the standard idiom for "N instances of the same columns". The NetBurner runtime exposes the underlying registration APIs that the macro wraps:
| API | Purpose |
|---|---|
| AddSnmpEntry(subid, prefix, len, suffix, fn, data_el, m) | Register one column of one row |
| AddSnmpWriteEntry(...) | Register a writable column |
| SnmpRemoveTableElement(prefix, data_el) | Remove a row at runtime |
The handler signatures carry the context the macro form lacks:
subid – column number within the row
One handler serves every OID in the table.** Registering N rows is a simple loop; updating values is just writing into a struct.
Keep the scalar macros for true singletons that have no natural index:
Use a table for any repeating shape (rows of sensors, ports, boards, sessions, connections). This example uses one read-only scalar (sensorTableNumber – the row count) plus a full sensor table to illustrate both styles side by side.
Defined in mib/NburnSensorTable_Mib.txt and implemented in src/sensor.cpp.
Scalar:
Table (under 1.3.6.1.4.1.8174.20):
Columns within sensorEntry:
SNMP support is enabled by the predef-overload.h file located at:
overload/nbrtos/include/predef-overload.h
which contains:
#define ENABLE_SNMP (1)
The table is built around three pieces in src/sensor.cpp, exposed via src/sensor.h:
This is the model recommended for systems that poll N similar data sources: build the tree once, then keep updating the row structs.
The CLI ('D' to dump the SNMP tree, 'T' to send a trap, logout to end the session) lives in src/commands.cpp, exposed through a single public function StartCommandLine() in src/commands.h. The trap PDU itself is built in src/trap.cpp; commands.cpp includes trap.h and calls SendTestTrap() when the user types 'T'.
The web UI in html/index.html and src/web.cpp is a different view of the same data: a single HTML page with a <meta http-equiv="refresh" content="5"> tag so the browser re-fetches every 5 seconds (matching the device's polling cadence). The page contains:
Encapsulation: the SensorData struct stays private to sensor.cpp; web.cpp only sees the WriteSensorTableRows(int sock) declaration in sensor.h. This keeps the row-data layout free to evolve without touching the web layer.
Connect via serial console or Telnet to port 23. Log in with any username and password that are not identical (e.g., user: "hello", pass: "world").
The NetBurner SDK ships a portable net-snmp 5.9.1 distribution at:
C:\nburn\snmp\net-snmp\\endiskip
containing snmpget.exe, snmpset.exe, snmpwalk.exe, snmptable.exe, snmptranslate.exe, etc. The standard MIBs (RFC1155-SMI, RFC1213-MIB, SNMPv2-SMI, SNMPv2-TC, ...) live alongside the per-example MIBs at:
C:\nburn\snmp\mibs\\endiskip
If you copy this example's mib\NburnSensorTable_Mib.txt into that mibs folder, the tools will resolve symbolic names like sensorTableNumber.0, sensorTemperature.5, sensorPressure.7, etc. from NBURNSENSOR-MIB. Without the copy you can still use full numeric OIDs and everything works.
All examples below use the example IP address 192.168.1.100. Substitute your NetBurner's actual IP (run nbdiscovery if you do not know it).
Windows cmd:
set PATH=C:\nburn\snmp\net-snmp;PATH% set MIBDIRS=C:\nburn\snmp\mibs set MIBS=ALL
PowerShell:
$env:PATH = "C:\nburn\snmp\net-snmp;$env:PATH" $env:MIBDIRS = "C:\nburn\snmp\mibs" $env:MIBS = "ALL"
Bash (Git Bash / MSYS):
export PATH="/c/nburn/snmp/net-snmp:$PATH" export MIBDIRS="/c/nburn/snmp/mibs" export MIBS="ALL"
After that the -M / -m flags below can be omitted. All examples include them explicitly so they work even without the env vars.
The row count scalar:
snmpget -v2c -c public -M C:\nburn\snmp\mibs -m ALL 192.168.1.100 sensorTableNumber.0
Expected output:
NBURNSENSOR-MIB::sensorTableNumber.0 = INTEGER: 8
Pick specific cells (column.row syntax):
snmpget -v2c -c public -M C:\nburn\snmp\mibs -m ALL 192.168.1.100 sensorName.3 snmpget -v2c -c public -M C:\nburn\snmp\mibs -m ALL 192.168.1.100 sensorTemperature.5 sensorPressure.7 snmpget -v2c -c public -M C:\nburn\snmp\mibs -m ALL 192.168.1.100 sensorStatus.0 sensorReadCount.0 sensorUptime.0
Numeric form (no MIB needed):
snmpget -v2c -c public 192.168.1.100 .1.3.6.1.4.1.8174.19.0 snmpget -v2c -c public 192.168.1.100 .1.3.6.1.4.1.8174.20.1.2.3
Walk the entire sensor table (8 columns x 8 rows = 64 OIDs):
snmpwalk -v2c -c public -M C:\nburn\snmp\mibs -m ALL 192.168.1.100 sensorTable
Walk both the scalar and the table:
snmpwalk -v2c -c public -M C:\nburn\snmp\mibs -m ALL 192.168.1.100 .1.3.6.1.4.1.8174
Walk the table twice ~10 seconds apart and observe that sensorTemperature, sensorReadCount, and sensorUptime change between walks – that is the polling task updating the row structs.
Much easier to read than a column-major snmpwalk:
snmptable -v2c -c public -M C:\nburn\snmp\mibs -m ALL -Cb 192.168.1.100 sensorTable
Expected output (values jitter between polls):
SNMP table: NBURNSENSOR-MIB::sensorTable
Index Name Temperature Humidity Pressure Uptime ReadCount Status 0 "Sensor #0" 2230 41 10146 0:0:00:28.65 5 1 1 "Sensor #1" 2281 42 10150 0:0:00:28.65 5 1 2 "Sensor #2" 2300 43 10154 0:0:00:28.65 5 1 3 "Sensor #3" 2351 44 10158 0:0:00:28.65 5 1 ...
Every column is read-only. A SET on any cell must be rejected:
snmpset -v2c -c public -M C:\nburn\snmp\mibs -m ALL 192.168.1.100 sensorTemperature.0 i 9999
Expected response:
Error in packet. Reason: notWritable (That object does not support modification) Failed object: NBURNSENSOR-MIB::sensorTemperature.0
Read-only enforcement comes from what sensor.cpp never registers – there are AddSnmpEntry() calls but no AddSnmpWriteEntry() calls.
snmptranslate -M C:\nburn\snmp\mibs -m ALL -On sensorTableNumber.0 snmptranslate -M C:\nburn\snmp\mibs -m ALL .1.3.6.1.4.1.8174.20.1.3.0
Cannot find module (NBURNSENSOR-MIB) Copy this example's mib\NburnSensorTable_Mib.txt to C:\nburn\snmp\mibs\\endiskip and retry.
Timeout Verify with ping 192.168.1.100 and confirm the device is on the same subnet. SNMP listens on UDP/161; check Windows Firewall.
Error in packet, Reason: notWritable You attempted to SET a read-only column. Every column in this table is read-only by design.
Same values returned every poll The polling loop updates the row structs every 5 seconds. If sensorReadCount and sensorUptime never increment, check that UserMain reached the while(1) { OSTimeDly(...); PollSensors(); } loop.
sysDescr.0 : "NetBurner SNMP Table Read example" sysObjectID.0 : 1.3.6.1.4.1.8174.2.41