2013-11-24 15:00:12 +00:00
|
|
|
How to make a new subdriver to support another SNMP device
|
|
|
|
----------------------------------------------------------
|
|
|
|
|
|
|
|
Overall concept
|
|
|
|
~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
The SNMP protocol allow for a common way to interact with devices over
|
|
|
|
the network.
|
|
|
|
|
|
|
|
The NUT "snmp-ups" driver is a meta-driver that handles many SNMP devices,
|
|
|
|
such as UPS and PDU. It consists of a core driver that handles most of the
|
|
|
|
work of talking to the SNMP agent, and several sub-drivers to handle
|
|
|
|
specific device manufacturers. Adding support for a new SNMP device is
|
|
|
|
easy, because it requires only the creation of a new sub-driver.
|
|
|
|
|
|
|
|
SNMP data Tree
|
|
|
|
~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
From the point of view of writing an SNMP subdriver, an SNMP device
|
|
|
|
consists of a bunch of variables, called OIDs (for Object IDentifiers).
|
|
|
|
Some OIDs (such as the current input voltage) are read-only, whereas
|
|
|
|
others (such as the beeper enabled/disabled/muted status) can be read and
|
|
|
|
written. OID are grouped together and arranged in a hierarchical tree
|
|
|
|
shape, similar to directories in a file system. OID components are
|
|
|
|
separated by ".", and can be expressed in numeric or textual form.
|
|
|
|
For example:
|
|
|
|
|
|
|
|
.iso.org.dod.internet.mgmt.mib-2.system.sysObjectID
|
|
|
|
|
|
|
|
is equivalent to:
|
|
|
|
|
|
|
|
.1.3.6.1.2.1.1.2.0
|
|
|
|
|
|
|
|
Here is an excerpt tree, showing only two OIDs, sysDescr and sysObjectID:
|
|
|
|
|
|
|
|
.iso
|
|
|
|
.org
|
|
|
|
.dod
|
|
|
|
.internet
|
|
|
|
.mgmt
|
|
|
|
.mib-2
|
|
|
|
.system
|
|
|
|
.sysDescr.0 = STRING: Dell UPS Tower 1920W HV
|
|
|
|
.sysObjectID.0 = OID: .iso.org.dod.internet.private.enterprises.674.10902.2
|
|
|
|
(...)
|
|
|
|
.upsMIB
|
|
|
|
.upsObjects
|
|
|
|
.upsIdent
|
|
|
|
.upsIdentModel = STRING: "Dell UPS Tower 1920W HV"
|
|
|
|
(...)
|
|
|
|
.private
|
|
|
|
.enterprises
|
|
|
|
.674
|
|
|
|
.10902
|
|
|
|
.2
|
|
|
|
.100
|
|
|
|
.1.0 = STRING: "Dell UPS Tower 1920W HV"
|
|
|
|
(...)
|
|
|
|
|
|
|
|
As you can see in the above example, the device name is exposed three times,
|
|
|
|
through three different MIBs:
|
|
|
|
|
|
|
|
- Generic MIB-II (RFC 1213):
|
|
|
|
|
|
|
|
.iso.org.dod.internet.mgmt.mib-2.system.sysDescr.0 = STRING: Dell UPS Tower 1920W HV
|
|
|
|
.1.3.6.1.2.1.1.1.0 = STRING: Dell UPS Tower 1920W HV
|
|
|
|
|
|
|
|
- UPS MIB (RFC 1628):
|
|
|
|
|
|
|
|
.iso.org.dod.internet.mgmt.mib-2.upsMIB.upsObjects.upsIdent.upsIdentModel = STRING: "Dell UPS Tower 1920W HV"
|
|
|
|
.1.3.6.1.2.1.33.1.1.2.0 = STRING: "Dell UPS Tower 1920W HV"
|
|
|
|
|
|
|
|
- DELL SNMP UPS MIB:
|
|
|
|
|
|
|
|
.iso.org.dod.internet.private.enterprises.674.10902.2.100.1.0 = STRING: "Dell UPS Tower 1920W HV"
|
|
|
|
|
|
|
|
But only the two last can serve useful data for NUT.
|
|
|
|
|
|
|
|
An highly interesting OID is *sysObjectID*: its value is an OID that refers to
|
|
|
|
the main MIB of the device. In the above example, the device points us at the
|
|
|
|
Dell UPS MIB. *sysObjectID*, also called "sysOID" is used by snmp-ups to find
|
|
|
|
the right mapping structure.
|
|
|
|
|
|
|
|
For more information on SNMP, refer to the
|
|
|
|
link:http://en.wikipedia.org/wiki/Simple_Network_Management_Protocol[Wikipedia]
|
|
|
|
article, or browse the Internet.
|
|
|
|
|
|
|
|
|
|
|
|
To be able to convert values, NUT SNMP subdrivers need to provide:
|
|
|
|
|
|
|
|
- manufacturer-specific sysOID, to determine which lookup structure applies
|
|
|
|
to which devices,
|
|
|
|
- a mapping of SNMP variables to NUT variables,
|
|
|
|
- a mapping of SNMP values to NUT values.
|
|
|
|
|
|
|
|
Moreover, subdrivers might have to provide additional functionality,
|
|
|
|
such as custom implementations of specific instant commands (load.off,
|
|
|
|
shutdown.restart), and conversions of manufacturer specific data
|
|
|
|
formats. At the time of writing this document, snmp-ups doesn't provide
|
|
|
|
such mechanisms (only formatting ones), but it is planned in a future release.
|
|
|
|
|
|
|
|
|
|
|
|
Creating a subdriver
|
|
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
In order to create a subdriver, you will need the following:
|
|
|
|
|
|
|
|
- the "MIB definition file. This file has a ".mib" extension, and is
|
|
|
|
generally available on the accompanying disc, or on the manufacturer
|
|
|
|
website. It should either be placed in a system directory
|
|
|
|
(/usr/share/mibs/ or equivalent), or pointed using *-M* option,
|
|
|
|
|
|
|
|
- a network access to the device
|
|
|
|
- OR information dumps.
|
|
|
|
|
|
|
|
|
|
|
|
You can create an initial "stub" subdriver for your device by using the helper
|
|
|
|
script *scripts/subdriver/gen-snmp-subdriver.sh*. Note that this only creates
|
|
|
|
a "stub" which MUST be customized to be useful (see CUSTOMIZATION below).
|
|
|
|
|
|
|
|
You have two options to run gen-snmp-subdriver.sh:
|
|
|
|
|
|
|
|
mode 1: get SNMP data from a real agent
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
This method requires to have a network access to the device, in order to
|
|
|
|
automatically retrieve the needed information.
|
|
|
|
|
2016-07-18 00:11:41 +00:00
|
|
|
You have to specify the following parameters:
|
2013-11-24 15:00:12 +00:00
|
|
|
|
|
|
|
- *-H* host address: is the SNMP host IP address or name
|
|
|
|
- *-c* community: is the SNMP v1 community name (default: public)"
|
|
|
|
|
|
|
|
For example:
|
|
|
|
|
|
|
|
$ gen-snmp-subdriver.sh -H W.X.Y.Z -c foobar -n <MIB name>.mib
|
|
|
|
|
|
|
|
mode 2: get data from files
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
This method does not require direct access to the device, at least
|
|
|
|
not for the one using gen-snmp-subdriver.sh.
|
|
|
|
|
|
|
|
The following SNMP data need to be dumped first:
|
|
|
|
|
|
|
|
- sysOID value: for example '.1.3.6.1.4.1.705.1'
|
|
|
|
- a numeric SNMP walk (OIDs in dotted numeric format) of the tree
|
|
|
|
pointed by sysOID. For example:
|
|
|
|
|
|
|
|
snmpwalk -On -c foobar W.X.Y.Z .1.3.6.1.4.1.705.1 > snmpwalk-On.log
|
|
|
|
|
|
|
|
- a textual SNMP walk (OIDs in string format) of the tree pointed by
|
|
|
|
sysOID. For example:
|
|
|
|
|
|
|
|
snmpwalk -Os -c foobar W.X.Y.Z .1.3.6.1.4.1.705.1 > snmpwalk-Os.log
|
|
|
|
|
|
|
|
NOTE: if the OID are only partially resolved (i.e, there are still parts
|
|
|
|
expressed in numeric form), then try using *-M* to point your .mib file.
|
|
|
|
|
|
|
|
Then call the script using:
|
|
|
|
|
|
|
|
$ gen-snmp-subdriver.sh -s <sysOID value> <numeric SNMP walk> <string SNMP walk>
|
|
|
|
|
|
|
|
For example:
|
|
|
|
|
|
|
|
$ gen-snmp-subdriver.sh -s .1.3.6.1.4.1.705.1 snmpwalk-On.log snmpwalk-Os.log
|
|
|
|
|
|
|
|
This script prompts you for a name for the subdriver if you don't provide it
|
|
|
|
with *-n*. Use only letters and digits, and use natural capitalization such
|
|
|
|
as "Camel" (not "camel" or "CAMEL", apart if it natural). The script may
|
|
|
|
prompt you for additional information.
|
|
|
|
|
|
|
|
Integrating the subdriver with snmp-ups
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
Beside of the mandatory customization, there are a few things that you have
|
|
|
|
to do, as mentioned at the end of the script:
|
|
|
|
|
|
|
|
- edit drivers/snmp-ups.h and add #include "<HFILE>.h", where <HFILE> is the
|
|
|
|
name of the header file, with the *.h* extension,
|
|
|
|
- edit drivers/snmp-ups.c and bump DRIVER_VERSION by adding "0.01".
|
|
|
|
- also add "&<LDRIVER>" to snmp-ups.c:mib2nut[] list, where <LDRIVER> is the
|
|
|
|
lower case driver name
|
|
|
|
- add "<LDRIVER>-mib.c" to snmp_ups_SOURCES in drivers/Makefile.am
|
|
|
|
- add "<LDRIVER>-mib.h" to dist_noinst_HEADERS in drivers/Makefile.am
|
|
|
|
- copy "<LDRIVER>-mib.c" and "<LDRIVER>-mib.h" to ../drivers/
|
|
|
|
- finally call the following, from the top level directory, to test
|
|
|
|
compilation:
|
|
|
|
|
|
|
|
$ autoreconf && configure && make
|
|
|
|
|
|
|
|
|
|
|
|
You can already start experimenting with the new subdriver; but all data
|
|
|
|
will be prefixed by "unmapped.". You will now have to customize it.
|
|
|
|
|
|
|
|
|
|
|
|
CUSTOMIZATION
|
|
|
|
^^^^^^^^^^^^^
|
|
|
|
|
|
|
|
The initially generated subdriver code is only a stub (mainly a big C
|
|
|
|
structure to be precise), and will not implement any useful functionality
|
|
|
|
(in particular, it will be unable to shut down the UPS). In the beginning,
|
|
|
|
it simply attempts to monitor some UPS variables. To make this driver useful,
|
|
|
|
you must examine the NUT variables of the form "unmapped.*" in the
|
|
|
|
hid_info_t data structure, and map them to actual NUT variables and
|
|
|
|
instant commands. There are currently no step-by-step instructions for
|
|
|
|
how to do this. Please look at the files to see how the currently implemented
|
|
|
|
subdrivers are written.:
|
|
|
|
|
|
|
|
- apc-mib.c/h
|
|
|
|
- baytech-mib.c/h
|
|
|
|
- bestpower-mib.c/h
|
|
|
|
- compaq-mib.c/h
|
|
|
|
- cyberpower-mib.c/h
|
|
|
|
- eaton-mib.c/h
|
|
|
|
- ietf-mib.c/h
|
|
|
|
- mge-mib.c/h
|
|
|
|
- netvision-mib.c/h
|
|
|
|
- powerware-mib.c/h
|
|
|
|
- raritan-pdu-mib.c
|
2016-07-18 00:11:41 +00:00
|
|
|
- huawei-mib.c/h
|
2013-11-24 15:00:12 +00:00
|
|
|
|
|
|
|
To help you, above each entry in <LDRIVER>-mib.c, there is a comment that
|
|
|
|
displays the textual OID name. For example, the following entry:
|
|
|
|
|
|
|
|
/* upsMIB.upsObjects.upsIdent.upsIdentModel = STRING: "Dell UPS Tower 1920W HV" */
|
|
|
|
{ "unmapped.upsidentmodel", ST_FLAG_STRING, SU_INFOSIZE, ".1.3.6.1.4.1.2254.2.4.1.1.0", NULL, SU_FLAG_OK, NULL },
|
|
|
|
|
|
|
|
Many time, only the first field will need to be modified, to map to an actual
|
|
|
|
NUT variable name.
|
|
|
|
|
|
|
|
Check the <<nut-names,NUT command and variable naming scheme>> section first
|
|
|
|
to find a name that matches the OID name (closest fit). If nothing matches,
|
|
|
|
contact the upsdev list, and we'll figure it out.
|
|
|
|
|
|
|
|
In the above example, the right NUT variable is obviously "device.model".
|
|
|
|
|
|
|
|
The MIB definition file (.mib) also contains some description of these OIDs,
|
|
|
|
along with the possible enumerated values.
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
FIXME:
|
|
|
|
|
|
|
|
Shutting down the UPS
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
It is desireable to support shutting down the UPS. Usually (for
|
|
|
|
devices that follow the HID Power Device Class specification), this
|
|
|
|
requires sending the UPS two commands. One for shutting down the UPS
|
|
|
|
(with an 'offdelay') and one for restarting it (with an 'ondelay'),
|
|
|
|
where offdelay < ondelay. The two NUT commands for which this is
|
|
|
|
relevant, are 'shutdown.return' and 'shutdown.stayoff'.
|
|
|
|
|
|
|
|
Since the one-to-one mapping above doesn't allow sending two HID
|
|
|
|
commands to the UPS in response to sending one NUT command to the
|
|
|
|
driver, this is handled by the driver. In order to make this work,
|
|
|
|
you need to define the following four NUT values:
|
|
|
|
|
|
|
|
ups.delay.start (variable, R/W)
|
|
|
|
ups.delay.shutdown (variable, R/W)
|
|
|
|
load.off.delay (command)
|
|
|
|
load.on.delay (command)
|
|
|
|
|
|
|
|
If the UPS supports it, the following variables can be used to show
|
|
|
|
the countdown to start/shutdown:
|
|
|
|
|
|
|
|
ups.timer.start (variable, R/O)
|
|
|
|
ups.timer.shutdown (variable, R/O)
|
|
|
|
|
|
|
|
The `load.on` and `load.off` commands will be defined implicitly by
|
|
|
|
the driver (using a delay value of '0'). Define these commands
|
|
|
|
yourself, if your UPS requires a different value to switch on/off
|
|
|
|
the load without delay.
|
|
|
|
|
|
|
|
Note that the driver expects the `load.off.delay` and `load.on.delay`
|
|
|
|
to follow the HID Power Device Class specification, which means that
|
|
|
|
the `load.on.delay` command should NOT switch on the load in the
|
|
|
|
absence of mains power. If your UPS switches on the load regardless of
|
|
|
|
the mains status, DO NOT define this command. You probably want to
|
|
|
|
define the `shutdown.return` and/or `shutdown.stayoff` commands in
|
|
|
|
that case. Commands defined in the subdriver will take precedence over
|
|
|
|
the ones that are composed in the driver.
|
|
|
|
|
|
|
|
When running the driver with the '-k' flag, it will first attempt to
|
|
|
|
send a `shutdown.return` command and if that fails, will fallback to
|
|
|
|
`shutdown.reboot`.
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|