blob: 1c24b7891ed4408b6020c065de8972df376e903b [file] [log] [blame]
/*
* DisMan Expression MIB:
* Core implementation of the expression handling behaviour
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "disman/expr/expExpression.h"
#include "disman/expr/expObject.h"
netsnmp_tdata *expr_table_data;
/*
* Initializes the container for the expExpression table,
* regardless of which module initialisation routine is called first.
*/
void
init_expr_table_data(void)
{
DEBUGMSGTL(("disman:expr:init", "init expression container\n"));
if (!expr_table_data) {
expr_table_data = netsnmp_tdata_create_table("expExpressionTable", 0);
DEBUGMSGTL(("disman:expr:init", "create expression container (%x)\n",
expr_table_data));
}
}
/** Initialize the expExpression module */
void
init_expExpression(void)
{
init_expr_table_data();
}
/* ===================================================
*
* APIs for maintaining the contents of the
* expression table container.
*
* =================================================== */
void
_mteExpr_dump(void)
{
struct mteExpression *entry;
netsnmp_tdata_row *row;
int i = 0;
for (row = netsnmp_tdata_row_first(expr_table_data);
row;
row = netsnmp_tdata_row_next(expr_table_data, row)) {
entry = (struct mteExpression *)row->data;
DEBUGMSGTL(("disman:expr:dump", "ExpressionTable entry %d: ", i));
DEBUGMSGOID(("disman:expr:dump", row->oid_index.oids, row->oid_index.len));
DEBUGMSG(("disman:expr:dump", "(%s, %s)",
row->indexes->val.string,
row->indexes->next_variable->val.string));
DEBUGMSG(("disman:expr:dump", ": %x, %x\n", row, entry));
i++;
}
DEBUGMSGTL(("disman:expr:dump", "ExpressionTable %d entries\n", i));
}
/*
* Create a new row in the expression table
*/
struct expExpression *
expExpression_createEntry(const char *expOwner, const char *expName, int fixed)
{
netsnmp_tdata_row *row;
row = expExpression_createRow(expOwner, expName, fixed);
return row ? (struct expExpression *)row->data : NULL;
}
netsnmp_tdata_row *
expExpression_createRow(const char *expOwner, const char *expName, int fixed)
{
struct expExpression *entry;
netsnmp_tdata_row *row;
size_t expOwner_len = (expOwner) ? strlen(expOwner) : 0;
size_t expName_len = (expName) ? strlen(expName) : 0;
/*
* Create the expExpression entry, and the
* (table-independent) row wrapper structure...
*/
entry = SNMP_MALLOC_TYPEDEF(struct expExpression);
if (!entry)
return NULL;
row = netsnmp_tdata_create_row();
if (!row) {
SNMP_FREE(entry);
return NULL;
}
row->data = entry;
/*
* ... initialize this row with the indexes supplied
* and the default values for the row...
*/
if (expOwner)
memcpy(entry->expOwner, expOwner, expOwner_len);
netsnmp_tdata_row_add_index(row, ASN_OCTET_STR,
entry->expOwner, expOwner_len);
if (expName)
memcpy(entry->expName, expName, expName_len);
netsnmp_tdata_row_add_index(row, ASN_OCTET_STR,
entry->expName, expName_len);
entry->expValueType = EXPVALTYPE_COUNTER;
entry->expErrorCount = 0;
if (fixed)
entry->flags |= EXP_FLAG_FIXED;
/*
* ... and insert the row into the table container.
*/
netsnmp_tdata_add_row(expr_table_data, row);
DEBUGMSGTL(("disman:expr:table", "Expression entry created (%s, %s)\n",
expOwner, expName));
return row;
}
/*
* Remove a row from the expression table
*/
void
expExpression_removeEntry(netsnmp_tdata_row *row)
{
struct expExpression *entry;
if (!row)
return; /* Nothing to remove */
entry = (struct expExpression *)
netsnmp_tdata_remove_and_delete_row(expr_table_data, row);
if (entry) {
/* expExpression_disable( entry ) */
SNMP_FREE(entry);
}
}
struct expExpression *
expExpression_getFirstEntry( void )
{
return (struct expExpression *)
netsnmp_tdata_row_entry(netsnmp_tdata_row_first(expr_table_data));
}
struct expExpression *
expExpression_getNextEntry(const char *owner, const char *name )
{
netsnmp_variable_list owner_var, name_var;
memset(&owner_var, 0, sizeof(netsnmp_variable_list));
memset(&name_var, 0, sizeof(netsnmp_variable_list));
snmp_set_var_typed_value( &owner_var, ASN_OCTET_STR,
(const u_char*)owner, strlen(owner));
snmp_set_var_typed_value( &name_var, ASN_OCTET_STR,
(const u_char*)name, strlen(name));
owner_var.next_variable = &name_var;
return (struct expExpression *)
netsnmp_tdata_row_entry(
netsnmp_tdata_row_next_byidx(expr_table_data, &owner_var));
}
struct expExpression *
expExpression_getEntry(const char *owner, const char *name )
{
netsnmp_variable_list owner_var, name_var;
memset(&owner_var, 0, sizeof(netsnmp_variable_list));
memset(&name_var, 0, sizeof(netsnmp_variable_list));
snmp_set_var_typed_value( &owner_var, ASN_OCTET_STR,
(const u_char*)owner, strlen(owner));
snmp_set_var_typed_value( &name_var, ASN_OCTET_STR,
(const u_char*)name, strlen(name));
owner_var.next_variable = &name_var;
return (struct expExpression *)
netsnmp_tdata_row_entry(
netsnmp_tdata_row_get_byidx(expr_table_data, &owner_var));
}
/* ===================================================
*
* APIs for evaluating an expression - data gathering
*
* =================================================== */
/*
* Gather the data necessary for evaluating an expression.
*
* This will retrieve *all* the data relevant for all
* instances of this expression, rather than just the
* just the values needed for expanding a given instance.
*/
void
expExpression_getData( unsigned int reg, void *clientarg )
{
struct expExpression *entry = (struct expExpression *)clientarg;
netsnmp_tdata_row *row;
netsnmp_variable_list *var;
int ret;
if ( !entry && reg ) {
snmp_alarm_unregister( reg );
return;
}
if (( entry->expExpression[0] == '\0' ) ||
!(entry->flags & EXP_FLAG_ACTIVE) ||
!(entry->flags & EXP_FLAG_VALID))
return;
DEBUGMSGTL(("disman:expr:run", "Gathering expression data (%s, %s)\n",
entry->expOwner, entry->expName));
/*
* This routine can be called in two situations:
* - regularly by 'snmp_alarm' (reg != 0)
* (as part of ongoing delta-value sampling)
* - on-demand (reg == 0)
* (for evaluating a particular entry)
*
* If a regularly sampled expression (entry->alarm != 0)
* is invoked on-demand (reg == 0), then use the most
* recent sampled values, rather than retrieving them again.
*/
if ( !reg && entry->alarm )
return;
/*
* XXX - may want to implement caching for on-demand evaluation
* of non-regularly sampled expressions.
*/
/*
* For a wildcarded expression, expExpressionPrefix is used
* to determine which object instances to retrieve.
* (For a non-wildcarded expression, we already know
* explicitly which object instances will be needed).
*
* If we walk this object here, then the results can be
* used to build the necessary GET requests for each
* individual parameter object (within expObject_getData)
*
* This will probably be simpler (and definitely more efficient)
* than walking the object instances separately and merging
* merging the results).
*
* NB: Releasing any old results is handled by expObject_getData.
* Assigning to 'entry->pvars' without first releasing the
* previous contents does *not* introduce a memory leak.
*/
if ( entry->expPrefix_len ) {
var = (netsnmp_variable_list *)
SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
snmp_set_var_objid( var, entry->expPrefix, entry->expPrefix_len);
ret = netsnmp_query_walk( var, entry->session );
DEBUGMSGTL(("disman:expr:run", "Walk returned %d\n", ret ));
entry->pvars = var;
}
/* XXX - retrieve sysUpTime.0 value, and check for discontinuity */
/*
entry->flags &= ~EXP_FLAG_SYSUT;
var = (netsnmp_variable_list *)
SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
snmp_set_var_objid( var, sysUT_oid, sysUT_oid_len );
netsnmp_query_get( var, entry->session );
if ( *var->val.integer != entry->sysUpTime ) {
entry->flags |= EXP_FLAG_SYSUT;
entry->sysUpTime = *var->val.integer;
}
snmp_free_varbind(var);
*/
/*
* Loop through the list of relevant objects,
* and retrieve the corresponding values.
*/
for ( row = expObject_getFirst( entry->expOwner, entry->expName );
row;
row = expObject_getNext( row )) {
/* XXX - may need to check whether owner/name still match */
expObject_getData( entry, (struct expObject *)row->data);
}
}
void
expExpression_enable( struct expExpression *entry )
{
DEBUGMSG(("disman:expr:run", "Enabling %s\n", entry->expName));
if (!entry)
return;
if (entry->alarm) {
/* or explicitly call expExpression_disable ?? */
snmp_alarm_unregister( entry->alarm );
entry->alarm = 0;
}
if (entry->expDeltaInterval) {
entry->alarm = snmp_alarm_register(
entry->expDeltaInterval, SA_REPEAT,
expExpression_getData, entry );
expExpression_getData( entry->alarm, (void*)entry );
}
}
void
expExpression_disable( struct expExpression *entry )
{
if (!entry)
return;
if (entry->alarm) {
snmp_alarm_unregister( entry->alarm );
entry->alarm = 0;
/* Perhaps release any previous results ?? */
}
}
long _expExpression_MaxCount = 0;
long _expExpression_countEntries(void)
{
struct expExpression *entry;
netsnmp_tdata_row *row;
long count = 0;
for (row = netsnmp_tdata_row_first(expr_table_data);
row;
row = netsnmp_tdata_row_next(expr_table_data, row)) {
entry = (struct expExpression *)row->data;
count += entry->count;
}
return count;
}
long expExpression_getNumEntries(int max)
{
long count;
/* XXX - implement some form of caching ??? */
count = _expExpression_countEntries();
if ( count > _expExpression_MaxCount )
_expExpression_MaxCount = count;
return ( max ? _expExpression_MaxCount : count);
}