[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
TimeFilter text (summary for review)
Hi,
We need to finish up the TimeFilter discussions so RMON-2 can
be republished, so that documents waiting for RFC 2021-bis can
move along.
Attached is the proposed TimeFilter TC (para 1) and complete
appendix section. Please send any comments to the list ASAP,
otherwise we will use this text in the next draft.
thanks,
Andy
TimeFilter TC: para 1:
OLD:
"To be used for the index to a table. Allows an application
to download only those rows changed since a particular time.
A row is considered changed if the value of any object in the
row changes or if the row is created or deleted.
NEW:
"To be used for the index to a table. Allows an application
to download only those rows changed since a particular time.
A row is considered changed if the value of any object in the
row changes, if the row is created, or if any object in the
row is created or deleted. Note that deleted rows cannot be
detected or downloaded."
--------------------------------------------------------------------
8. Appendix - TimeFilter Implementation Notes
1) Theory of Operation
The TimeFilter mechanism allows an NMS to reduce the number of
SNMP transactions required for a 'table-update' operation,
by retrieving only the rows that have changed since a specified
time (usually the last poll time). Polling of tables that
incorporate a 'TimeFilter' INDEX can be reduced to a theoretical
minimum (if used correctly). It can be easily implemented by an
agent in a way independent of the number of NMS applications using
the same time-filtered table.
Although the name 'TimeFilter' may imply that a history of
change events is maintained by the agent, this is not the
case. A time-filtered-value represents the current value of
the object instance, not the 'saved' value at the time
indicated by the TimeFilter INDEX value. Note that TimeFilter
objects only appear in INDEX clauses (always not-accessible),
so their value is never retrieved. By design, the actual value
of a TimeFilter instance is not in itself meaningful (it's not
a 'last-change-timestamp').
The TimeFilter is a boolean filtering function applied in
internal Get* PDU processing. If the 'last-change-time' of the
specified instance is less than the particular TimeFilter
INDEX value, then the instance is considered 'not-present',
and it is skipped for GetNext and GetBulk PDUs, or
a 'noSuchInstance' exception is returned for Get PDUs.
1.1) Agent Implementation of a Time-Filtered Table
In implementation, the time-filtered rows (one for each tick
of sysUpTime) are only conceptual. The agent simply filters a
real table based on:
* the current value of sysUpTime
* the TimeFilter value passed in the varbind
* the last-update timestamp of each requested row
(agent implementation requirement)
For example, to implement a time-filtered table row
(e.g., set of counters), an agent maintains a timestamp
in a 32-bit storage location, initialized to zero. This
is in addition to whatever instrumentation is needed for
the set of counters.
Each time one of the counters is updated, the current value of
sysUpTime is recorded in the associated timestamp. If this is
not possible or practical, then a background polling process
must 'refresh' the timestamp by sampling counter values and
comparing them to recorded samples. The timestamp update must
occur within 5 seconds of the actual change event.
When an agent receives a Get, GetNext, or GetBulk PDU
requesting a time-filtered instance, after the agent has
determined that the instance is within the specified MIB view,
the following conceptual test is applied to determine if the
object is returned or filtered:
/* return TRUE if the object is present */
boolean time_filter_test (
TimeFilter last_modified_timestamp,
TimeFilter index_value_in_pdu )
{
if (last_modified_timestamp < index_value_in_pdu)
return FALSE;
else
return TRUE;
}
The agent applies this function regardless of the
lastActivationTime of the conceptual row in question. In other
words, counter discontinuities are ignored (i.e. conceptual
row deleted and then re-created later). An agent should
consider a object instance 'changed' when it is created
(either at restart time for scalars and static objects, or
row-creation-time for dynamic tables).
Note that using a timeFilter INDEX value of zero removes the
filtering functionality, as the instance will always be
'present' according to the test above.
After some deployment experience, it has been determined that a
time-filtered table is more efficient to use if the agent
stops a "MIB walk" operation after one time-filtered entry.
That is, a GetNext or GetBulk operation will provide one pass
through a given table, i.e., the agent will continue to the
next object or table, instead of incrementing a TimeMark INDEX
value, even if there exists higher TimeMark values which are
valid for the same conceptual row.
It is acceptable for an agent to implement a time-filtered table
in this manner, or in the traditional manner (i.e., every
conceptual time-filtered instance is returned in GetNext
and GetBulk PDU responses).
1.2) NMS Implementation of a Time-Filtered Table
The particular TimeFilter INDEX values used by an NMS reflect
the polling interval of the NMS, relative to the particular
agent's notion of sysUpTime.
An NMS needs to maintain one timestamp variable per agent
(initialized to zero) for an arbitrary group of time-filtered
MIB objects that are gathered together in the same PDU. Each
time the Get* PDU is sent, a request for sysUpTime is
included. The retrieved sysUpTime value is used as the
timeFilter value in the next polling cycle. If a polling sweep
of a time-filtered group of objects requires more than one
SNMP transaction, then the sysUpTime value retrieved in the
first GetResponse PDU of the polling sweep is saved as the
next timeFilter value.
The actual last-update time of a given object is not indicated
in the returned GetResponse instance identifier, but rather
the timeFilter value passed in the Get*Request PDU is
returned.
A "time-filtered get-next/bulk-sweep", done once per polling
cycle, is a series of GetNext or GetBulk transactions, and is
over when one of the following events occurs:
1) the TimeFilter index value returned in the GetResponse is
different than the TimeFilter index value passed in the
GetNext or GetBulk request. Counter values will still be
returned beyond this point (until the last-change-time is
reached), but most likely the same values will be
returned.
2) the return PDU includes instances lexigraphically greater
than the objects expected (i.e. same GetNext semantics as
if the TimeFilter wasn't there)
3) a noSuchName or other exception/error is returned.
Note that the use of a time-filtered table in combination with
a GetRequest PDU neutralizes any optimization that otherwise
might be achieved with the TimeFilter, because no PDU
transactions are saved. Either the current time-filtered
object-value is returned, or a 'noSuchInstance' exception
(SNMPv1c) or 'noSuchName' error (SNMPv1) is returned.
If GetBulk PDUs are used, then the value selected for response
PDUs generated by the agent, since duplicate entries (one per
'tick' of sysUpTime) are likely to pad the PDU to its maximum
size. An appropriate of conceptual rows in the time-filtered
table if known, or equal to the number of instances expected
to fit in a GetResponse PDU without causing a 'tooBig' error
from the agent.
2) TimeFilter Example
The following example demonstrates how an NMS and Agent might
use a table with a TimeFilter object in the INDEX. A static
table is assumed to keep the example simple, but dynamic
tables can also be supported.
2.1) General Assumptions
fooEntry INDEX { fooTimeMark, fooIfIndex }
FooEntry = SEQUENCE {
fooTimeMark TimeFilter,
fooIfIndex Integer32,
fooCounts Counter32
}
The NMS polls the fooTable every 15 seconds and the
baseline poll occurs when the agent has been up for
6 seconds, and the NMS has been up for 10 seconds.
There are 2 static rows in this table at system
initialization (fooCounts.0.1 and fooCounts.0.2).
Row 1 was updated as follows:
SysUpTime fooCounts.*.1 value
500 1
900 2
2300 3
Row 2 was updated as follows:
SysUpTime fooCounts.*.2 value
1100 1
1400 2
2.2) SNMP Transactions from NMS Perspective
Time nms-1000:
# NMS baseline poll -- get everything since last agent
# restart - TimeFilter == 0
get-bulk(nonRptrs=1, maxReps=2, sysUpTime.0,
fooCounts.0);
returns:
sysUpTime.0 == 600
fooCounts.0.1 == 1 # incremented at time 500
fooCounts.0.2 == 0 # visible; created at time 0
Time nms-2500:
# NMS 1st poll
# TimeFilter index == 600
get-bulk(nonRptrs=1, maxReps=2, sysUpTime.0,
fooCounts.600);
returns:
sysUpTime.0 == 2100
fooCounts.600.1 == 2 # incremented at time 900
fooCounts.600.2 == 2 # incremented at times
# 1100 and 1400
fooCounts.601.1 == 2 # indicates end of sweep
Time nms-4000:
# NMS 2nd poll
# TimeFilter == 2100
get-bulk(nonRptrs=1, maxReps=2, sysUpTime.0,
fooCounts.2100);
returns:
sysUpTime.0 == 3600
fooCounts.2100.1 == 3 # incremented at time 2300
fooCounts.2102.1 == 3 # indicates end-of-sweep
# the counter value for row 2 is not returned because
# it hasn't changed since sysUpTime == 2100.
# The next timetick value for row 1 is returned instead
Time nms-5500:
# NMS 3rd poll
# TimeFilter == 3600
get-bulk(nonRptrs=1, maxReps=2, sysUpTime.0,
fooCounts.3600);
returns:
sysUpTime.0 == 5100
some-instance-outside-the-fooTable == <don't care>
some-instance-outside-the-fooTable == <don't care>
# no 'fooTable' counter values at all are returned
# because neither counter has been updated since
# sysUpTime == 3600
2.3) Transactions and TimeFilter Maintenance: Agent
Perspective
Time agt-0:
# initialize fooTable
fooCounts.1 = 0; changed.1 = 0;
fooCounts.2 = 0; changed.2 = 0;
Time agt-500:
# increment fooCounts.1
++fooCounts.1; changed.1 = 500;
Time agt-600
# answer get-bulk
# get-bulk(nonRptrs=1, maxReps=2, sysUpTime.0,
# fooCounts.0);
# (changed >= 0)
# return both counters
Time agt-900:
# increment fooCounts.1
++fooCounts.1; changed.1 = 900;
Time agt-1100:
# increment fooCounts.2
++fooCounts.2; changed.2 = 1100;
Time agt-1400:
# increment fooCounts.2
++fooCounts.2; changed.2 = 1400;
Time agt-2100
# answer get-bulk
# get-bulk(nonRptrs=1, maxReps=2, sysUpTime.0,
# fooCounts.600);
# (changed >= 600)
# return both counters
Time agt-2300:
# increment fooCounts.1
++fooCounts.1; changed.1 = 2300;
Time agt-3600:
# answer get-bulk
# get-bulk(nonRptrs=1, maxReps=2, sysUpTime.0,
# fooCounts.2100);
# (changed >= 2100)
# return only fooCounts.1 from the fooTable--twice
Time agt-5100:
# answer get-bulk
# get-bulk(nonRptrs=1, maxReps=2, sysUpTime.0,
# fooCounts.3600);
# (changed >= 3600)
# return lexigraphically-next two MIB instances