In the previous tutorial we wrote a simple read-only counter variable. Here we will continue this work and add write support to the simpleCounter variable. Writing to the variable will set it to a new value, and it will continue to count from there.
The updated MIB looks like that:
SIMPLE-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI enterprises FROM SNMPv2-SMI; simpleCounter OBJECT-TYPE SYNTAX INTEGER ACCESS read-write STATUS current DESCRIPTION "A simple counter which is incremented each time it is queried. Starts with 0." ::={ enterprises 42 1 } END
This is the same as before, but with "ACCESS read-write".
A single SNMP Set request may set multiple variables at once (possibly distributed over multiple subagents), and SNMP guarantees an atomic operation in that case. This means that, should any variable fail to perform the Set operation, no other variable is allowed to perform the Set operation either. Therefore, the SET operation is carried out in multiple distinct steps:
To implement these actions, the Variable classes provides the methods perform_testset()
, perform_commitset()
, perform_cleanupset()
and perform_undoset()
, which can be overridden by a concrete implementation.
To implement write support for the SimpleCounter class, we implement all four methods. The perform_testset()
implementation allocates an quint32 value, which is deallocated by perform_cleanupset()
respectively perform_undoset()
. This is not very realistic, but it demonstrates the usage of the individual steps. The perform_commitset()
method stores the old value (in case an undo needs to be carried out by perform_undoset()
) and sets the new value.
The perform_testset()
method must be overridden by any variable which should be writeable. If it is not overridden, agentXcpp assumes that the variable is read-only (which we exploited in the first, read-only version). This also means that an e.g. IntegerVariable object is read-only by default and needs to be subclassed to add write support. Hence, we implement it for our SimpleCounter class by adding the following code to it:
The perform_testset() method receives the value and can check whether setting the variable to this value would work. Here, we don't check the value, but we allocate an quint32 to store the old value, which is needed for perform_undoset()
. If allocation fails, we return the error resourceUnavailable.
The perform_commitset()
method must also be implemented for writeable variables. In the SimpleCounter class, this method stores the old value and sets the internal value:
The perform_cleanupset()
method releases old_value again:
If old_value were an quint32 (instead of a pointer to quint32), no allocation and deallocation would have been necessary. The perform_cleanupset()
method would not be implemented then. In fact, this method is the only one which is optional for writeable variables, while the other methods are mandatory.
The perform_undoset()
method must be implemented by each writeable variable and shall perform a rollback. It is technically possible to omit this method; the compiler has no way to detect a missing implementation. However, it is an error to omit it, and an error will be reported to the master agent if it is missing. For simpleCounter implementation is easy:
It's important to note that the method releases old_value.
Again, we compile and run the subagent. This is exactly the same as in the first tutorial (it is assumed that your system is already setup accordingly):
g++ simpleagent.cpp -o simpleagent -lagentxcpp `pkg-config --cflags --libs QtNetwork QtCore`
Next, we start the subagent again:
./simpleagent
Now, we can query the variable:
snmpget -v1 -c rw localhost SIMPLE-MIB::simpleCounter.0
Each time the variable is queried, the counter increments. Now, let's set the counter to, say, 42:
snmpset -v1 -c rw localhost SIMPLE-MIB::simpleCounter.0 i 42
Now, we continue to query it again several times and the counter should continue at 43, further incrementing.
Et voilá: a read-write variable. Now go on and learn how to send notifications!