3
* Core implementation of the trigger handling behaviour
6
#include <net-snmp/net-snmp-config.h>
7
#include <net-snmp/net-snmp-includes.h>
8
#include <net-snmp/agent/net-snmp-agent-includes.h>
9
#include "disman/event/mteTrigger.h"
10
#include "disman/event/mteEvent.h"
12
netsnmp_tdata *trigger_table_data;
14
oid _sysUpTime_instance[] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
15
size_t _sysUpTime_inst_len = OID_LENGTH(_sysUpTime_instance);
17
long mteTriggerFailures;
20
* Initialize the container for the (combined) mteTrigger*Table,
21
* regardless of which table initialisation routine is called first.
25
init_trigger_table_data(void)
27
DEBUGMSGTL(("disman:event:init", "init trigger container\n"));
28
if (!trigger_table_data) {
29
trigger_table_data = netsnmp_tdata_create_table("mteTriggerTable", 0);
30
if (!trigger_table_data) {
31
snmp_log(LOG_ERR, "failed to create mteTriggerTable");
34
DEBUGMSGTL(("disman:event:init", "create trigger container (%x)\n",
37
mteTriggerFailures = 0;
41
/** Initializes the mteTrigger module */
45
init_trigger_table_data();
49
/* ===================================================
51
* APIs for maintaining the contents of the (combined)
52
* mteTrigger*Table container.
54
* =================================================== */
57
_mteTrigger_dump(void)
59
struct mteTrigger *entry;
60
netsnmp_tdata_row *row;
63
for (row = netsnmp_tdata_row_first(trigger_table_data);
65
row = netsnmp_tdata_row_next(trigger_table_data, row)) {
66
entry = (struct mteTrigger *)row->data;
67
DEBUGMSGTL(("disman:event:dump", "TriggerTable entry %d: ", i));
68
DEBUGMSGOID(("disman:event:dump", row->oid_index.oids, row->oid_index.len));
69
DEBUGMSG(("disman:event:dump", "(%s, %s)",
70
row->indexes->val.string,
71
row->indexes->next_variable->val.string));
72
DEBUGMSG(("disman:event:dump", ": %x, %x\n", row, entry));
75
DEBUGMSGTL(("disman:event:dump", "TriggerTable %d entries\n", i));
80
* Create a new row in the trigger table
83
mteTrigger_createEntry(char *mteOwner, char *mteTName, int fixed)
85
struct mteTrigger *entry;
86
netsnmp_tdata_row *row;
87
size_t mteOwner_len = (mteOwner) ? strlen(mteOwner) : 0;
88
size_t mteTName_len = (mteTName) ? strlen(mteTName) : 0;
90
DEBUGMSGTL(("disman:event:table", "Create trigger entry (%s, %s)\n",
93
* Create the mteTrigger entry, and the
94
* (table-independent) row wrapper structure...
96
entry = SNMP_MALLOC_TYPEDEF(struct mteTrigger);
100
row = netsnmp_tdata_create_row();
108
* ... initialize this row with the indexes supplied
109
* and the default values for the row...
112
memcpy(entry->mteOwner, mteOwner, mteOwner_len);
113
netsnmp_table_row_add_index(row, ASN_OCTET_STR,
114
entry->mteOwner, mteOwner_len);
116
memcpy(entry->mteTName, mteTName, mteTName_len);
117
netsnmp_table_row_add_index(row, ASN_PRIV_IMPLIED_OCTET_STR,
118
entry->mteTName, mteTName_len);
120
/* entry->mteTriggerTest = MTE_TRIGGER_BOOLEAN; */
121
entry->mteTriggerValueID_len = 2; /* .0.0 */
122
entry->mteTriggerFrequency = 600;
123
memcpy(entry->mteDeltaDiscontID, _sysUpTime_instance,
124
sizeof(_sysUpTime_instance));
125
entry->mteDeltaDiscontID_len = _sysUpTime_inst_len;
126
entry->mteDeltaDiscontIDType = MTE_DELTAD_TTICKS;
127
entry->flags |= MTE_TRIGGER_FLAG_SYSUPT;
128
entry->mteTExTest = (MTE_EXIST_PRESENT | MTE_EXIST_ABSENT);
129
entry->mteTExStartup = (MTE_EXIST_PRESENT | MTE_EXIST_ABSENT);
130
entry->mteTBoolComparison = MTE_BOOL_UNEQUAL;
131
entry->flags |= MTE_TRIGGER_FLAG_BSTART;
132
entry->mteTThStartup = MTE_THRESH_START_RISEFALL;
135
entry->flags |= MTE_TRIGGER_FLAG_FIXED;
138
* ... and insert the row into the (common) table container
140
netsnmp_tdata_add_row(trigger_table_data, row);
141
DEBUGMSGTL(("disman:event:table", "Trigger entry created\n"));
146
* Remove a row from the trigger table
149
mteTrigger_removeEntry(netsnmp_tdata_row *row)
151
struct mteTrigger *entry;
154
return; /* Nothing to remove */
155
entry = (struct mteTrigger *)
156
netsnmp_tdata_remove_and_delete_row(trigger_table_data, row);
158
mteTrigger_disable( entry );
163
/* ===================================================
165
* APIs for evaluating a trigger,
166
* and firing the appropriate event
168
* =================================================== */
169
const char *_ops[] = { "",
170
"!=", /* MTE_BOOL_UNEQUAL */
171
"==", /* MTE_BOOL_EQUAL */
172
"<", /* MTE_BOOL_LESS */
173
"<=", /* MTE_BOOL_LESSEQUAL */
174
">", /* MTE_BOOL_GREATER */
175
">=" /* MTE_BOOL_GREATEREQUAL */ };
178
_mteTrigger_failure( /* int error, */ const char *msg )
181
* XXX - Send an mteTriggerFailure trap
182
* (if configured to do so)
184
mteTriggerFailures++;
185
snmp_log(LOG_ERR, "%s\n", msg );
190
mteTrigger_run( unsigned int reg, void *clientarg)
192
struct mteTrigger *entry = (struct mteTrigger *)clientarg;
193
netsnmp_variable_list *var, *vtmp;
194
netsnmp_variable_list *vp1, *vp1_prev;
195
netsnmp_variable_list *vp2, *vp2_prev;
196
netsnmp_variable_list *dvar = NULL;
197
netsnmp_variable_list *dv1 = NULL, *dv2 = NULL;
198
netsnmp_variable_list sysUT_var;
204
snmp_alarm_unregister( reg );
207
if (!(entry->flags & MTE_TRIGGER_FLAG_ENABLED ) ||
208
!(entry->flags & MTE_TRIGGER_FLAG_ACTIVE ) ||
209
!(entry->flags & MTE_TRIGGER_FLAG_VALID )) {
214
* Retrieve the requested MIB value(s)...
216
DEBUGMSGTL(( "disman:event:trigger:monitor", "Running trigger (%s)\n", entry->mteTName));
217
var = (netsnmp_variable_list *)SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
219
_mteTrigger_failure("failed to create mteTrigger query varbind");
222
snmp_set_var_objid( var, entry->mteTriggerValueID,
223
entry->mteTriggerValueID_len );
224
if ( entry->flags & MTE_TRIGGER_FLAG_VWILD ) {
225
n = netsnmp_query_walk( var, entry->session );
227
n = netsnmp_query_get( var, entry->session );
229
if ( n != SNMP_ERR_NOERROR ) {
230
DEBUGMSGTL(( "disman:event:trigger:monitor", "Trigger query (%s) failed: %d\n",
231
(( entry->flags & MTE_TRIGGER_FLAG_VWILD ) ? "walk" : "get"), n));
232
_mteTrigger_failure( "failed to run mteTrigger query" );
237
* ... canonicalise the results (to simplify later comparisons)...
240
vp1 = var; vp1_prev = NULL;
241
vp2 = entry->old_results; vp2_prev = NULL;
245
* Flatten various missing values/exceptions into a single form
248
case SNMP_NOSUCHINSTANCE:
249
case SNMP_NOSUCHOBJECT:
250
case ASN_PRIV_RETRY: /* Internal only ? */
251
vp1->type = ASN_NULL;
254
* Keep track of how many entries have been retrieved.
259
* Ensure previous and current result match
260
* (with corresponding entries in both lists)
261
* and set the flags indicating which triggers are armed
264
cmp = snmp_oid_compare(vp1->name, vp1->name_length,
265
vp2->name, vp2->name_length);
268
* If a new value has appeared, insert a matching
269
* dummy entry into the previous result list.
271
* XXX - check how this is best done.
273
vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
276
"failed to create mteTrigger temp varbind");
279
vtmp->type = ASN_NULL;
280
snmp_set_var_objid( vtmp, vp1->name, vp1->name_length );
281
vtmp->next_variable = vp2;
283
vp2_prev->next_variable = vtmp;
285
entry->old_results = vtmp;
288
vp1->index = MTE_ARMED_ALL; /* XXX - plus a new flag */
290
vp1 = vp1->next_variable;
292
else if ( cmp == 0 ) {
294
* If it's a continuing entry, just copy across the armed flags
296
vp1->index = vp2->index;
298
vp1 = vp1->next_variable;
300
vp2 = vp2->next_variable;
303
* If a value has just disappeared, insert a
304
* matching dummy entry into the current result list.
306
* XXX - check how this is best done.
309
if ( vp2->type != ASN_NULL ) {
310
vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
313
"failed to create mteTrigger temp varbind");
316
vtmp->type = ASN_NULL;
317
snmp_set_var_objid( vtmp, vp2->name, vp2->name_length );
318
vtmp->next_variable = vp1;
320
vp1_prev->next_variable = vtmp;
322
entry->old_results = vtmp;
326
vp2 = vp2->next_variable;
329
* But only if this entry has *just* disappeared. If the
330
* entry from the last run was a dummy too, then remove it.
331
* (leaving vp2_prev unchanged)
335
vp2_prev->next_variable = vp2->next_variable;
337
entry->old_results = vp2->next_variable;
339
vp2 = vp2->next_variable;
340
vtmp->next_variable = NULL;
341
snmp_free_varbind( vtmp );
346
* No more old results to compare.
347
* Either all remaining values have only just been created ...
348
* (and we need to create dummy 'old' entries for them)
351
vtmp = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
354
"failed to create mteTrigger temp varbind");
357
vtmp->type = ASN_NULL;
358
snmp_set_var_objid( vtmp, vp1->name, vp1->name_length );
359
vtmp->next_variable = vp2_prev->next_variable;
360
vp2_prev->next_variable = vtmp;
364
* ... or this is the first run through
365
* (and there were no old results at all)
367
* In either case, mark the current entry as armed and new.
368
* Note that we no longer need to maintain 'vp1_prev'
370
vp1->index = MTE_ARMED_ALL; /* XXX - plus a new flag */
371
vp1 = vp1->next_variable;
376
* ... and then work through these result(s), deciding
377
* whether or not to trigger the corresponding event.
379
* Note that there's no point in evaluating Existence or
380
* Boolean tests if there's no corresponding event.
381
* (Even if the trigger matched, nothing would be done anyway).
383
if ((entry->mteTriggerTest & MTE_TRIGGER_EXISTENCE) &&
384
(entry->mteTExEvent[0] != '\0' )) {
386
* If we don't have a record of previous results,
387
* this must be the first time through, so consider
388
* the mteTriggerExistenceStartup tests.
390
if ( !entry->old_results ) {
392
* With the 'present(0)' test, the trigger should fire
393
* for each value in the varbind list returned
394
* (whether the monitored value is wildcarded or not).
396
if (entry->mteTExTest & entry->mteTExStartup & MTE_EXIST_PRESENT) {
397
for (vp1 = var; vp1; vp1=vp1->next_variable) {
398
DEBUGMSGTL(( "disman:event:trigger:fire",
399
"Firing initial existence test: "));
400
DEBUGMSGOID(("disman:event:trigger:fire",
401
vp1->name, vp1->name_length));
402
DEBUGMSG(( "disman:event:trigger:fire",
404
entry->mteTriggerXOwner = entry->mteTExObjOwner;
405
entry->mteTriggerXObjects = entry->mteTExObjects;
406
entry->mteTriggerFired = vp1;
407
n = entry->mteTriggerValueID_len;
408
mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent,
409
entry, vp1->name+n, vp1->name_length-n);
413
* An initial 'absent(1)' test only makes sense when
414
* monitoring a non-wildcarded OID (how would we know
415
* which rows of the table "ought" to exist, but don't?)
417
if (entry->mteTExTest & entry->mteTExStartup & MTE_EXIST_ABSENT) {
418
if (!(entry->flags & MTE_TRIGGER_FLAG_VWILD) &&
419
vp1->type == ASN_NULL ) {
420
DEBUGMSGTL(( "disman:event:trigger:fire",
421
"Firing initial existence test: "));
422
DEBUGMSGOID(("disman:event:trigger:fire",
423
var->name, var->name_length));
424
DEBUGMSG(( "disman:event:trigger:fire",
426
entry->mteTriggerXOwner = entry->mteTExObjOwner;
427
entry->mteTriggerXObjects = entry->mteTExObjects;
429
* It's unclear what value the 'mteHotValue' payload
430
* should take when a monitored instance does not
431
* exist on startup. The only sensible option is
432
* to report a NULL value, but this clashes with
433
* the syntax of the mteHotValue MIB object.
435
entry->mteTriggerFired = vp1;
436
n = entry->mteTriggerValueID_len;
437
mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent,
438
entry, vp1->name+n, vp1->name_length-n);
443
* Otherwise, compare the current set of results with
444
* the previous ones, looking for changes. We can
445
* assume that the two lists match (see above).
448
for (vp1 = var, vp2 = entry->old_results;
450
vp1=vp1->next_variable, vp2=vp2->next_variable) {
452
/* Use this field to indicate that the trigger should fire */
453
entry->mteTriggerFired = NULL;
456
if ((entry->mteTExTest & MTE_EXIST_PRESENT) &&
457
(vp1->type != ASN_NULL) &&
458
(vp2->type == ASN_NULL)) {
459
/* A new instance has appeared */
460
entry->mteTriggerFired = vp1;
461
reason = "(present)";
463
} else if ((entry->mteTExTest & MTE_EXIST_ABSENT) &&
464
(vp1->type == ASN_NULL) &&
465
(vp2->type != ASN_NULL)) {
468
* A previous instance has disappeared.
470
* It's unclear what value the 'mteHotValue' payload
471
* should take when this happens - the previous
472
* value (vp2), or a NULL value (vp1) ?
473
* NULL makes more sense logically, but clashes
474
* with the syntax of the mteHotValue MIB object.
476
entry->mteTriggerFired = vp2;
479
} else if ((entry->mteTExTest & MTE_EXIST_CHANGED) &&
480
((vp1->val_len != vp2->val_len) ||
481
(memcmp( vp1->val.string, vp2->val.string,
482
vp1->val_len) != 0 ))) {
484
* This comparison detects changes in *any* type
485
* of value, numeric or string (or even OID).
487
* Unfortunately, the default 'mteTriggerFired'
488
* notification payload can't report non-numeric
489
* changes properly (see syntax of 'mteHotValue')
491
entry->mteTriggerFired = vp1;
492
reason = "(changed)";
494
if ( entry->mteTriggerFired ) {
496
* One of the above tests has matched,
497
* so fire the trigger.
499
DEBUGMSGTL(( "disman:event:trigger:fire",
500
"Firing existence test: "));
501
DEBUGMSGOID(("disman:event:trigger:fire",
502
vp1->name, vp1->name_length));
503
DEBUGMSG(( "disman:event:trigger:fire",
505
entry->mteTriggerXOwner = entry->mteTExObjOwner;
506
entry->mteTriggerXObjects = entry->mteTExObjects;
507
n = entry->mteTriggerValueID_len;
508
mteEvent_fire(entry->mteTExEvOwner, entry->mteTExEvent,
509
entry, vp1->name+n, vp1->name_length-n);
512
} /* !old_results - end of else block */
513
} /* MTE_TRIGGER_EXISTENCE */
516
if (( entry->mteTriggerTest & MTE_TRIGGER_BOOLEAN ) ||
517
( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD )) {
519
* Although Existence tests can work with any syntax values,
520
* Boolean and Threshold tests are integer-only. Ensure that
521
* the returned value(s) are appropriate.
523
* Note that we only need to check the first value, since all
524
* instances of a given object should have the same syntax.
533
#ifdef OPAQUE_SPECIAL_TYPES
534
case ASN_OPAQUE_COUNTER64:
542
* Other syntax values can't be used for Boolean/Theshold
543
* tests. Report this as an error, and then rotate the
544
* results ready for the next run, (which will presumably
545
* also detect this as an error once again!)
547
DEBUGMSGTL(( "disman:event:trigger:fire",
548
"Returned non-integer result(s): "));
549
DEBUGMSGOID(("disman:event:trigger:fire",
550
var->name, var->name_length));
551
DEBUGMSG(( "disman:event:trigger:fire",
552
" (boolean/threshold) %d\n", var->type));;
553
snmp_free_varbind( entry->old_results );
554
entry->old_results = var;
560
* Retrieve the discontinuity markers for delta-valued samples.
561
* (including sysUpTime.0 if not specified explicitly).
563
if ( entry->flags & MTE_TRIGGER_FLAG_DELTA ) {
565
* We'll need sysUpTime.0 regardless...
567
DEBUGMSGTL(("disman:event:delta", "retrieve sysUpTime.0\n"));
568
memset( &sysUT_var, 0, sizeof( netsnmp_variable_list ));
569
snmp_set_var_objid( &sysUT_var, _sysUpTime_instance,
570
_sysUpTime_inst_len );
571
netsnmp_query_get( &sysUT_var, entry->session );
573
if (!(entry->flags & MTE_TRIGGER_FLAG_SYSUPT)) {
575
* ... but only retrieve the configured discontinuity
576
* marker(s) if they refer to something different.
578
DEBUGMSGTL(( "disman:event:delta",
579
"retrieve discontinuity marker(s): "));
580
DEBUGMSGOID(("disman:event:delta", entry->mteDeltaDiscontID,
581
entry->mteDeltaDiscontID_len ));
582
DEBUGMSG(( "disman:event:delta", " %s\n",
583
(entry->flags & MTE_TRIGGER_FLAG_DWILD ? " (wild)" : "")));
585
dvar = (netsnmp_variable_list *)
586
SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
589
"failed to create mteTrigger delta query varbind");
592
snmp_set_var_objid( dvar, entry->mteDeltaDiscontID,
593
entry->mteDeltaDiscontID_len );
594
if ( entry->flags & MTE_TRIGGER_FLAG_DWILD ) {
595
netsnmp_query_walk( dvar, entry->session );
597
netsnmp_query_get( dvar, entry->session );
599
if ( n != SNMP_ERR_NOERROR ) {
600
_mteTrigger_failure( "failed to run mteTrigger delta query" );
601
snmp_free_varbind( dvar );
607
* We can't calculate delta values the first time through,
608
* so there's no point in evaluating the remaining tests.
610
* Save the results (and discontinuity markers),
611
* ready for the next run.
613
if ( !entry->old_results ) {
614
entry->old_results = var;
615
entry->old_deltaDs = dvar;
616
entry->sysUpTime = *sysUT_var.val.integer;
620
* If the sysUpTime marker has been reset (or strictly,
621
* has advanced by less than the monitor frequency),
622
* there's no point in trying the remaining tests.
625
if (*sysUT_var.val.integer < entry->sysUpTime) {
626
DEBUGMSGTL(( "disman:event:delta",
627
"single discontinuity: (sysUT)\n"));
628
snmp_free_varbind( entry->old_results );
629
snmp_free_varbind( entry->old_deltaDs );
630
entry->old_results = var;
631
entry->old_deltaDs = dvar;
632
entry->sysUpTime = *sysUT_var.val.integer;
636
* Similarly if a separate (non-wildcarded) discontinuity
637
* marker has changed, then there's no
638
* point in trying to evaluate these tests either.
640
if (!(entry->flags & MTE_TRIGGER_FLAG_DWILD) &&
641
!(entry->flags & MTE_TRIGGER_FLAG_SYSUPT) &&
642
(!entry->old_deltaDs ||
643
(entry->old_deltaDs->val.integer != dvar->val.integer))) {
644
DEBUGMSGTL(( "disman:event:delta", "single discontinuity: ("));
645
DEBUGMSGOID(( "disman:event:delta", entry->mteDeltaDiscontID,
646
entry->mteDeltaDiscontID_len));
647
DEBUGMSG(( "disman:event:delta", ")\n"));
648
snmp_free_varbind( entry->old_results );
649
snmp_free_varbind( entry->old_deltaDs );
650
entry->old_results = var;
651
entry->old_deltaDs = dvar;
652
entry->sysUpTime = *sysUT_var.val.integer;
657
* Ensure that the list of (wildcarded) discontinuity
658
* markers matches the list of monitored values
659
* (inserting/removing discontinuity varbinds as needed)
661
* XXX - An alternative approach would be to use the list
662
* of monitored values (instance subidentifiers) to build
663
* the exact list of delta markers to retrieve earlier.
665
if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
669
n = entry->mteTriggerValueID_len;
670
n2 = entry->mteDeltaDiscontID_len;
673
* For each monitored instance, check whether
674
* there's a matching discontinuity entry.
676
cmp = snmp_oid_compare(vp1->name+n, vp1->name_length-n,
677
vp2->name+n2, vp2->name_length-n2 );
680
* If a discontinuity entry is missing,
681
* insert a (dummy) varbind.
682
* The corresponding delta calculation will
683
* fail, but this simplifies the later code.
685
vtmp = (netsnmp_variable_list *)
686
SNMP_MALLOC_TYPEDEF( netsnmp_variable_list );
689
"failed to create mteTrigger discontinuity varbind");
692
snmp_set_var_objid(vtmp, entry->mteDeltaDiscontID,
693
entry->mteDeltaDiscontID_len);
694
/* XXX - append instance subids */
695
vtmp->next_variable = vp2;
696
vp2_prev->next_variable = vtmp;
698
vp1 = vp1->next_variable;
699
} else if ( cmp == 0 ) {
701
* Matching discontinuity entry - all OK.
704
vp2 = vp2->next_variable;
705
vp1 = vp1->next_variable;
708
* Remove unneeded discontinuity entry
711
vp2_prev->next_variable = vp2->next_variable;
712
vp2 = vp2->next_variable;
713
vtmp->next_variable = NULL;
714
snmp_free_varbind( vtmp );
718
* XXX - Now need to ensure that the old list of
719
* delta discontinuity markers matches as well.
722
} /* delta samples */
723
} /* Boolean/Threshold test checks */
728
* Only run the Boolean tests if there's an event to be triggered
730
if ((entry->mteTriggerTest & MTE_TRIGGER_BOOLEAN) &&
731
(entry->mteTBoolEvent[0] != '\0' )) {
733
if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
734
vp2 = entry->old_results;
735
if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
737
dv2 = entry->old_deltaDs;
740
for ( vp1 = var; vp1; vp1=vp1->next_variable ) {
742
* Determine the value to be monitored...
744
if ( !vp1->val.integer ) { /* No value */
746
vp2 = vp2->next_variable;
749
if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
750
if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
752
* We've already checked any non-wildcarded
753
* discontinuity markers (inc. sysUpTime.0).
754
* Validate this particular sample against
755
* the relevant wildcarded marker...
757
if ((dv1->type == ASN_NULL) ||
758
(dv1->type != dv2->type) ||
759
(*dv1->val.integer != *dv2->val.integer)) {
761
* Bogus or changed discontinuity marker.
762
* Need to skip this sample.
764
DEBUGMSGTL(( "disman:event:delta", "discontinuity occurred: "));
765
DEBUGMSGOID(("disman:event:delta", vp1->name,
767
DEBUGMSG(( "disman:event:delta", " \n" ));
768
vp2 = vp2->next_variable;
773
* ... and check there is a previous sample to calculate
774
* the delta value against (regardless of whether the
775
* discontinuity marker was wildcarded or not).
777
if (vp2->type == ASN_NULL) {
778
DEBUGMSGTL(( "disman:event:delta", "missing sample: "));
779
DEBUGMSGOID(("disman:event:delta", vp1->name,
781
DEBUGMSG(( "disman:event:delta", " \n" ));
782
vp2 = vp2->next_variable;
785
value = (*vp1->val.integer - *vp2->val.integer);
786
DEBUGMSGTL(( "disman:event:delta", "delta sample: "));
787
DEBUGMSGOID(("disman:event:delta", vp1->name,
789
DEBUGMSG(( "disman:event:delta", " (%d - %d) = %d\n",
790
*vp1->val.integer, *vp2->val.integer, value));
791
vp2 = vp2->next_variable;
793
value = *vp1->val.integer;
797
* ... evaluate the comparison ...
799
switch (entry->mteTBoolComparison) {
800
case MTE_BOOL_UNEQUAL:
801
cmp = ( value != entry->mteTBoolValue );
804
cmp = ( value == entry->mteTBoolValue );
807
cmp = ( value < entry->mteTBoolValue );
809
case MTE_BOOL_LESSEQUAL:
810
cmp = ( value <= entry->mteTBoolValue );
812
case MTE_BOOL_GREATER:
813
cmp = ( value > entry->mteTBoolValue );
815
case MTE_BOOL_GREATEREQUAL:
816
cmp = ( value >= entry->mteTBoolValue );
819
DEBUGMSGTL(( "disman:event:delta", "Bool comparison: (%d %s %d) %d\n",
820
value, _ops[entry->mteTBoolComparison],
821
entry->mteTBoolValue, cmp));
824
* ... and decide whether to trigger the event.
825
* (using the 'index' field of the varbind structure
826
* to remember whether the trigger has already fired)
829
if ((entry->old_results ||
830
(entry->flags & MTE_TRIGGER_FLAG_BSTART)) &&
831
(vp1->index & MTE_ARMED_BOOLEAN )) {
832
DEBUGMSGTL(( "disman:event:trigger:fire",
833
"Firing boolean test: "));
834
DEBUGMSGOID(("disman:event:trigger:fire",
835
vp1->name, vp1->name_length));
836
DEBUGMSG(( "disman:event:trigger:fire", "%s\n",
837
(entry->old_results ? "" : " (startup)")));
838
vp1->index &= ~MTE_ARMED_BOOLEAN;
839
entry->mteTriggerXOwner = entry->mteTBoolObjOwner;
840
entry->mteTriggerXObjects = entry->mteTBoolObjects;
842
* XXX - when firing a delta-based trigger, should
843
* 'mteHotValue' report the actual value sampled
844
* (as here), or the delta that triggered the event ?
846
entry->mteTriggerFired = vp1;
847
n = entry->mteTriggerValueID_len;
848
mteEvent_fire(entry->mteTBoolEvOwner, entry->mteTBoolEvent,
849
entry, vp1->name+n, vp1->name_length-n);
852
vp1->index |= MTE_ARMED_BOOLEAN;
859
* Only run the basic threshold tests if there's an event to
860
* be triggered. (Either rising or falling will do)
862
if (( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD ) &&
863
((entry->mteTThRiseEvent[0] != '\0' ) ||
864
(entry->mteTThFallEvent[0] != '\0' ))) {
867
* The same delta-sample validation from Boolean
868
* tests also applies here too.
870
if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
871
vp2 = entry->old_results;
872
if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
874
dv2 = entry->old_deltaDs;
877
for ( vp1 = var; vp1; vp1=vp1->next_variable ) {
879
* Determine the value to be monitored...
881
if ( !vp1->val.integer ) { /* No value */
883
vp2 = vp2->next_variable;
886
if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
887
if (entry->flags & MTE_TRIGGER_FLAG_DWILD) {
889
* We've already checked any non-wildcarded
890
* discontinuity markers (inc. sysUpTime.0).
891
* Validate this particular sample against
892
* the relevant wildcarded marker...
894
if ((dv1->type == ASN_NULL) ||
895
(dv1->type != dv2->type) ||
896
(*dv1->val.integer != *dv2->val.integer)) {
898
* Bogus or changed discontinuity marker.
899
* Need to skip this sample.
901
vp2 = vp2->next_variable;
906
* ... and check there is a previous sample to calculate
907
* the delta value against (regardless of whether the
908
* discontinuity marker was wildcarded or not).
910
if (vp2->type == ASN_NULL) {
911
vp2 = vp2->next_variable;
914
value = (*vp1->val.integer - *vp2->val.integer);
915
vp2 = vp2->next_variable;
917
value = *vp1->val.integer;
921
* ... evaluate the single-value comparisons,
922
* and decide whether to trigger the event.
924
cmp = vp1->index; /* working copy of 'armed' flags */
925
if ( value >= entry->mteTThRiseValue ) {
926
if ((entry->old_results ||
927
(entry->mteTThStartup & MTE_THRESH_START_RISE)) &&
928
(vp1->index & MTE_ARMED_TH_RISE )) {
929
DEBUGMSGTL(( "disman:event:trigger:fire",
930
"Firing rising threshold test: "));
931
DEBUGMSGOID(("disman:event:trigger:fire",
932
vp1->name, vp1->name_length));
933
DEBUGMSG(( "disman:event:trigger:fire", "%s\n",
934
(entry->old_results ? "" : " (startup)")));
935
cmp &= ~MTE_ARMED_TH_RISE;
936
cmp |= MTE_ARMED_TH_FALL;
938
* If no riseEvent is configured, we need still to
939
* set the armed flags appropriately, but there's
940
* no point in trying to fire the (missing) event.
942
if (entry->mteTThRiseEvent[0] != '\0' ) {
943
entry->mteTriggerXOwner = entry->mteTThObjOwner;
944
entry->mteTriggerXObjects = entry->mteTThObjects;
945
entry->mteTriggerFired = vp1;
946
n = entry->mteTriggerValueID_len;
947
mteEvent_fire(entry->mteTThRiseOwner,
948
entry->mteTThRiseEvent,
949
entry, vp1->name+n, vp1->name_length-n);
954
if ( value <= entry->mteTThFallValue ) {
955
if ((entry->old_results ||
956
(entry->mteTThStartup & MTE_THRESH_START_FALL)) &&
957
(vp1->index & MTE_ARMED_TH_FALL )) {
958
DEBUGMSGTL(( "disman:event:trigger:fire",
959
"Firing falling threshold test: "));
960
DEBUGMSGOID(("disman:event:trigger:fire",
961
vp1->name, vp1->name_length));
962
DEBUGMSG(( "disman:event:trigger:fire", "%s\n",
963
(entry->old_results ? "" : " (startup)")));
964
cmp &= ~MTE_ARMED_TH_FALL;
965
cmp |= MTE_ARMED_TH_RISE;
967
* Similarly, if no fallEvent is configured,
968
* there's no point in trying to fire it either.
970
if (entry->mteTThRiseEvent[0] != '\0' ) {
971
entry->mteTriggerXOwner = entry->mteTThObjOwner;
972
entry->mteTriggerXObjects = entry->mteTThObjects;
973
entry->mteTriggerFired = vp1;
974
n = entry->mteTriggerValueID_len;
975
mteEvent_fire(entry->mteTThFallOwner,
976
entry->mteTThFallEvent,
977
entry, vp1->name+n, vp1->name_length-n);
986
* The same processing also works for delta-threshold tests (if configured)
988
if (( entry->mteTriggerTest & MTE_TRIGGER_THRESHOLD ) &&
989
((entry->mteTThDRiseEvent[0] != '\0' ) ||
990
(entry->mteTThDFallEvent[0] != '\0' ))) {
993
* Delta-threshold tests can only be used with
994
* absolute valued samples.
996
vp2 = entry->old_results;
997
if (entry->flags & MTE_TRIGGER_FLAG_DELTA) {
998
DEBUGMSGTL(( "disman:event:trigger",
999
"Delta-threshold on delta-sample\n"));
1000
} else if ( vp2 != NULL ) {
1001
for ( vp1 = var; vp1; vp1=vp1->next_variable ) {
1003
* Determine the value to be monitored...
1004
* (similar to previous delta-sample processing,
1005
* but without the discontinuity marker checks)
1008
break; /* Run out of 'old' values */
1010
if (( !vp1->val.integer ) ||
1011
(vp2->type == ASN_NULL)) {
1012
vp2 = vp2->next_variable;
1015
value = (*vp1->val.integer - *vp2->val.integer);
1016
vp2 = vp2->next_variable;
1019
* ... evaluate the single-value comparisons,
1020
* and decide whether to trigger the event.
1022
cmp = vp1->index; /* working copy of 'armed' flags */
1023
if ( value >= entry->mteTThDRiseValue ) {
1024
if (vp1->index & MTE_ARMED_TH_DRISE ) {
1025
DEBUGMSGTL(( "disman:event:trigger:fire",
1026
"Firing rising delta threshold test: "));
1027
DEBUGMSGOID(("disman:event:trigger:fire",
1028
vp1->name, vp1->name_length));
1029
DEBUGMSG(( "disman:event:trigger:fire", "\n"));
1030
cmp &= ~MTE_ARMED_TH_DRISE;
1031
cmp |= MTE_ARMED_TH_DFALL;
1033
* If no riseEvent is configured, we need still to
1034
* set the armed flags appropriately, but there's
1035
* no point in trying to fire the (missing) event.
1037
if (entry->mteTThDRiseEvent[0] != '\0' ) {
1038
entry->mteTriggerXOwner = entry->mteTThObjOwner;
1039
entry->mteTriggerXObjects = entry->mteTThObjects;
1040
entry->mteTriggerFired = vp1;
1041
n = entry->mteTriggerValueID_len;
1042
mteEvent_fire(entry->mteTThDRiseOwner,
1043
entry->mteTThDRiseEvent,
1044
entry, vp1->name+n, vp1->name_length-n);
1049
if ( value <= entry->mteTThDFallValue ) {
1050
if (vp1->index & MTE_ARMED_TH_DFALL ) {
1051
DEBUGMSGTL(( "disman:event:trigger:fire",
1052
"Firing falling delta threshold test: "));
1053
DEBUGMSGOID(("disman:event:trigger:fire",
1054
vp1->name, vp1->name_length));
1055
DEBUGMSG(( "disman:event:trigger:fire", "\n"));
1056
cmp &= ~MTE_ARMED_TH_DFALL;
1057
cmp |= MTE_ARMED_TH_DRISE;
1059
* Similarly, if no fallEvent is configured,
1060
* there's no point in trying to fire it either.
1062
if (entry->mteTThDRiseEvent[0] != '\0' ) {
1063
entry->mteTriggerXOwner = entry->mteTThObjOwner;
1064
entry->mteTriggerXObjects = entry->mteTThObjects;
1065
entry->mteTriggerFired = vp1;
1066
n = entry->mteTriggerValueID_len;
1067
mteEvent_fire(entry->mteTThDFallOwner,
1068
entry->mteTThDFallEvent,
1069
entry, vp1->name+n, vp1->name_length-n);
1079
* Finally, rotate the results - ready for the next run.
1081
snmp_free_varbind( entry->old_results );
1082
entry->old_results = var;
1083
if ( entry->flags & MTE_TRIGGER_FLAG_DELTA ) {
1084
snmp_free_varbind( entry->old_deltaDs );
1085
entry->old_deltaDs = dvar;
1086
entry->sysUpTime = *sysUT_var.val.integer;
1091
mteTrigger_enable( struct mteTrigger *entry )
1097
/* XXX - or explicitly call mteTrigger_disable ?? */
1098
snmp_alarm_unregister( entry->alarm );
1102
if (entry->mteTriggerFrequency) {
1104
* register once to run ASAP, and another to run
1105
* at the trigger frequency
1107
snmp_alarm_register(0, 0, mteTrigger_run, entry );
1108
entry->alarm = snmp_alarm_register(
1109
entry->mteTriggerFrequency, SA_REPEAT,
1110
mteTrigger_run, entry );
1115
mteTrigger_disable( struct mteTrigger *entry )
1121
snmp_alarm_unregister( entry->alarm );
1123
/* XXX - perhaps release any previous results */
1127
long _mteTrigger_MaxCount = 0;
1128
long _mteTrigger_countEntries(void)
1130
struct mteTrigger *entry;
1131
netsnmp_tdata_row *row;
1134
for (row = netsnmp_tdata_row_first(trigger_table_data);
1136
row = netsnmp_tdata_row_next(trigger_table_data, row)) {
1137
entry = (struct mteTrigger *)row->data;
1138
count += entry->count;
1144
long mteTrigger_getNumEntries(int max)
1147
/* XXX - implement some form of caching ??? */
1148
count = _mteTrigger_countEntries();
1149
if ( count > _mteTrigger_MaxCount )
1150
_mteTrigger_MaxCount = count;
1152
return ( max ? _mteTrigger_MaxCount : count);