BSNMPAGENT(3) | MidnightBSD Library Functions Manual | BSNMPAGENT(3) |
bsnmpagent
,
snmp_depop_t
, snmp_op_t
,
tree
, tree_size
,
snmp_trace
, snmp_debug
,
snmp_get
, snmp_getnext
,
snmp_getbulk
, snmp_set
,
snmp_make_errresp
,
snmp_dep_lookup
,
snmp_init_context
,
snmp_dep_commit
,
snmp_dep_rollback
,
snmp_dep_finish
— SNMP agent
library
Begemot SNMP library (libbsnmp, -lbsnmp)
#include <asn1.h>
#include <snmp.h>
#include <snmpagent.h>
typedef int
(*snmp_depop_t)
(struct
snmp_context *ctx, struct
snmp_dependency *dep,
enum snmp_depop op);
typedef int
(*snmp_op_t)
(struct
snmp_context *ctx, struct
snmp_value *val, u_int
len, u_int idx,
enum snmp_op op);
extern struct snmp_node *tree;
extern u_int tree_size;
extern u_int snmp_trace;
extern void (*snmp_debug)(const char *fmt, ...);
enum snmp_ret
snmp_get
(struct
snmp_pdu *pdu, struct
asn_buf *resp_b, struct
snmp_pdu *resp, void
*data);
enum snmp_ret
snmp_getnext
(struct
snmp_pdu *pdu, struct
asn_buf *resp_b, struct
snmp_pdu *resp, void
*data);
enum snmp_ret
snmp_getbulk
(struct
snmp_pdu *pdu, struct
asn_buf *resp_b, struct
snmp_pdu *resp, void
*data);
enum snmp_ret
snmp_set
(struct
snmp_pdu *pdu, struct
asn_buf *resp_b, struct
snmp_pdu *resp, void
*data);
enum snmp_ret
snmp_make_errresp
(const
struct snmp_pdu *pdu,
struct asn_buf *req_b,
struct asn_buf
*resp_b);
struct snmp_dependency *
snmp_dep_lookup
(struct
snmp_context *ctx, const
struct asn_oid *base,
const struct asn_oid
*idx, size_t alloc,
snmp_depop_t func);
struct snmp_context *
snmp_init_context
(void);
int
snmp_dep_commit
(struct
snmp_context *ctx);
int
snmp_dep_rollback
(struct
snmp_context *ctx);
void
snmp_dep_finish
(struct
snmp_context *ctx);
The SNMP library contains routines to easily build SNMP agent applications that use SNMP versions 1 or 2. Note, however, that it may be even easier to build an bsnmpd(1) loadable module, that handles the new MIB (see snmpmod(3)).
Most of the agent routines operate on a global array that the describes the complete MIB served by the agent. This array is held in the two variables:
extern struct snmp_node *tree; extern u_int tree_size;
The elements of the array are of type struct snmp_node:
typedef int (*snmp_op_t)(struct snmp_context *, struct snmp_value *, u_int, u_int, enum snmp_op); struct snmp_node { struct asn_oid oid; const char *name; /* name of the leaf */ enum snmp_node_type type; /* type of this node */ enum snmp_syntax syntax; snmp_op_t op; u_int flags; u_int32_t index; /* index data */ void *data; /* application data */ void *tree_data; /* application data */ };
The fields of this structure are described below.
enum snmp_node_type { SNMP_NODE_LEAF = 1, SNMP_NODE_COLUMN };
NULL
.SNMP_ERR_NOSUCHNAME
. For all other operations
the oid in val is the oid to fetch or set.enum snmp_op { SNMP_OP_GET = 1, SNMP_OP_GETNEXT, SNMP_OP_SET, SNMP_OP_COMMIT, SNMP_OP_ROLLBACK, };
The user handler must return an appropriate SNMP v2 error code. If the original PDU was a version 1 PDU, the error code is mapped automatically.
SNMP_NODE_CANSET is defined and
set for nodes, that can be written or
created.#define SNMP_INDEXES_MAX 7 #define SNMP_INDEX_SHIFT 4 #define SNMP_INDEX_MASK 0xf #define SNMP_INDEX_COUNT(V) ((V) & SNMP_INDEX_MASK) #define SNMP_INDEX(V,I) \ (((V) >> (((I) + 1) * SNMP_INDEX_SHIFT)) & \ SNMP_INDEX_MASK)
The easiest way to construct the node table is gensnmptree(1). Note, that one must be careful when changing the tree while executing a SET operation. Consult the sources for bsnmpd(1).
The global variable snmp_trace together with the function pointed to by snmp_debug help in debugging the library and the agent. snmp_trace is a bit mask with the following bits:
enum { SNMP_TRACE_GET, SNMP_TRACE_GETNEXT, SNMP_TRACE_SET, SNMP_TRACE_DEPEND, SNMP_TRACE_FIND, };
Setting a bit to true causes the library to call
snmp_debug
()
in strategic places with a debug string. The library contains a default
implementation for the debug function that prints a message to standard
error.
Many of the functions use a so called context:
struct snmp_context { u_int var_index; struct snmp_scratch *scratch; struct snmp_dependency *dep; void *data; /* user data */ enum snmp_ret code; /* return code */ }; struct snmp_scratch { void *ptr1; void *ptr2; uint32_t int1; uint32_t int2; };
The fields are used as follows:
The next three functions execute different kinds of
GET requests. The function
snmp_get
()
executes an SNMP GET operation, the function
snmp_getnext
()
executes an SNMP GETNEXT operation and the function
snmp_getbulk
()
executes an SNMP GETBULK operation. For all three functions the response PDU
is constructed and encoded on the fly. If everything is ok, the response PDU
is returned in resp and resp_b.
The caller must call
snmp_pdu_free
()
to free the response PDU in this case. One of the following values may be
returned:
SNMP_RET_OK
SNMP_RET_IGN
SNMP_RET_ERR
snmp_make_errresp
().The function
snmp_set
()
executes an SNMP SET operation. The arguments are the same as for the
previous three functions. The operation of this functions is, however, much
more complex.
The SET operation occurs in several stages:
snmp_error
().)SNMP_DEPOP_FINISH.
Then the function
returns SNMP_ERR_OK
.There are to mechanisms to help in complex SET
operations: dependencies and finalizers. A dependency is used if several
bindings depend on each other. A typical example is the creation of a
conceptual row, which requires the setting of several columns to succeed. A
dependency is identified by two OIDs. In the table case, the first oid is
typically the table's base OID and the second one the index. Both of these
can easily be generated from the variables OID with
asn_slice_oid
().
The function
snmp_dep_lookup
()
tries to find a dependency based on these two OIDs and, if it cannot find
one creates a new one. This means for the table example, that the function
returns the same dependency for each of the columns of the same table row.
This allows during the SNMP_OP_SET processing to collect all information
about the row into the dependency. The arguments to
snmp_dep_lookup
() are: the two OIDs to identify the
dependency (they are copied into newly created dependencies), the size of
the structure to allocate and the dependency callback.
When all SNMP_OP_SET operations have succeeded the dependencies are executed. At this stage the dependency callback has all information about the given table row that was available in this SET PDU and can operate accordingly.
It is guaranteed that each dependency callback is executed at
minimum once - with an operation of
SNMP_OP_ROLLBACK
. This ensures that all dynamically
allocated resources in a callback can be freed correctly.
The function
snmp_make_errresp
()
makes an error response if an operation has failed. It takes the original
request PDU (it will look only on the error code and index fields), the
buffer containing the original PDU and a buffer for the error PDU. It copies
the bindings field from the original PDUs buffer directly to the response
PDU and thus does not depend on the decodability of this field. It may
return the same values as the operation functions.
The next four functions allow some parts of
the SET operation to be executed. This is only used in
bsnmpd(1) to implement
the configuration as a single transaction. The function
snmp_init_context
()
creates and initializes a context. The function
snmp_dep_commit
()
executes SNMP_DEPOP_COMMIT for all dependencies in the context stopping at
the first error. The function
snmp_dep_rollback
()
executes SNMP_DEPOP_ROLLBACK starting at the previous of the current
dependency in the context. The function
snmp_dep_finish
()
executes SNMP_DEPOP_FINISH for all dependencies.
If an error occurs in any of the function an error indication as described above is returned. Additionally the functions may call snmp_error on unexpected errors.
gensnmptree(1), bsnmpd(1), bsnmpclient(3), bsnmplib(3), snmpmod(3)
This implementation conforms to the applicable IETF RFCs and ITU-T recommendations.
Hartmut Brandt ⟨harti@FreeBSD.org⟩
October 4, 2005 | midnightbsd-3.1 |